diff -u --recursive --new-file v2.5.2/linux/CREDITS linux/CREDITS
--- v2.5.2/linux/CREDITS	Mon Jan 14 18:25:07 2002
+++ linux/CREDITS	Mon Jan 21 15:57:51 2002
@@ -588,6 +588,13 @@
 S: University of Michigan
 S: Ann Arbor, MI
 
+N: Michael Cornwell
+E: cornwell@acm.org
+D: Original designer and co-author of ATA Taskfile
+D: Kernel module SMART utilities
+S: Santa Cruz, California
+S: USA
+
 N: Kees Cook
 E: cook@cpoint.net
 W: http://outflux.net/
@@ -1186,22 +1193,19 @@
 
 N: Andre Hedrick
 E: andre@linux-ide.org
-E: andre@aslab.com
-E: andre@suse.com
+E: andre@linuxdiskcert.org
 W: http://www.linux-ide.org/
+W: http://www.linuxdiskcert.org/
 D: Random SMP kernel hacker...
 D: Uniform Multi-Platform E-IDE driver
 D: Active-ATA-Chipset maddness..........
-D: Ultra DMA 100/66/33
-D: ATA-Disconnect
+D: Ultra DMA 133/100/66/33 w/48-bit Addressing
+D: ATA-Disconnect, ATA-TCQ
 D: ATA-Smart Kernel Daemon
+D: Serial ATA
+D: ATA Command Block and Taskfile
 S: Linux ATA Development (LAD)
 S: Concord, CA
-S: ASL, Inc. 1-877-ASL-3535
-S: 1757 Houret Court, Milpitas, CA 95035
-S: SuSE Linux, Inc.
-S: 580 Second Street, Suite 210  Oakland, CA  94607
-S: USA
 
 N: Jochen Hein
 E: jochen@jochen.org
@@ -1277,6 +1281,13 @@
 D: bug toaster (A1 sauce makes all the difference)
 D: Random linux hacker
 
+N: Tim Hockin
+E: thockin@hockin.org
+W: http://www.hockin.org/~thockin
+D: Natsemi ethernet
+D: Cobalt Networks (x86) support
+D: This-and-That
+
 N: Dirk Hohndel
 E: hohndel@suse.de
 D: The XFree86[tm] Project
@@ -1447,11 +1458,10 @@
 
 N: Dave Jones
 E: davej@suse.de
-W: http://www.suse.de/~davej
-D: Moved PCI bridge tuning to userspace (Powertweak).
-D: Various x86 (& clones) setup code hacking.
-D: AFFS fixes for 2.3.x
-D: Various Janitorial hacks. (kernel-janitor.sourceforge.net)
+W: http://www.codemonkey.org.uk
+D: x86 errata/setup maintenance.
+D: Backport/Forwardport merge monkey.
+D: Various Janitor work.
 S: c/o SuSE Linux UK Ltd
 S: The Kinetic Centre
 S: Theobald Street
@@ -1656,6 +1666,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
@@ -1828,6 +1845,11 @@
 S: 00200 Helsinki
 S: Finland
 
+N: Daniel J. Maas
+E: dmaas@dcine.com
+W: http://www.maasdigital.com
+D: dv1394
+
 N: Hamish Macdonald
 E: hamishm@lucent.com
 D: Linux/68k port
@@ -2522,7 +2544,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 -u --recursive --new-file v2.5.2/linux/Documentation/Changes linux/Documentation/Changes
--- v2.5.2/linux/Documentation/Changes	Tue Dec 18 14:56:33 2001
+++ linux/Documentation/Changes	Wed Jan 23 23:57:47 2002
@@ -31,7 +31,7 @@
 Eine deutsche Version dieser Datei finden Sie unter
 <http://www.stefan-winter.de/Changes-2.4.0.txt>.
 
-Last updated: November 29, 2001
+Last updated: January 22, 2002
 
 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu).
 
@@ -50,10 +50,10 @@
 
 o  Gnu C                  2.95.3                  # gcc --version
 o  Gnu make               3.77                    # make --version
-o  binutils               2.9.5.0.24              # ld -v
+o  binutils               2.9.5.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
@@ -106,8 +106,8 @@
 your kernel.  This change does, however, mean that you need a recent
 release of binutils.
 
-System utils
-============
+System utililities
+==================
 
 Architectural changes
 ---------------------
@@ -261,8 +261,8 @@
 Getting updated software
 ========================
 
-Compilers
-*********
+Kernel compilation
+******************
 
 egcs 1.1.2 (gcc 2.91.66)
 ------------------------
@@ -272,15 +272,12 @@
 ----------
 o  <ftp://ftp.gnu.org/gnu/gcc/gcc-2.95.3.tar.gz>
 
-Gnu Make
-********
-
 Make 3.77
 ---------
 o  <ftp://ftp.gnu.org/gnu/make/make-3.77.tar.gz>
 
 Binutils
-********
+--------
 o  <ftp://ftp.kernel.org/pub/linux/devel/binutils/>
 
 System utilities
@@ -304,8 +301,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
 -------------
@@ -333,10 +329,10 @@
 
 Powertweak
 ----------
-o  <http://powertweak.sourceforge.net>
+o  <http://powertweak.sourceforge.net/>
 
-Network
-*******
+Networking
+**********
 
 PPP
 ---
diff -u --recursive --new-file v2.5.2/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.5.2/linux/Documentation/Configure.help	Mon Jan 14 18:25:07 2002
+++ linux/Documentation/Configure.help	Wed Dec 31 16:00:00 1969
@@ -1,24374 +0,0 @@
-# Maintained by:
-#	Eric S. Raymond <mailto:esr@thyrsus.com>
-#	Steven Cole <mailto:elenstev@mesatop.com>
-#
-# Merged version 2.61: current with 2.4.16/2.5.1-pre1.
-#
-# This version of the Linux kernel configuration help texts
-# corresponds to kernel versions 2.4.x and 2.5.x.
-#
-# Translations of this file available on the WWW:
-#
-#   - Japanese, maintained by the JF Project <mailto:JF@linux.or.jp>, at
-#     <http://www.linux.or.jp/JF/JFdocs/Configure.help/>
-#   - 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/>
-#   - 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
-#     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
-# only have email access, you can still use FTP and WWW servers: send
-# an email to <mailto:mail-server@rtfm.mit.edu> with the text
-#   send usenet/news.answers/internet-services/access-via-email
-# in the body of the message.
-#
-# Information about what a kernel is, what it does, how to patch and
-# compile it and much more is contained in the Kernel-HOWTO, available
-# at <http://www.linuxdoc.org/docs.html#howto>. Before you start
-# compiling, make sure that you have the necessary versions of all
-# programs and libraries required to compile and run this kernel; they
-# are listed in the <file:Documentation/Changes>. Make sure to read the
-# toplevel kernel README file as well.
-#
-# Format of this file: description<nl>variable<nl>help text<nl><nl>.
-# The help texts may contain empty lines, but every non-empty line must
-# be indented two positions.  Order of the help texts does not matter,
-# however, no variable should be documented twice: if it is, only the
-# first occurrence will be used. We try to keep the help texts of related
-# variables close together. Lines starting with `#' are ignored. To be
-# nice to menuconfig, limit your line length to 70 characters. Use emacs'
-# kfill.el to edit and ispell.el to spell check this file or you lose.
-#
-# Comments of the form "# Choice:" followed by a menu name are used
-# internally by the maintainers' consistency-checking tools.
-#
-# If you add a help text to this file, please try to be as gentle as
-# possible. Don't use unexplained acronyms and generally write for the
-# hypothetical ignorant but intelligent user who has just bought a PC,
-# removed Windows, installed Linux and is now recompiling the kernel
-# for the first time. Tell them what to do if they're unsure. Technical
-# information should go in a README in the Documentation directory.
-#
-# Mention all the relevant READMEs and HOWTOs in the help text.
-# Make them file URLs relative to the top level of the source tree so
-# that help browsers can turn them into hotlinks.  All URLs ahould be
-# surrounded by <>.
-#
-# Repetitions are fine since the help texts are not meant to be read
-# in sequence.  It is good style to include URLs pointing to more
-# detailed technical information, pictures of the hardware, etc.
-#
-# The most important thing to include in a help entry is *motivation*.
-# Explain why someone configuring a kernel might want to select your
-# option.
-#
-# All this was shamelessly stolen from several different sources. Many
-# thanks to all the contributors. Feel free to use these help texts in
-# your own kernel configuration tools. The texts are copyrighted (c)
-# 1995-2000 by Axel Boldt and many others and are governed by the GNU
-# General Public License.
-
-Prompt for development and/or incomplete code/drivers
-CONFIG_EXPERIMENTAL
-  Some of the various things that Linux supports (such as network
-  drivers, file systems, network protocols, etc.) can be in a state
-  of development where the functionality, stability, or the level of
-  testing is not yet high enough for general use. This is usually
-  known as the "alpha-test" phase among developers. If a feature is
-  currently in alpha-test, then the developers usually discourage
-  uninformed widespread use of this feature by the general public to
-  avoid "Why doesn't this work?" type mail messages. However, active
-  testing and use of these systems is welcomed. Just be aware that it
-  may not meet the normal level of reliability or it may fail to work
-  in some special cases. Detailed bug reports from people familiar
-  with the kernel internals are usually welcomed by the developers
-  (before submitting bug reports, please read the documents
-  <file:README>, <file:MAINTAINERS>, <file:REPORTING-BUGS>,
-  <file:Documentation/BUG-HUNTING>, and
-  <file:Documentation/oops-tracing.txt> in the kernel source).
-
-  This option will also make obsoleted drivers available. These are
-  drivers that have been replaced by something else, and/or are
-  scheduled to be removed in a future kernel release.
-
-  Unless you intend to help test and develop a feature or driver that
-  falls into this category, or you have a situation that requires
-  using these features, you should probably say N here, which will
-  cause the configurator to present you with fewer choices. If
-  you say Y here, you will be offered the choice of using features or
-  drivers that are currently considered to be in the alpha-test phase.
-
-Prompt for drivers for obsolete features and hardware
-CONFIG_OBSOLETE
-  Obsolete drivers have usually been replaced by more recent software
-  that can talk to the same hardware.  Obsolete hardware is things
-  like MGA monitors that you are very unlikely to see on today's
-  systems.
-
-Symmetric Multi-Processing support
-CONFIG_SMP
-  This enables support for systems with more than one CPU. If you have
-  a system with only one CPU, like most personal computers, say N. If
-  you have a system with more than one CPU, say Y.
-
-  If you say N here, the kernel will run on single and multiprocessor
-  machines, but will use only one CPU of a multiprocessor machine. If
-  you say Y here, the kernel will run on many, but not all,
-  singleprocessor machines. On a singleprocessor machine, the kernel
-  will run faster if you say N here.
-
-  Note that if you say Y here and choose architecture "586" or
-  "Pentium" under "Processor family", the kernel will not work on 486
-  architectures. Similarly, multiprocessor kernels for the "PPro"
-  architecture may not work on all Pentium based boards.
-
-  People using multiprocessor machines who say Y here should also say
-  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
-  Management" code will be disabled if you say Y here.
-
-  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-HOWTO available at
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you don't know what to do here, say N.
-
-Intel or compatible 80x86 processor
-CONFIG_X86
-  This is Linux's home port.  Linux was originally native to the Intel
-  386, and runs on all the later x86 processors including the Intel
-  486, 586, Pentiums, and various instruction-set-compatible chips by
-  AMD, Cyrix, and others.
-
-Alpha processor
-CONFIG_ALPHA
-  The Alpha is a 64-bit general-purpose processor designed and
-  marketed by the Digital Equipment Corporation of blessed memory, now
-  Compaq.  Alpha Linux dates from 1995-1996 and was the first non-x86
-  port. The Alpha Linux project has a home page at
-  <http://www.alphalinux.org/>.
-
-32-bit Sun Sparc
-CONFIG_SPARC32
-  SPARC is a family of RISC microprocessors designed and marketed by
-  Sun Microsystems, incorporated.  They are very widely found in Sun
-  workstations and clones. This port covers the original 32-bit SPARC;
-  it is old and stable and usually considered one of the "big three"
-  along with the Intel and Alpha ports.  The UltraLinux project
-  maintains both the SPARC32 and SPARC64 ports; its web page is
-  available at <http://www.ultralinux.org/>.
-
-64-bit Sun Sparc
-CONFIG_SPARC64
-  SPARC is a family of RISC microprocessors designed and marketed by
-  Sun Microsystems, incorporated.  This port covers the newer 64-bit
-  UltraSPARC.  The UltraLinux project maintains both the SPARC32 and
-  SPARC64 ports; its web page is available at
-  <http://www.ultralinux.org/>.
-
-Power PC processor
-CONFIG_PPC
-  The PowerPC is a very capable 32-bit RISC processor from Motorola,
-  the successor to their 68000 and 88000 series.  It powers recent
-  Macintoshes and also a widely-used series of single-board computers
-  from Motorola.  The Linux PowerPC port has a home page at
-  <http://penguinppc.org/>.
-
-Motorola 68K processors
-CONFIG_M68K
-  The Motorola 68K microprocessors are now obsolete, having been
-  superseded by the PowerPC line also from Motorola.  But they powered
-  the first wave of workstation hardware in the 1980s, including Sun
-  workstations; they were also the basis of the original Amiga and
-  later Atari personal computers.  A lot of this hardware is still
-  around.  The m68k project has a home page at
-  <http://www.linux-m68k.org/>.
-
-ARM processors
-CONFIG_ARM
-  The ARM series is a line of low-power-consumption RISC chip designs
-  licensed by ARM ltd and targeted at embedded applications and
-  handhelds such as the Compaq IPAQ.  ARM-based PCs are no longer
-  manufactured, but  legacy ARM-based PC hardware remains popular in
-  Europe.  There is an ARM Linux project with a web page at
-  <http://www.arm.linux.org.uk/>.
-
-SuperH processors
-CONFIG_SUPERH
-  The SuperH is a RISC processor targeted for use in embedded systems
-  and consumer electronics; it was also used in the Sega Dreamcast
-  gaming console.  The SuperH port has a home page at
-  <http://www.sh-linux.org/>.
-
-IA64 processors, including Intel Itanium
-CONFIG_IA64
-  The Itanium is Intel's 64-bit successor to the 32-bit X86 line.  As
-  of early 2001 it is not yet in widespread production use.  The Linux
-  IA-64 project has a home page at <http://www.linuxia64.org/>.
-
-HP PA-RISC processor
-CONFIG_PARISC
-  The PA-RISC microprocessor is a RISC chip designed by
-  Hewlett-Packard and used in their line of workstations.  The PA-RISC
-  Linux project has a home page at <www.parisc-linux.org>.
-
-IBM System/390
-CONFIG_S390
-  Linux now runs on the venerable System/390 mainframe from IBM, in a
-  guest partition under VM.  In fact, over 40,000 simultaneous Linux
-  images have been run on a single mainframe!  The S390 Linux project
-  has a home page at <http://linux.s390.org/>.
-
-Axis Communications ETRAX 100LX embedded network CPU
-CONFIG_CRIS
-  Linux has been ported to run on the Axis Communications ETRAX 100LX
-  CPU and the single-board computers built around it, targeted for
-  network and embedded applications.  For more information see the
-  Axis Communication site, <http://developer.axis.com/>.
-
-Multiquad support for NUMA systems
-CONFIG_MULTIQUAD
-  This option is used for getting Linux to run on a (IBM/Sequent) NUMA 
-  multiquad box. This changes the way that processors are bootstrapped,
-  and uses Clustered Logical APIC addressing mode instead of Flat Logical.
-  You will need a new lynxer.elf file to flash your firmware with - send
-  email to Martin.Bligh@us.ibm.com
-
-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
-  SMP systems and a small number of uniprocessor systems have one.
-  If you have a single-CPU system with an IO-APIC, you can say Y here
-  to use it. If you say Y here even though your machine doesn't have
-  an IO-APIC, then the kernel will still run with no slowdown at all.
-
-  If you have a system with several CPUs, you do not need to say Y
-  here: the IO-APIC will be used automatically.
-
-Local APIC Support on Uniprocessors
-CONFIG_X86_UP_APIC
-  A local APIC (Advanced Programmable Interrupt Controller) is an
-  integrated interrupt controller in the CPU. If you have a single-CPU
-  system which has a processor with a local APIC, you can say Y here to
-  enable and use it. If you say Y here even though your machine doesn't
-  have a local APIC, then the kernel will still run with no slowdown at
-  all. The local APIC supports CPU-generated self-interrupts (timer,
-  performance counters), and the NMI watchdog which detects hard lockups.
-
-  If you have a system with several CPUs, you do not need to say Y
-  here: the local APIC will be used automatically.
-
-Kernel math emulation
-CONFIG_MATH_EMULATION
-  Linux can emulate a math coprocessor (used for floating point
-  operations) if you don't have one. 486DX and Pentium processors have
-  a math coprocessor built in, 486SX and 386 do not, unless you added
-  a 487DX or 387, respectively. (The messages during boot time can
-  give you some hints here ["man dmesg"].) Everyone needs either a
-  coprocessor or this emulation.
-
-  If you don't have a math coprocessor, you need to say Y here; if you
-  say Y here even though you have a coprocessor, the coprocessor will
-  be used nevertheless. (This behavior can be changed with the kernel
-  command line option "no387", which comes handy if your coprocessor
-  is broken. Try "man bootparam" or see the documentation of your boot
-  loader (lilo or loadlin) about how to pass options to the kernel at
-  boot time.) This means that it is a good idea to say Y here if you
-  intend to use this kernel on different machines.
-
-  More information about the internals of the Linux math coprocessor
-  emulation can be found in <file:arch/i386/math-emu/README>.
-
-  If you are not sure, say Y; apart from resulting in a 66 KB bigger
-  kernel, it won't hurt.
-
-Timer and CPU usage LEDs
-CONFIG_LEDS
-  If you say Y here, the LEDs on your machine will be used
-  to provide useful information about your current system status.
-
-  If you are compiling a kernel for a NetWinder or EBSA-285, you will
-  be able to select which LEDs are active using the options below. If
-  you are compiling a kernel for the EBSA-110 or the LART however, the
-  red LED will simply flash regularly to indicate that the system is
-  still functional. It is safe to say Y here if you have a CATS
-  system, but the driver will do nothing.
-
-Timer LED
-CONFIG_LEDS_TIMER
-  If you say Y here, one of the system LEDs (the green one on the
-  NetWinder, the amber one on the EBSA285, or the red one on the LART)
-  will flash regularly to indicate that the system is still
-  operational. This is mainly useful to kernel hackers who are
-  debugging unstable kernels.
-
-  The LART uses the same LED for both Timer LED and CPU usage LED
-  functions. You may choose to use both, but the Timer LED function
-  will overrule the CPU usage LED.
-
-CPU usage LED
-CONFIG_LEDS_CPU
-  If you say Y here, the red LED will be used to give a good real
-  time indication of CPU usage, by lighting whenever the idle task
-  is not currently executing.
-
-  The LART uses the same LED for both Timer LED and CPU usage LED
-  functions. You may choose to use both, but the Timer LED function
-  will overrule the CPU usage LED.
-
-Kernel FP software completion
-CONFIG_MATHEMU
-  This option is required for IEEE compliant floating point arithmetic
-  on the Alpha. The only time you would ever not say Y is to say M in
-  order to debug the code. Say Y unless you know what you are doing.
-
-# Choice: himem
-High Memory support
-CONFIG_NOHIGHMEM
-  Linux can use up to 64 Gigabytes of physical memory on x86 systems.
-  However, the address space of 32-bit x86 processors is only 4
-  Gigabytes large. That means that, if you have a large amount of
-  physical memory, not all of it can be "permanently mapped" by the
-  kernel. The physical memory that's not permanently mapped is called
-  "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
-  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
-  by the kernel to permanently map as much physical memory as
-  possible.
-
-  If the machine has between 1 and 4 Gigabytes physical RAM, then
-  answer "4GB" here.
-
-  If more than 4 Gigabytes is used then answer "64GB" here. This
-  selection turns Intel PAE (Physical Address Extension) mode on.
-  PAE implements 3-level paging on IA32 processors. PAE is fully
-  supported by Linux, PAE mode is implemented on all recent Intel
-  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
-  kernel at boot time.)
-
-  If unsure, say "off".
-
-4GB
-CONFIG_HIGHMEM4G
-  Select this if you have a 32-bit processor and between 1 and 4
-  gigabytes of physical RAM.
-
-64GB
-CONFIG_HIGHMEM64G
-  Select this if you have a 32-bit processor and more than 4
-  gigabytes of physical RAM.
-
-Normal PC 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
-  Thinkpad users, is contained in <file:Documentation/floppy.txt>.
-  That file also contains the location of the Floppy driver FAQ as
-  well as location of the fdutils package used to configure additional
-  parameters of the driver at run time.
-
-  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 floppy.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-iSeries Virtual I/O Disk Support
-CONFIG_VIODASD
-  If you are running on an iSeries system and you want to use
-  virtual disks created and managed by OS/400, say Y.
-
-iSeries Virtual I/O Disk IDE Emulation
-CONFIG_VIODASD_IDE
-  This causes the iSeries virtual disks to look like IDE disks.
-  If you have programs or utilities that only support certain
-  kinds of disks, this option will cause iSeries virtual disks
-  to pretend to be IDE disks, which may satisfy the program.
-
-Support for PowerMac floppy
-CONFIG_MAC_FLOPPY
-  If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple)
-  floppy controller, say Y here. Most commonly found in PowerMacs.
-
-RAM disk support
-CONFIG_BLK_DEV_RAM
-  Saying Y here will allow you to use a portion of your RAM memory as
-  a block device, so that you can make file systems on it, read and
-  write to it and do all the other things that you can do with normal
-  block devices (such as hard drives). It is usually used to load and
-  store a copy of a minimal root file system off of a floppy into RAM
-  during the initial install of Linux.
-
-  Note that the kernel command line option "ramdisk=XX" is now
-  obsolete. For details, read <file:Documentation/ramdisk.txt>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M and read <file:Documentation/modules.txt>. The module will be
-  called rd.o.
-
-  Most normal users won't need the RAM disk functionality, and can
-  thus say N here.
-
-Default RAM disk size
-CONFIG_BLK_DEV_RAM_SIZE
-  The default value is 4096. Only change this if you know what are
-  you doing. If you are using IBM S/390, then set this to 8192.
-
-Initial RAM disk (initrd) support
-CONFIG_BLK_DEV_INITRD
-  The initial RAM disk is a RAM disk that is loaded by the boot loader
-  (loadlin or lilo) and that is mounted as root before the normal boot
-  procedure. It is typically used to load modules needed to mount the
-  "real" root file system, etc. See <file:Documentation/initrd.txt>
-  for details.
-
-Loopback device support
-CONFIG_BLK_DEV_LOOP
-  Saying Y here will allow you to use a regular file as a block
-  device; you can then create a file system on that block device and
-  mount it just as you would mount other block devices such as hard
-  drive partitions, CD-ROM drives or floppy drives. The loop devices
-  are block special device files with major number 7 and typically
-  called /dev/loop0, /dev/loop1 etc.
-
-  This is useful if you want to check an ISO 9660 file system before
-  burning the CD, or if you want to use floppy images without first
-  writing them to floppy. Furthermore, some Linux distributions avoid
-  the need for a dedicated Linux partition by keeping their complete
-  root file system inside a DOS FAT file using this loop device
-  driver.
-
-  The loop device driver can also be used to "hide" a file system in a
-  disk partition, floppy, or regular file, either using encryption
-  (scrambling the data) or steganography (hiding the data in the low
-  bits of, say, a sound file). This is also safe if the file resides
-  on a remote file server. If you want to do this, you will first have
-  to acquire and install a kernel patch from
-  <ftp://ftp.kerneli.org/pub/kerneli/>, and then you need to
-  say Y to this option.
-
-  Note that alternative ways to use encrypted file systems are
-  provided by the cfs package, which can be gotten from
-  <ftp://ftp.kerneli.org/pub/kerneli/net-source/>, and the newer tcfs
-  package, available at <http://tcfs.dia.unisa.it/>. You do not need
-  to say Y here if you want to use one of these. However, using cfs
-  requires saying Y to "NFS file system support" below while using
-  tcfs requires applying a kernel patch. An alternative steganography
-  solution is provided by StegFS, also available from
-  <ftp://ftp.kerneli.org/pub/kerneli/net-source/>.
-
-  To use the loop device, you need the losetup utility and a recent
-  version of the mount program, both contained in the util-linux
-  package. The location and current version number of util-linux is
-  contained in the file <file:Documentation/Changes>.
-
-  Note that this loop device has nothing to do with the loopback
-  device used for network connections from the machine to itself.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>. The module
-  will be called loop.o.
-
-  Most users will answer N here.
-
-Network block device support
-CONFIG_BLK_DEV_NBD
-  Saying Y here will allow your computer to be a client for network
-  block devices, i.e. it will be able to use block devices exported by
-  servers (mount file systems on them etc.). Communication between
-  client and server works over TCP/IP networking, but to the client
-  program this is hidden: it looks like a regular local file access to
-  a block device special file such as /dev/nd0.
-
-  Network block devices also allows you to run a block-device in
-  userland (making server and client physically the same computer,
-  communicating using the loopback network device).
-
-  Read <file:Documentation/nbd.txt> for more information, especially
-  about where to find the server code, which runs in user space and
-  does not need special kernel support.
-
-  Note that this has nothing to do with the network file systems NFS
-  or Coda; you can say N here even if you intend to use NFS or Coda.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>. The module
-  will be called nbd.o.
-
-  If unsure, say N.
-
-ATA/IDE/MFM/RLL support
-CONFIG_IDE
-  If you say Y here, your kernel will be able to manage low cost mass
-  storage units such as ATA/(E)IDE and ATAPI units. The most common
-  cases are IDE hard drives and ATAPI CD-ROM drives.
-
-  If your system is pure SCSI and doesn't use these interfaces, you
-  can say N here.
-
-  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
-  for mass storage units such as hard disks. It was designed by
-  Western Digital and Compaq Computer in 1984. It was then named
-  ST506. Quite a number of disks use the IDE interface.
-
-  AT Attachment (ATA) is the superset of the IDE specifications.
-  ST506 was also called ATA-1.
-
-  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
-  ATA-3. It provides support for larger disks (up to 8.4GB by means of
-  the LBA standard), more disks (4 instead of 2) and for other mass
-  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
-  ATA-4 and provides faster (and more CPU friendly) transfer modes
-  than previous PIO (Programmed processor Input/Output) from previous
-  ATA/IDE standards by means of fast DMA controllers.
-
-  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
-  CD-ROM drives, similar in many respects to the SCSI protocol.
-
-  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
-  designed in order to prevent data corruption and disk crash by
-  detecting pre hardware failure conditions (heat, access time, and
-  the like...). Disks built since June 1995 may follow this standard.
-  The kernel itself don't manage this; however there are quite a
-  number of user programs such as smart that can query the status of
-  SMART parameters disk.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>. The module
-  will be called ide.o.
-
-  For further information, please read <file:Documentation/ide.txt>.
-
-  If unsure, say Y.
-
-Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support
-CONFIG_BLK_DEV_IDE
-  If you say Y here, you will use the full-featured IDE driver to
-  control up to ten ATA/IDE interfaces, each being able to serve a
-  "master" and a "slave" device, for a total of up to twenty ATA/IDE
-  disk/cdrom/tape/floppy drives.
-
-  Useful information about large (>540 MB) IDE disks, multiple
-  interfaces, what to do if ATA/IDE devices are not automatically
-  detected, sound card ATA/IDE ports, module support, and other
-  topics, is contained in <file:Documentation/ide.txt>. For detailed
-  information about hard drives, consult the Disk-HOWTO and the
-  Multi-Disk-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  To fine-tune ATA/IDE drive/interface parameters for improved
-  performance, look for the hdparm package at
-  <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),
-  say M here and read <file:Documentation/modules.txt> and
-  <file:Documentation/ide.txt>. The module will be called ide-mod.o.
-  Do not compile this driver as a module if your root file system (the
-  one containing the directory /) is located on an IDE device.
-
-  If you have one or more IDE drives, say Y or M here. If your system
-  has no IDE drives, or if memory requirements are really tight, you
-  could say N here, and select the "Old hard disk driver" below
-  instead to save about 13 KB of memory in the kernel.
-
-Old hard disk (MFM/RLL/IDE) driver
-CONFIG_BLK_DEV_HD_ONLY
-  There are two drivers for MFM/RLL/IDE hard disks. Most people use
-  the newer enhanced driver, but this old one is still around for two
-  reasons. Some older systems have strange timing problems and seem to
-  work only with the old driver (which itself does not work with some
-  newer systems). The other reason is that the old driver is smaller,
-  since it lacks the enhanced functionality of the new one. This makes
-  it a good choice for systems with very tight memory restrictions, or
-  for systems with only older MFM/RLL/ESDI drives. Choosing the old
-  driver can save 13 KB or so of kernel memory.
-
-  If you are unsure, then just choose the Enhanced IDE/MFM/RLL driver
-  instead of this one. For more detailed information, read the
-  Disk-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-Use old disk-only driver on primary interface
-CONFIG_BLK_DEV_HD_IDE
-  There are two drivers for MFM/RLL/IDE disks.  Most people use just
-  the new enhanced driver by itself.  This option however installs the
-  old hard disk driver to control the primary IDE/disk interface in
-  the system, leaving the new enhanced IDE driver to take care of only
-  the 2nd/3rd/4th IDE interfaces.  Doing this will prevent you from
-  having an IDE/ATAPI CD-ROM or tape drive connected to the primary
-  IDE interface.  Choosing this option may be useful for older systems
-  which have MFM/RLL/ESDI controller+drives at the primary port
-  address (0x1f0), along with IDE drives at the secondary/3rd/4th port
-  addresses.
-
-  Normally, just say N here; you will then use the new driver for all
-  4 interfaces.
-
-Include IDE/ATA-2 DISK support
-CONFIG_BLK_DEV_IDEDISK
-  This will include enhanced support for MFM/RLL/IDE hard disks.  If
-  you have a MFM/RLL/IDE disk, and there is no special reason to use
-  the old hard disk driver instead, say Y.  If you have an SCSI-only
-  system, you can say N here.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called ide-disk.o.  Do not compile this driver as a module
-  if your root file system (the one containing the directory /) is
-  located on the IDE disk. If unsure, say Y.
-
-Use multi-mode by default
-CONFIG_IDEDISK_MULTI_MODE
-  If you get this error, try to say Y here:
-
-  hda: set_multmode: status=0x51 { DriveReady SeekComplete Error }
-  hda: set_multmode: error=0x04 { DriveStatusError }
-
-  If in doubt, say N.
-
-PCMCIA IDE support
-CONFIG_BLK_DEV_IDECS
-  Support for outboard IDE disks, tape drives, and CD-ROM drives
-  connected through a  PCMCIA card.
-
-Include IDE/ATAPI CD-ROM support
-CONFIG_BLK_DEV_IDECD
-  If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is
-  a newer protocol used by IDE CD-ROM and TAPE drives, similar to the
-  SCSI protocol. Most new CD-ROM drives use ATAPI, including the
-  NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI
-  double(2X) or better speed drives.
-
-  If you say Y here, the CD-ROM drive will be identified at boot time
-  along with other IDE devices, as "hdb" or "hdc", or something
-  similar (check the boot messages with dmesg). If this is your only
-  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".
-
-  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),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called ide-cd.o.
-
-Include IDE/ATAPI TAPE support
-CONFIG_BLK_DEV_IDETAPE
-  If you have an IDE tape drive using the ATAPI protocol, say Y.
-  ATAPI is a newer protocol used by IDE tape and CD-ROM drives,
-  similar to the SCSI protocol.  If you have an SCSI tape drive
-  however, you can say N here.
-
-  You should also say Y if you have an OnStream DI-30 tape drive; this
-  will not work with the SCSI protocol, until there is support for the
-  SC-30 and SC-50 versions.
-
-  If you say Y here, the tape drive will be identified at boot time
-  along with other IDE devices, as "hdb" or "hdc", or something
-  similar, and will be mapped to a character device such as "ht0"
-  (check the boot messages with dmesg).  Be sure to consult the
-  <file:drivers/ide/ide-tape.c> and <file:Documentation/ide.txt> files
-  for usage information.
-
-  If you want to compile the driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called ide-tape.o.
-
-Include IDE/ATAPI FLOPPY support
-CONFIG_BLK_DEV_IDEFLOPPY
-  If you have an IDE floppy drive which uses the ATAPI protocol,
-  answer Y.  ATAPI is a newer protocol used by IDE CD-ROM/tape/floppy
-  drives, similar to the SCSI protocol.
-
-  The LS-120 and the IDE/ATAPI Iomega ZIP drive are also supported by
-  this driver. For information about jumper settings and the question
-  of when a ZIP drive uses a partition table, see
-  <http://www.win.tue.nl/~aeb/linux/zip/zip-1.html>.
-  (ATAPI PD-CD/CDR drives are not supported by this driver; support
-  for PD-CD/CDR drives is available if you answer Y to
-  "SCSI emulation support", below).
-
-  If you say Y here, the FLOPPY drive will be identified along with
-  other IDE devices, as "hdb" or "hdc", or something similar (check
-  the boot messages with dmesg).
-
-  If you want to compile the driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called ide-floppy.o.
-
-SCSI emulation support
-CONFIG_BLK_DEV_IDESCSI
-  This will provide SCSI host adapter emulation for IDE ATAPI devices,
-  and will allow you to use a SCSI device driver instead of a native
-  ATAPI driver.
-
-  This is useful if you have an ATAPI device for which no native
-  driver has been written (for example, an ATAPI PD-CD or CDR drive);
-  you can then use this emulation together with an appropriate SCSI
-  device driver. In order to do this, say Y here and to "SCSI support"
-  and "SCSI generic support", below. You must then provide the kernel
-  command line "hdx=scsi" (try "man bootparam" or see the
-  documentation of your boot loader (lilo or loadlin) about how to
-  pass options to the kernel at boot time) for devices if you want the
-  native EIDE sub-drivers to skip over the native support, so that
-  this SCSI emulation can be used instead. This is required for use of
-  CD-RW's.
-
-  Note that this option does NOT allow you to attach SCSI devices to a
-  box that doesn't have a SCSI host adapter installed.
-
-  If both this SCSI emulation and native ATAPI support are compiled
-  into the kernel, the native support will be used.
-
-ISA-PNP EIDE support
-CONFIG_BLK_DEV_ISAPNP
-  If you have an ISA EIDE card that is PnP (Plug and Play) and
-  requires setup first before scanning for devices, say Y here.
-
-  If unsure, say N.
-
-CMD640 chipset bugfix/support
-CONFIG_BLK_DEV_CMD640
-  The CMD-Technologies CMD640 IDE chip is used on many common 486 and
-  Pentium motherboards, usually in combination with a "Neptune" or
-  "SiS" chipset. Unfortunately, it has a number of rather nasty
-  design flaws that can cause severe data corruption under many common
-  conditions. Say Y here to include code which tries to automatically
-  detect and correct the problems under Linux. This option also
-  enables access to the secondary IDE ports in some CMD640 based
-  systems.
-
-  This driver will work automatically in PCI based systems (most new
-  systems have PCI slots). But if your system uses VESA local bus
-  (VLB) instead of PCI, you must also supply a kernel boot parameter
-  to enable the CMD640 bugfix/support: "ide0=cmd640_vlb". (Try "man
-  bootparam" or see the documentation of your boot loader about how to
-  pass options to the kernel.)
-
-  The CMD640 chip is also used on add-in cards by Acculogic, and on
-  the "CSA-6400E PCI to IDE controller" that some people have. For
-  details, read <file:Documentation/ide.txt>.
-
-CMD640 enhanced support
-CONFIG_BLK_DEV_CMD640_ENHANCED
-  This option includes support for setting/autotuning PIO modes and
-  prefetch on CMD640 IDE interfaces.  For details, read
-  <file:Documentation/ide.txt>. If you have a CMD640 IDE interface
-  and your BIOS does not already do this for you, then say Y here.
-  Otherwise say N.
-
-RZ1000 chipset bugfix/support
-CONFIG_BLK_DEV_RZ1000
-  The PC-Technologies RZ1000 IDE chip is used on many common 486 and
-  Pentium motherboards, usually along with the "Neptune" chipset.
-  Unfortunately, it has a rather nasty design flaw that can cause
-  severe data corruption under many conditions. Say Y here to include
-  code which automatically detects and corrects the problem under
-  Linux. This may slow disk throughput by a few percent, but at least
-  things will operate 100% reliably.
-
-Generic PCI IDE chipset support
-CONFIG_BLK_DEV_IDEPCI
-  Say Y here for PCI systems which use IDE drive(s).
-  This option helps the IDE driver to automatically detect and
-  configure all PCI-based IDE interfaces in your system.
-
-Support for sharing PCI IDE interrupts
-CONFIG_IDEPCI_SHARE_IRQ
-  Some ATA/IDE chipsets have hardware support which allows for
-  sharing a single IRQ with other cards. To enable support for
-  this in the ATA/IDE driver, say Y here.
-
-  It is safe to say Y to this question, in most cases.
-  If unsure, say N.
-
-Generic PCI bus-master DMA support
-CONFIG_BLK_DEV_IDEDMA_PCI
-  If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and
-  is capable of bus-master DMA operation (most Pentium PCI systems),
-  you will want to say Y here to reduce CPU overhead. You can then use
-  the "hdparm" utility to enable DMA for drives for which it was not
-  enabled automatically. By default, DMA is not enabled automatically
-  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://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.
-
-  It is safe to say Y to this question.
-
-Good-Bad DMA Model-Firmware (WIP)
-CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
-  If you say Y here, the model and firmware revision of your drive
-  will be compared against a blacklist of buggy drives that claim to
-  be (U)DMA capable but aren't. This is a blanket on/off test with no
-  speed limit options.
-
-  Straight GNU GCC 2.7.3/2.8.X compilers are known to be safe;
-  whereas, many versions of EGCS have a problem and miscompile if you
-  say Y here.
-
-  If in doubt, say N.
-
-Attempt to HACK around Chipsets that TIMEOUT (WIP)
-CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-  If you say Y here, this is a NASTY UGLY HACK!
-
-  We have to issue an abort and requeue the request DMA engine got
-  turned off by a goofy ASIC, and we have to clean up the mess, and
-  here is as good as any.  Do it globally for all chipsets.
-
-  If in doubt, say N.
-
-Boot off-board chipsets first support
-CONFIG_BLK_DEV_OFFBOARD
-  Normally, IDE controllers built into the motherboard (on-board
-  controllers) are assigned to ide0 and ide1 while those on add-in PCI
-  cards (off-board controllers) are relegated to ide2 and ide3.
-  Answering Y here will allow you to reverse the situation, with
-  off-board controllers on ide0/1 and on-board controllers on ide2/3.
-  This can improve the usability of some boot managers such as lilo
-  when booting from a drive on an off-board controller.
-
-  If you say Y here, and you actually want to reverse the device scan
-  order as explained above, you also need to issue the kernel command
-  line option "ide=reverse". (Try "man bootparam" or see the
-  documentation of your boot loader (lilo or loadlin) about how to
-  pass options to the kernel at boot time.)
-
-  Note that, if you do this, the order of the hd* devices will be
-  rearranged which may require modification of fstab and other files.
-
-  If in doubt, say N.
-
-Use PCI DMA by default when available
-CONFIG_IDEDMA_PCI_AUTO
-  Prior to kernel version 2.1.112, Linux used to automatically use
-  DMA for IDE drives and chipsets which support it. Due to concerns
-  about a couple of cases where buggy hardware may have caused damage,
-  the default is now to NOT use DMA automatically. To revert to the
-  previous behaviour, say Y to this question.
-
-  If you suspect your hardware is at all flakey, say N here.
-  Do NOT email the IDE kernel people regarding this issue!
-
-  It is normally safe to answer Y to this question unless your
-  motherboard uses a VIA VP2 chipset, in which case you should say N.
-
-IGNORE word93 Validation BITS
-CONFIG_IDEDMA_IVB
-  There are unclear terms is ATA-4 and ATA-5 standards how certain
-  hardware (an 80c ribbon) should be detected. Different interpretations
-  of the standards have been released in hardware. This causes problems:
-  for example, a host with Ultra Mode 4 (or higher) will not run
-  in that mode with an 80c ribbon.
-
-  If you are experiencing compatibility or performance problems, you
-  MAY try to answering Y here. However, it does not necessarily solve
-  any of your problems, it could even cause more of them.
-
-  It is normally safe to answer Y; however, the default is N.
-
-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
-  simply skip those options.
-
-  It is SAFEST to say N to this question.
-
-Asyncronious DMA support (EXPERIMENTAL)
-CONFIG_BLK_DEV_ADMA
-  Please read the comments at the top of
-  <file:drivers/ide/ide-adma.c>.
-
-Pacific Digital A-DMA support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PDC_ADMA
-  Please read the comments at the top of <file:drivers/ide/ide-pci.c>.
-
-3ware Hardware ATA-RAID support
-CONFIG_BLK_DEV_3W_XXXX_RAID
-  3ware is the only hardware ATA-Raid product in Linux to date.
-  This card is 2,4, or 8 channel master mode support only.
-  SCSI support required!!!
-
-  <http://www.3ware.com/>
-
-  Please read the comments at the top of
-  <file:drivers/scsi/3w-xxxx.c>.
-
-AEC62XX chipset support
-CONFIG_BLK_DEV_AEC62XX
-  This driver adds up to 4 more EIDE devices sharing a single
-  interrupt. This add-on card is a bootable PCI UDMA controller. In
-  order to get this card to initialize correctly in some cases, you
-  should say Y here, and preferably also to "Use DMA by default when
-  available".
-
-  The ATP850U/UF is an UltraDMA 33 chipset base.
-  The ATP860 is an UltraDMA 66 chipset base.
-  The ATP860M(acintosh) version is an UltraDMA 66 chipset base.
-
-  Please read the comments at the top of <file:drivers/ide/aec62xx.c>.
-  If you say Y here, then say Y to "Use DMA by default when available"
-  as well.
-
-AEC62XX Tuning support
-CONFIG_AEC62XX_TUNING
-  Please read the comments at the top of <file:drivers/ide/aec62xx.c>.
-  If unsure, say N.
-
-ALI M15x3 chipset support
-CONFIG_BLK_DEV_ALI15X3
-  This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
-  onboard chipsets.  It also tests for Simplex mode and enables
-  normal dual channel support.
-
-  If you say Y here, you also need to say Y to "Use DMA by default
-  when available", above.  Please read the comments at the top of
-  <file:drivers/ide/alim15x3.c>.
-
-  If unsure, say N.
-
-ALI M15x3 WDC support (DANGEROUS)
-CONFIG_WDC_ALI15X3
-  This allows for UltraDMA support for WDC drives that ignore CRC
-  checking. You are a fool for enabling this option, but there have
-  been requests. DO NOT COMPLAIN IF YOUR DRIVE HAS FS CORRUPTION, IF
-  YOU ENABLE THIS! No one will listen, just laugh for ignoring this
-  SERIOUS WARNING.
-
-  Using this option can allow WDC drives to run at ATA-4/5 transfer
-  rates with only an ATA-2 support structure.
-
-  SAY N!
-
-AMD Viper support
-CONFIG_BLK_DEV_AMD74XX
-  This driver ensures (U)DMA support for the AMD756/760 Viper
-  chipsets.
-
-  If you say Y here, you also need to say Y to "Use DMA by default
-  when available", above.
-  Please read the comments at the top of <file:drivers/ide/amd74xx.c>.
-
-  If unsure, say N.
-
-AMD Viper ATA-66 Override (WIP)
-CONFIG_AMD74XX_OVERRIDE
-  This option auto-forces the ata66 flag.
-  This effect can be also invoked by calling "idex=ata66"
-  If unsure, say N.
-
-CMD64X chipset support
-CONFIG_BLK_DEV_CMD64X
-  Say Y here if you have an IDE controller which uses any of these
-  chipsets: CMD643, CMD646, or CMD648.
-
-CY82C693 chipset support
-CONFIG_BLK_DEV_CY82C693
-  This driver adds detection and support for the CY82C693 chipset
-  used on Digital's PC-Alpha 164SX boards.
-
-  If you say Y here, you need to say Y to "Use DMA by default
-  when available" as well.
-
-Cyrix CS5530 MediaGX chipset support
-CONFIG_BLK_DEV_CS5530
-  Include support for UDMA on the Cyrix MediaGX 5530 chipset. This
-  will automatically be detected and configured if found.
-
-  It is safe to say Y to this question.
-
-  People with SCSI-only systems should say N here. If unsure, say Y.
-
-HPT34X chipset support
-CONFIG_BLK_DEV_HPT34X
-  This driver adds up to 4 more EIDE devices sharing a single
-  interrupt. The HPT343 chipset in its current form is a non-bootable
-  controller; the HPT345/HPT363 chipset is a bootable (needs BIOS FIX)
-  PCI UDMA controllers. This driver requires dynamic tuning of the
-  chipset during the ide-probe at boot time. It is reported to support
-  DVD II drives, by the manufacturer.
-
-HPT34X AUTODMA support (WIP)
-CONFIG_HPT34X_AUTODMA
-  This is a dangerous thing to attempt currently! Please read the
-  comments at the top of <file:drivers/ide/hpt34x.c>.  If you say Y
-  here, then say Y to "Use DMA by default when available" as well.
-
-  If unsure, say N.
-
-HPT366 chipset support
-CONFIG_BLK_DEV_HPT366
-  HPT366 is an Ultra DMA chipset for ATA-66.
-  HPT368 is an Ultra DMA chipset for ATA-66 RAID Based.
-  HPT370 is an Ultra DMA chipset for ATA-100.
-
-  This driver adds up to 4 more EIDE devices sharing a single
-  interrupt.
-
-  The HPT366 chipset in its current form is bootable. One solution
-  for this problem are special LILO commands for redirecting the
-  reference to device 0x80. The other solution is to say Y to "Boot
-  off-board chipsets first support" (CONFIG_BLK_DEV_OFFBOARD) unless
-  your mother board has the chipset natively mounted. Regardless one
-  should use the fore mentioned option and call at LILO or include
-  "ide=reverse" in LILO's append-line.
-
-  This driver requires dynamic tuning of the chipset during the
-  ide-probe at boot. It is reported to support DVD II drives, by the
-  manufacturer.
-
-NS87415 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_NS87415
-  This driver adds detection and support for the NS87415 chip
-  (used in SPARC64, among others).
-
-  Please read the comments at the top of <file:drivers/ide/ns87415.c>.
-
-OPTi 82C621 chipset enhanced support (EXPERIMENTAL)
-CONFIG_BLK_DEV_OPTI621
-  This is a driver for the OPTi 82C621 EIDE controller.
-  Please read the comments at the top of <file:drivers/ide/opti621.c>.
-
-ServerWorks OSB4/CSB5 chipset support
-CONFIG_BLK_DEV_SVWKS
-  This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
-  chipsets.
-
-Intel PIIXn chipsets support
-CONFIG_BLK_DEV_PIIX
-  This driver adds PIO mode setting and tuning for all PIIX IDE
-  controllers by Intel.  Since the BIOS can sometimes improperly tune
-  PIO 0-4 mode settings, this allows dynamic tuning of the chipset
-  via the standard end-user tool 'hdparm'.
-
-  Please read the comments at the top of <file:drivers/ide/piix.c>.
-
-  If you say Y here, you should also say Y to "PIIXn Tuning support",
-  below.
-
-  If unsure, say N.
-
-PIIXn Tuning support
-CONFIG_PIIX_TUNING
-  This driver extension adds DMA mode setting and tuning for all PIIX
-  IDE controllers by Intel. Since the BIOS can sometimes improperly
-  set up the device/adapter combination and speed limits, it has
-  become a necessity to back/forward speed devices as needed.
-
-  Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode
-  2 if the BIOS can not perform this task at initialization.
-
-  If unsure, say N.
-
-PROMISE PDC20246/PDC20262/PDC20265/PDC20267/PDC20268 support
-CONFIG_BLK_DEV_PDC202XX
-  Promise Ultra33 or PDC20246
-  Promise Ultra66 or PDC20262
-  Promise Ultra100 or PDC20265/PDC20267/PDC20268
-
-  This driver adds up to 4 more EIDE devices sharing a single
-  interrupt. This add-on card is a bootable PCI UDMA controller. Since
-  multiple cards can be installed and there are BIOS ROM problems that
-  happen if the BIOS revisions of all installed cards (three-max) do
-  not match, the driver attempts to do dynamic tuning of the chipset
-  at boot-time for max-speed.  Ultra33 BIOS 1.25 or newer is required
-  for more than one card. This card may require that you say Y to
-  "Special UDMA Feature".
-
-  If you say Y here, you need to say Y to "Use DMA by default when
-  available" as well.
-
-  Please read the comments at the top of
-  <file:drivers/ide/pdc202xx.c>.
-
-  If unsure, say N.
-
-Special UDMA Feature
-CONFIG_PDC202XX_BURST
-  This option causes the pdc202xx driver to enable UDMA modes on the
-  PDC202xx even when the PDC202xx BIOS has not done so.
-
-  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>.
-
-  If unsure, say N.
-
-Special FastTrak Feature
-CONFIG_PDC202XX_FORCE
-  For FastTrak enable overriding BIOS.
-
-SiS5513 chipset support
-CONFIG_BLK_DEV_SIS5513
-  This driver ensures (U)DMA support for SIS5513 chipset based
-  mainboards. SiS620/530 UDMA mode 4, SiS5600/5597 UDMA mode 2, all
-  other DMA mode 2 limited chipsets are unsupported to date.
-
-  If you say Y here, you need to say Y to "Use DMA by default when
-  available" as well.
-
-  Please read the comments at the top of <file:drivers/ide/sis5513.c>.
-
-SLC90E66 chipset support
-CONFIG_BLK_DEV_SLC90E66
-  This driver ensures (U)DMA support for Victroy66 SouthBridges for
-  SMsC with Intel NorthBridges.  This is an Ultra66 based chipset.
-  The nice thing about it is that you can mix Ultra/DMA/PIO devices
-  and it will handle timing cycles.  Since this is an improved
-  look-a-like to the PIIX4 it should be a nice addition.
-
-  If you say Y here, you need to say Y to "Use DMA by default when
-  available" as well.
-
-  Please read the comments at the top of
-  <file:drivers/ide/slc90e66.c>.
-
-Winbond SL82c105 support
-CONFIG_BLK_DEV_SL82C105
-  If you have a Winbond SL82c105 IDE controller, say Y here to enable
-  special configuration for this chip. This is common on various CHRP
-  motherboards, but could be used elsewhere. If in doubt, say Y.
-
-Tekram TRM290 chipset support
-CONFIG_BLK_DEV_TRM290
-  This driver adds support for bus master DMA transfers
-  using the Tekram TRM290 PCI IDE chip. Volunteers are
-  needed for further tweaking and development.
-  Please read the comments at the top of <file:drivers/ide/trm290.c>.
-
-VIA82CXXX chipset support
-CONFIG_BLK_DEV_VIA82CXXX
-  This allows you to configure your chipset for a better use while
-  running PIO/(U)DMA, it will allow you to enable efficiently the
-  second channel dma usage, as it may not be set by BIOS.  It will try
-  to set fifo configuration at its best.  It will allow you to get
-  information from /proc/ide/via provided you enabled "/proc file
-  system" support.
-
-  Please read the comments at the top of
-  <file:drivers/ide/via82cxxx.c>.
-
-  If you say Y here, then say Y to "Use DMA by default when available"
-  as well.
-
-  If unsure, say N.
-
-RapIDE interface support
-CONFIG_BLK_DEV_IDE_RAPIDE
-  Say Y here if you want to support the Yellowstone RapIDE controller
-  manufactured for use with Acorn computers.
-
-Other IDE chipset support
-CONFIG_IDE_CHIPSETS
-  Say Y here if you want to include enhanced support for various IDE
-  interface chipsets used on motherboards and add-on cards. You can
-  then pick your particular IDE chip from among the following options.
-  This enhanced support may be necessary for Linux to be able to
-  access the 3rd/4th drives in some systems. It may also enable
-  setting of higher speed I/O rates to improve system performance with
-  these chipsets. Most of these also require special kernel boot
-  parameters to actually turn on the support at runtime; you can find
-  a list of these in the file <file:Documentation/ide.txt>.
-
-  People with SCSI-only systems can say N here.
-
-Generic 4 drives/port support
-CONFIG_BLK_DEV_4DRIVES
-  Certain older chipsets, including the Tekram 690CD, use a single set
-  of I/O ports at 0x1f0 to control up to four drives, instead of the
-  customary two drives per port. Support for this can be enabled at
-  runtime using the "ide0=four" kernel boot parameter if you say Y
-  here.
-
-ALI M14xx support
-CONFIG_BLK_DEV_ALI14XX
-  This driver is enabled at runtime using the "ide0=ali14xx" kernel
-  boot parameter.  It enables support for the secondary IDE interface
-  of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
-  I/O speeds to be set as well.  See the files
-  <file:Documentation/ide.txt> and <file:drivers/ide/ali14xx.c> for
-  more info.
-
-DTC-2278 support
-CONFIG_BLK_DEV_DTC2278
-  This driver is enabled at runtime using the "ide0=dtc2278" kernel
-  boot parameter. It enables support for the secondary IDE interface
-  of the DTC-2278 card, and permits faster I/O speeds to be set as
-  well. See the <file:Documentation/ide.txt> and
-  <file:drivers/ide/dtc2278.c> files for more info.
-
-Holtek HT6560B support
-CONFIG_BLK_DEV_HT6560B
-  This driver is enabled at runtime using the "ide0=ht6560b" kernel
-  boot parameter. It enables support for the secondary IDE interface
-  of the Holtek card, and permits faster I/O speeds to be set as well.
-  See the <file:Documentation/ide.txt> and
-  <file:drivers/ide/ht6560b.c> files for more info.
-
-PROMISE DC4030 support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PDC4030
-  This driver provides support for the secondary IDE interface and
-  cache of Promise IDE chipsets, e.g. DC4030 and DC5030.  This driver
-  is known to incur timeouts/retries during heavy I/O to drives
-  attached to the secondary interface.  CD-ROM and TAPE devices are
-  not supported yet.  This driver is enabled at runtime using the
-  "ide0=dc4030" kernel boot parameter.  See the
-  <file:Documentation/ide.txt> and <file:drivers/ide/pdc4030.c> files
-  for more info.
-
-QDI QD65XX support
-CONFIG_BLK_DEV_QD65XX
-  This driver is enabled at runtime using the "ide0=qd65xx" kernel
-  boot parameter.  It permits faster I/O speeds to be set.  See the
-  <file:Documentation/ide.txt> and <file:drivers/ide/qd65xx.c> for
-  more info.
-
-UMC 8672 support
-CONFIG_BLK_DEV_UMC8672
-  This driver is enabled at runtime using the "ide0=umc8672" kernel
-  boot parameter. It enables support for the secondary IDE interface
-  of the UMC-8672, and permits faster I/O speeds to be set as well.
-  See the files <file:Documentation/ide.txt> and
-  <file:drivers/ide/umc8672.c> for more info.
-
-Amiga Gayle IDE interface support
-CONFIG_BLK_DEV_GAYLE
-  This is the IDE driver for the builtin IDE interface on some Amiga
-  models. It supports both the `A1200 style' (used in A600 and A1200)
-  and `A4000 style' (used in A4000 and A4000T) of the Gayle IDE
-  interface. Say Y if you have such an Amiga model and want to use IDE
-  devices (hard disks, CD-ROM drives, etc.) that are connected to the
-  builtin IDE interface.
-
-Falcon IDE interface support
-CONFIG_BLK_DEV_FALCON_IDE
-  This is the IDE driver for the builtin IDE interface on the Atari
-  Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
-  disks, CD-ROM drives, etc.) that are connected to the builtin IDE
-  interface.
-
-Amiga Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)
-CONFIG_BLK_DEV_BUDDHA
-  This is the IDE driver for the IDE interfaces on the Buddha, 
-  Catweasel and X-Surf expansion boards.  It supports up to two interfaces 
-  on the Buddha, three on the Catweasel and two on the X-Surf.
-
-  Say Y if you have a Buddha or Catweasel expansion board and want to
-  use IDE devices (hard disks, CD-ROM drives, etc.) that are connected
-  to one of its IDE interfaces.
-
-Amiga IDE Doubler support (EXPERIMENTAL)
-CONFIG_BLK_DEV_IDEDOUBLER
-  This driver provides support for the so-called `IDE doublers' (made
-  by various manufacturers, e.g. Eyetech) that can be connected to the
-  builtin IDE interface of some Amiga models. Using such an IDE
-  doubler, you can connect up to four instead of two IDE devices on
-  the Amiga's builtin IDE interface.
-
-  Note that the normal Amiga Gayle IDE driver may not work correctly
-  if you have an IDE doubler and don't enable this driver!
-
-  Say Y if you have an IDE doubler.  The driver is enabled at kernel
-  runtime using the "ide=doubler" kernel boot parameter.
-
-WarpEngine SCSI support
-CONFIG_WARPENGINE_SCSI
-  Support for MacroSystem Development's WarpEngine Amiga SCSI-2
-  controller. Info at
-  <http://www.lysator.liu.se/amiga/ar/guide/ar310.guide?FEATURE5>.
-
-Builtin PowerMac IDE support
-CONFIG_BLK_DEV_IDE_PMAC
-  This driver provides support for the built-in IDE controller on
-  most of the recent Apple Power Macintoshes and PowerBooks.
-  If unsure, say Y.
-
-PowerMac IDE DMA support
-CONFIG_BLK_DEV_IDEDMA_PMAC
-  This option allows the driver for the built-in IDE controller on
-  Power Macintoshes and PowerBooks to use DMA (direct memory access)
-  to transfer data to and from memory.  Saying Y is safe and improves
-  performance.
-
-Use DMA by default
-CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
-  This option allows the driver for the built-in IDE controller on
-  Power Macintoshes and PowerBooks to use DMA automatically, without
-  it having to be explicitly enabled.  This option is provided because
-  of concerns about a couple of cases where using DMA on buggy PC
-  hardware may have caused damage.  Saying Y should be safe on all
-  Apple machines.
-
-Macintosh Quadra/Powerbook IDE interface support
-CONFIG_BLK_DEV_MAC_IDE
-  This is the IDE driver for the builtin IDE interface on some m68k
-  Macintosh models. It supports both the `Quadra style' (used in
-  Quadra/ Centris 630 and Performa 588 models) and `Powerbook style'
-  (used in the Powerbook 150 and 190 models) IDE interface.
-
-  Say Y if you have such an Macintosh model and want to use IDE
-  devices (hard disks, CD-ROM drives, etc.) that are connected to the
-  builtin IDE interface.
-
-ICS IDE interface support
-CONFIG_BLK_DEV_IDE_ICSIDE
-  On Acorn systems, say Y here if you wish to use the ICS IDE
-  interface card.  This is not required for ICS partition support.
-  If you are unsure, say N to this.
-
-ICS DMA support
-CONFIG_BLK_DEV_IDEDMA_ICS
-  Say Y here if you want to add DMA (Direct Memory Access) support to
-  the ICS IDE driver.
-
-Use ICS DMA by default
-CONFIG_IDEDMA_ICS_AUTO
-  Prior to kernel version 2.1.112, Linux used to automatically use
-  DMA for IDE drives and chipsets which support it. Due to concerns
-  about a couple of cases where buggy hardware may have caused damage,
-  the default is now to NOT use DMA automatically. To revert to the
-  previous behaviour, say Y to this question.
-
-  If you suspect your hardware is at all flakey, say N here.
-  Do NOT email the IDE kernel people regarding this issue!
-
-XT hard disk support
-CONFIG_BLK_DEV_XD
-  Very old 8 bit hard disk controllers used in the IBM XT computer
-  will be supported if you say Y here.
-
-  If you want to compile the driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>. The module
-  will be called xd.o.
-
-  It's pretty unlikely that you have one of these: say N.
-
-PS/2 ESDI hard disk support
-CONFIG_BLK_DEV_PS2
-  Say Y here if you have a PS/2 machine with a MCA bus and an ESDI
-  hard disk.
-
-  If you want to compile the driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called ps2esdi.o.
-
-Mylex DAC960/DAC1100 PCI RAID Controller support
-CONFIG_BLK_DEV_DAC960
-  This driver adds support for the Mylex DAC960, AcceleRAID, and
-  eXtremeRAID PCI RAID controllers.  See the file
-  <file:Documentation/README.DAC960> for further information about
-  this driver.
-
-  If you want to compile the driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called DAC960.o.
-
-Parallel port IDE device support
-CONFIG_PARIDE
-  There are many external CD-ROM and disk devices that connect through
-  your computer's parallel port. Most of them are actually IDE devices
-  using a parallel port IDE adapter. This option enables the PARIDE
-  subsystem which contains drivers for many of these external drives.
-  Read <file:Documentation/paride.txt> for more information.
-
-  If you have said Y to the "Parallel-port support" configuration
-  option, you may share a single port between your printer and other
-  parallel port devices. Answer Y to build PARIDE support into your
-  kernel, or M if you would like to build it as a loadable module. If
-  your parallel port support is in a loadable module, you must build
-  PARIDE as a module. If you built PARIDE support into your kernel,
-  you may still build the individual protocol modules and high-level
-  drivers as loadable modules. If you build this support as a module,
-  it will be called paride.o.
-
-  To use the PARIDE support, you must say Y or M here and also to at
-  least one high-level driver (e.g. "Parallel port IDE disks",
-  "Parallel port ATAPI CD-ROMs", "Parallel port ATAPI disks" etc.) and
-  to at least one protocol driver (e.g. "ATEN EH-100 protocol",
-  "MicroSolutions backpack protocol", "DataStor Commuter protocol"
-  etc.).
-
-Parallel port IDE disks
-CONFIG_PARIDE_PD
-  This option enables the high-level driver for IDE-type disk devices
-  connected through a parallel port. If you chose to build PARIDE
-  support into your kernel, you may answer Y here to build in the
-  parallel port IDE driver, otherwise you should answer M to build
-  it as a loadable module. The module will be called pd.o. You
-  must also have at least one parallel port protocol driver in your
-  system. Among the devices supported by this driver are the SyQuest
-  EZ-135, EZ-230 and SparQ drives, the Avatar Shark and the backpack
-  hard drives from MicroSolutions.
-
-Parallel port ATAPI CD-ROMs
-CONFIG_PARIDE_PCD
-  This option enables the high-level driver for ATAPI CD-ROM devices
-  connected through a parallel port. If you chose to build PARIDE
-  support into your kernel, you may answer Y here to build in the
-  parallel port ATAPI CD-ROM driver, otherwise you should answer M to
-  build it as a loadable module. The module will be called pcd.o. You
-  must also have at least one parallel port protocol driver in your
-  system. Among the devices supported by this driver are the
-  MicroSolutions backpack CD-ROM drives and the Freecom Power CD. If
-  you have such a CD-ROM drive, you should also say Y or M to "ISO
-  9660 CD-ROM file system support" below, because that's the file
-  system used on CD-ROMs.
-
-Parallel port ATAPI disks
-CONFIG_PARIDE_PF
-  This option enables the high-level driver for ATAPI disk devices
-  connected through a parallel port. If you chose to build PARIDE
-  support into your kernel, you may answer Y here to build in the
-  parallel port ATAPI disk driver, otherwise you should answer M
-  to build it as a loadable module. The module will be called pf.o.
-  You must also have at least one parallel port protocol driver in
-  your system. Among the devices supported by this driver are the
-  MicroSolutions backpack PD/CD drive and the Imation Superdisk
-  LS-120 drive.
-
-Parallel port ATAPI tapes
-CONFIG_PARIDE_PT
-  This option enables the high-level driver for ATAPI tape devices
-  connected through a parallel port. If you chose to build PARIDE
-  support into your kernel, you may answer Y here to build in the
-  parallel port ATAPI disk driver, otherwise you should answer M
-  to build it as a loadable module. The module will be called pt.o.
-  You must also have at least one parallel port protocol driver in
-  your system. Among the devices supported by this driver is the
-  parallel port version of the HP 5GB drive.
-
-Parallel port generic ATAPI devices
-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 cdrtools, to send ATAPI commands directly to a
-  device.
-
-  If you chose to build PARIDE support into your kernel, you may
-  answer Y here to build in the parallel port generic ATAPI driver,
-  otherwise you should answer M to build it as a loadable module. The
-  module will be called pg.o.
-
-  You must also have at least one parallel port protocol driver in
-  your system.
-
-  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 cdrtools from
-  <ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/>. Versions 1.6.1a3 and
-  later fully support this driver.
-
-ATEN EH-100 protocol
-CONFIG_PARIDE_ATEN
-  This option enables support for the ATEN EH-100 parallel port IDE
-  protocol. This protocol is used in some inexpensive low performance
-  parallel port kits made in Hong Kong. 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 aten.o. You must also
-  have a high-level driver for the type of device that you want to
-  support.
-
-Micro Solutions BACKPACK Series 5 protocol
-CONFIG_PARIDE_BPCK
-  This option enables support for the Micro Solutions BACKPACK
-  parallel port Series 5 IDE protocol.  (Most BACKPACK drives made
-  before 1999 were Series 5) Series 5 drives will NOT always have the
-  Series noted on the bottom of the drive. Series 6 drivers will.
-
-  In other words, if your BACKPACK drive dosen't say "Series 6" on the
-  bottom, enable this option.
-
-  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 bpck.o.  You must also have a high-level driver for the type
-  of device that you want to support.
-
-Micro Solutions BACKPACK Series 6 protocol
-CONFIG_PARIDE_BPCK6
-  This option enables support for the Micro Solutions BACKPACK
-  parallel port Series 6 IDE protocol.  (Most BACKPACK drives made
-  after 1999 were Series 6) Series 6 drives will have the Series noted
-  on the bottom of the drive.  Series 5 drivers don't always have it
-  noted.
-
-  In other words, if your BACKPACK drive says "Series 6" on the
-  bottom, enable this option.
-
-  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 bpck6.o.  You must also have a high-level driver for the type
-  of device that you want to support.
-
-DataStor Commuter protocol
-CONFIG_PARIDE_COMM
-  This option enables support for the Commuter parallel port IDE
-  protocol from DataStor. 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 comm.o. You must also have
-  a high-level driver for the type of device that you want to support.
-
-DataStor EP-2000 protocol
-CONFIG_PARIDE_DSTR
-  This option enables support for the EP-2000 parallel port IDE
-  protocol from DataStor. 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 dstr.o. You must also have
-  a high-level driver for the type of device that you want to support.
-
-Shuttle EPAT/EPEZ protocol
-CONFIG_PARIDE_EPAT
-  This option enables support for the EPAT parallel port IDE protocol.
-  EPAT is a parallel port IDE adapter manufactured by Shuttle
-  Technology and widely used in devices from major vendors such as
-  Hewlett-Packard, SyQuest, Imation and Avatar. 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 epat.o. You must also
-  have a high-level driver for the type of device that you want to
-  support.
-
-Shuttle EPAT c7/c8 extension
-CONFIG_PARIDE_EPATC8
-  This option enables support for the newer Shuttle EP1284 (aka c7 and
-  c8) chip. You need this if you are using any recent Imation SuperDisk
-  (LS-120) drive.
-
-Shuttle EPIA protocol
-CONFIG_PARIDE_EPIA
-  This option enables support for the (obsolete) EPIA parallel port
-  IDE protocol from Shuttle Technology. This adapter can still be
-  found in some no-name kits. 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 epia.o. You must also have a
-  high-level driver for the type of device that you want to support.
-
-FIT TD-2000 protocol
-CONFIG_PARIDE_FIT2
-  This option enables support for the TD-2000 parallel port IDE
-  protocol from Fidelity International Technology. This is a simple
-  (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.
-  You must also have a high-level driver for the type of device that
-  you want to support.
-
-FIT TD-3000 protocol
-CONFIG_PARIDE_FIT3
-  This option enables support for the TD-3000 parallel port IDE
-  protocol from Fidelity International Technology. This protocol is
-  used in newer models of their portable disk, CD-ROM and PD/CD
-  devices. 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 fit3.o. You must also have a high-level driver for the type
-  of device that you want to support.
-
-Freecom IQ ASIC-2 protocol
-CONFIG_PARIDE_FRIQ
-  This option enables support for version 2 of the Freecom IQ parallel
-  port IDE adapter.  This adapter is used by the Maxell Superdisk
-  drive.  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 friq.o. You must also have a high-level driver for the type
-  of device that you want to support.
-
-FreeCom power protocol
-CONFIG_PARIDE_FRPW
-  This option enables support for the Freecom power parallel port IDE
-  protocol. 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 frpw.o. You must also have a high-level driver for the type
-  of device that you want to support.
-
-KingByte KBIC-951A/971A protocols
-CONFIG_PARIDE_KBIC
-  This option enables support for the KBIC-951A and KBIC-971A parallel
-  port IDE protocols from KingByte Information Corp. KingByte's
-  adapters appear in many no-name portable disk and CD-ROM products,
-  especially in Europe. 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 kbic.o. You must also have a high-level driver
-  for the type of device that you want to support.
-
-KT PHd protocol
-CONFIG_PARIDE_KTTI
-  This option enables support for the "PHd" parallel port IDE protocol
-  from KT Technology. This is a simple (low speed) adapter that is
-  used in some 2.5" 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. You must also
-  have a high-level driver for the type of device that you want to
-  support.
-
-OnSpec 90c20 protocol
-CONFIG_PARIDE_ON20
-  This option enables support for the (obsolete) 90c20 parallel port
-  IDE protocol from OnSpec (often marketed under the ValuStore brand
-  name). 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 on20.o. You must also have a high-level driver for the
-  type of device that you want to support.
-
-OnSpec 90c26 protocol
-CONFIG_PARIDE_ON26
-  This option enables support for the 90c26 parallel port IDE protocol
-  from OnSpec Electronics (often marketed under the ValuStore brand
-  name). 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 on26.o. You must also have a high-level driver for the type
-  of device that you want to support.
-
-Logical Volume Manager (LVM) support
-CONFIG_BLK_DEV_LVM
-  This driver lets you combine several hard disks, hard disk
-  partitions, multiple devices or even loop devices (for evaluation
-  purposes) into a volume group.  Imagine a volume group as a kind of
-  virtual disk. Logical volumes, which can be thought of as virtual
-  partitions, can be created in the volume group.  You can resize
-  volume groups and logical volumes after creation time, corresponding
-  to new capacity needs.  Logical volumes are accessed as block
-  devices named /dev/VolumeGroupName/LogicalVolumeName.
-
-  For details see <file:Documentation/LVM-HOWTO>.  You will need
-  supporting user space software; location is in
-  <file:Documentation/Changes>.
-
-  If you want to compile this 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 lvm-mod.o.
-
-Multiple devices driver support (RAID and LVM)
-CONFIG_MD
-  Support multiple physical spindles through a single logical device.
-  Required for RAID and logical volume management (LVM).
-
-Multiple devices driver support
-CONFIG_BLK_DEV_MD
-  This driver lets you combine several hard disk partitions into one
-  logical block device. This can be used to simply append one
-  partition to another one or to combine several redundant hard disks
-  into a RAID1/4/5 device so as to provide protection against hard
-  disk failures. This is called "Software RAID" since the combining of
-  the partitions is done by the kernel. "Hardware RAID" means that the
-  combining is done by a dedicated controller; if you have such a
-  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.
-
-  If unsure, say N.
-
-Linear (append) mode
-CONFIG_MD_LINEAR
-  If you say Y here, then your multiple devices driver will be able to
-  use the so-called linear mode, i.e. it will combine the hard disk
-  partitions by simply appending one to the other.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called linear.o.
-
-  If unsure, say Y.
-
-RAID-0 (striping) mode
-CONFIG_MD_RAID0
-  If you say Y here, then your multiple devices driver will be able to
-  use the so-called raid0 mode, i.e. it will combine the hard disk
-  partitions into one logical device in such a fashion as to fill them
-  up evenly, one chunk here and one chunk there. This will increase
-  the throughput rate if the partitions reside on distinct disks.
-
-  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.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called raid0.o.
-
-  If unsure, say Y.
-
-RAID-1 (mirroring) mode
-CONFIG_MD_RAID1
-  A RAID-1 set consists of several disk drives which are exact copies
-  of each other.  In the event of a mirror failure, the RAID driver
-  will continue to use the operational mirrors in the set, providing
-  an error free MD (multiple device) to the higher levels of the
-  kernel.  In a set with N drives, the available space is the capacity
-  of a single drive, and the set protects against a failure of (N - 1)
-  drives.
-
-  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.
-
-  If you want to use such a RAID-1 set, say Y. This code is also
-  available as a module called raid1.o ( = 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>.
-
-  If unsure, say Y.
-
-RAID-4/RAID-5 mode
-CONFIG_MD_RAID5
-  A RAID-5 set of N drives with a capacity of C MB per drive provides
-  the capacity of C * (N - 1) MB, and protects against a failure
-  of a single drive. For a given sector (row) number, (N - 1) drives
-  contain data sectors, and one drive contains the parity protection.
-  For a RAID-4 set, the parity blocks are present on a single drive,
-  while a RAID-5 set distributes the parity across the drives in one
-  of the available parity distribution methods.
-
-  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.
-
-  If you want to use such a RAID-4/RAID-5 set, say Y. This code is
-  also available as a module called raid5.o ( = 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>.
-
-  If unsure, say Y.
-
-Multipath I/O support
-CONFIG_MD_MULTIPATH
-  Multipath-IO is the ability of certain devices to address the same
-  physical disk over multiple 'IO paths'. The code ensures that such
-  paths can be defined and handled at runtime, and ensures that a
-  transparent failover to the backup path(s) happens if a IO errors
-  arrives on the primary path.
-
-  If unsure, say N.
-
-Support for IDE Raid controllers
-CONFIG_BLK_DEV_ATARAID
-  Say Y or M if you have an IDE Raid controller and want linux
-  to use its softwareraid feature.  You must also select an
-  appropriate for your board low-level driver below.
-
-  Note, that Linux does not use the Raid implemetation in BIOS, and
-  the main purpose for this feature is to retain compatibility and
-  data integrity with other OS-es, using the same disk array. Linux
-  has its own Raid drivers, which you should use if you need better
-  performance.
-
-Support Promise software RAID (Fasttrak(tm))
-CONFIG_BLK_DEV_ATARAID_PDC
-  Say Y or M if you have a Promise Fasttrak (tm) Raid controller
-  and want linux to use the softwareraid feature of this card.
-  This driver uses /dev/ataraid/dXpY (X and Y numbers) as device
-  names.
-
-  If you choose to compile this as a module, the module will be called
-  pdcraid.o.
-
-Highpoint 370 software RAID
-CONFIG_BLK_DEV_ATARAID_HPT
-  Say Y or M if you have a Highpoint HPT 370 Raid controller
-  and want linux to use the softwareraid feature of this card.
-  This driver uses /dev/ataraid/dXpY (X and Y numbers) as device
-  names.
-
-  If you choose to compile this as a module, the module will be called
-  hptraid.o.
-
-Support for Acer PICA 1 chipset
-CONFIG_ACER_PICA_61
-  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/>.
-
-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/>.
-
-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/>.
-
-Baget AMD LANCE support
-CONFIG_BAGETLANCE
-  Say Y to enable kernel support for AMD Lance Ethernet cards on the
-  MIPS-32-based Baget embedded system.  This chipset is better known
-  via the NE2100 cards.
-
-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/>.
-
-  If you have one of the following DECstation Models you definitely
-  want to choose R4xx0 for the CPU Type:
-
-	DECstation 5000/50
-	DECstation 5000/150
-	DECstation 5000/260
-	DECsystem 5900/260
-
-  otherwise choose R3000.
-
-Support for Cobalt Micro Server
-CONFIG_COBALT_MICRO_SERVER
-  Support for MIPS-based Cobalt boxes (they have been bought by Sun
-  and are now the "Server Appliance Business Unit") including the 2700
-  series -- versions 1 of the Qube and Raq.  To compile a Linux kernel
-  for this hardware, say Y here.
-
-Support for Cobalt 2800
-CONFIG_COBALT_28
-  Support for the second generation of MIPS-based Cobalt boxes (they
-  have been bought by Sun and are now the "Server Appliance Business
-  Unit") including the 2800 series -- versions 2 of the Qube and Raq.
-  To compile a Linux kernel for this hardware, say Y here.
-
-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/>.
-
-Support for NEC DDB Vrc-5074
-CONFIG_DDB5074
-  This enables support for the VR5000-based NEC DDB Vrc-5074
-  evaluation board.
-
-Support for NEC DDB Vrc-5476
-CONFIG_DDB5476
-  This enables support for the R5432-based NEC DDB Vrc-5476
-  evaluation board.
-
-  Features : kernel debugging, serial terminal, NFS root fs, on-board
-  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.
-
-Support for NEC DDB Vrc-5477
-CONFIG_DDB5477
-  This enables support for the R5432-based NEC DDB Vrc-5477
-  evaluation board.
-
-  Features : kernel debugging, serial terminal, NFS root fs, on-board
-  ether port (Need an additional patch at <http://linux.junsun.net/>),
-  USB, AC97, PCI, etc.
-
-Support for MIPS Atlas board
-CONFIG_MIPS_ATLAS
-  This enables support for the QED R5231-based MIPS Atlas evaluation
-  board.
-
-Support for MIPS Malta board
-CONFIG_MIPS_MALTA
-  This enables support for the VR5000-based MIPS Malta evaluation
-  board.
-
-Support for Galileo Evaluation board or CoSine Orion
-CONFIG_ORION
-  Say Y if configuring for the Galileo evaluation board
-  or CoSine Orion.  More information is available at
-  <http://tochna.technion.ac.il/project/linux/html/linux.html>.
-
-  Otherwise, say N.
-
-Support for Mips Magnum 4000
-CONFIG_MIPS_MAGNUM_4000
-  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/>.
-
-Enable Qtronix 990P Keyboard Support
-CONFIG_QTRONIX_KEYBOARD
-  Images of Qtronix keyboards are at
-  <http://www.qtronix.com/keyboard.html>.
-
-Support for Olivetti M700
-CONFIG_OLIVETTI_M700
-  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/>.
-
-Support for SNI RM200 PCI
-CONFIG_SNI_RM200_PCI
-  The SNI RM200 PCI was a MIPS-based platform manufactured by Siemens
-  Nixdorf Informationssysteme (SNI), parent company of Pyramid
-  Technology and now in turn merged with Fujitsu.  Say Y here to
-  support this machine type.
-
-Support for SGI IP22
-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
-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
-  here.
-
-IP27 N-Mode
-CONFIG_SGI_SN0_N_MODE
-  The nodes of Origin 200, Origin 2000 and Onyx 2 systems can be
-  configured in either N-Modes which allows for more nodes or M-Mode
-  which allows for more memory.  Your system is most probably
-  running in M-Mode, so you should say N here.
-
-MIPS JAZZ onboard SONIC Ethernet support
-CONFIG_MIPS_JAZZ_SONIC
-  This is the driver for the onboard card of MIPS Magnum 4000,
-  Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
-
-MIPS JAZZ FAS216 SCSI support
-CONFIG_JAZZ_ESP
-  This is the driver for the onboard SCSI host adapter of MIPS Magnum
-  4000, Acer PICA, Olivetti M700-10 and a few other identical OEM
-  systems.
-
-MIPS GT96100 support
-CONFIG_MIPS_GT96100
-  Say Y here to support the Galileo Technology GT96100 communications
-  controller card.  There is a web page at <http://www.galileot.com/>.
-
-MIPS GT96100 Ethernet support
-CONFIG_MIPS_GT96100ETH
-  Say Y here to support the Ethernet subsystem on your GT96100 card.
-
-Zalon SCSI support
-CONFIG_SCSI_ZALON
-  The Zalon is an interface chip that sits between the PA-RISC
-  processor and the NCR 53c720 SCSI controller on K-series PA-RISC
-  boards (these are used, among other places, on some HP 780
-  workstations).  Say Y here to make sure it gets initialized
-  correctly before the Linux kernel tries to talk to the controller.
-
-Kernel floating-point instruction emulation
-CONFIG_MIPS_FPU_EMULATOR
-  This option enables the MIPS software floatingpoint support.  Due to
-  the way floating point works you should always enable this option
-  unless you exactly know what you're doing.
-
-SGI PROM Console Support
-CONFIG_SGI_PROM_CONSOLE
-  Say Y here to set up the boot console on serial port 0.
-
-DZ11 Serial Support
-CONFIG_DZ
-  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>.
-
-Z85C30 Serial Support
-CONFIG_ZS
-  Documentation on the Zilog 85C350 serial communications controller
-  is downloadable at <http://www.zilog.com/pdfs/serial/z85c30.pdf>.
-
-PCMCIA SCSI adapter support
-CONFIG_SCSI_PCMCIA
-  Say Y here if you intend to attach a PCMCIA or CardBus card to your
-  computer which acts as a SCSI host adapter. These are credit card
-  size devices often used with laptops.
-
-  Note that the answer to this question won't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions PCMCIA SCSI host adapters.
-
-Adaptec APA1480 CardBus support
-CONFIG_PCMCIA_APA1480
-  Say Y here if you intend to attach this type of CardBus SCSI host
-  adapter to your computer.
-
-  This driver is also available as a module called apa1480_cb.o ( =
-  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>.
-
-NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support
-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.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
-  whenever you want). If you want to compile it as a module, say M
-  here and read <file:Documentation/modules.txt>.
-
-Adaptec AHA152X PCMCIA support
-CONFIG_PCMCIA_AHA152X
-  Say Y here if you intend to attach this type of PCMCIA SCSI host
-  adapter to your computer.
-
-  This driver is also available as a module called aha152x_cs.o ( =
-  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>.
-
-Qlogic PCMCIA support
-CONFIG_PCMCIA_QLOGIC
-  Say Y here if you intend to attach this type of PCMCIA SCSI host
-  adapter to your computer.
-
-  This driver is also available as a module called qlogic_cs.o ( =
-  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>.
-
-Future Domain PCMCIA support
-CONFIG_PCMCIA_FDOMAIN
-  Say Y here if you intend to attach this type of PCMCIA SCSI host
-  adapter to your computer.
-
-  This driver is also available as a module called fdomain_cs.o ( =
-  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>.
-
-# Choice: mipstype
-CPU type
-CONFIG_CPU_R3000
-  Please make sure to pick the right CPU type. Linux/MIPS is not
-  designed to be generic, i.e. Kernels compiled for R3000 CPUs will
-  *not* work on R4000 machines and vice versa.  However, since most
-  of the supported machines have an R4000 (or similar) CPU, R4x00
-  might be a safe bet.  If the resulting kernel does not work,
-  try to recompile with R3000.
-
-  R3000    MIPS Technologies R3000-series processors,
-           including the 3041, 3051, and 3081.
-
-  R6000    MIPS Technologies R6000-series processors,
-           including the 64474, 64475, 64574 and 64575.
-
-  R4300    MIPS Technologies R4300-series processors.
-
-  R4x00    MIPS Technologies R4000-series processors other than 4300,
-           including the 4640, 4650, and 4700.
-
-  R5000    MIPS Technologies R5000-series processors other than the
-           Nevada.
-
-  R52xx    MIPS Technologies R52xx-series ("Nevada") processors.
-
-  R10000   MIPS Technologies R10000-series processors.
-
-R6000
-CONFIG_CPU_R6000
-  MIPS Technologies R6000-series processors, including the 64474,
-  64475, 64574 and 64575.
-
-R4300
-CONFIG_CPU_R4300
-  MIPS Technologies R4300-series processors.
-
-R4x00
-CONFIG_CPU_R4X00
-  MIPS Technologies R4000-series processors other than 4300, including
-  the 4640, 4650, and 4700.
-
-R5000
-CONFIG_CPU_R5000
-  MIPS Technologies R5000-series processors other than the Nevada.
-
-R52x0
-CONFIG_CPU_NEVADA
-  MIPS Technologies R52x0-series ("Nevada") processors.
-
-R8000
-CONFIG_CPU_R8000
-  MIPS Technologies R8000-series processors.
-
-R10000
-CONFIG_CPU_R10000
-  MIPS Technologies R10000-series processors.
-
-Discontiguous Memory Support
-CONFIG_DISCONTIGMEM
-  Say Y to upport efficient handling of discontiguous physical memory,
-  for architectures which are either NUMA (Non-Uniform Memory Access)
-  or have huge holes in the physical address space for other reasons.
-  See <file:Documentation/vm/numa> for more.
-
-Mapped kernel support
-CONFIG_MAPPED_KERNEL
-  Change the way a Linux kernel is loaded unto memory on a MIPS64
-  machine.  This is required in order to support text replication and
-  NUMA.  If you need to undersatand it, read the source code.
-
-Kernel text replication support
-CONFIG_REPLICATE_KTEXT
-  Say Y here to enable replicating the kernel text across multiple
-  nodes in a NUMA cluster.  This trades memory for speed.
-
-Exception handler replication support
-CONFIG_REPLICATE_EXHANDLERS
-  Say Y here to enable replicating the kernel exception handlers
-  across multiple nodes in a NUMA cluster. This trades memory for
-  speed.
-
-NUMA support?
-CONFIG_NUMA
-  Say Y to compile the kernel to support NUMA (Non-Uniform Memory
-  Access).  This option is for configuring high-end multiprocessor
-  server machines.  If in doubt, say N.
-
-CPU type
-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
-  kernel built with this option will not run on any other type of
-  processor or vice versa.
-
-CPU feature configuration
-CONFIG_CPU_ADVANCED
-  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
-CONFIG_CPU_HAS_LLSC
-  MIPS R4000 series and later provide the Load Linked (ll)
-  and Store Conditional (sc) instructions. More information is
-  available at <http://www.go-ecs.com/mips/miptek1.htm>.
-
-  Say Y here if your CPU has the ll and sc instructions.  Say Y here
-  for better performance, N if you don't know.  You must say Y here
-  for multiprocessor machines.
-
-lld and scd instructions
-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
-  you don't know.  You must say Y here for multiprocessor machines.
-
-Writeback Buffer available
-CONFIG_CPU_HAS_WB
-  Say N here for slightly better performance.  You must say Y here for
-  machines which require flushing of write buffers in software.  Saying
-  Y is the safe option; N may result in kernel malfunction and crashes.
-
-Support for large 64-bit configurations
-CONFIG_MIPS_INSANE_LARGE
-  MIPS R10000 does support a 44 bit / 16TB address space as opposed to
-  previous 64-bit processors which only supported 40 bit / 1TB. If you
-  need processes of more than 1TB virtual address space, say Y here.
-  This will result in additional memory usage, so it is not
-  recommended for normal users.
-
-Generate little endian code
-CONFIG_CPU_LITTLE_ENDIAN
-  Some MIPS machines can be configured for either little or big endian
-  byte order. These modes require different kernels. Say Y if your
-  machine is little endian, N if it's a big endian machine.
-
-Use power LED as a heartbeat
-CONFIG_HEARTBEAT
-  Use the power-on LED on your machine as a load meter.  The exact
-  behavior is platform-dependent, but normally the flash frequency is
-  a hyperbolic function of the 5-minute load average.
-
-Networking support
-CONFIG_NET
-  Unless you really know what you are doing, you should say Y here.
-  The reason is that some programs need kernel networking support even
-  when running on a stand-alone machine that isn't connected to any
-  other computer. If you are upgrading from an older kernel, you
-  should consider updating your networking tools too because changes
-  in the kernel and the tools often go hand in hand. The tools are
-  contained in the package net-tools, the location and version number
-  of which are given in <file:Documentation/Changes>.
-
-  For a general introduction to Linux networking, it is highly
-  recommended to read the NET-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-Socket filtering
-CONFIG_FILTER
-  The Linux Socket Filter is derived from the Berkeley Packet Filter.
-  If you say Y here, user-space programs can attach a filter to any
-  socket and thereby tell the kernel that it should allow or disallow
-  certain types of data to get through the socket.  Linux Socket
-  Filtering works on all socket types except TCP for now.  See the
-  text file <file:Documentation/networking/filter.txt> for more
-  information.
-
-  You need to say Y here if you want to use PPP packet filtering
-  (see the CONFIG_PPP_FILTER option below).
-
-  If unsure, say N.
-
-Network packet filtering (replaces ipchains)
-CONFIG_NETFILTER
-  Netfilter is a framework for filtering and mangling network packets
-  that pass through your Linux box.
-
-  The most common use of packet filtering is to run your Linux box as
-  a firewall protecting a local network from the Internet. The type of
-  firewall provided by this kernel support is called a "packet
-  filter", which means that it can reject individual network packets
-  based on type, source, destination etc. The other kind of firewall,
-  a "proxy-based" one, is more secure but more intrusive and more
-  bothersome to set up; it inspects the network traffic much more
-  closely, modifies it and has knowledge about the higher level
-  protocols, which a packet filter lacks. Moreover, proxy-based
-  firewalls often require changes to the programs running on the local
-  clients. Proxy-based firewalls don't need support by the kernel, but
-  they are often combined with a packet filter, which only works if
-  you say Y here.
-
-  You should also say Y here if you intend to use your Linux box as
-  the gateway to the Internet for a local network of machines without
-  globally valid IP addresses. This is called "masquerading": if one
-  of the computers on your local network wants to send something to
-  the outside, your box can "masquerade" as that computer, i.e. it
-  forwards the traffic to the intended outside destination, but
-  modifies the packets to make it look like they came from the
-  firewall box itself. It works both ways: if the outside host
-  replies, the Linux box will silently forward the traffic to the
-  correct local computer. This way, the computers on your local net
-  are completely invisible to the outside world, even though they can
-  reach the outside and can receive replies. It is even possible to
-  run globally visible servers from within a masqueraded local network
-  using a mechanism called portforwarding. Masquerading is also often
-  called NAT (Network Address Translation).
-
-  Another use of Netfilter is in transparent proxying: if a machine on
-  the local network tries to connect to an outside host, your Linux
-  box can transparently forward the traffic to a local server,
-  typically a caching proxy server.
-
-  Various modules exist for netfilter which replace the previous
-  masquerading (ipmasqadm), packet filtering (ipchains), transparent
-  proxying, and portforwarding mechanisms. Please see
-  <file:Documentation/Changes> under "iptables" for the location of
-  these packages.
-
-  Make sure to say N to "Fast switching" below if you intend to say Y
-  here, as Fast switching currently bypasses netfilter.
-
-  Chances are that you should say Y here if you compile a kernel which
-  will run as a router and N for regular hosts. If unsure, say N.
-
-Network packet filtering debugging
-CONFIG_NETFILTER_DEBUG
-  You can say Y here if you want to get additional messages useful in
-  debugging the netfilter code.
-
-Connection tracking (required for masq/NAT)
-CONFIG_IP_NF_CONNTRACK
-  Connection tracking keeps a record of what packets have passed
-  through your machine, in order to figure out how they are related
-  into connections.
-
-  This is required to do Masquerading or other kinds of Network
-  Address Translation (except for Fast NAT).  It can also be used to
-  enhance packet filtering (see `Connection state match support'
-  below).
-
-  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
-CONFIG_IP_NF_IRC
-  There is a commonly-used extension to IRC called
-  Direct Client-to-Client Protocol (DCC).  This enables users to send
-  files to each other, and also chat to each other without the need
-  of a server.  DCC Sending is used anywhere you send files over IRC,
-  and DCC Chat is most commonly used by Eggdrop bots.  If you are
-  using NAT, this extension will enable you to send files and initiate
-  chats.  Note that you do NOT need this extension to get files or
-  have others initiate chats, or everything else in IRC.
-
-  If you want to compile it as a module, say 'M' here and read
-  Documentation/modules.txt.  If unsure, say 'N'.
-
-FTP protocol support
-CONFIG_IP_NF_FTP
-  Tracking FTP connections is problematic: special helpers are
-  required for tracking them, and doing masquerading and other forms
-  of Network Address Translation on them.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `Y'.
-
-User space queueing via NETLINK
-CONFIG_IP_NF_QUEUE
-  Netfilter has the ability to queue packets to user space: the
-  netlink device can be used to access them using this driver.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-IP tables support (required for filtering/masq/NAT)
-CONFIG_IP_NF_IPTABLES
-  iptables is a general, extensible packet identification framework.
-  The packet filtering and full NAT (masquerading, port forwarding,
-  etc) subsystems now use this: say `Y' or `M' here if you want to use
-  either of those.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-limit match support
-CONFIG_IP_NF_MATCH_LIMIT
-  limit matching allows you to control the rate at which a rule can be
-  matched: mainly useful in combination with the LOG target ("LOG
-  target support", below) and to avoid some Denial of Service attacks.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-MAC address match support
-CONFIG_IP_NF_MATCH_MAC
-  MAC matching allows you to match packets based on the source
-  Ethernet address of the packet.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-Netfilter MARK match support
-CONFIG_IP_NF_MATCH_MARK
-  Netfilter mark matching allows you to match packets based on the
-  `nfmark' value in the packet.  This can be set by the MARK target
-  (see below).
-
-  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_IP_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'.
-
-TTL match support
-CONFIG_IP_NF_MATCH_TTL
-  This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user
-  to match packets by their TTL value.
-
-  If you want to compile it as a module, say M here and read
-  Documentation/modules.txt.  If unsure, say `N'.
-
-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.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-TOS match support
-CONFIG_IP_NF_MATCH_TOS
-  TOS matching allows you to match packets based on the Type Of
-  Service fields of the IP packet.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-Connection state match support
-CONFIG_IP_NF_MATCH_STATE
-  Connection state matching allows you to match packets based on their
-  relationship to a tracked connection (ie. previous packets).  This
-  is a powerful tool for packet classification.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-Unclean match support
-CONFIG_IP_NF_MATCH_UNCLEAN
-  Unclean packet matching matches any strange or invalid packets, by
-  looking at a series of fields in the IP, TCP, UDP and ICMP headers.
-
-  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_IP_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_IP_NF_FILTER
-  Packet filtering defines a table `filter', which has a series of
-  rules for simple packet filtering at local input, forwarding and
-  local output.  See the man page for iptables(8).
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-REJECT target support
-CONFIG_IP_NF_TARGET_REJECT
-  The REJECT target allows a filtering rule to specify that an ICMP
-  error should be issued in response to an incoming packet, rather
-  than silently being dropped.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-MIRROR target support
-CONFIG_IP_NF_TARGET_MIRROR
-  The MIRROR target allows a filtering rule to specify that an
-  incoming packet should be bounced back to the sender.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-Full NAT (Network Address Translation)
-CONFIG_IP_NF_NAT
-  The Full NAT option allows masquerading, port forwarding and other
-  forms of full Network Address Port Translation.  It is controlled by
-  the `nat' table in iptables: see the man page for iptables(8).
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-MASQUERADE target support
-CONFIG_IP_NF_TARGET_MASQUERADE
-  Masquerading is a special case of NAT: all outgoing connections are
-  changed to seem to come from a particular interface's address, and
-  if the interface goes down, those connections are lost.  This is
-  only useful for dialup accounts with dynamic IP address (ie. your IP
-  address will be different on next dialup).
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-Basic SNMP-ALG support
-CONFIG_IP_NF_NAT_SNMP_BASIC
-
-  This module implements an Application Layer Gateway (ALG) for
-  SNMP payloads.  In conjunction with NAT, it allows a network
-  management system to access multiple private networks with
-  conflicting addresses.  It works by modifying IP addresses
-  inside SNMP payloads to match IP-layer NAT mapping.
-
-  This is the "basic" form of SNMP-ALG, as described in RFC 2962
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-REDIRECT target support
-CONFIG_IP_NF_TARGET_REDIRECT
-  REDIRECT is a special case of NAT: all incoming connections are
-  mapped onto the incoming interface's address, causing the packets to
-  come to the local machine instead of passing through.  This is
-  useful for transparent proxies.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-Packet mangling
-CONFIG_IP_NF_MANGLE
-  This option adds a `mangle' table to iptables: see the man page for
-  iptables(8).  This table is used for various packet alterations
-  which can effect how the packet is routed.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-TOS target support
-CONFIG_IP_NF_TARGET_TOS
-  This option adds a `TOS' target, which allows you to create rules in
-  the `mangle' table which alter the Type Of Service field of an IP
-  packet prior to routing.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-MARK target support
-CONFIG_IP_NF_TARGET_MARK
-  This option adds a `MARK' target, which allows you to create rules
-  in the `mangle' table which alter the netfilter mark (nfmark) field
-  associated with the packet prior to routing. This can change
-  the routing method (see `Use netfilter MARK value as routing
-  key') and can also be used by other subsystems to change their
-  behavior.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-TCPMSS target support
-CONFIG_IP_NF_TARGET_TCPMSS
-  This option adds a `TCPMSS' target, which allows you to alter the
-  MSS value of TCP SYN packets, to control the maximum size for that
-  connection (usually limiting it to your outgoing interface's MTU
-  minus 40).
-
-  This is used to overcome criminally braindead ISPs or servers which
-  block ICMP Fragmentation Needed packets.  The symptoms of this
-  problem are that everything works fine from your Linux
-  firewall/router, but machines behind it can never exchange large
-  packets:
-	1) Web browsers connect, then hang with no data received.
-	2) Small mail works fine, but large emails hang.
-	3) ssh works fine, but scp hangs after initial handshaking.
-
-  Workaround: activate this option and add a rule to your firewall
-  configuration like:
-
-        iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-		 -j TCPMSS --clamp-mss-to-pmtu
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-TCPMSS match support
-CONFIG_IP_NF_MATCH_TCPMSS
-  This option adds a `tcpmss' match, which allows you to examine the
-  MSS value of TCP SYN packets, which control the maximum packet size
-  for that connection.
-
-  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_IP_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'.
-
-ipchains (2.2-style) support
-CONFIG_IP_NF_COMPAT_IPCHAINS
-  This option places ipchains (with masquerading and redirection
-  support) back into the kernel, using the new netfilter
-  infrastructure.  It is not recommended for new installations (see
-  `Packet filtering').  With this enabled, you should be able to use
-  the ipchains tool exactly as in 2.2 kernels.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-ipfwadm (2.0-style) support
-CONFIG_IP_NF_COMPAT_IPFWADM
-  This option places ipfwadm (with masquerading and redirection
-  support) back into the kernel, using the new netfilter
-  infrastructure.  It is not recommended for new installations (see
-  `Packet filtering').  With this enabled, you should be able to use
-  the ipfwadm tool exactly as in 2.0 kernels.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-MAC address match support
-CONFIG_IP6_NF_MATCH_MAC
-  mac matching allows you to match packets based on the source
-  Ethernet address of the packet.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-Netfilter MARK match support
-CONFIG_IP6_NF_MATCH_MARK
-  Netfilter mark matching allows you to match packets based on the
-  `nfmark' value in the packet.  This can be set by the MARK target
-  (see below).
-
-  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
-  rules for simple packet filtering at local input, forwarding and
-  local output.  See the man page for iptables(8).
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-Packet mangling
-CONFIG_IP6_NF_MANGLE
-  This option adds a `mangle' table to iptables: see the man page for
-  iptables(8).  This table is used for various packet alterations
-  which can effect how the packet is routed.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-MARK target support
-CONFIG_IP6_NF_TARGET_MARK
-  This option adds a `MARK' target, which allows you to create rules
-  in the `mangle' table which alter the netfilter mark (nfmark) field
-  associated with the packet packet prior to routing. This can change
-  the routing method (see `Use netfilter MARK value as routing
-  key') and can also be used by other subsystems to change their
-  behavior.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-TCP Explicit Congestion Notification support
-CONFIG_INET_ECN
-  Explicit Congestion Notification (ECN) allows routers to notify
-  clients about network congestion, resulting in fewer dropped packets
-  and increased network performance.  This option adds ECN support to
-  the Linux kernel, as well as a sysctl (/proc/sys/net/ipv4/tcp_ecn)
-  which allows ECN support to be disabled at runtime.
-
-  Note that, on the Internet, there are many broken firewalls which
-  refuse connections from ECN-enabled machines, and it may be a while
-  before these firewalls are fixed.  Until then, to access a site
-  behind such a firewall (some of which are major sites, at the time
-  of this writing) you will have to disable this option, either by
-  saying N now or by using the sysctl.
-
-  If in doubt, say N.
-
-IPv6 tables support (required for filtering/masq/NAT)
-CONFIG_IP6_NF_IPTABLES
-  ip6tables is a general, extensible packet identification framework.
-  Currently only the packet filtering and packet mangling subsystem
-  for IPv6 use this, but connection tracking is going to follow.
-  Say 'Y' or 'M' here if you want to use either of those.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-IPv6 limit match support
-CONFIG_IP6_NF_MATCH_LIMIT
-  limit matching allows you to control the rate at which a rule can be
-  matched: mainly useful in combination with the LOG target ("LOG
-  target support", below) and to avoid some Denial of Service attacks.
-
-  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
-  flooding". This denial-of-service attack prevents legitimate remote
-  users from being able to connect to your computer during an ongoing
-  attack and requires very little work from the attacker, who can
-  operate from anywhere on the Internet.
-
-  SYN cookies provide protection against this type of attack. If you
-  say Y here, the TCP/IP stack will use a cryptographic challenge
-  protocol known as "SYN cookies" to enable legitimate users to
-  continue to connect, even when your machine is under attack. There
-  is no need for the legitimate users to change their TCP/IP software;
-  SYN cookies work transparently to them. For technical information
-  about SYN cookies, check out <http://cr.yp.to/syncookies.html>.
-
-  If you are SYN flooded, the source address reported by the kernel is
-  likely to have been forged by the attacker; it is only reported as
-  an aid in tracing the packets to their actual source and should not
-  be taken as absolute truth.
-
-  SYN cookies may prevent correct error reporting on clients when the
-  server is really overloaded. If this happens frequently better turn
-  them off.
-
-  If you say Y here, note that SYN cookies aren't enabled by default;
-  you can enable them by saying Y to "/proc file system support" and
-  "Sysctl support" below and executing the command
-
-    echo 1 >/proc/sys/net/ipv4/tcp_syncookies
-
-  at boot time after the /proc file system has been mounted.
-
-  If unsure, say N.
-
-HCI EMU (virtual device) driver
-CONFIG_BLUEZ_HCIEMU
-  Bluetooth Virtual HCI device driver.
-  This driver is required if you want to use HCI Emulation software.
-
-  Say Y here to compile support for Virtual HCI devices into the
-  kernel or say M to compile it as module (hci_usb.o).
-
-# Choice: alphatype
-Alpha system type
-CONFIG_ALPHA_GENERIC
-  This is the system type of your hardware.  A "generic" kernel will
-  run on any supported Alpha system. However, if you configure a
-  kernel for your specific system, it will be faster and smaller.
-
-  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:
-
-  Alcor/Alpha-XLT     AS 600
-  Alpha-XL            XL-233, XL-266
-  AlphaBook1          Alpha laptop
-  Avanti              AS 200, AS 205, AS 250, AS 255, AS 300, AS 400
-  Cabriolet           AlphaPC64, AlphaPCI64
-  DP264               DP264
-  EB164               EB164 21164 evaluation board
-  EB64+               EB64+ 21064 evaluation board
-  EB66                EB66 21066 evaluation board
-  EB66+               EB66+ 21066 evaluation board
-  Jensen              DECpc 150, DEC 2000 model 300,
-                      DEC 2000 model 500
-  LX164               AlphaPC164-LX
-  Miata               Personal Workstation 433a, 433au, 500a,
-                      500au, 600a, or 600au
-  Mikasa              AS 1000
-  Noname              AXPpci33, UDB (Multia)
-  Noritake            AS 1000A, AS 600A, AS 800
-  PC164               AlphaPC164
-  Rawhide             AS 1200, AS 4000, AS 4100
-  Ruffian             RPX164-2, AlphaPC164-UX, AlphaPC164-BX
-  SX164               AlphaPC164-SX
-  Sable               AS 2000, AS 2100
-  Shark		      DS 20L
-  Takara              Takara
-  Titan               Privateer
-  Wildfire            AlphaServer GS 40/80/160/320
-
-  If you don't know what to do, choose "generic".
-
-# Most of the information on these variants is from
-# <http://www.alphalinux.org/docs/alpha-howto.html>
-Alcor/Alpha-XLT
-CONFIG_ALPHA_ALCOR
-  For systems using the Digital ALCOR chipset: 5 chips (4, 64-bit data
-  slices (Data Switch, DSW) - 208-pin PQFP and 1 control (Control, I/O
-  Address, CIA) - a 383 pin plastic PGA).  It provides a DRAM
-  controller (256-bit memory bus) and a PCI interface.  It also does
-  all the work required to support an external Bcache and to maintain
-  memory coherence when a PCI device DMAs into (or out of) memory.
-
-Alpha-XL
-CONFIG_ALPHA_XL
-  XL-233 and XL-266-based Alpha systems.
-
-AlphaBook1
-CONFIG_ALPHA_BOOK1
-  Dec AlphaBook1/Burns Alpha-based laptops.
-
-Avanti
-CONFIG_ALPHA_AVANTI
-  Avanti AS 200, AS 205, AS 250, AS 255, AS 300, and AS 400-based
-  Alphas. Info at
-  <http://www.unix-ag.org/Linux-Alpha/Architectures/Avanti.html>.
-
-Cabriolet
-CONFIG_ALPHA_CABRIOLET
-  Cabriolet AlphaPC64, AlphaPCI64 systems.  Derived from EB64+ but now
-  baby-AT with Flash boot ROM, no on-board SCSI or Ethernet. 3 ISA
-  slots, 4 PCI slots (one pair are on a shared slot), uses plug-in
-  Bcache SIMMs.  Requires power supply with 3.3V output.
-
-DP264
-CONFIG_ALPHA_DP264
-  Various 21264 systems with the tsunami core logic chipset.
-  API Networks: 264DP, UP2000(+), CS20;
-  Compaq: DS10(E,L), XP900, XP1000, DS20(E), ES40.
-
-EB164
-CONFIG_ALPHA_EB164
-  EB164 21164 evaluation board from DEC.  Uses 21164 and ALCOR.  Has
-  ISA and PCI expansion (3 ISA slots, 2 64-bit PCI slots (one is
-  shared with an ISA slot) and 2 32-bit PCI slots.  Uses plus-in
-  Bcache SIMMs. I/O sub-system provides SuperI/O (2S, 1P, FD), KBD,
-  MOUSE (PS2 style), RTC/NVRAM.  Boot ROM is Flash.  PC-AT-sized
-  motherboard.  Requires power supply with 3.3V output.
-
-EB64+
-CONFIG_ALPHA_EB64P
-  Uses 21064 or 21064A and APECs.  Has ISA and PCI expansion (3 ISA,
-  2 PCI, one pair are on a shared slot). Supports 36-bit DRAM SIMs.
-  ISA bus generated by Intel SaturnI/O PCI-ISA bridge. On-board SCSI
-  (NCR 810 on PCI) Ethernet (Digital 21040), KBD, MOUSE (PS2 style),
-  SuperI/O (2S, 1P, FD), RTC/NVRAM. Boot ROM is EPROM.  PC-AT size.
-  Runs from standard PC power supply.
-
-EB66
-CONFIG_ALPHA_EB66
-  A Digital DS group board.  Uses 21066 or 21066A.  I/O sub-system is
-  identical to EB64+.  Baby PC-AT size.  Runs from standard PC power
-  supply.  The EB66 schematic was published as a marketing poster
-  advertising the 21066 as "the first microprocessor in the world with
-  embedded PCI".
-
-EB66+
-CONFIG_ALPHA_EB66P
-  Later variant of the EB66 board.
-
-Eiger
-CONFIG_ALPHA_EIGER
-  Apparently an obscure OEM single-board computer based on the
-  Typhoon/Tsunami chipset family. Information on it is scanty.
-
-Jensen
-CONFIG_ALPHA_JENSEN
-  DEC PC 150 AXP (aka Jensen): This is a very old Digital system - one
-  of the first-generation Alpha systems. A number of these systems
-  seem to be available on the second- hand market. The Jensen is a
-  floor-standing tower system which originally used a 150MHz 21064 It
-  used programmable logic to interface a 486 EISA I/O bridge to the
-  CPU.
-
-LX164
-CONFIG_ALPHA_LX164
-  A technical overview of this board is available at
-  <http://www.unix-ag.org/Linux-Alpha/Architectures/LX164.html>.
-
-Miata
-CONFIG_ALPHA_MIATA
-  The Digital PersonalWorkStation (PWS 433a, 433au, 500a, 500au, 600a,
-  or 600au).  There is an Installation HOWTO for this hardware at
-  <http://members.brabant.chello.nl/~s.vandereijk/miata.html>.
-
-Mikasa
-CONFIG_ALPHA_MIKASA
-  AlphaServer 1000-based Alpha systems.
-
-Nautilus
-CONFIG_ALPHA_NAUTILUS
-  Alpha systems based on the AMD 751 & ALI 1543C chipsets.
-
-Noname
-CONFIG_ALPHA_NONAME
-  The AXPpci33 (aka NoName), is based on the EB66 (includes the Multia
-  UDB).  This design was produced by Digital's Technical OEM (TOEM)
-  group. It uses the 21066 processor running at 166MHz or 233MHz. It
-  is a baby-AT size, and runs from a standard PC power supply. It has
-  5 ISA slots and 3 PCI slots (one pair are a shared slot). There are
-  2 versions, with either PS/2 or large DIN connectors for the
-  keyboard.
-
-Noritake
-CONFIG_ALPHA_NORITAKE
-  AlphaServer 1000A, AlphaServer 600A, and AlphaServer 800-based
-  systems.
-
-Rawhide
-CONFIG_ALPHA_RAWHIDE
-  AlphaServer 1200, AlphaServer 4000 and AlphaServer 4100 machines.
-  See HOWTO at
-  <http://www.alphalinux.org/docs/rawhide/4100_install.shtml>.
-
-Ruffian
-CONFIG_ALPHA_RUFFIAN
-  Samsung APC164UX.  There is a page on known problems and workarounds
-  at <http://www.alphalinux.org/faq/FAQ-11.html>.
-
-Sable
-CONFIG_ALPHA_SABLE
-  Digital AlphaServer 2000 and 2100-based systems.
-
-Takara
-CONFIG_ALPHA_TAKARA
-  Alpha 11164-based OEM single-board computer.
-
-Wildfire
-CONFIG_ALPHA_WILDFIRE
-  AlphaServer GS 40/80/160/320 SMP based on the EV67 core.
-
-EV5 CPU daughtercard (model 5/xxx)
-CONFIG_ALPHA_PRIMO
-  Say Y if you have an AS 1000 5/xxx or an AS 1000A 5/xxx.
-
-EV5 CPU(s) (model 5/xxx)
-CONFIG_ALPHA_GAMMA
-  Say Y if you have an AS 2000 5/xxx or an AS 2100 5/xxx.
-
-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/>.
-
-  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
-  kernel just like lilo does for the x86 architecture) which can be
-  loaded either from ARC or can be installed directly as a permanent
-  firmware replacement from floppy (which requires changing a certain
-  jumper on the motherboard). If you want to do either of these, say N
-  here. If MILO doesn't work on your system (true for Jensen
-  motherboards), you can bypass it altogether and boot Linux directly
-  from an SRM console; say Y here in order to do that. Note that you
-  won't be able to boot from an IDE disk using SRM.
-
-  If unsure, say N.
-
-Legacy kernel start address
-CONFIG_ALPHA_LEGACY_START_ADDRESS
-  The 2.4 kernel changed the kernel start address from 0x310000
-  to 0x810000 to make room for the Wildfire's larger SRM console.
-
-  If you're using aboot 0.7 or later, the bootloader will examine the
-  ELF headers to determine where to transfer control. Unfortunately,
-  most older bootloaders -- APB or MILO -- hardcoded the kernel start
-  address rather than examining the ELF headers, and the result is a
-  hard lockup.
-
-  Say Y if you have a broken bootloader.  Say N if you do not, or if
-  you wish to run on Wildfire.
-
-Large VMALLOC support
-CONFIG_ALPHA_LARGE_VMALLOC
-  Process creation and other aspects of virtual memory management can
-  be streamlined if we restrict the kernel to one PGD for all vmalloc
-  allocations.  This equates to about 8GB.
-
-  Under normal circumstances, this is so far and above what is needed
-  as to be laughable.  However, there are certain applications (such
-  as benchmark-grade in-kernel web serving) that can make use of as
-  much vmalloc space as is available.
-
-  Say N unless you know you need gobs and gobs of vmalloc space.
-
-Non-standard serial port support
-CONFIG_SERIAL_NONSTANDARD
-  Say Y here if you have any non-standard serial boards -- boards
-  which aren't supported using the standard "dumb" serial driver.
-  This includes intelligent serial boards such as Cyclades,
-  Digiboards, etc. These are usually used for systems that need many
-  serial ports because they serve many terminals or dial-in
-  connections.
-
-  Note that the answer to this question won't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about non-standard serial boards.
-
-  Most people can say N here.
-
-Extended dumb serial driver options
-CONFIG_SERIAL_EXTENDED
-  If you wish to use any non-standard features of the standard "dumb"
-  driver, say Y here. This includes HUB6 support, shared serial
-  interrupts, special multiport support, support for more than the
-  four COM 1/2/3/4 boards, etc.
-
-  Note that the answer to this question won't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about serial driver options. If unsure, say N.
-
-Support more than 4 serial ports
-CONFIG_SERIAL_MANY_PORTS
-  Say Y here if you have dumb serial boards other than the four
-  standard COM 1/2/3/4 ports. This may happen if you have an AST
-  FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
-  from <http://www.linuxdoc.org/docs.html#howto>), or other custom
-  serial port hardware which acts similar to standard serial port
-  hardware. If you only use the standard COM 1/2/3/4 ports, you can
-  say N here to save some memory. You can also say Y if you have an
-  "intelligent" multiport card such as Cyclades, Digiboards, etc.
-
-Support for serial ports defined by ACPI tables
-CONFIG_SERIAL_ACPI
-  Legacy free machines may not have serial ports at the legacy COM1, 
-  COM2 etc addresses. Serial ports on such machines are described by
-  the ACPI tables SPCR (Serial Port Console Redirection) table and 
-  DBGP (Debug Port) table. Say Y here if you want to include support
-  for these serial ports.
-
-Support for sharing serial interrupts
-CONFIG_SERIAL_SHARE_IRQ
-  Some serial boards have hardware support which allows multiple dumb
-  serial ports on the same board to share a single IRQ. To enable
-  support for this in the serial driver, say Y here.
-
-Auto-detect IRQ on standard ports (unsafe)
-CONFIG_SERIAL_DETECT_IRQ
-  Say Y here if you want the kernel to try to guess which IRQ
-  to use for your serial port.
-
-  This is considered unsafe; it is far better to configure the IRQ in
-  a boot script using the setserial command.
-
-  If unsure, say N.
-
-Support special multiport boards
-CONFIG_SERIAL_MULTIPORT
-  Some multiport serial ports have special ports which are used to
-  signal when there are any serial ports on the board which need
-  servicing. Say Y here to enable the serial driver to take advantage
-  of those special I/O ports.
-
-SGI Zilog85C30 serial support
-CONFIG_SGI_SERIAL
-  If you want to use your SGI's built-in serial ports under Linux,
-  answer Y.
-
-SGI Newport Graphics support
-CONFIG_SGI_NEWPORT_GFX
-  If you have an SGI machine and you want to compile the graphics
-  drivers, say Y here. This will include the code for the
-  /dev/graphics and /dev/gfx drivers into the kernel for supporting
-  virtualized access to your graphics hardware.
-
-SGI Newport Console support
-CONFIG_SGI_NEWPORT_CONSOLE
-  Say Y here if you want the console on the Newport aka XL graphics
-  card of your Indy.  Most people say Y here.
-
-SGI DS1286 RTC support
-CONFIG_SGI_DS1286
-  If you say Y here and create a character special file /dev/rtc with
-  major number 10 and minor number 135 using mknod ("man mknod"), you
-  will get access to the real time clock built into your computer.
-  Every SGI has such a clock built in. It reports status information
-  via the file /proc/rtc and its behaviour is set by various ioctls on
-  /dev/rtc.
-
-Support the Bell Technologies HUB6 card
-CONFIG_HUB6
-  Say Y here to enable support in the dumb serial driver to support
-  the HUB6 card.
-
-PCMCIA serial device support
-CONFIG_PCMCIA_SERIAL_CS
-  Say Y here to enable support for 16-bit PCMCIA serial devices,
-  including serial port cards, modems, and the modem functions of
-  multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are
-  credit-card size devices often used with laptops.)
-
-  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 serial_cs.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-  If unsure, say N.
-
-ACP Modem (Mwave) support
-CONFIG_MWAVE
-  The ACP modem (Mwave) for Linux is a WinModem. It is composed of a
-  kernel driver and a user level application. Together these components
-  support direct attachment to public switched telephone networks (PSTNs)
-  and support selected world wide countries.
-
-  This version of the ACP Modem driver supports the IBM Thinkpad 600E,
-  600, and 770 that include on board ACP modem hardware.
-
-  The modem also supports the standard communications port interface
-  (ttySx) and is compatible with the Hayes AT Command Set.
-
-  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/>.
-
-  If you own one of the above IBM Thinkpads which has the Mwave chipset
-  in it, say Y.
-
-  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 mwave.o. If you want to compile it as
-  a module, say M here and read Documentation/modules.txt.
-
-/dev/agpgart (AGP Support)
-CONFIG_AGP
-  AGP (Accelerated Graphics Port) is a bus system mainly used to
-  connect graphics cards to the rest of the system.
-
-  If you have an AGP system and you say Y here, it will be possible to
-  use the AGP features of your 3D rendering video card. This code acts
-  as a sort of "AGP driver" for the motherboard's chipset.
-
-  If you need more texture memory than you can get with the AGP GART
-  (theoretically up to 256 MB, but in practice usually 64 or 128 MB
-  due to kernel allocation issues), you could use PCI accesses
-  and have up to a couple gigs of texture space.
-
-  Note that this is the only means to have XFree4/GLX use
-  write-combining with MTRR support on the AGP bus. Without it, OpenGL
-  direct rendering will be a lot slower but still faster than PIO.
-
-  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-  use GLX or DRI.  If unsure, say N.
-
-  This driver is available as a module.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.  The
-  module will be called agpgart.o.
-
-Intel 440LX/BX/GX/815/820/830/840/845/850/860 support
-CONFIG_AGP_INTEL
-  This option gives you AGP support for the GLX component of the
-  XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850 and 860 chipsets.
-
-  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-  use GLX or DRI.  If unsure, say N.
-
-Intel I810/I815 DC100/I810e support
-CONFIG_AGP_I810
-  This option gives you AGP support for the Xserver on the Intel 810
-  815 and 830m chipset boards for their on-board integrated graphics. This
-  is required to do any useful video modes with these boards.
-
-VIA chipset support
-CONFIG_AGP_VIA
-  This option gives you AGP support for the GLX component of the
-  XFree86 4.x on VIA MPV3/Apollo Pro chipsets.
-
-  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-  use GLX or DRI.  If unsure, say N.
-
-AMD Irongate, 761, and 762 support
-CONFIG_AGP_AMD
-  This option gives you AGP support for the GLX component of the
-  XFree86 4.x on AMD Irongate, 761, and 762 chipsets.
-
-  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-  use GLX or DRI.  If unsure, say N.
-
-Generic SiS support
-CONFIG_AGP_SIS
-  This option gives you AGP support for the GLX component of the "soon
-  to be released" XFree86 4.x on Silicon Integrated Systems [SiS]
-  chipsets.
-
-  Note that 5591/5592 AGP chipsets are NOT supported.
-
-  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-  use GLX or DRI.  If unsure, say N.
-
-Serverworks LE/HE support
-CONFIG_AGP_SWORKS
-  Say Y here to support the Serverworks AGP card.  See 
-  <http://www.serverworks.com/> for product descriptions and images.
-
-ALI chipset support
-CONFIG_AGP_ALI
-  This option gives you AGP support for the GLX component of the
-  XFree86 4.x on the following ALi chipsets.  The supported chipsets
-  include M1541, M1621, M1631, M1632, M1641,M1647,and M1651.
-  For the ALi-chipset question, ALi suggests you refer to
-  <http://www.ali.com.tw/eng/support/index.shtml>.
-
-  The M1541 chipset can do AGP 1x and 2x, but note that there is an
-  acknowledged incompatibility with Matrox G200 cards. Due to
-  timing issues, this chipset cannot do AGP 2x with the G200.
-  This is a hardware limitation. AGP 1x seems to be fine, though.
-
-  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-  use GLX or DRI.  If unsure, say N.
-
-Support for ISA-bus hardware
-CONFIG_ISA
-  Find out whether you have ISA slots on your motherboard.  ISA is the
-  name of a bus system, i.e. the way the CPU talks to the other stuff
-  inside your box.  Other bus systems are PCI, EISA, MicroChannel
-  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
-  newer boards don't support it.  If you have ISA, say Y, otherwise N.
-
-Support for PCI bus hardware
-CONFIG_PCI
-  Find out whether you have a PCI motherboard. PCI is the name of a
-  bus system, i.e. the way the CPU talks to the other stuff inside
-  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
-  VESA. If you have PCI, say Y, otherwise N.
-
-  The PCI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
-  information about which PCI hardware does work under Linux and which
-  doesn't.
-
-PCI support
-CONFIG_PCI_INTEGRATOR
-  Find out whether you have a PCI motherboard. PCI is the name of a
-  bus system, i.e. the way the CPU talks to the other stuff inside
-  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
-  VESA. If you have PCI, say Y, otherwise N.
-
-  The PCI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
-  information about which PCI hardware does work under Linux and which
-  doesn't.
-
-QSpan PCI
-CONFIG_PCI_QSPAN
-  Find out whether you have a PCI motherboard. PCI is the name of a
-  bus system, i.e. the way the CPU talks to the other stuff inside
-  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
-  VESA. If you have PCI, say Y, otherwise N.
-
-  The PCI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
-  information about which PCI hardware does work under Linux and which
-  doesn't.
-
-# Choice: pci_access
-PCI access mode
-CONFIG_PCI_GOBIOS
-  On PCI systems, the BIOS can be used to detect the PCI devices and
-  determine their configuration. However, some old PCI motherboards
-  have BIOS bugs and may crash if this is done. Also, some embedded
-  PCI-based systems don't have any BIOS at all. Linux can also try to
-  detect the PCI hardware directly without using the BIOS.
-
-  With this option, you can specify how Linux should detect the PCI
-  devices. If you choose "BIOS", the BIOS will be used, if you choose
-  "Direct", the BIOS won't be used, and if you choose "Any", the
-  kernel will try the direct access method and falls back to the BIOS
-  if that doesn't work. If unsure, go with the default, which is
-  "Any".
-
-PCI device name database
-CONFIG_PCI_NAMES
-  By default, the kernel contains a database of all known PCI device
-  names to make the information in /proc/pci, /proc/ioports and
-  similar files comprehensible to the user. This database increases
-  size of the kernel image by about 80KB, but it gets freed after the
-  system boots up, so it doesn't take up kernel memory. Anyway, if you
-  are building an installation floppy or kernel for an embedded system
-  where kernel image size really matters, you can disable this feature
-  and you'll get device ID numbers instead of names.
-
-  When in doubt, say Y.
-
-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
-  powered up and running.  The file system pcihpfs must be mounted
-  in order to interact with any PCI Hotplug controllers.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called pci_hotplug.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-  When in doubt, say N.
-
-PCI Compaq Hotplug controller
-CONFIG_HOTPLUG_PCI_COMPAQ
-  Say Y here if you have a motherboard with a Compaq PCI Hotplug
-  controller.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called cpqphp.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-  When in doubt, say N.
-
-PCI Compaq Hotplug controller NVRAM support
-CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM
-  Say Y here if you have a Compaq server that has a PCI Hotplug
-  controller.  This will allow the PCI Hotplug driver to store the PCI
-  system configuration options in NVRAM.
-
-  When in doubt, say N.
-
-MCA support
-CONFIG_MCA
-  MicroChannel Architecture is found in some IBM PS/2 machines and
-  laptops.  It is a bus system similar to PCI or ISA. See
-  <file:Documentation/mca.txt> (and especially the web page given
-  there) before attempting to build an MCA bus kernel.
-
-Support for EISA-bus hardware
-CONFIG_EISA
-  The Extended Industry Standard Architecture (EISA) bus was
-  developed as an open alternative to the IBM MicroChannel bus.
-
-  The EISA bus provided some of the features of the IBM MicroChannel
-  bus while maintaining backward compatibility with cards made for
-  the older ISA bus.  The EISA bus saw limited use between 1988 and
-  1995 when it was made obsolete by the PCI bus.
-
-  Say Y here if you are building a kernel for an EISA-based machine.
-
-  Otherwise, say N.
-
-SGI Visual Workstation support
-CONFIG_VISWS
-  The SGI Visual Workstation series is an IA32-based workstation
-  based on SGI systems chips with some legacy PC hardware attached.
-  Say Y here to create a kernel to run on the SGI 320 or 540.
-  A kernel compiled for the Visual Workstation will not run on other
-  PC boards and vice versa.
-  See <file:Documentation/sgi-visws.txt> for more.
-
-SGI Visual Workstation framebuffer support
-CONFIG_FB_SGIVW
-  SGI Visual Workstation support for framebuffer graphics.
-
-I2O support
-CONFIG_I2O
-  The Intelligent Input/Output (I2O) architecture allows hardware
-  drivers to be split into two parts: an operating system specific
-  module called the OSM and an hardware specific module called the
-  HDM. The OSM can talk to a whole range of HDM's, and ideally the
-  HDM's are not OS dependent. This allows for the same HDM driver to
-  be used under different operating systems if the relevant OSM is in
-  place. In order for this to work, you need to have an I2O interface
-  adapter card in your computer. This card contains a special I/O
-  processor (IOP), thus allowing high speeds since the CPU does not
-  have to deal with I/O.
-
-  If you say Y here, you will get a choice of interface adapter
-  drivers and OSM's with the following questions.
-
-  This support is also available 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>.  You will get modules called
-  i2o_core.o and i2o_config.o.
-
-  If unsure, say N.
-
-I2O PCI support
-CONFIG_I2O_PCI
-  Say Y for support of PCI bus I2O interface adapters. Currently this
-  is the only variety supported, so you should say Y.
-
-  This support is also available as a module called i2o_pci.o ( = 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>.
-
-I2O Block OSM
-CONFIG_I2O_BLOCK
-  Include support for the I2O Block OSM. The Block OSM presents disk
-  and other structured block devices to the operating system.
-
-  This support is also available as a module called i2o_block.o ( =
-  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>.
-
-I2O LAN OSM
-CONFIG_I2O_LAN
-  Include support for the LAN OSM. You will also need to include
-  support for token ring or FDDI if you wish to use token ring or FDDI
-  I2O cards with this driver.
-
-  This support is also available as a module called i2o_lan.o ( = 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>.
-
-I2O SCSI OSM
-CONFIG_I2O_SCSI
-  Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel
-  I2O controller. You can use both the SCSI and Block OSM together if
-  you wish.
-
-  This support is also available as a module called i2o_scsi.o ( =
-  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>.
-
-I2O /proc support
-CONFIG_I2O_PROC
-  If you say Y here and to "/proc file system support", you will be
-  able to read I2O related information from the virtual directory
-  /proc/i2o.
-
-  This support is also available as a module called i2o_proc.o ( =
-  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>.
-
-Plug and Play support
-CONFIG_PNP
-  Plug and Play (PnP) is a standard for peripherals which allows those
-  peripherals to be configured by software, e.g. assign IRQ's or other
-  parameters. No jumpers on the cards are needed, instead the values
-  are provided to the cards from the BIOS, from the operating system,
-  or using a user-space utility.
-
-  Say Y here if you would like Linux to configure your Plug and Play
-  devices. You should then also say Y to "ISA Plug and Play support",
-  below. Alternatively, you can say N here and configure your PnP
-  devices using the user space utilities contained in the isapnptools
-  package.
-
-  This support is also available 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>.
-
-ISA Plug and Play support
-CONFIG_ISAPNP
-  Say Y here if you would like support for ISA Plug and Play devices.
-  Some information is in <file:Documentation/isapnp.txt>.
-
-  This support is also available as a module called isapnp.o ( =
-  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>.
-
-  If unsure, say Y.
-
-PNPBIOS support
-CONFIG_PNPBIOS
-  Linux uses the PNPBIOS as defined in "Plug and Play BIOS
-  Specification Version 1.0A May 5, 1994" to autodetect built-in
-  mainboard resources (e.g. parallel port resources).
-
-  Other features (e.g. change resources, ESCD, event notification,
-  Docking station information, ISAPNP services) are not used.
-
-  Note: ACPI is expected to supersede PNPBIOS some day, currently it
-  co-exists nicely.
-
-  See latest pcmcia-cs (stand-alone package) for a nice "lspnp" tools,
-  or have a look at /proc/bus/pnp.
-
-  If unsure, say Y.
-
-Support for hot-pluggable devices
-CONFIG_HOTPLUG
-  Say Y here if you want to plug devices into your computer while
-  the system is running, and be able to use them quickly.  In many
-  cases, the devices can likewise be unplugged at any time too.
-
-  One well known example of this is PCMCIA- or PC-cards, credit-card
-  size devices such as network cards, modems or hard drives which are
-  plugged into slots found on all modern laptop computers.  Another
-  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.
-  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.
-
-PCMCIA/CardBus support
-CONFIG_PCMCIA
-  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
-  computer.  These are credit-card size devices such as network cards,
-  modems or hard drives often used with laptops computers.  There are
-  actually two varieties of these cards: the older 16 bit PCMCIA cards
-  and the newer 32 bit CardBus cards.  If you want to use CardBus
-  cards, you need to say Y here and also to "CardBus support" below.
-
-  To use your PC-cards, you will need supporting software from David
-  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-  for location).  Please also read the PCMCIA-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).
-  When compiled this way, there will be modules called pcmcia_core.o
-  and ds.o.  If you want to compile it as a module, say M here and
-  read <file:Documentation/modules.txt>.
-
-CardBus card and (Yenta) bridge support
-CONFIG_CARDBUS
-  CardBus is a bus mastering architecture for PC-cards, which allows
-  for 32 bit PC-cards (the original PCMCIA standard specifies only
-  a 16 bit wide bus). Many newer PC-cards are actually CardBus cards.
-
-  This option enables support for CardBus PC Cards, as well as support
-  for CardBus host bridges.  Virtually all modern PCMCIA bridges are
-  CardBus compatible.  A "bridge" is the hardware inside your computer
-  that PCMCIA cards are plugged into.
-
-  To use your PC-cards, you will need supporting software from David
-  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-  for location).
-
-  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
-  are register compatible with the Intel i82365.  These are found on
-  older laptops and ISA-bus card readers for desktop systems.  A
-  "bridge" is the hardware inside your computer that PCMCIA cards are
-  plugged into. If unsure, say N.
-
-Databook TCIC host bridge support
-CONFIG_TCIC
-  Say Y here to include support for the Databook TCIC family of PCMCIA
-  host bridges. These are only found on a handful of old systems.
-  "Bridge" is the name used for the hardware inside your computer that
-  PCMCIA cards are plugged into. If unsure, say N.
-
-System V IPC
-CONFIG_SYSVIPC
-  Inter Process Communication is a suite of library functions and
-  system calls which let processes (running programs) synchronize and
-  exchange information. It is generally considered to be a good thing,
-  and some programs won't run unless you say Y here. In particular, if
-  you want to run the DOS emulator dosemu under Linux (read the
-  DOSEMU-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>), you'll need to say Y
-  here.
-
-  You can find documentation about IPC with "info ipc" and also in
-  section 6.4 of the Linux Programmer's Guide, available from
-  <http://www.linuxdoc.org/docs.html#guide>.
-
-BSD Process Accounting
-CONFIG_BSD_PROCESS_ACCT
-  If you say Y here, a user level program will be able to instruct the
-  kernel (via a special system call) to write process accounting
-  information to a file: whenever a process exits, information about
-  that process will be appended to the file by the kernel.  The
-  information includes things such as creation time, owning user,
-  command name, memory usage, controlling terminal etc. (the complete
-  list is in the struct acct in <file:include/linux/acct.h>).  It is
-  up to the user level program to do useful things with this
-  information.  This is generally a good idea, so say Y.
-
-Sysctl support
-CONFIG_SYSCTL
-  The sysctl interface provides a means of dynamically changing
-  certain kernel parameters and variables on the fly without requiring
-  a recompile of the kernel or reboot of the system.  The primary
-  interface consists of a system call, but if you say Y to "/proc
-  file system support", a tree of modifiable sysctl entries will be
-  generated beneath the /proc/sys directory. They are explained in the
-  files in <file:Documentation/sysctl/>.  Note that enabling this
-  option will enlarge the kernel by at least 8 KB.
-
-  As it is generally a good thing, you should say Y here unless
-  building a kernel for install/rescue disks or your system is very
-  limited in memory.
-
-# Choice: kcore
-Kernel core (/proc/kcore) format
-CONFIG_KCORE_ELF
-  If you enabled support for /proc file system then the file
-  /proc/kcore will contain the kernel core image. This can be used
-  in gdb:
-
-  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
-
-  You have two choices here: ELF and A.OUT. Selecting ELF will make
-  /proc/kcore appear in ELF core format as defined by the Executable
-  and Linking Format specification. Selecting A.OUT will choose the
-  old "a.out" format which may be necessary for some old versions
-  of binutils or on some architectures.
-
-  This is especially useful if you have compiled the kernel with the
-  "-g" option to preserve debugging information. It is mainly used
-  for examining kernel data structures on the live kernel so if you
-  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
-  version.  You probably want KCORE_ELF.
-
-Kernel support for ELF binaries
-CONFIG_BINFMT_ELF
-  ELF (Executable and Linkable Format) is a format for libraries and
-  executables used across different architectures and operating
-  systems. Saying Y here will enable your kernel to run ELF binaries
-  and enlarge it by about 13 KB. ELF support under Linux has now all
-  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
-  because it is portable (this does *not* mean that you will be able
-  to run executables from different architectures or operating systems
-  however) and makes building run-time libraries very easy. Many new
-  executables are distributed solely in ELF format. You definitely
-  want to say Y here.
-
-  Information about ELF is contained in the ELF HOWTO available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you find that after upgrading from Linux kernel 1.2 and saying Y
-  here, you still can't run any ELF binaries (they just crash), then
-  you'll have to install the newest ELF runtime libraries, including
-  ld.so (check the file <file:Documentation/Changes> for location and
-  latest version).
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called binfmt_elf.o. Saying M or N here is dangerous because
-  some crucial programs on your system might be in ELF format.
-
-Kernel support for a.out binaries
-CONFIG_BINFMT_AOUT
-  A.out (Assembler.OUTput) is a set of formats for libraries and
-  executables used in the earliest versions of UNIX. Linux used the
-  a.out formats QMAGIC and ZMAGIC until they were replaced with the
-  ELF format.
-
-  As more and more programs are converted to ELF, the use for a.out
-  will gradually diminish. If you disable this option it will reduce
-  your kernel by one page. This is not much and by itself does not
-  warrant removing support. However its removal is a good idea if you
-  wish to ensure that absolutely none of your programs will use this
-  older executable format. If you don't know what to answer at this
-  point then answer Y. If someone told you "You need a kernel with
-  QMAGIC support" then you'll have to say Y here. You may answer M to
-  compile a.out support as a module and later load the module when you
-  want to use a program or library in a.out format. The module will be
-  called binfmt_aout.o. Saying M or N here is dangerous though,
-  because some crucial programs on your system might still be in A.OUT
-  format.
-
-Kernel support for Linux/Intel ELF binaries
-CONFIG_BINFMT_EM86
-  Say Y here if you want to be able to execute Linux/Intel ELF
-  binaries just like native Alpha binaries on your Alpha machine. For
-  this to work, you need to have the emulator /usr/bin/em86 in place.
-
-  You can get the same functionality by saying N here and saying Y to
-  "Kernel support for MISC binaries".
-
-  You may answer M to compile the emulation support as a module and
-  later load the module when you want to use a Linux/Intel binary. The
-  module will be called binfmt_em86.o. If unsure, say Y.
-
-Kernel support for SOM binaries
-CONFIG_BINFMT_SOM
-  SOM is a binary executable format inherited from HP/UX.  Say Y here
-  to be able to load and execute SOM binaries directly.
-
-Kernel support for MISC binaries
-CONFIG_BINFMT_MISC
-  If you say Y here, it will be possible to plug wrapper-driven binary
-  formats into the kernel. You will like this especially when you use
-  programs that need an interpreter to run like Java, Python or
-  Emacs-Lisp. It's also useful if you often run DOS executables under
-  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>). Once you have
-  registered such a binary class with the kernel, you can start one of
-  those programs simply by typing in its name at a shell prompt; Linux
-  will automatically feed it to the correct interpreter.
-
-  You can do other nice things, too. Read the file
-  <file:Documentation/binfmt_misc.txt> to learn how to use this
-  feature, and <file:Documentation/java.txt> for information about how
-  to include Java support.
-
-  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
-  use this part of the kernel.
-
-  You may say M here for module support and later load the module when
-  you have use for it; the module is called binfmt_misc.o. If you
-  don't know what to answer at this point, say Y.
-
-Kernel support for JAVA binaries
-CONFIG_BINFMT_JAVA
-  If you say Y here, the kernel will load and execute Java J-code
-  binaries directly.  Note: this option is obsolete and scheduled for
-  removal, use CONFIG_BINFMT_MISC instead.
-
-Solaris binary emulation
-CONFIG_SOLARIS_EMUL
-  This is experimental code which will enable you to run (many)
-  Solaris binaries on your SPARC Linux machine.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called solaris.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-SUN SME environment monitoring
-CONFIG_ENVCTRL
-  Kernel support for temperature and fan monitoring on Sun SME
-  machines.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called envctrl.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-# Choice: x86
-Processor family
-CONFIG_M386
-  This is the processor type of your CPU. This information is used for
-  optimizing purposes. In order to compile a kernel that can run on
-  all x86 CPU types (albeit not optimally fast), you can specify
-  "386" here.
-
-  The kernel will not necessarily run on earlier architectures than
-  the one you have chosen, e.g. a Pentium optimized kernel will run on
-  a PPro, but not necessarily on a i486.
-
-  Here are the settings recommended for greatest speed:
-   - "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI
-     486DLC/DLC2, UMC 486SX-S and NexGen Nx586.  Only "386" kernels
-     will run on a 386 class machine.
-   - "486" for the AMD/Cyrix/IBM/Intel 486DX/DX2/DX4 or
-     SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or U5S.
-   - "586" for generic Pentium CPUs, possibly lacking the TSC
-     (time stamp counter) register.
-   - "Pentium-Classic" for the Intel Pentium.
-   - "Pentium-MMX" for the Intel Pentium MMX.
-   - "Pentium-Pro" for the Intel Pentium Pro/Celeron/Pentium II.
-   - "Pentium-III" for the Intel Pentium III
-     and Celerons based on the Coppermine core.
-   - "Pentium-4" for the Intel Pentium 4.
-   - "K6" for the AMD K6, K6-II and K6-III (aka K6-3D).
-   - "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird).
-   - "Crusoe" for the Transmeta Crusoe series.
-   - "Winchip-C6" for original IDT Winchip.
-   - "Winchip-2" for IDT Winchip 2.
-   - "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
-   - "CyrixIII" for VIA Cyrix III or VIA C3.
-
-  If you don't know what to do, choose "386".
-
-486
-CONFIG_M486
-  Select this for a x486 processor, ether Intel or one of the
-  compatible processors from AMD, Cyrix, IBM, or Intel.  Includes DX,
-  DX2, and DX4 variants; also SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or
-  U5S.
-
-586/K5/5x86/6x86/6x86MX
-CONFIG_M586
-  Select this for an x586 or x686 processor such as the AMD K5, the
-  Intel 5x86 or 6x86, or the Intel 6x86MX.  This choice does not
-  assume the RDTSC instruction.
-
-Pentium Classic
-CONFIG_M586TSC
-  Select this for a Pentium Classic processor with the RDTSC (Read
-  Time Stamp Counter) instruction for benchmarking.
-
-32-bit PDC
-CONFIG_PDC_NARROW
-  Saying Y here will allow developers with a C180, C200, C240, C360,
-  J200, J210, and/or a J2240 to test 64-bit kernels by providing a
-  wrapper for the 32-bit PDC calls.  Since the machines which require
-  this option do not support over 4G of RAM, this option is targeted
-  for developers of these machines wishing to test changes on both
-  32-bit and 64-bit configurations.
-
-  If unsure, say N.
-
-VGA text console
-CONFIG_VGA_CONSOLE
-  Saying Y here will allow you to use Linux in text mode through a
-  display that complies with the generic VGA standard. Virtually
-  everyone wants that.
-
-  The program SVGATextMode can be used to utilize SVGA video cards to
-  their full potential in text mode. Download it from
-  <ftp://ibiblio.org/pub/Linux/utils/console/>.
-
-  Say Y.
-
-Distribute interrupts on all CPUs by default
-CONFIG_IRQ_ALL_CPUS
-  This option gives the kernel permission to distribute IRQs across
-  multiple CPUs.  Saying N here will route all IRQs to the first
-  CPU. Generally SMP PowerMacs can answer Y. SMP IBM CHRP boxes or
-  Power3 boxes should say N for now.
-
-Video mode selection support
-CONFIG_VIDEO_SELECT
-  This enables support for text mode selection on kernel startup. If
-  you want to take advantage of some high-resolution text mode your
-  card's BIOS offers, but the traditional Linux utilities like
-  SVGATextMode don't, you can say Y here and set the mode using the
-  "vga=" option from your boot loader (lilo or loadlin) or set
-  "vga=ask" which brings up a video mode menu on kernel startup. (Try
-  "man bootparam" or see the documentation of your boot loader about
-  how to pass options to the kernel.)
-
-  Read the file <file:Documentation/svga.txt> for more information
-  about the Video mode selection support. If unsure, say N.
-
-Support for frame buffer devices
-CONFIG_FB
-  The frame buffer device provides an abstraction for the graphics
-  hardware. It represents the frame buffer of some video hardware and
-  allows application software to access the graphics hardware through
-  a well-defined interface, so the software doesn't need to know
-  anything about the low-level (hardware register) stuff.
-
-  Frame buffer devices work identically across the different
-  architectures supported by Linux and make the implementation of
-  application programs easier and more portable; at this point, an X
-  server exists which uses the frame buffer device exclusively.
-  On several non-X86 architectures, the frame buffer device is the
-  only way to use the graphics hardware.
-
-  The device is accessed through special device nodes, usually located
-  in the /dev directory, i.e. /dev/fb*.
-
-  You need an utility program called fbset to make full use of frame
-  buffer devices. Please read <file:Documentation/fb/framebuffer.txt>
-  and the Framebuffer-HOWTO at
-  <http://www.tahallah.demon.co.uk/programming/prog.html> for more
-  information.
-
-  Say Y here and to the driver for your graphics board below if you
-  are compiling a kernel for a non-x86 architecture.
-
-  If you are compiling for the x86 architecture, you can say Y if you
-  want to play with it, but it is not essential. Please note that
-  running graphical applications that directly touch the hardware
-  (e.g. an accelerated X server) and that are not frame buffer
-  device-aware may cause unexpected results. If unsure, say N.
-
-Acorn VIDC support
-CONFIG_FB_ACORN
-  This is the frame buffer device driver for the Acorn VIDC graphics
-  hardware found in Acorn RISC PCs and other ARM-based machines.  If
-  unsure, say N.
-
-Permedia2 support
-CONFIG_FB_PM2
-  This is the frame buffer device driver for the Permedia2 AGP frame
-  buffer card from ASK, aka `Graphic Blaster Exxtreme'.  There is a
-  product page at
-  <http://www.ask.com.hk/product/Permedia%202/permedia2.htm>.
-
-Enable FIFO disconnect feature
-CONFIG_FB_PM2_FIFO_DISCONNECT
-  Support the Permedia2 FIFOI disconnect feature (see CONFIG_FB_PM2).
-
-Generic Permedia2 PCI board support
-CONFIG_FB_PM2_PCI
-  Say Y to enable support for Permedia2 AGP frame buffer card from
-  3Dlabs (aka `Graphic Blaster Exxtreme') on the PCI bus.
-
-Phase5 CVisionPPC/BVisionPPC support
-CONFIG_FB_PM2_CVPPC
-  Say Y to enable support for the Amiga Phase 5 CVisionPPC BVisionPPC
-  framebuffer cards.  Phase 5 is no longer with us, alas.
-
-Amiga native chipset support
-CONFIG_FB_AMIGA
-  This is the frame buffer device driver for the builtin graphics
-  chipset found in Amigas.
-
-  The driver is also available as a module ( = code which can be
-  inserted and removed from the running kernel whenever you want). The
-  module will be called amifb.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Amiga OCS chipset support
-CONFIG_FB_AMIGA_OCS
-  This enables support for the original Agnus and Denise video chips,
-  found in the Amiga 1000 and most A500's and A2000's. If you intend
-  to run Linux on any of these systems, say Y; otherwise say N.
-
-Amiga ECS chipset support
-CONFIG_FB_AMIGA_ECS
-  This enables support for the Enhanced Chip Set, found in later
-  A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If
-  you intend to run Linux on any of these systems, say Y; otherwise
-  say N.
-
-Amiga AGA chipset support
-CONFIG_FB_AMIGA_AGA
-  This enables support for the Advanced Graphics Architecture (also
-  known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T
-  and CD32. If you intend to run Linux on any of these systems, say Y;
-  otherwise say N.
-
-Amiga CyberVision support
-CONFIG_FB_CYBER
-  This enables support for the Cybervision 64 graphics card from
-  Phase5. Please note that its use is not all that intuitive (i.e. if
-  you have any questions, be sure to ask!). Say N unless you have a
-  Cybervision 64 or plan to get one before you next recompile the
-  kernel. Please note that this driver DOES NOT support the
-  Cybervision 64 3D card, as they use incompatible video chips.
-
-CyberPro 20x0 support
-CONFIG_FB_CYBER2000
-  This enables support for the Integraphics CyberPro 20x0 and 5000
-  VGA chips used in the Rebel.com Netwinder and other machines.
-  Say Y if you have a NetWinder or a graphics card containing this
-  device, otherwise say N.
-
-Amiga CyberVision3D support
-CONFIG_FB_VIRGE
-  This enables support for the Cybervision 64/3D graphics card from
-  Phase5. Please note that its use is not all that intuitive (i.e. if
-  you have any questions, be sure to ask!). Say N unless you have a
-  Cybervision 64/3D or plan to get one before you next recompile the
-  kernel. Please note that this driver DOES NOT support the older
-  Cybervision 64 card, as they use incompatible video chips.
-
-Amiga RetinaZ3 support
-CONFIG_FB_RETINAZ3
-  This enables support for the Retina Z3 graphics card. Say N unless
-  you have a Retina Z3 or plan to get one before you next recompile
-  the kernel.
-
-Cirrus Logic generic driver
-CONFIG_FB_CLGEN
-  This enables support for Cirrus Logic GD542x/543x based boards on
-  Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum.
-
-  If you have a PCI-based system, this enables support for these
-  chips: GD-543x, GD-544x, GD-5480.
-
-  Please read the file <file:Documentation/fb/clgenfb.txt>.
-
-  Say N unless you have such a graphics board or plan to get one
-  before you next recompile the kernel.
-
-Apollo support
-CONFIG_APOLLO
-  Say Y here if you want to run Linux on an MC680x0-based Apollo
-  Domain workstation such as the DN3500.
-
-Apollo 3c505 "EtherLink Plus" support
-CONFIG_APOLLO_ELPLUS
-  Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card.
-  If you don't have one made for Apollos, you can use one from a PC,
-  except that your Apollo won't be able to boot from it (because the
-  code in the ROM will be for a PC).
-
-Atari native chipset support
-CONFIG_FB_ATARI
-  This is the frame buffer device driver for the builtin graphics
-  chipset found in Ataris.
-
-Amiga FrameMaster II/Rainbow II support
-CONFIG_FB_FM2
-  This is the frame buffer device driver for the Amiga FrameMaster
-  card from BSC (exhibited 1992 but not shipped as a CBM product).
-
-Open Firmware frame buffer device support
-CONFIG_FB_OF
-  Say Y if you want support with Open Firmware for your graphics
-  board.
-
-S3 Trio frame buffer device support
-CONFIG_FB_S3TRIO
-  If you have a S3 Trio say Y. Say N for S3 Virge.
-
-3Dfx Banshee/Voodoo3 display support
-CONFIG_FB_3DFX
-  This driver supports graphics boards with the 3Dfx Banshee/Voodoo3
-  chips. Say Y if you have such a graphics board.
-
-  The driver is also available as a module ( = code which can be
-  inserted and removed from the running kernel whenever you want). The
-  module will be called tdfxfb.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-nVidia Riva support
-CONFIG_FB_RIVA
-  This driver supports graphics boards with the nVidia Riva/Geforce
-  chips.
-  Say Y if you have such a graphics board.
-
-  The driver is also available as a module ( = code which can be
-  inserted and removed from the running kernel whenever you want). The
-  module will be called rivafb.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-ATI Mach64 display support
-CONFIG_FB_ATY
-  This driver supports graphics boards with the ATI Mach64 chips.
-  Say Y if you have such a graphics board.
-
-  The driver is also available as a module ( = code which can be
-  inserted and removed from the running kernel whenever you want). The
-  module will be called atyfb.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-ATI Rage128 display support
-CONFIG_FB_ATY128
-  This driver supports graphics boards with the ATI Rage128 chips.
-  Say Y if you have such a graphics board and read
-  <file:Documentation/fb/aty128fb.txt>.
-
-  The driver is also available as a module ( = code which can be
-  inserted and removed from the running kernel whenever you want). The
-  module will be called aty128fb.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-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/>.
-
-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/>.
-
-PMAGB-B TURBOchannel framebuffer support
-CONFIG_FB_PMAGB_B
-  Say Y here to directly support the on-board PMAGB-B framebuffer in
-  the 5000/1xx versions of the DECstation.  There is a page dedicated
-  to Linux on DECstations at <http://decstation.unix-ag.org/>.
-
-FutureTV PCI card
-CONFIG_ARCH_FTVPCI
-  Say Y here if you intend to run this kernel on a FutureTV (nee Nexus
-  Electronics) StrongARM PCI card.
-
-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
-  This driver supports the L7200 Color LCD.
-  Say Y if you want graphics support.
-
-PowerMac "control" frame buffer device support
-CONFIG_FB_CONTROL
-  This driver supports a frame buffer for the graphics adapter in the
-  Power Macintosh 7300 and others.
-
-PowerMac "platinum" frame buffer device support
-CONFIG_FB_PLATINUM
-  This driver supports a frame buffer for the "platinum" graphics
-  adapter in some Power Macintoshes.
-
-PowerMac "valkyrie" frame buffer device support
-CONFIG_FB_VALKYRIE
-  This driver supports a frame buffer for the "valkyrie" graphics
-  adapter in some Power Macintoshes.
-
-Chips 65550 display support
-CONFIG_FB_CT65550
-  This is the frame buffer device driver for the Chips & Technologies
-  65550 graphics chip in PowerBooks.
-
-TGA frame buffer support
-CONFIG_FB_TGA
-  This is the frame buffer device driver for generic TGA graphic
-  cards. Say Y if you have one of those.
-
-VESA VGA graphics console
-CONFIG_FB_VESA
-  This is the frame buffer device driver for generic VESA 2.0
-  compliant graphic cards. The older VESA 1.2 cards are not supported.
-  You will get a boot time penguin logo at no additional cost. Please
-  read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
-
-VGA 16-color planar support
-CONFIG_FBCON_VGA_PLANES
-  This low level frame buffer console driver enable the kernel to use
-  the 16-color planar modes of the old VGA cards where the bits of
-  each pixel are separated into 4 planes.
-
-  Only answer Y here if you have a (very old) VGA card that isn't VESA
-  2 compatible.
-
-VGA 16-color graphics console
-CONFIG_FB_VGA16
-  This is the frame buffer device driver for VGA 16 color graphic
-  cards. Say Y if you have such a card.
-
-  This code is also available as a module. If you want to compile it
-  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
-  vga16fb.o.
-
-Generic STI frame buffer device support
-CONFIG_FB_STI
-  STI refers to the HP "Standard Text Interface" which is a set of
-  BIOS routines contained in a ROM chip in HP PA-RISC based machines.
-  Enabling this option will implement the linux framebuffer device and
-  an fbcon color text console using calls to the STI BIOS routines.
-  The HP framebuffer device is usually planar, uses a strange memory
-  layout, and changing the plane mask to create colored pixels
-  requires a call to the STI routines, so do not expect /dev/fb to
-  actually be useful.  However, it is the best we have as far as
-  graphics on the HP chipsets due to lack of hardware level
-  documentation for the various on-board HP chipsets used in these
-  systems.  It is sufficient for basic text console functions,
-  including fonts.
-
-  You should probably enable this option, unless you are having
-  trouble getting video when booting the kernel (make sure it isn't
-  just that you are running the console on the serial port, though).
-  Really old HP boxes may not have STI, and must use the PDC BIOS
-  console or the IODC BIOS.
-
-Select other compiled-in fonts
-CONFIG_FBCON_FONTS
-  Say Y here if you would like to use fonts other than the default
-  your frame buffer console usually use.
-
-  Note that the answer to this question won't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about foreign fonts.
-
-  If unsure, say N (the default choices are safe).
-
-VGA 8x16 font
-CONFIG_FONT_8x16
-  This is the "high resolution" font for the VGA frame buffer (the one
-  provided by the VGA text console 80x25 mode.
-
-  If unsure, say Y.
-
-Support only 8 pixels wide fonts
-CONFIG_FBCON_FONTWIDTH8_ONLY
-  Answer Y here will make the kernel provide only the 8x8 fonts (these
-  are the less readable).
-
-  If unsure, say N.
-
-Sparc console 8x16 font
-CONFIG_FONT_SUN8x16
-  This is the high resolution console font for Sun machines. Say Y.
-
-Sparc console 12x22 font (not supported by all drivers)
-CONFIG_FONT_SUN12x22
-  This is the high resolution console font for Sun machines with very
-  big letters (like the letters used in the SPARC PROM). If the
-  standard font is unreadable for you, say Y, otherwise say N.
-
-VGA 8x8 font
-CONFIG_FONT_8x8
-  This is the "high resolution" font for the VGA frame buffer (the one
-  provided by the text console 80x50 (and higher) modes).
-
-  Note that this is a poor quality font. The VGA 8x16 font is quite a
-  lot more readable.
-
-  Given the resolution provided by the frame buffer device, answer N
-  here is safe.
-
-Mac console 6x11 font (not supported by all drivers)
-CONFIG_FONT_6x11
-  Small console font with Macintosh-style high-half glyphs.  Some Mac
-  framebuffer drivers don't support this one at all.
-
-Pearl (old m68k) console 8x8 font
-CONFIG_FONT_PEARL_8x8
-  Small console font with PC-style control-character and high-half
-  glyphs.
-
-Acorn console 8x8 font
-CONFIG_FONT_ACORN_8x8
-  Small console font with PC-style control characters and high-half
-  glyphs.
-
-Backward compatibility mode for Xpmac
-CONFIG_FB_COMPAT_XPMAC
-  If you use the Xpmac X server (common with mklinux), you'll need to
-  say Y here to use X. You should consider changing to XFree86 which
-  includes a server that supports the frame buffer device directly
-  (XF68_FBDev).
-
-Hercules (HGA) mono graphics support
-CONFIG_FB_HGA
-  Say Y here if you have a Hercules mono graphics card.
-
-  This driver is also available as a module ( = code which can be
-  inserted and removed from the running kernel whenever you want).
-  The module will be called hgafb.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-  As this card technology is 15 years old, most people will answer N
-  here.
-
-Epson 1355 framebuffer support
-CONFIG_FB_E1355
-  Build in support for the SED1355 Epson Research Embedded RAMDAC
-  LCD/CRT Controller (since redesignated as the S1D13505) as a
-  framebuffer.  Product specs at
-  <http://www.erd.epson.com/vdc/html/products.htm>.
-
-Dreamcast Frame Buffer support
-CONFIG_FB_DC
-  Say Y here to enable support for the framebuffer on the Sega
-  Dreamcast.  This driver is also available as a module, dcfb.o.
-
-Register Base Address
-CONFIG_E1355_REG_BASE
-  Epson SED1355/S1D13505 LCD/CRT controller register base address.
-  See the manuals at
-  <http://www.erd.epson.com/vdc/html/contents/S1D13505.htm> for
-  discussion.
-
-Framebuffer Base Address
-CONFIG_E1355_FB_BASE
-  Epson SED1355/S1D13505 LCD/CRT controller memory base address.  See
-  the manuals at
-  <http://www.erd.epson.com/vdc/html/contents/S1D13505.htm> for
-  discussion.
-
-NEC PowerVR 2 display support
-CONFIG_FB_PVR2
-  Say Y here if you have a PowerVR 2 card in your box.  If you plan to
-  run linux on your Dreamcast, you will have to say Y here.
-  This driver may or may not work on other PowerVR 2 cards, but is
-  totally untested.  Use at your own risk.  If unsure, say N.
-
-  This driver is also available as a module ( = code which can be
-  inserted and removed from the running kernel whenever you want).
-  The module will be called pvr2fb.o.  If you want to compile it as
-  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=pvr2:XXX", where
-  the meaning of XXX can be found at the end of the main source file
-  (<file:drivers/video/pvr2fb.c>). Please see the file
-  <file:Documentation/fb/pvr2fb.txt>.
-
-Debug pvr2fb
-CONFIG_FB_PVR2_DEBUG
-  Say Y here if you wish for the pvr2fb driver to print out debugging
-  messages. Most people will want to say N here. If unsure, you will
-  also want to say N.
-
-Matrox unified accelerated driver
-CONFIG_FB_MATROX
-  Say Y here if you have a Matrox Millennium, Matrox Millennium II,
-  Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox
-  Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video,
-  Matrox G400 or G450 card in your box. At this time, support for the
-  G100 is untested and support for G450 is highly experimental.
-
-  This driver is also available as a module ( = code which can be
-  inserted and removed from the running kernel whenever you want).
-  The module will be called matroxfb.o. If you want to compile it as
-  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", and
-  are described in <file:Documentation/fb/matroxfb.txt>.
-
-Matrox Millennium I/II support
-CONFIG_FB_MATROX_MILLENIUM
-  Say Y here if you have a Matrox Millennium or Matrox Millennium II
-  video card. If you select "Advanced lowlevel driver options" below,
-  you should check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp
-  packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can
-  also use font widths different from 8.
-
-Matrox Mystique support
-CONFIG_FB_MATROX_MYSTIQUE
-  Say Y here if you have a Matrox Mystique or Matrox Mystique 220
-  video card. If you select "Advanced lowlevel driver options" below,
-  you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp
-  packed pixel and 32 bpp packed pixel. You can also use font widths
-  different from 8.
-
-Matrox G100/G200/G400/G450 support
-CONFIG_FB_MATROX_G100
-  Say Y here if you have a Matrox G100, G200, G400 or G450 based
-  video card. If you select "Advanced lowlevel driver options", you
-  should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed
-  pixel and 32 bpp packed pixel. You can also use font widths
-  different from 8.
-
-  If you need support for G400 secondary head, you must first say Y to
-  "I2C support" and "I2C bit-banging support" in the character devices
-  section, and then to "Matrox I2C support" and "G400 second head
-  support" here in the framebuffer section.
-
-Matrox I2C support
-CONFIG_FB_MATROX_I2C
-  This drivers creates I2C buses which are needed for accessing the
-  DDC (I2C) bus present on all Matroxes, an I2C bus which
-  interconnects Matrox optional devices, like MGA-TVO on G200 and
-  G400, and the secondary head DDC bus, present on G400 only.
-
-  You can say Y or M here if you want to experiment with monitor
-  detection code. You must say Y or M here if you want to use either
-  second head of G400 or MGA-TVO on G200 or G400.
-
-  If you compile it as module, it will create a module named
-  i2c-matroxfb.o.
-
-Matrox G400 second head support
-CONFIG_FB_MATROX_MAVEN
-  WARNING !!! This support does not work with G450 !!!
-
-  Say Y or M here if you want to use a secondary head (meaning two
-  monitors in parallel) on G400 or MGA-TVO add-on on G200. Secondary
-  head is not compatible with accelerated XFree 3.3.x SVGA servers -
-  secondary head output is blanked while you are in X. With XFree
-  3.9.17 preview you can use both heads if you use SVGA over fbdev or
-  the fbdev driver on first head and the fbdev driver on second head.
-
-  If you compile it as module, two modules are created,
-  matroxfb_crtc2.o and matroxfb_maven.o. Matroxfb_maven is needed for
-  both G200 and G400, matroxfb_crtc2 is needed only by G400. You must
-  also load i2c-matroxfb to get it to run.
-
-  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
-  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.
-
-  Also do not forget that second head supports only 16 and 32 bpp
-  packed pixels, so it is a good idea to compile them into the kernel
-  too.  You can use only some font widths, as the driver uses generic
-  painting procedures (the secondary head does not use acceleration
-  engine).
-
-Matrox G450 second head support
-CONFIG_FB_MATROX_G450
-  Say Y or M here if you want to use a secondary head (meaning two
-  monitors in parallel) on G450.
-
-  If you compile it as module, two modules are created,
-  matroxfb_crtc2.o and matroxfb_g450.o. Both modules are needed if you
-  want two independent display devices.
-
-  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
-  primary and secondary head outputs.  Secondary head driver always
-  start in 640x480 resolution and you must use fbset to change it.
-
-  Also do not forget that second head supports only 16 and 32 bpp
-  packed pixels, so it is a good idea to compile them into the kernel
-  too. You can use only some font widths, as the driver uses generic
-  painting procedures (the secondary head does not use acceleration
-  engine).
-
-Matrox unified driver multihead support
-CONFIG_FB_MATROX_MULTIHEAD
-  Say Y here if you have more than one (supported) Matrox device in
-  your computer and you want to use all of them for different monitors
-  ("multihead"). If you have only one device, you should say N because
-  the driver compiled with Y is larger and a bit slower, especially on
-  ia32 (ix86).
-
-  If you said M to "Matrox unified accelerated driver" and N here, you
-  will still be able to use several Matrox devices simultaneously:
-  insert several instances of the module matroxfb.o into the kernel
-  with insmod, supplying the parameter "dev=N" where N is 0, 1, etc.
-  for the different Matrox devices. This method is slightly faster but
-  uses 40 KB of kernel memory per Matrox card.
-
-  There is no need for enabling 'Matrox multihead support' if you have
-  only one Matrox card in the box.
-
-3Dfx Voodoo Graphics / Voodoo2 frame buffer support
-CONFIG_FB_VOODOO1
-  Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or 
-  Voodoo2 (cvg) based graphics card.
-
-  This driver is also available as a module ( = code which can be 
-  inserted and removed from the running kernel whenever you want).
-  The module will be called sstfb.o. If you want to compile it as
-  a module, say M here and read Documentation/modules.txt.
-
-  WARNING: Do not use any application that uses the 3D engine
-  (namely glide) while using this driver.
-  Please read the file Documentation/fb/README-sstfb.txt for supported
-  options and other important info  support.
-
-MDA text console (dual-headed)
-CONFIG_MDA_CONSOLE
-  Say Y here if you have an old MDA or monochrome Hercules graphics
-  adapter in your system acting as a second head ( = video card). You
-  will then be able to use two monitors with your Linux system. Do not
-  say Y here if your MDA card is the primary card in your system; the
-  normal VGA driver will handle it.
-
-  This driver is also available as a module ( = code which can be
-  inserted and removed from the running kernel whenever you want).
-  The module will be called mdacon.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-  If unsure, say N.
-
-SBUS and UPA framebuffers
-CONFIG_FB_SBUS
-  Say Y if you want support for SBUS or UPA based frame buffer device.
-
-Creator/Creator3D support
-CONFIG_FB_CREATOR
-  This is the frame buffer device driver for the Creator and Creator3D
-  graphics boards.
-
-CGsix (GX,TurboGX) support
-CONFIG_FB_CGSIX
-  This is the frame buffer device driver for the CGsix (GX, TurboGX)
-  frame buffer.
-
-BWtwo support
-CONFIG_FB_BWTWO
-  This is the frame buffer device driver for the BWtwo frame buffer.
-
-CGthree support
-CONFIG_FB_CGTHREE
-  This is the frame buffer device driver for the CGthree frame buffer.
-
-CGfourteen (SX) support
-CONFIG_FB_CGFOURTEEN
-  This is the frame buffer device driver for the CGfourteen frame
-  buffer on Desktop SPARCsystems with the SX graphics option.
-
-P9100 (Sparcbook 3 only) support
-CONFIG_FB_P9100
-  This is the frame buffer device driver for the P9100 card
-  supported on Sparcbook 3 machines.
-
-Leo (ZX) support
-CONFIG_FB_LEO
-  This is the frame buffer device driver for the SBUS-based Sun ZX
-  (leo) frame buffer cards.
-
-IGA 168x display support
-CONFIG_FB_IGA
-  This is the framebuffer device for the INTERGRAPHICS 1680 and
-  successor frame buffer cards.
-
-TCX (SS4/SS5 only) support
-CONFIG_FB_TCX
-  This is the frame buffer device driver for the TCX 24/8bit frame
-  buffer.
-
-HD64461 Frame Buffer support
-CONFIG_FB_HIT
-  This is the frame buffer device driver for the Hitachi HD64461 LCD
-  frame buffer card.
-
-SIS 630/540 display support
-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/>.
-
-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/>.
-
-SIS 315H/315 support
-CONFIG_FB_SIS_315
-  This is the frame buffer device driver for the SiS 315 graphics
-  card.  Specs available at <http://www.sis.com.tw/>.
-
-IMS Twin Turbo display support
-CONFIG_FB_IMSTT
-  The IMS Twin Turbo is a PCI-based frame buffer card bundled with
-  many Macintosh and compatible computers.
-
-Virtual Frame Buffer support (ONLY FOR TESTING!)
-CONFIG_FB_VIRTUAL
-  This is a `virtual' frame buffer device. It operates on a chunk of
-  unswappable kernel memory instead of on the memory of a graphics
-  board. This means you cannot see any output sent to this frame
-  buffer device, while it does consume precious memory. The main use
-  of this frame buffer device is testing and debugging the frame
-  buffer subsystem. Do NOT enable it for normal systems! To protect
-  the innocent, it has to be enabled explicitly at boot time using the
-  kernel option `video=vfb:'.
-
-  This driver is also available as a module ( = code which can be
-  inserted and removed from the running kernel whenever you want). The
-  module will be called vfb.o. If you want to compile it as a module,
-  say M here and read <file:Documentation/modules.txt>.
-
-  If unsure, say N.
-
-Mach64 CT/VT/GT/LT (incl. 3D RAGE) support
-CONFIG_FB_ATY_CT
-  Say Y here to support use of ATI's 64-bit Rage boards (or other
-  boards based on the Mach64 CT, VT, GT, and LT chipsets) as a
-  framebuffer device.  The ATI product support page for these boards
-  is at <http://support.ati.com/products/pc/mach64/>.
-
-Sony Vaio Picturebook laptop LCD panel support
-CONFIG_FB_ATY_CT_VAIO_LCD
-  Say Y here if you want to use the full width of the Sony Vaio 
-  Picturebook laptops LCD panels (you will get a 128x30 console).
-
-  Note that you need to activate this mode using the 'vga=0x301'
-  option from your boot loader (lilo or loadlin).  See the
-  documentation of your boot loader about how to pass options to the
-  kernel.
-  
-Mach64 GX support
-CONFIG_FB_ATY_GX
-  Say Y here to support use of the ATI Mach64 Graphics Expression
-  board (or other boards based on the Mach64 GX chipset) as a
-  framebuffer device.  The ATI product support page for these boards
-  is at
-  <http://support.ati.com/products/pc/mach64/graphics_xpression.html>.
-
-ATI Radeon display support
-CONFIG_FB_RADEON
-  Choose this option if you want to use an ATI Radeon graphics card as
-  a framebuffer device.  There are both PCI and AGP versions.  You
-  don't need to choose this to run the Radeon in plain VGA mode.
-  There is a product page at
-  <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
-
-SA-1100 LCD support
-CONFIG_FB_SA1100
-  This is a framebuffer device for the SA-1100 LCD Controller.
-  See <http://www.linux-fbdev.org/> for information on framebuffer
-  devices.
-
-  If you plan to use the LCD display with your SA-1100 system, say
-  Y here.
-
-Advanced low level driver options
-CONFIG_FBCON_ADVANCED
-  The frame buffer console uses character drawing routines that are
-  tailored to the specific organization of pixels in the memory of
-  your graphics hardware. These are called the low level frame buffer
-  console drivers. Note that they are used for text console output
-  only; they are NOT needed for graphical applications.
-
-  If you say N here, the needed low level drivers are automatically
-  enabled, depending on what frame buffer devices you selected above.
-  This is recommended for most users.
-
-  If you say Y here, you have more fine-grained control over which low
-  level drivers are enabled. You can e.g. leave out low level drivers
-  for color depths you do not intend to use for text consoles.
-
-  Low level frame buffer console drivers can be modules ( = code which
-  can be inserted and removed from the running kernel whenever you
-  want). The modules will be called fbcon-*.o. If you want to compile
-  (some of) them as modules, read <file:Documentation/modules.txt>.
-
-  If unsure, say N.
-
-Monochrome support
-CONFIG_FBCON_MFB
-  This is the low level frame buffer console driver for monochrome
-  (2 colors) packed pixels.
-
-2 bpp packed pixels support
-CONFIG_FBCON_CFB2
-  This is the low level frame buffer console driver for 2 bits per
-  pixel (4 colors) packed pixels.
-
-4 bpp packed pixels support
-CONFIG_FBCON_CFB4
-  This is the low level frame buffer console driver for 4 bits per
-  pixel (16 colors) packed pixels.
-
-8 bpp packed pixels support
-CONFIG_FBCON_CFB8
-  This is the low level frame buffer console driver for 8 bits per
-  pixel (256 colors) packed pixels.
-
-16 bpp packed pixels support
-CONFIG_FBCON_CFB16
-  This is the low level frame buffer console driver for 15 or 16 bits
-  per pixel (32K or 64K colors, also known as `hicolor') packed
-  pixels.
-
-24 bpp packed pixels support
-CONFIG_FBCON_CFB24
-  This is the low level frame buffer console driver for 24 bits per
-  pixel (16M colors, also known as `truecolor') packed pixels. It is
-  NOT for `sparse' 32 bits per pixel mode.
-
-32 bpp packed pixels support
-CONFIG_FBCON_CFB32
-  This is the low level frame buffer console driver for 32 bits per
-  pixel (16M colors, also known as `truecolor') sparse packed pixels.
-
-Amiga bitplanes support
-CONFIG_FBCON_AFB
-  This is the low level frame buffer console driver for 1 to 8
-  bitplanes (2 to 256 colors) on Amiga.
-
-Amiga interleaved bitplanes support
-CONFIG_FBCON_ILBM
-  This is the low level frame buffer console driver for 1 to 8
-  interleaved bitplanes (2 to 256 colors) on Amiga.
-
-Atari interleaved bitplanes (2 planes) support
-CONFIG_FBCON_IPLAN2P2
-  This is the low level frame buffer console driver for 2 interleaved
-  bitplanes (4 colors) on Atari.
-
-Atari interleaved bitplanes (4 planes) support
-CONFIG_FBCON_IPLAN2P4
-  This is the low level frame buffer console driver for 4 interleaved
-  bitplanes (16 colors) on Atari.
-
-Atari interleaved bitplanes (8 planes) support
-CONFIG_FBCON_IPLAN2P8
-  This is the low level frame buffer console driver for 8 interleaved
-  bitplanes (256 colors) on Atari.
-
-Mac variable bpp packed pixels support
-CONFIG_FBCON_MAC
-  This is the low level frame buffer console driver for 1/2/4/8/16/32
-  bits per pixel packed pixels on Mac. It supports variable font
-  widths for low resolution screens.
-
-HGA monochrome support
-CONFIG_FBCON_HGA
-  This is the low level frame buffer console driver for Hercules mono
-  graphics cards.
-
-VGA characters/attributes support
-CONFIG_FBCON_VGA
-  This is the low level frame buffer console driver for VGA text mode;
-  it is used by frame buffer device drivers that support VGA text
-  mode.
-
-Parallel-port support
-CONFIG_PARPORT
-  If you want to use devices connected to your machine's parallel port
-  (the connector at the computer with 25 holes), e.g. printer, ZIP
-  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
-  <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
-  the WWW.
-
-  It is possible to share a single parallel port among several devices
-  and it is safe to compile all the corresponding drivers into the
-  kernel.  If you want to compile parallel port 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
-  parport.o.  If you have more than one parallel port and want to
-  specify which port and IRQ to be used by this driver at module load
-  time, take a look at <file:Documentation/parport.txt>.
-
-  If unsure, say Y.
-
-PC-style hardware
-CONFIG_PARPORT_PC
-  You should say Y here if you have a PC-style parallel port. All IBM
-  PC compatible computers and some Alphas have PC-style parallel
-  ports.
-
-  This code is also available as a module.  If you want to compile it
-  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
-  parport_pc.o.
-
-  If unsure, say Y.
-
-Parallel+serial PCI 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
-  will be called parport_serial.o.
-
-Use FIFO/DMA if available
-CONFIG_PARPORT_PC_FIFO
-  Many parallel port chipsets provide hardware that can speed up
-  printing. Say Y here if you want to take advantage of that.
-
-  As well as actually having a FIFO, or DMA capability, the kernel
-  will need to know which IRQ the parallel port has.  By default,
-  parallel port interrupts will not be used, and so neither will the
-  FIFO.  See <file:Documentation/parport.txt> to find out how to
-  specify which IRQ/DMA to use.
-
-SuperIO chipset support
-CONFIG_PARPORT_PC_SUPERIO
-  Saying Y here enables some probes for Super-IO chipsets in order to
-  find out things like base addresses, IRQ lines and DMA channels.  It
-  is safe to say N.
-
-Support for PCMCIA management for PC-style ports
-CONFIG_PARPORT_PC_PCMCIA
-  Say Y here if you need PCMCIA support for your PC-style parallel
-  ports. If unsure, say N.
-
-Support foreign hardware
-CONFIG_PARPORT_OTHER
-  Say Y here if you want to be able to load driver modules to support
-  other non-standard types of parallel ports. This causes a
-  performance loss, so most people say N.
-
-Amiga built-in parallel port support
-CONFIG_PARPORT_AMIGA
-  Say Y here if you need support for the parallel port hardware on
-  Amiga machines. This code is also available as a module (say M),
-  called parport_amiga.o. If in doubt, saying N is the safe plan.
-
-Atari built-in parallel port support
-CONFIG_PARPORT_ATARI
-  Say Y here if you need support for the parallel port hardware on
-  Atari machines. This code is also available as a module (say M),
-  called parport_atari.o. If in doubt, saying N is the safe plan.
-
-Multiface III parallel port support
-CONFIG_PARPORT_MFC3
-  Say Y here if you need parallel port support for the MFC3 card.
-  This code is also available as a module (say M), called
-  parport_mfc3.o. If in doubt, saying N is the safe plan.
-
-Support IEEE 1284 status readback
-CONFIG_PRINTER_READBACK
-  If you have a device on your parallel port that support this
-  protocol, this option will allow the device to report its status. It
-  is safe to say Y.
-
-IEEE 1284 transfer modes
-CONFIG_PARPORT_1284
-  If you have a printer that supports status readback or device ID, or
-  want to use a device that uses enhanced parallel port transfer modes
-  such as EPP and ECP, say Y here to enable advanced IEEE 1284
-  transfer modes. Also say Y if you want device ID information to
-  appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N.
-
-Enable loadable module support
-CONFIG_MODULES
-  Kernel modules are small pieces of compiled code which can be
-  inserted in or removed from the running kernel, using the programs
-  insmod and rmmod. This is described in the file
-  <file:Documentation/modules.txt>, including the fact that you have
-  to say "make modules" in order to compile the modules that you chose
-  during kernel configuration.  Modules can be device drivers, file
-  systems, binary executable formats, and so on. If you think that you
-  may want to make use of modules with this kernel in the future, then
-  say Y here.  If unsure, say Y.
-
-Set version information on all symbols for modules
-CONFIG_MODVERSIONS
-  Usually, modules have to be recompiled whenever you switch to a new
-  kernel.  Saying Y here makes it possible, and safe, to use the
-  same modules even after compiling a new kernel; this requires the
-  program modprobe. All the software needed for module support is in
-  the modutils package (check the file <file:Documentation/Changes>
-  for location and latest version).  NOTE: if you say Y here but don't
-  have the program genksyms (which is also contained in the above
-  mentioned modutils package), then the building of your kernel will
-  fail.  If you are going to use modules that are generated from
-  non-kernel sources, you would benefit from this option.  Otherwise
-  it's not that important.  So, N ought to be a safe bet.
-
-Kernel module loader support
-CONFIG_KMOD
-  Normally when you have selected some drivers and/or file systems to
-  be created as loadable modules, you also have the responsibility to
-  load the corresponding modules (using the programs insmod or
-  modprobe) before you can use them. If you say Y here however, the
-  kernel will be able to load modules for itself: when a part of the
-  kernel needs a module, it runs modprobe with the appropriate
-  arguments, thereby loading the module if it is available. (This is a
-  replacement for kerneld.) Say Y here and read about configuring it
-  in <file:Documentation/kmod.txt>.
-
-ARP daemon support
-CONFIG_ARPD
-  Normally, the kernel maintains an internal cache which maps IP
-  addresses to hardware addresses on the local network, so that
-  Ethernet/Token Ring/ etc. frames are sent to the proper address on
-  the physical networking layer. For small networks having a few
-  hundred directly connected hosts or less, keeping this address
-  resolution (ARP) cache inside the kernel works well. However,
-  maintaining an internal ARP cache does not work well for very large
-  switched networks, and will use a lot of kernel memory if TCP/IP
-  connections are made to many machines on the network.
-
-  If you say Y here, the kernel's internal ARP cache will never grow
-  to more than 256 entries (the oldest entries are expired in a LIFO
-  manner) and communication will be attempted with the user space ARP
-  daemon arpd. Arpd then answers the address resolution request either
-  from its own cache or by asking the net.
-
-  This code is experimental and also obsolete. If you want to use it,
-  you need to find a version of the daemon arpd on the net somewhere,
-  and you should also say Y to "Kernel/User network link driver",
-  below. If unsure, say N.
-
-TCP/IP networking
-CONFIG_INET
-  These are the protocols used on the Internet and on most local
-  Ethernets. It is highly recommended to say Y here (this will enlarge
-  your kernel by about 144 KB), since some programs (e.g. the X window
-  system) use TCP/IP even if your machine is not connected to any
-  other computer. You will get the so-called loopback device which
-  allows you to ping yourself (great fun, that!).
-
-  For an excellent introduction to Linux networking, please read the
-  NET-3-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This option is also necessary if you want to use the full power of
-  term (term is a program which gives you almost full Internet
-  connectivity if you have a regular dial up shell account on some
-  Internet connected Unix computer; for more information, read
-  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
-
-  If you say Y here and also to "/proc file system support" and
-  "Sysctl support" below, you can change various aspects of the
-  behavior of the TCP/IP code by writing to the (virtual) files in
-  /proc/sys/net/ipv4/*; the options are explained in the file
-  <file:Documentation/networking/ip-sysctl.txt>.
-
-  Short answer: say Y.
-
-IP multicasting
-CONFIG_IP_MULTICAST
-  This is code for addressing several networked computers at once,
-  enlarging your kernel by about 2 KB. You need multicasting if you
-  intend to participate in the MBONE, a high bandwidth network on top
-  of the Internet which carries audio and video broadcasts. More
-  information about the MBONE is on the WWW at
-  <http://www-itg.lbl.gov/mbone/>. Information about the multicast
-  capabilities of the various network cards is contained in
-  <file:Documentation/networking/multicast.txt>. For most people, it's
-  safe to say N.
-
-Advanced router
-CONFIG_IP_ADVANCED_ROUTER
-  If you intend to run your Linux box mostly as a router, i.e. as a
-  computer that forwards and redistributes network packets, say Y; you
-  will then be presented with several options that allow more precise
-  control about the routing process.
-
-  The answer to this question won't directly affect the kernel:
-  answering N will just cause the configurator to skip all the
-  questions about advanced routing.
-
-  Note that your box can only act as a router if you enable IP
-  forwarding in your kernel; you can do that by saying Y to "/proc
-  file system support" and "Sysctl support" below and executing the
-  line
-
-    echo "1" > /proc/sys/net/ipv4/ip_forward
-
-  at boot time after the /proc file system has been mounted.
-
-  If you turn on IP forwarding, you will also get the rp_filter, which
-  automatically rejects incoming packets if the routing table entry
-  for their source address doesn't match the network interface they're
-  arriving on. This has security advantages because it prevents the
-  so-called IP spoofing, however it can pose problems if you use
-  asymmetric routing (packets from you to a host take a different path
-  than packets from that host to you) or if you operate a non-routing
-  host which has several IP addresses on different interfaces. To turn
-  rp_filter off use:
-
-        echo 0 > /proc/sys/net/ipv4/conf/<device>/rp_filter
-  or
-        echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
-
-  If unsure, say N here.
-
-Policy routing
-CONFIG_IP_MULTIPLE_TABLES
-  Normally, a router decides what to do with a received packet based
-  solely on the packet's final destination address. If you say Y here,
-  the Linux router will also be able to take the packet's source
-  address into account. Furthermore, if you also say Y to "Use TOS
-  value as routing key" below, the TOS (Type-Of-Service) field of the
-  packet can be used for routing decisions as well. In addition, if
-  you say Y here and to "Fast network address translation" below,
-  the router will also be able to modify source and destination
-  addresses of forwarded packets.
-
-  If you are interested in this, please see the preliminary
-  documentation at <http://www.compendium.com.ar/policy-routing.txt>
-  and <ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex>.
-  You will need supporting software from
-  <ftp://ftp.inr.ac.ru/ip-routing/>.
-
-  If unsure, say N.
-
-Equal cost multipath
-CONFIG_IP_ROUTE_MULTIPATH
-  Normally, the routing tables specify a single action to be taken in
-  a deterministic manner for a given packet. If you say Y here
-  however, it becomes possible to attach several actions to a packet
-  pattern, in effect specifying several alternative paths to travel
-  for those packets. The router considers all these paths to be of
-  equal "cost" and chooses one of them in a non-deterministic fashion
-  if a matching packet arrives.
-
-Use TOS value as routing key
-CONFIG_IP_ROUTE_TOS
-  The header of every IP packet carries a TOS (Type Of Service) value
-  with which the packet requests a certain treatment, e.g. low
-  latency (for interactive traffic), high throughput, or high
-  reliability.  If you say Y here, you will be able to specify
-  different routes for packets with different TOS values.
-
-Use netfilter MARK value as routing key
-CONFIG_IP_ROUTE_FWMARK
-  If you say Y here, you will be able to specify different routes for
-  packets with different mark values (see iptables(8), MARK target).
-
-Verbose route monitoring
-CONFIG_IP_ROUTE_VERBOSE
-  If you say Y here, which is recommended, then the kernel will print
-  verbose messages regarding the routing, for example warnings about
-  received packets which look strange and could be evidence of an
-  attack or a misconfigured system somewhere. The information is
-  handled by the klogd daemon which is responsible for kernel messages
-  ("man klogd").
-
-Large routing tables
-CONFIG_IP_ROUTE_LARGE_TABLES
-  If you have routing zones that grow to more than about 64 entries,
-  you may want to say Y here to speed up the routing process.
-
-Fast network address translation
-CONFIG_IP_ROUTE_NAT
-  If you say Y here, your router will be able to modify source and
-  destination addresses of packets that pass through it, in a manner
-  you specify.  General information about Network Address Translation
-  can be gotten from the document
-  <http://www.csn.tu-chemnitz.de/~mha/linux-ip-nat/diplom/nat.html>.
-
-Kernel level IP autoconfiguration
-CONFIG_IP_PNP
-  This enables automatic configuration of IP addresses of devices and
-  of the routing table during kernel boot, based on either information
-  supplied on the kernel command line or by BOOTP or RARP protocols.
-  You need to say Y only for diskless machines requiring network
-  access to boot (in which case you want to say Y to "Root file system
-  on NFS" as well), because all other machines configure the network
-  in their startup scripts.
-
-BOOTP support
-CONFIG_IP_PNP_BOOTP
-  If you want your Linux box to mount its whole root file system (the
-  one containing the directory /) from some other computer over the
-  net via NFS and you want the IP address of your computer to be
-  discovered automatically at boot time using the BOOTP protocol (a
-  special protocol designed for doing this job), say Y here. In case
-  the boot ROM of your network card was designed for booting Linux and
-  does BOOTP itself, providing all necessary information on the kernel
-  command line, you can say N here. If unsure, say Y. Note that if you
-  want to use BOOTP, a BOOTP server must be operating on your network.
-  Read <file:Documentation/nfsroot.txt> for details.
-
-DHCP support
-CONFIG_IP_PNP_DHCP
-  If you want your Linux box to mount its whole root file system (the
-  one containing the directory /) from some other computer over the
-  net via NFS and you want the IP address of your computer to be
-  discovered automatically at boot time using the DHCP protocol (a
-  special protocol designed for doing this job), say Y here. In case
-  the boot ROM of your network card was designed for booting Linux and
-  does DHCP itself, providing all necessary information on the kernel
-  command line, you can say N here.
-
-  If unsure, say Y. Note that if you want to use DHCP, a DHCP server
-  must be operating on your network.  Read
-  <file:Documentation/nfsroot.txt> for details.
-
-RARP support
-CONFIG_IP_PNP_RARP
-  If you want your Linux box to mount its whole root file system (the
-  one containing the directory /) from some other computer over the
-  net via NFS and you want the IP address of your computer to be
-  discovered automatically at boot time using the RARP protocol (an
-  older protocol which is being obsoleted by BOOTP and DHCP), say Y
-  here. Note that if you want to use RARP, a RARP server must be
-  operating on your network. Read <file:Documentation/nfsroot.txt> for
-  details.
-
-IP tunneling
-CONFIG_NET_IPIP
-  Tunneling means encapsulating data of one protocol type within
-  another protocol and sending it over a channel that understands the
-  encapsulating protocol. This particular tunneling driver implements
-  encapsulation of IP within IP, which sounds kind of pointless, but
-  can be useful if you want to make your (or some other) machine
-  appear on a different network than it physically is, or to use
-  mobile-IP facilities (allowing laptops to seamlessly move between
-  networks without changing their IP addresses; check out
-  <http://anchor.cs.binghamton.edu/~mobileip/LJ/index.html>).
-
-  Saying Y to this option will produce two modules ( = code which can
-  be inserted in and removed from the running kernel whenever you
-  want). Most people won't need this and can say N.
-
-GRE tunnels over IP
-CONFIG_NET_IPGRE
-  Tunneling means encapsulating data of one protocol type within
-  another protocol and sending it over a channel that understands the
-  encapsulating protocol. This particular tunneling driver implements
-  GRE (Generic Routing Encapsulation) and at this time allows
-  encapsulating of IPv4 or IPv6 over existing IPv4 infrastructure.
-  This driver is useful if the other endpoint is a Cisco router: Cisco
-  likes GRE much better than the other Linux tunneling driver ("IP
-  tunneling" above). In addition, GRE allows multicast redistribution
-  through the tunnel.
-
-Broadcast GRE over IP
-CONFIG_NET_IPGRE_BROADCAST
-  One application of GRE/IP is to construct a broadcast WAN (Wide Area
-  Network), which looks like a normal Ethernet LAN (Local Area
-  Network), but can be distributed all over the Internet. If you want
-  to do that, say Y here and to "IP multicast routing" below.
-
-IP multicast routing
-CONFIG_IP_MROUTE
-  This is used if you want your machine to act as a router for IP
-  packets that have several destination addresses. It is needed on the
-  MBONE, a high bandwidth network on top of the Internet which carries
-  audio and video broadcasts. In order to do that, you would most
-  likely run the program mrouted. Information about the multicast
-  capabilities of the various network cards is contained in
-  <file:Documentation/networking/multicast.txt>. If you haven't heard
-  about it, you don't need it.
-
-PIM-SM version 1 support
-CONFIG_IP_PIMSM_V1
-  Kernel side support for Sparse Mode PIM (Protocol Independent
-  Multicast) version 1. This multicast routing protocol is used widely
-  because Cisco supports it. You need special software to use it
-  (pimd-v1). Please see <http://netweb.usc.edu/pim/> for more
-  information about PIM.
-
-  Say Y if you want to use PIM-SM v1. Note that you can say N here if
-  you just want to use Dense Mode PIM.
-
-PIM-SM version 2 support
-CONFIG_IP_PIMSM_V2
-  Kernel side support for Sparse Mode PIM version 2. In order to use
-  this, you need an experimental routing daemon supporting it (pimd or
-  gated-5). This routing protocol is not used widely, so say N unless
-  you want to play with it.
-
-Unix domain sockets
-CONFIG_UNIX
-  If you say Y here, you will include support for Unix domain sockets;
-  sockets are the standard Unix mechanism for establishing and
-  accessing network connections.  Many commonly used programs such as
-  the X Window system and syslog use these sockets even if your
-  machine is not connected to any network.  Unless you are working on
-  an embedded system or something similar, you therefore definitely
-  want to say Y here.
-
-  However, the socket support is also available 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>. The module will be
-  called unix.o.  If you try building this as a module and you have
-  said Y to "Kernel module loader support" above, be sure to add
-  'alias net-pf-1 unix' to your /etc/modules.conf file. Note that
-  several important services won't work correctly if you say M here
-  and then neglect to load the module.
-
-  Say Y unless you know what you are doing.
-
-The IPv6 protocol
-CONFIG_IPV6
-  This is experimental support for the next version of the Internet
-  Protocol: IP version 6 (also called IPng "IP next generation").
-  Features of this new protocol include: expanded address space,
-  authentication and privacy, and seamless interoperability with the
-  current version of IP (IP version 4). For general information about
-  IPv6, see <http://playground.sun.com/pub/ipng/html/ipng-main.html>;
-  for specific information about IPv6 under Linux read the HOWTO at
-  <http://www.bieringer.de/linux/IPv6/> and the file net/ipv6/README
-  in the kernel source.
-
-  If you want to use IPv6, please upgrade to the newest net-tools as
-  given in <file:Documentation/Changes>. You will still be able to do
-  regular IPv4 networking as well.
-
-  This protocol support 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 ipv6.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-  It is safe to say N here for now.
-
-IPv6: routing messages via old netlink
-CONFIG_IPV6_NETLINK
-  You can say Y here to receive routing messages from the IPv6 code
-  through the old netlink interface. However, a better option is to
-  say Y to "Kernel/User network link driver" and to "Routing
-  messages" instead.
-
-Kernel httpd acceleration
-CONFIG_KHTTPD
-  The kernel httpd acceleration daemon (kHTTPd) is a (limited) web
-  server built into the kernel. It is limited since it can only serve
-  files from the file system and cannot deal with executable content
-  such as CGI scripts. Serving files is sped up if you use kHTTPd.
-  If kHTTPd is not able to fulfill a request, it can transparently
-  pass it through to a user space web server such as apache.
-
-  Saying "M" here builds the kHTTPd module; this is NOT enough to have
-  a working kHTTPd. For safety reasons, the module has to be activated
-  by doing a "echo 1 > /proc/sys/net/khttpd/start" after inserting the
-  module.
-
-  Before using this, read the README in net/khttpd !
-
-  The kHTTPd is experimental. Be careful when using it on a production
-  machine. Also note that kHTTPd doesn't support virtual servers yet.
-
-The IPX protocol
-CONFIG_IPX
-  This is support for the Novell networking protocol, IPX, commonly
-  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://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
-  support", below.
-
-  IPX is similar in scope to IP, while SPX, which runs on top of IPX,
-  is similar to TCP. There is also experimental support for SPX in
-  Linux (see "SPX networking", below).
-
-  To turn your Linux box into a fully featured NetWare file server and
-  IPX router, say Y here and fetch either lwared from
-  <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>.
-
-  General information about how to connect Linux, Windows machines and
-  Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
-
-  The IPX driver would enlarge your kernel by about 16 KB. 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 ipx.o.  If you want to compile it as a module, say M here
-  and read <file:Documentation/modules.txt>.  Unless you want to
-  integrate your Linux box with a local Novell network, say N.
-
-Full internal IPX network
-CONFIG_IPX_INTERN
-  Every IPX network has an address that identifies it. Sometimes it is
-  useful to give an IPX "network" address to your Linux box as well
-  (for example if your box is acting as a file server for different
-  IPX networks: it will then be accessible from everywhere using the
-  same address). The way this is done is to create a virtual internal
-  "network" inside your box and to assign an IPX address to this
-  network. Say Y here if you want to do this; read the IPX-HOWTO at
-  <http://www.linuxdoc.org/docs.html#howto> for details.
-
-  The full internal IPX network enables you to allocate sockets on
-  different virtual nodes of the internal network. This is done by
-  evaluating the field sipx_node of the socket address given to the
-  bind call. So applications should always initialize the node field
-  to 0 when binding a socket on the primary network. In this case the
-  socket is assigned the default node that has been given to the
-  kernel when the internal network was created. By enabling the full
-  internal IPX network the cross-forwarding of packets targeted at
-  '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/>.
-
-  If you don't know what you are doing, say N.
-
-#(We're told this will come back someday)
-
-SPX networking
-CONFIG_SPX
-  * Orphaned entry retained 20 April 2001 by Petr Vandrovec     *
-  * If you read this note from the configurator, please contact *
-  * the Configure.help maintainers.                             *
-  The Sequenced Packet eXchange protocol is a transport layer protocol
-  built on top of IPX. It is used in Novell NetWare systems for
-  client-server applications and is similar to TCP (which runs on top
-  of IP).
-
-  Note that Novell NetWare file sharing does not use SPX; it uses a
-  protocol called NCP, for which separate Linux support is available
-  ("NCP file system support" below for the client side, and the user
-  space programs lwared or mars_nwe for the server side).
-
-  Say Y here if you have use for SPX; read the IPX-HOWTO at
-  <http://www.linuxdoc.org/docs.html#howto> for details.
-
-  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 af_spx.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-DECnet networking
-CONFIG_DECNET
-  The DECnet networking protocol was used in many products made by
-  Digital (now Compaq).  It provides reliable stream and sequenced
-  packet communications over which run a variety of services similar
-  to those which run over TCP/IP.
-
-  To find some tools to use with the kernel layer support, please
-  look at Patrick Caulfield's web site:
-  <http://linux.dreamtime.org/decnet/>.
-
-  More detailed documentation is available in
-  <file:Documentation/networking/decnet.txt>.
-
-  Be sure to say Y to "/proc file system support" and "Sysctl support"
-  below when using DECnet, since you will need sysctl support to aid
-  in configuration at run time.
-
-  The DECnet code 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 decnet.o.
-
-DECnet SIOCFIGCONF support
-CONFIG_DECNET_SIOCGIFCONF
-  This option should only be turned on if you are really sure that
-  you know what you are doing. It can break other applications which
-  use this system call and the proper way to get the information
-  provided by this call is to use rtnetlink.
-
-  If unsure, say N.
-
-DECnet router support
-CONFIG_DECNET_ROUTER
-  Add support for turning your DECnet Endnode into a level 1 or 2
-  router.  This is an unfinished option for developers only.  If you
-  do say Y here, then make sure that you also say Y to "Kernel/User
-  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
-  will be required for the forthcoming routing daemon to work.
-
-  See <file:Documentation/networking/decnet.txt> for more information.
-
-Use FWMARK value as DECnet routing key
-CONFIG_DECNET_ROUTE_FWMARK
-  If you say Y here, you will be able to specify different routes for
-  packets with different FWMARK ("firewalling mark") values
-  (see ipchains(8), "-m" argument).
-
-AppleTalk interfaces support
-CONFIG_APPLETALK
-  AppleTalk is the way Apple computers speak to each other on a
-  network. If your Linux box is connected to such a network and you
-  want to join the conversation, say Y.
-
-AppleTalk protocol support
-CONFIG_ATALK
-  AppleTalk is the way Apple computers speak to each other on a
-  network.  If your Linux box is connected to such a network and you
-  want to join the conversation, say Y.  You will need to use the
-  netatalk package so that your Linux box can act as a print and file
-  server for Macs as well as access AppleTalk printers.  Check out
-  <http://www.zettabyte.net/netatalk/> on the WWW for details.
-  EtherTalk is the name used for AppleTalk over Ethernet and the
-  cheaper and slower LocalTalk is AppleTalk over a proprietary Apple
-  network using serial links.  EtherTalk and LocalTalk are fully
-  supported by Linux.
-
-  General information about how to connect Linux, Windows machines and
-  Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.  The
-  NET-3-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
-  information as well.
-
-  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 is called appletalk.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.  You
-  almost certainly want to compile it as a module so you can restart
-  your AppleTalk stack without rebooting your machine.  I hear that
-  the GNU boycott of Apple is over, so even politically correct people
-  are allowed to say Y here.
-
-AppleTalk-IP driver support
-CONFIG_IPDDP
-  This allows IP networking for users who only have AppleTalk
-  networking available. This feature is experimental. With this
-  driver, you can encapsulate IP inside AppleTalk (e.g. if your Linux
-  box is stuck on an AppleTalk only network) or decapsulate (e.g. if
-  you want your Linux box to act as an Internet gateway for a zoo of
-  AppleTalk connected Macs). Please see the file
-  <file:Documentation/networking/ipddp.txt> for more information.
-
-  If you say Y here, the AppleTalk-IP support will be compiled into
-  the kernel. In this case, you can either use encapsulation or
-  decapsulation, but not both. With the following two questions, you
-  decide which one you want.
-
-  If you say M here, the AppleTalk-IP support will be compiled as a
-  module ( = code which can be inserted in and removed from the
-  running kernel whenever you want, read
-  <file:Documentation/modules.txt>).  The module is called ipddp.o.
-  In this case, you will be able to use both encapsulation and
-  decapsulation simultaneously, by loading two copies of the module
-  and specifying different values for the module option ipddp_mode.
-
-IP to AppleTalk-IP Encapsulation support
-CONFIG_IPDDP_ENCAP
-  If you say Y here, the AppleTalk-IP code will be able to encapsulate
-  IP packets inside AppleTalk frames; this is useful if your Linux box
-  is stuck on an AppleTalk network (which hopefully contains a
-  decapsulator somewhere). Please see
-  <file:Documentation/networking/ipddp.txt> for more information. If
-  you said Y to "AppleTalk-IP driver support" above and you say Y
-  here, then you cannot say Y to "AppleTalk-IP to IP Decapsulation
-  support", below.
-
-AppleTalk-IP to IP Decapsulation support
-CONFIG_IPDDP_DECAP
-  If you say Y here, the AppleTalk-IP code will be able to decapsulate
-  AppleTalk-IP frames to IP packets; this is useful if you want your
-  Linux box to act as an Internet gateway for an AppleTalk network.
-  Please see <file:Documentation/networking/ipddp.txt> for more
-  information.  If you said Y to "AppleTalk-IP driver support" above
-  and you say Y here, then you cannot say Y to "IP to AppleTalk-IP
-  Encapsulation support", above.
-
-Apple/Farallon LocalTalk PC card support
-CONFIG_LTPC
-  This allows you to use the AppleTalk PC card to connect to LocalTalk
-  networks. The card is also known as the Farallon PhoneNet PC card.
-  If you are in doubt, this card is the one with the 65C02 chip on it.
-  You also need version 1.3.3 or later of the netatalk package.
-  This driver is experimental, which means that it may not work.
-  See the file <file:Documentation/networking/ltpc.txt>.
-
-COPS LocalTalk PC card support
-CONFIG_COPS
-  This allows you to use COPS AppleTalk cards to connect to LocalTalk
-  networks. You also need version 1.3.3 or later of the netatalk
-  package. This driver is experimental, which means that it may not
-  work. This driver will only work if you choose "AppleTalk DDP"
-  networking support, above.
-  Please read the file <file:Documentation/networking/cops.txt>.
-
-Dayna firmware support
-CONFIG_COPS_DAYNA
-  Support COPS compatible cards with Dayna style firmware (Dayna
-  DL2000/ Daynatalk/PC (half length), COPS LT-95, Farallon PhoneNET PC
-  III, Farallon PhoneNET PC II).
-
-Tangent firmware support
-CONFIG_COPS_TANGENT
-  Support COPS compatible cards with Tangent style firmware (Tangent
-  ATB_II, Novell NL-1000, Daystar Digital LT-200.
-
-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 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
-  the questions about amateur radio.
-
-Amateur Radio AX.25 Level 2 protocol
-CONFIG_AX25
-  This is the protocol used for computer communication over amateur
-  radio. It is either used by itself for point-to-point links, or to
-  carry other protocols such as tcp/ip. To use it, you need a device
-  that connects your Linux box to your amateur radio. You can either
-  use a low speed TNC (a Terminal Node Controller acts as a kind of
-  modem connecting your computer's serial port to your radio's
-  microphone input and speaker output) supporting the KISS protocol or
-  one of the various SCC cards that are supported by the generic Z8530
-  or the DMA SCC driver. Another option are the Baycom modem serial
-  and parallel port hacks or the sound card modem (supported by their
-  own drivers). If you say Y here, you also have to say Y to one of
-  those drivers.
-
-  Information about where to get supporting software for Linux amateur
-  radio as well as information about how to configure an AX.25 port is
-  contained in the AX25-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. You might also want to
-  check out the file <file:Documentation/networking/ax25.txt> in the
-  kernel source. More information about digital amateur radio in
-  general is on the WWW at
-  <http://www.tapr.org/tapr/html/pkthome.html>.
-
-  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 ax25.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-AX.25 DAMA Slave support
-CONFIG_AX25_DAMA_SLAVE
-  DAMA is a mechanism to prevent collisions when doing AX.25
-  networking. A DAMA server (called "master") accepts incoming traffic
-  from clients (called "slaves") and redistributes it to other slaves.
-  If you say Y here, your Linux box will act as a DAMA slave; this is
-  transparent in that you don't have to do any special DAMA
-  configuration. (Linux cannot yet act as a DAMA server.) If unsure,
-  say N.
-
-AX.25 DAMA Master support
-CONFIG_AX25_DAMA_MASTER
-  DAMA is a mechanism to prevent collisions when doing AX.25
-  networking. A DAMA server (called "master") accepts incoming traffic
-  from clients (called "slaves") and redistributes it to other
-  slaves. If you say Y here, your Linux box will act as a DAMA server.
-  If unsure, say N.
-
-Amateur Radio NET/ROM support
-CONFIG_NETROM
-  NET/ROM is a network layer protocol on top of AX.25 useful for
-  routing.
-
-  A comprehensive listing of all the software for Linux amateur radio
-  users as well as information about how to configure an AX.25 port is
-  contained in the AX25-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. You also might want to
-  check out the file <file:Documentation/networking/ax25.txt>. More
-  information about digital amateur radio in general is on the WWW at
-  <http://www.tapr.org/tapr/html/pkthome.html>.
-
-  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 netrom.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Amateur Radio X.25 PLP (Rose)
-CONFIG_ROSE
-  The Packet Layer Protocol (PLP) is a way to route packets over X.25
-  connections in general and amateur radio AX.25 connections in
-  particular, essentially an alternative to NET/ROM.
-
-  A comprehensive listing of all the software for Linux amateur radio
-  users as well as information about how to configure an AX.25 port is
-  contained in the AX25-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  You also might want to
-  check out the file <file:Documentation/networking/ax25.txt>. More
-  information about digital amateur radio in general is on the WWW at
-  <http://www.tapr.org/tapr/html/pkthome.html>.
-
-  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 rose.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Serial port KISS driver for AX.25
-CONFIG_MKISS
-  KISS is a protocol used for the exchange of data between a computer
-  and a Terminal Node Controller (a small embedded system commonly
-  used for networking over AX.25 amateur radio connections; it
-  connects the computer's serial port with the radio's microphone
-  input and speaker output).
-
-  Although KISS is less advanced than the 6pack protocol, it has
-  the advantage that it is already supported by most modern TNCs
-  without the need for a firmware upgrade.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called mkiss.o.
-
-Serial port 6PACK driver for AX.25
-CONFIG_6PACK
-  6pack is a transmission protocol for the data exchange between your
-  PC and your TNC (the Terminal Node Controller acts as a kind of
-  modem connecting your computer's serial port to your radio's
-  microphone input and speaker output). This protocol can be used as
-  an alternative to KISS for networking over AX.25 amateur radio
-  connections, but it has some extended functionality.
-
-  Note that this driver is still experimental and might cause
-  problems. For details about the features and the usage of the
-  driver, read <file:Documentation/networking/6pack.txt>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called 6pack.o.
-
-BPQ Ethernet driver
-CONFIG_BPQETHER
-  AX.25 is the protocol used for computer communication over amateur
-  radio. If you say Y here, you will be able to send and receive AX.25
-  traffic over Ethernet (also called "BPQ AX.25"), which could be
-  useful if some other computer on your local network has a direct
-  amateur radio connection.
-
-High-speed (DMA) SCC driver for AX.25
-CONFIG_DMASCC
-  This is a driver for high-speed SCC boards, i.e. those supporting
-  DMA on one port. You usually use those boards to connect your
-  computer to an amateur radio modem (such as the WA4DSY 56kbps
-  modem), in order to send and receive AX.25 packet radio network
-  traffic.
-
-  Currently, this driver supports Ottawa PI/PI2, Paccomm/Gracilis
-  PackeTwin, and S5SCC/DMA boards. They are detected automatically.
-  If you have one of these cards, say Y here and read the AX25-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver can operate multiple boards simultaneously. If you
-  compile it as a module (by saying M instead of Y), it will be called
-  dmascc.o. If you don't pass any parameter to the driver, all
-  possible I/O addresses are probed. This could irritate other devices
-  that are currently not in use. You may specify the list of addresses
-  to be probed by "dmascc=addr1,addr2,..." (when compiled into the
-  kernel image) or "io=addr1,addr2,..." (when loaded as a module). The
-  network interfaces will be called dmascc0 and dmascc1 for the board
-  detected first, dmascc2 and dmascc3 for the second one, and so on.
-
-  Before you configure each interface with ifconfig, you MUST set
-  certain parameters, such as channel access timing, clock mode, and
-  DMA channel. This is accomplished with a small utility program,
-  dmascc_cfg, available at
-  <http://www.nt.tuwien.ac.at/~kkudielk/Linux/>. Please be sure to get
-  at least version 1.27 of dmascc_cfg, as older versions will not
-  work with the current driver.
-
-Z8530 SCC driver for AX.25
-CONFIG_SCC
-  These cards are used to connect your Linux box to an amateur radio
-  in order to communicate with other computers. If you want to use
-  this, read <file:Documentation/networking/z8530drv.txt> and the
-  AX25-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. Also make sure to say Y
-  to "Amateur Radio AX.25 Level 2" support.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called scc.o.
-
-Support for TRX that feedback the tx signal to rx
-CONFIG_SCC_TRXECHO
-  Some transmitters feed the transmitted signal back to the receive
-  line.  Say Y here to foil this by explicitly disabling the receiver
-  during data transmission.  If in doubt, say Y.
-
-Additional delay for PA0HZP OptoSCC compatible boards
-CONFIG_SCC_DELAY
-  Say Y here if you experience problems with the SCC driver not
-  working properly; please read
-  <file:Documentation/networking/z8530drv.txt> for details. If unsure,
-  say N.
-
-YAM driver for AX.25
-CONFIG_YAM
-  The YAM is a modem for packet radio which connects to the serial
-  port and includes some of the functions of a Terminal Node
-  Controller. If you have one of those, say Y here.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.
-
-BAYCOM picpar and par96 driver for AX.25
-CONFIG_BAYCOM_PAR
-  This is a driver for Baycom style simple amateur radio modems that
-  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
-  <file:Documentation/networking/baycom.txt>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called baycom_par.o.
-
-BAYCOM EPP driver for AX.25
-CONFIG_BAYCOM_EPP
-  This is a driver for Baycom style simple amateur radio modems that
-  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
-  <file:Documentation/networking/baycom.txt>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called baycom_par.o.
-
-BAYCOM ser12 full-duplex driver for AX.25
-CONFIG_BAYCOM_SER_FDX
-  This is one of two drivers for Baycom style simple amateur radio
-  modems that connect to a serial interface. The driver supports the
-  ser12 design in full-duplex mode. In addition, it allows the
-  baudrate to be set between 300 and 4800 baud (however not all modems
-  support all baudrates). This is the preferred driver. The next
-  driver, "BAYCOM ser12 half-duplex driver for AX.25" is the old
-  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
-  <file:Documentation/networking/baycom.txt>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called baycom_ser_fdx.o.
-
-BAYCOM ser12 half-duplex driver for AX.25
-CONFIG_BAYCOM_SER_HDX
-  This is one of two drivers for Baycom style simple amateur radio
-  modems that connect to a serial interface. The driver supports the
-  ser12 design in full-duplex mode. This is the old driver.  It is
-  still provided in case your serial interface chip does not work with
-  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
-  <file:Documentation/networking/baycom.txt>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called baycom_ser_hdx.o.
-
-Sound card modem driver for AX.25
-CONFIG_SOUNDMODEM
-  This experimental driver allows a standard Sound Blaster or
-  WindowsSoundSystem compatible sound card to be used as a packet
-  radio modem (NOT as a telephone modem!), to send digital traffic
-  over amateur radio.
-
-  To configure the driver, use the sethdlc, smdiag and smmixer
-  utilities available in the standard ax25 utilities package. For
-  information on how to key the transmitter, see
-  <http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html> and
-  <file:Documentation/networking/soundmodem.txt>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called soundmodem.o.
-
-Sound card modem support for Sound Blaster and compatible cards
-CONFIG_SOUNDMODEM_SBC
-  This option enables the soundmodem driver to use Sound Blaster and
-  compatible cards. If you have a dual mode card (i.e. a WSS cards
-  with a Sound Blaster emulation) you should say N here and Y to
-  "Sound card modem support for WSS and Crystal cards", below, because
-  this usually results in better performance. This option also
-  supports SB16/32/64 in full-duplex mode.
-
-Sound card modem support for WSS and Crystal cards
-CONFIG_SOUNDMODEM_WSS
-  This option enables the soundmodem driver to use WindowsSoundSystem
-  compatible cards. These cards feature a codec chip from either
-  Analog Devices (such as AD1848, AD1845, AD1812) or Crystal
-  Semiconductors (such as CS4248, CS423x). This option also supports
-  the WSS full-duplex operation which currently works with Crystal
-  CS423x chips. If you don't need full-duplex operation, do not enable
-  it to save performance.
-
-Sound card modem support for 1200 baud AFSK modulation
-CONFIG_SOUNDMODEM_AFSK1200
-  This option enables the soundmodem driver 1200 baud AFSK modem,
-  compatible to popular modems using TCM3105 or AM7911. The
-  demodulator requires about 12% of the CPU power of a Pentium 75 CPU
-  per channel.
-
-Sound card modem support for 2400 baud AFSK modulation (7.3728MHz crystal)
-CONFIG_SOUNDMODEM_AFSK2400_7
-  This option enables the soundmodem driver 2400 baud AFSK modem,
-  compatible to TCM3105 modems (over-)clocked with a 7.3728MHz
-  crystal. Note that the availability of this driver does _not_ imply
-  that I recommend building such links. It is only here since users
-  especially in eastern Europe have asked me to do so. In fact this
-  modulation scheme has many disadvantages, mainly its incompatibility
-  with many transceiver designs and the fact that the TCM3105 (if
-  used) is operated widely outside its specifications.
-
-Sound card modem support for 2400 baud AFSK modulation (8MHz crystal)
-CONFIG_SOUNDMODEM_AFSK2400_8
-  This option enables the soundmodem driver 2400 baud AFSK modem,
-  compatible to TCM3105 modems (over-)clocked with an 8MHz crystal.
-  Note that the availability of this driver does _not_ imply that I
-  recommend building such links. It is only here since users
-  especially in eastern Europe have asked me to do so. In fact this
-  modulation scheme has many disadvantages, mainly its incompatibility
-  with many transceiver designs and the fact that the TCM3105 (if
-  used) is operated widely outside its specifications.
-
-Sound card modem support for 2666 baud AFSK modulation
-CONFIG_SOUNDMODEM_AFSK2666
-  This option enables the soundmodem driver 2666 baud AFSK modem.
-  This modem is experimental, and not compatible to anything
-  else I know of.
-
-Sound card modem support for 4800 baud 8PSK modulation
-CONFIG_SOUNDMODEM_PSK4800
-  This option enables the soundmodem driver 4800 baud 8PSK modem.
-  This modem is experimental, and not compatible to anything
-  else I know of.
-
-Sound card modem support for 4800 baud HAPN-1 modulation
-CONFIG_SOUNDMODEM_HAPN4800
-  This option enables the soundmodem driver 4800 baud HAPN-1
-  compatible modem. This modulation seems to be widely used 'down
-  under' and in the Netherlands. Here, nobody uses it, so I could not
-  test if it works. It is compatible to itself, however :-)
-
-Sound card modem support for 9600 baud FSK G3RUH modulation
-CONFIG_SOUNDMODEM_FSK9600
-  This option enables the soundmodem driver 9600 baud FSK modem,
-  compatible to the G3RUH standard. The demodulator requires about 4%
-  of the CPU power of a Pentium 75 CPU per channel. You can say Y to
-  both 1200 baud AFSK and 9600 baud FSK if you want (but obviously you
-  can only use one protocol at a time, depending on what the other end
-  can understand).
-
-CCITT X.25 Packet Layer
-CONFIG_X25
-  X.25 is a set of standardized network protocols, similar in scope to
-  frame relay; the one physical line from your box to the X.25 network
-  entry point can carry several logical point-to-point connections
-  (called "virtual circuits") to other computers connected to the X.25
-  network. Governments, banks, and other organizations tend to use it
-  to connect to each other or to form Wide Area Networks (WANs). Many
-  countries have public X.25 networks. X.25 consists of two
-  protocols: the higher level Packet Layer Protocol (PLP) (say Y here
-  if you want that) and the lower level data link layer protocol LAPB
-  (say Y to "LAPB Data Link Driver" below if you want that).
-
-  You can read more about X.25 at <http://www.sangoma.com/x25.htm> and
-  <http://www.cisco.com/univercd/data/doc/software/11_0/rpcg/cx25.htm>.
-  Information about X.25 for Linux is contained in the files
-  <file:Documentation/networking/x25.txt> and
-  <file:Documentation/networking/x25-iface.txt>.
-
-  One connects to an X.25 network either with a dedicated network card
-  using the X.21 protocol (not yet supported by Linux) or one can do
-  X.25 over a standard telephone line using an ordinary modem (say Y
-  to "X.25 async driver" below) or over Ethernet using an ordinary
-  Ethernet card and either the 802.2 LLC protocol (say Y to "802.2
-  LLC" below) or LAPB over Ethernet (say Y to "LAPB Data Link Driver"
-  and "LAPB over Ethernet driver" below).
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called x25.o. If unsure, say N.
-
-LAPB Data Link Driver
-CONFIG_LAPB
-  Link Access Procedure, Balanced (LAPB) is the data link layer (i.e.
-  the lower) part of the X.25 protocol. It offers a reliable
-  connection service to exchange data frames with one other host, and
-  it is used to transport higher level protocols (mostly X.25 Packet
-  Layer, the higher part of X.25, but others are possible as well).
-  Usually, LAPB is used with specialized X.21 network cards, but Linux
-  currently supports LAPB only over Ethernet connections. If you want
-  to use LAPB connections over Ethernet, say Y here and to "LAPB over
-  Ethernet driver" below. Read
-  <file:Documentation/networking/lapb-module.txt> for technical
-  details.
-
-  If you want to compile this driver as a module though ( = 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 lapb.o.  If unsure, say N.
-
-802.2 LLC
-CONFIG_LLC
-  This is a Logical Link Layer protocol used for X.25 connections over
-  Ethernet, using ordinary Ethernet cards.
-
-Frame Diverter
-CONFIG_NET_DIVERT
-  The Frame Diverter allows you to divert packets from the
-  network, that are not aimed at the interface receiving it (in
-  promisc. mode). Typically, a Linux box setup as an Ethernet bridge
-  with the Frames Diverter on, can do some *really* transparent www
-  caching using a Squid proxy for example.
-
-  This is very useful when you don't want to change your router's
-  config (or if you simply don't have access to it).
-
-  The other possible usages of diverting Ethernet Frames are
-  numberous:
-   - reroute smtp traffic to another interface
-   - traffic-shape certain network streams
-   - transparently proxy smtp connections
-   - etc...
-
-  For more informations, please refer to:
-    <http://diverter.sourceforge.net/>
-    <http://perso.wanadoo.fr/magpie/EtherDivert.html>
-
-  If unsure, say N.
-
-802.1d Ethernet Bridging
-CONFIG_BRIDGE
-  If you say Y here, then your Linux box will be able to act as an
-  Ethernet bridge, which means that the different Ethernet segments it
-  is connected to will appear as one Ethernet to the participants.
-  Several such bridges can work together to create even larger
-  networks of Ethernets using the IEEE 802.1 spanning tree algorithm.
-  As this is a standard, Linux bridges will cooperate properly with
-  other third party bridge products.
-
-  In order to use the Ethernet bridge, you'll need the bridge
-  configuration tools; see <file:Documentation/networking/bridge.txt>
-  for location. Please read the Bridge mini-HOWTO for more
-  information.
-
-  Note that if your box acts as a bridge, it probably contains several
-  Ethernet devices, but the kernel is not able to recognize more than
-  one at boot time without help; for details read the Ethernet-HOWTO,
-  available from in <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this code 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 bridge.o.
-
-  If unsure, say N.
-
-Packet socket
-CONFIG_PACKET
-  The Packet protocol is used by applications which communicate
-  directly with network devices without an intermediate network
-  protocol implemented in the kernel, e.g. tcpdump.  If you want them
-  to work, choose Y.
-
-  This driver is also available as a module called af_packet.o ( =
-  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>; if you use modprobe
-  or kmod, you may also want to add "alias net-pf-17 af_packet" to
-  /etc/modules.conf.
-
-  If unsure, say Y.
-
-Packet socket: mmapped IO
-CONFIG_PACKET_MMAP
-  If you say Y here, the Packet protocol driver will use an IO
-  mechanism that results in faster communication.
-
-  If unsure, say N.
-
-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).
-
-  So far, the kernel uses this feature to publish some network related
-  information if you say Y to "Routing messages", below. You also need
-  to say Y here if you want to use arpd, a daemon that helps keep the
-  internal ARP cache (a mapping between IP addresses and hardware
-  addresses on the local network) small.  The ethertap device, which
-  lets user space programs read and write raw Ethernet frames, also
-  needs the network link driver.
-
-  If unsure, say Y.
-
-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
-  interpret this data.  Information sent to the kernel over this link
-  is ignored.
-
-Netlink device emulation
-CONFIG_NETLINK_DEV
-  This option will be removed soon. Any programs that want to use
-  character special nodes like /dev/tap0 or /dev/route (all with major
-  number 36) need this option, and need to be rewritten soon to use
-  the real netlink socket.
-  This is a backward compatibility option, choose Y for now.
-
-Asynchronous Transfer Mode (ATM)
-CONFIG_ATM
-  ATM is a high-speed networking technology for Local Area Networks
-  and Wide Area Networks.  It uses a fixed packet size and is
-  connection oriented, allowing for the negotiation of minimum
-  bandwidth requirements.
-
-  In order to participate in an ATM network, your Linux box needs an
-  ATM networking card. If you have that, say Y here and to the driver
-  of your ATM card below.
-
-  Note that you need a set of user-space programs to actually make use
-  of ATM.  See the file <file:Documentation/networking/atm.txt> for
-  further details.
-
-Classical IP over ATM
-CONFIG_ATM_CLIP
-  Classical IP over ATM for PVCs and SVCs, supporting InARP and
-  ATMARP. If you want to communication with other IP hosts on your ATM
-  network, you will typically either say Y here or to "LAN Emulation
-  (LANE)" below.
-
-Do NOT send ICMP if no neighbour
-CONFIG_ATM_CLIP_NO_ICMP
-  Normally, an "ICMP host unreachable" message is sent if a neighbour
-  cannot be reached because there is no VC to it in the kernel's
-  ATMARP table. This may cause problems when ATMARP table entries are
-  briefly removed during revalidation. If you say Y here, packets to
-  such neighbours are silently discarded instead.
-
-LAN Emulation (LANE) support
-CONFIG_ATM_LANE
-  LAN Emulation emulates services of existing LANs across an ATM
-  network. Besides operating as a normal ATM end station client, Linux
-  LANE client can also act as an proxy client bridging packets between
-  ELAN and Ethernet segments. You need LANE if you want to try MPOA.
-
-Multi-Protocol Over ATM (MPOA) support
-CONFIG_ATM_MPOA
-  Multi-Protocol Over ATM allows ATM edge devices such as routers,
-  bridges and ATM attached hosts establish direct ATM VCs across
-  subnetwork boundaries. These shortcut connections bypass routers
-  enhancing overall network performance.
-
-ATM over TCP
-CONFIG_ATM_TCP
-  ATM over TCP driver. Useful mainly for development and for
-  experiments. If unsure, say N.
-
-Efficient Networks ENI155P
-CONFIG_ATM_ENI
-  Driver for the Efficient Networks ENI155p series and SMC ATM
-  Power155 155 Mbps ATM adapters. Both, the versions with 512KB and
-  2MB on-board RAM (Efficient calls them "C" and "S", respectively),
-  and the FPGA and the ASIC Tonga versions of the board are supported.
-  The driver works with MMF (-MF or ...F) and UTP-5 (-U5 or ...D)
-  adapters.
-
-  This driver is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called eni.o.
-
-Enable extended debugging
-CONFIG_ATM_ENI_DEBUG
-  Extended debugging records various events and displays that list
-  when an inconsistency is detected. This mechanism is faster than
-  generally using printks, but still has some impact on performance.
-  Note that extended debugging may create certain race conditions
-  itself. Enable this ONLY if you suspect problems with the driver.
-
-Fine-tune burst settings
-CONFIG_ATM_ENI_TUNE_BURST
-  In order to obtain good throughput, the ENI NIC can transfer
-  multiple words of data per PCI bus access cycle. Such a multi-word
-  transfer is called a burst.
-
-  The default settings for the burst sizes are suitable for most PCI
-  chipsets. However, in some cases, large bursts may overrun buffers
-  in the PCI chipset and cause data corruption. In such cases, large
-  bursts must be disabled and only (slower) small bursts can be used.
-  The burst sizes can be set independently in the send (TX) and
-  receive (RX) direction.
-
-  Note that enabling many different burst sizes in the same direction
-  may increase the cost of setting up a transfer such that the
-  resulting throughput is lower than when using only the largest
-  available burst size.
-
-  Also, sometimes larger bursts lead to lower throughput, e.g. on an
-  Intel 440FX board, a drop from 135 Mbps to 103 Mbps was observed
-  when going from 8W to 16W bursts.
-
-Enable 16W TX bursts (discouraged)
-CONFIG_ATM_ENI_BURST_TX_16W
-  Burst sixteen words at once in the send direction. This may work
-  with recent PCI chipsets, but is known to fail with older chipsets.
-
-Enable 8W TX bursts (recommended)
-CONFIG_ATM_ENI_BURST_TX_8W
-  Burst eight words at once in the send direction. This is the default
-  setting.
-
-Enable 4W TX bursts (optional)
-CONFIG_ATM_ENI_BURST_TX_4W
-  Burst four words at once in the send direction. You may want to try
-  this if you have disabled 8W bursts. Enabling 4W if 8W is also set
-  may or may not improve throughput.
-
-Enable 2W TX bursts (optional)
-CONFIG_ATM_ENI_BURST_TX_2W
-  Burst two words at once in the send direction. You may want to try
-  this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or 8W
-  are also set may or may not improve throughput.
-
-Enable 16W RX bursts (discouraged)
-CONFIG_ATM_ENI_BURST_RX_16W
-  Burst sixteen words at once in the receive direction. This may work
-  with recent PCI chipsets, but is known to fail with older chipsets.
-
-Enable 8W RX bursts (discouraged)
-CONFIG_ATM_ENI_BURST_RX_8W
-  Burst eight words at once in the receive direction. This may work
-  with recent PCI chipsets, but is known to fail with older chipsets,
-  such as the Intel Neptune series.
-
-Enable 4W RX bursts (recommended)
-CONFIG_ATM_ENI_BURST_RX_4W
-  Burst four words at once in the receive direction. This is the
-  default setting. Enabling 4W if 8W is also set may or may not
-  improve throughput.
-
-Enable 2W RX bursts (optional)
-CONFIG_ATM_ENI_BURST_RX_2W
-  Burst two words at once in the receive direction. You may want to
-  try this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or
-  8W are also set may or may not improve throughput.
-
-ZeitNet ZN1221/ZN1225
-CONFIG_ATM_ZATM
-  Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM
-  adapters.
-
-  This driver is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called zatm.o.
-
-Enable extended debugging
-CONFIG_ATM_ZATM_DEBUG
-  Extended debugging records various events and displays that list
-  when an inconsistency is detected. This mechanism is faster than
-  generally using printks, but still has some impact on performance.
-  Note that extended debugging may create certain race conditions
-  itself. Enable this ONLY if you suspect problems with the driver.
-
-Fujitsu FireStream (FS50/FS155)
-CONFIG_ATM_FIRESTREAM
-  Driver for the Fujitsu FireStream 155 (MB86697) and
-  FireStream 50 (MB86695) ATM PCI chips.
-
-  This driver is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called
-  firestream.o.
-
-Enable usec resolution timestamps
-CONFIG_ATM_ZATM_EXACT_TS
-  The uPD98401 SAR chip supports a high-resolution timer (approx. 30
-  MHz) that is used for very accurate reception timestamps. Because
-  that timer overflows after 140 seconds, and also to avoid timer
-  drift, time measurements need to be periodically synchronized with
-  the normal system time. Enabling this feature will add some general
-  overhead for timer synchronization and also per-packet overhead for
-  time conversion.
-
-IDT 77201/11 (NICStAR) (ForeRunnerLE)
-CONFIG_ATM_NICSTAR
-  The NICStAR chipset family is used in a large number of ATM NICs for
-  25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
-  series. Say Y if you have one of those.
-
-  This driver is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>. The module will be called
-  nicstar.o.
-
-Use suni PHY driver (155Mbps)
-CONFIG_ATM_NICSTAR_USE_SUNI
-  Support for the S-UNI and compatible PHYsical layer chips. These are
-  found in most 155Mbps NICStAR based ATM cards, namely in the
-  ForeRunner LE155 cards. This driver provides detection of cable~
-  removal and reinsertion and provides some statistics. This driver
-  doesn't have removal capability when compiled as a module, so if you
-  need that capability don't include S-UNI support (it's not needed to
-  make the card work).
-
-Use IDT77015 PHY driver (25Mbps)
-CONFIG_ATM_NICSTAR_USE_IDT77105
-  Support for the PHYsical layer chip in ForeRunner LE25 cards. In
-  addition to cable removal/reinsertion detection, this driver allows
-  you to control the loopback mode of the chip via a dedicated IOCTL.
-  This driver is required for proper handling of temporary carrier
-  loss, so if you have a 25Mbps NICStAR based ATM card you must say Y.
-
-IDT 77252 (NICStAR II)
-CONFIG_ATM_IDT77252
-  Driver for the IDT 77252 ATM PCI chips.
-
-  This driver is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>. The module will be called idt77252.o
-
-Enable debugging messages
-CONFIG_ATM_IDT77252_DEBUG
-  Somewhat useful debugging messages are available. The choice of
-  messages is controlled by a bitmap.  This may be specified as a
-  module argument.  See the file <file:drivers/atm/idt77252.h> for
-  the meanings of the bits in the mask.
-
-  When active, these messages can have a significant impact on the
-  speed of the driver, and the size of your syslog files! When
-  inactive, they will have only a modest impact on performance.
-
-Receive ALL cells in raw queue
-CONFIG_ATM_IDT77252_RCV_ALL
-  Enable receiving of all cells on the ATM link, that do not match
-  an open connection in the raw cell queue of the driver.  Useful
-  for debugging or special applications only, so the safe answer is N.
-
-Madge Ambassador (Collage PCI 155 Server)
-CONFIG_ATM_AMBASSADOR
-  This is a driver for ATMizer based ATM card produced by Madge
-  Networks Ltd. Say Y (or M to compile as a module named ambassador.o)
-  here if you have one of these cards.
-
-Enable debugging messages
-CONFIG_ATM_AMBASSADOR_DEBUG
-  Somewhat useful debugging messages are available. The choice of
-  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 (not yet) or changed by sending the
-  string "Dxxxx" to VCI 1023 (where x is a hex digit).  See the file
-  <file:drivers/atm/ambassador.h> for the meanings of the bits in the
-  mask.
-
-  When active, these messages can have a significant impact on the
-  speed of the driver, and the size of your syslog files! When
-  inactive, they will have only a modest impact on performance.
-
-Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)
-CONFIG_ATM_HORIZON
-  This is a driver for the Horizon chipset ATM adapter cards once
-  produced by Madge Networks Ltd. Say Y (or M to compile as a module
-  named horizon.o) here if you have one of these cards.
-
-Enable debugging messages
-CONFIG_ATM_HORIZON_DEBUG
-  Somewhat useful debugging messages are available. The choice of
-  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 (not yet) or changed by sending the
-  string "Dxxxx" to VCI 1023 (where x is a hex digit).  See the file
-  <file:drivers/atm/horizon.h> for the meanings of the bits in the
-  mask.
-
-  When active, these messages can have a significant impact on the
-  speed of the driver, and the size of your syslog files! When
-  inactive, they will have only a modest impact on performance.
-
-Interphase ATM PCI x575/x525/x531
-CONFIG_ATM_IA
-  This is a driver for the Interphase (i)ChipSAR adapter cards
-  which include a variety of variants in term of the size of the
-  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:
-  	<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.
-
-  See the file <file:Documentation/networking/iphase.txt> for further
-  details.
-
-Enable debugging messages
-CONFIG_ATM_IA_DEBUG
-  Somewhat useful debugging messages are available. The choice of
-  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/>).
-
-  See the file <file:drivers/atm/iphase.h> for the meanings of the
-  bits in the mask.
-
-  When active, these messages can have a significant impact on the
-  speed of the driver, and the size of your syslog files! When
-  inactive, they will have only a modest impact on performance.
-
-Linux telephony support
-CONFIG_PHONE
-  Say Y here if you have a telephony card, which for example allows
-  you to use a regular phone for voice-over-IP applications.
-
-  Note: this has nothing to do with modems.  You do not need to say Y
-  here in order to be able to use a modem under Linux.
-
-  This support is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called
-  phonedev.o.
-
-Compaq Smart Array support
-CONFIG_BLK_CPQ_CISS_DA
-  This is the driver for Compaq Smart Array 5xxx controllers.
-  Everyone using these boards should say Y here.
-  See <file:Documentation/cciss.txt> for the current list of
-  boards supported by this driver, and for further information
-  on the use of this driver.
-
-SCSI tape drive support for Smart Array 5xxx
-CONFIG_CISS_SCSI_TAPE
-  When enabled (Y), this option allows SCSI tape drives and SCSI medium
-  changers (tape robots) to be accessed via a Compaq 5xxx array 
-  controller.  (See Documentation/cciss.txt for more details.)
-
-  "SCSI support" and "SCSI tape support" must also be enabled for this 
-  option to work.
-
-  When this option is disabled (N), the SCSI portion of the driver 
-  is not compiled.
-
-QuickNet Internet LineJack/PhoneJack support
-CONFIG_PHONE_IXJ
-  Say M if you have a telephony card manufactured by Quicknet
-  Technologies, Inc.  These include the Internet PhoneJACK and
-  Internet LineJACK Telephony Cards. You will get a module called
-  ixj.o.
-
-  For the ISA versions of these products, you can configure the
-  cards using the isapnp tools (pnpdump/isapnp) or you can use the
-  isapnp support.  Please read <file:Documentation/telephony/ixj.txt>.
-
-  For more information on these cards, see Quicknet's web site at:
-  <http://www.quicknet.net/>.
-
-  If you do not have any Quicknet telephony cards, you can safely
-  say N here.
-
-FORE Systems 200E-series
-CONFIG_ATM_FORE200E_MAYBE
-  This is a driver for the FORE Systems 200E-series ATM adapter
-  cards. It simultaneously supports PCA-200E and SBA-200E models
-  on PCI and SBUS hosts. Say Y (or M to compile as a module
-  named fore_200e.o) here if you have one of these ATM adapters.
-
-  Note that the driver will actually be compiled only if you
-  additionally enable the support for PCA-200E and/or SBA-200E
-  cards.
-
-  See the file <file:Documentation/networking/fore200e.txt> for
-  further details.
-
-Enable PCA-200E card support on PCI-based hosts
-CONFIG_ATM_FORE200E_PCA
-  Say Y here if you want your PCA-200E cards to be probed.
-
-Use default PCA-200E firmware
-CONFIG_ATM_FORE200E_PCA_DEFAULT_FW
-  Use the default PCA-200E firmware data shipped with the driver.
-
-  Normal users do not have to deal with the firmware stuff, so
-  they should say Y here.
-
-Pathname of user-supplied binary firmware
-CONFIG_ATM_FORE200E_PCA_FW
-  This defines the pathname of an alternative PCA-200E binary
-  firmware image supplied by the user. This pathname may be
-  absolute or relative to the drivers/atm directory.
-
-  The driver comes with an adequate firmware image, so normal users do
-  not have to supply an alternative one. They just say Y to "Use
-  default PCA-200E firmware" instead.
-
-Enable SBA-200E card support on SBUS-based hosts
-CONFIG_ATM_FORE200E_SBA
-  Say Y here if you want your SBA-200E cards to be probed.
-
-Use default SBA-200E firmware
-CONFIG_ATM_FORE200E_SBA_DEFAULT_FW
-  Use the default SBA-200E firmware data shipped with the driver.
-
-  Normal users do not have to deal with the firmware stuff, so
-  they should say Y here.
-
-Pathname of user-supplied binary firmware
-CONFIG_ATM_FORE200E_SBA_FW
-  This defines the pathname of an alternative SBA-200E binary
-  firmware image supplied by the user. This pathname may be
-  absolute or relative to the drivers/atm directory.
-
-  The driver comes with an adequate firmware image, so normal users do
-  not have to supply an alternative one. They just say Y to "Use
-  default SBA-200E firmware", above.
-
-Maximum number of tx retries
-CONFIG_ATM_FORE200E_TX_RETRY
-  Specifies the number of times the driver attempts to transmit
-  a message before giving up, if the transmit queue of the ATM card
-  is transiently saturated.
-
-  Saturation of the transmit queue may occur only under extreme
-  conditions, e.g. when a fast host continuously submits very small
-  frames (<64 bytes) or raw AAL0 cells (48 bytes) to the ATM adapter.
-
-  Note that under common conditions, it is unlikely that you encounter
-  a saturation of the transmit queue, so the retry mechanism never
-  comes into play.
-
-Debugging level (0-3)
-CONFIG_ATM_FORE200E_DEBUG
-  Specifies the level of debugging messages issued by the driver.
-  The verbosity of the driver increases with the value of this
-  parameter.
-
-  When active, these messages can have a significant impact on
-  the performances of the driver, and the size of your syslog files!
-  Keep the debugging level to 0 during normal operations.
-
-Fusion MPT device support
-CONFIG_FUSION
-  LSI Logic Fusion(TM) Message Passing Technology (MPT) device support
-  provides high performance SCSI host initiator, and LAN [1] interface
-  services to a host system.  The Fusion architecture is capable of
-  duplexing these protocols on high-speed Fibre Channel
-  (up to 2 GHz x 2 ports = 4 GHz) and parallel SCSI (up to Ultra-320)
-  physical medium.
-
-          [1] LAN is not supported on parallel SCSI medium.
-
-  These drivers require a Fusion MPT compatible PCI adapter installed
-  in the host system.  MPT adapters contain specialized I/O processors
-  to handle I/O workload, and more importantly to offload this work
-  from the host CPU(s).
-
-  If you have Fusion MPT hardware and want to use it, you can say
-  Y or M here to add MPT (base + ScsiHost) drivers.
-    <Y> = build lib (fusion.o), and link [static] into the kernel [2]
-          proper
-    <M> = compiled as [dynamic] modules [3] named: (mptbase.o,
-          mptscsih.o)
-
-          [2] In order enable capability to boot the linux kernel
-              natively from a Fusion MPT target device, you MUST
-               answer Y here! (currently requires CONFIG_BLK_DEV_SD)
-          [3] This support is also available as a module ( = code
-              which can be inserted in and removed from the running
-              kernel whenever you want).  If you want to compile as
-              modules, say M here and read
-              <file:Documentation/modules.txt>.
-
-  If unsure, say N.
-
-  If you say Y or M here you will get a choice of these
-  additional protocol and support module options:         Module Name:
-    <M>   Enhanced SCSI error reporting                     (isense.o)
-    <M>   Fusion MPT misc device (ioctl) driver             (mptctl.o)
-    <M>   Fusion MPT LAN driver                             (mptlan.o)
-
-  ---
-  Fusion MPT is trademark of LSI Logic Corporation, and its
-  architecture is based on LSI Logic's Message Passing Interface (MPI)
-  specification.
-
-Fusion MPT enhanced SCSI error reporting [optional] module
-CONFIG_FUSION_ISENSE
-  The isense module (roughly stands for Interpret SENSE data) is
-  completely optional.  It simply provides extra English readable
-  strings in SCSI Error Report(s) that might be generated from the
-  Fusion MPT SCSI Host driver, for example when a target device
-  returns a SCSI check condition on a I/O.  Without this module
-  loaded you might see:
-
-    SCSI Error Report =-=-= (ioc0,scsi5:0)
-      SCSI_Status=02h (CHECK_CONDITION)
-      Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00
-      SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00
-      SenseKey=2h (NOT READY); FRU=02h
-      ASC/ASCQ=29h/00h
-
-  Where otherwise, if this module had been loaded, you would see:
-
-    SCSI Error Report =-=-= (ioc0,scsi5:0)
-      SCSI_Status=02h (CHECK_CONDITION)
-      Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 - "WRITE(10)"
-      SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00
-      SenseKey=2h (NOT READY); FRU=02h
-      ASC/ASCQ=29h/00h "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED"
-
-  Say M for "Enhanced SCSI error reporting" to compile this optional module,
-  creating a driver named: isense.o.
-
-  NOTE: Support for building this feature into the kernel is not
-  available, due to kernel size considerations.
-
-Fusion MPT misc device (ioctl) driver [optional] module
-CONFIG_FUSION_CTL
-  The Fusion MPT misc device driver provides specialized control
-  of MPT adapters via system ioctl calls.  Use of ioctl calls to
-  the MPT driver requires that you create and use a misc device
-  node ala:
-    mknod /dev/mptctl c 10 240
-
-  One use of this ioctl interface is to perform an upgrade (reflash)
-  of the MPT adapter firmware.  Refer to readme file(s) distributed
-  with the Fusion MPT linux driver for additional details.
-
-  If enabled by saying M to this, a driver named: mptctl.o
-  will be compiled.
-
-  If unsure whether you really want or need this, say N.
-
-Fusion MPT LAN driver [optional]
-CONFIG_FUSION_LAN
-  This module supports LAN IP traffic over Fibre Channel port(s)
-  on Fusion MPT compatible hardware (LSIFC9xx chips).
-  The physical interface used is defined in RFC 2625.
-  Please refer to that document for details.
-
-  Installing this driver requires the knowledge to configure and
-  activate a new network interface, "fc0", using standard Linux tools.
-
-  If enabled by saying M to this, a driver named: mptlan.o
-  will be compiled.
-
-  If unsure whether you really want or need this, say N.
-
-  NOTES: This feature is NOT available nor supported for linux-2.2.x
-  kernels.  You must be building a linux-2.3.x or linux-2.4.x kernel
-  in order to configure this option.
-  Support for building this feature into the linux kernel is not
-  yet available.
-
-SCSI support
-CONFIG_SCSI
-  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
-  any other SCSI device under Linux, say Y and make sure that you know
-  the name of your SCSI host adapter (the card inside your computer
-  that "speaks" the SCSI protocol, also called SCSI controller),
-  because you will be asked for it.
-
-  You also need to say Y here if you want support for the parallel
-  port version of the 100 MB IOMEGA ZIP drive.
-
-  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
-  a module, say M here and read <file:Documentation/modules.txt> and
-  <file:Documentation/scsi.txt>.  However, do not compile this as a
-  module if your root file system (the one containing the directory /)
-  is located on a SCSI device.
-
-SCSI disk support
-CONFIG_BLK_DEV_SD
-  If you want to use a SCSI hard disk or the SCSI or parallel port
-  version of the IOMEGA ZIP drive under Linux, say Y and read the
-  SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. This is NOT for SCSI
-  CD-ROMs.
-
-  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 sd_mod.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> and
-  <file:Documentation/scsi.txt>.  Do not compile this driver as a
-  module if your root file system (the one containing the directory /)
-  is located on a SCSI disk. In this case, do not compile the driver
-  for your SCSI host adapter (below) as a module either.
-
-Maximum number of SCSI disks that can be loaded as modules
-CONFIG_SD_EXTRA_DEVS
-  This controls the amount of additional space allocated in tables for
-  drivers that are loaded as modules after the kernel is booted.  In
-  the event that the SCSI core itself was loaded as a module, this
-  value is the number of additional disks that can be loaded after the
-  first host driver is loaded.
-
-  Admittedly this isn't pretty, but there are tons of race conditions
-  involved with resizing the internal arrays on the fly.  Someday this
-  flag will go away, and everything will work automatically.
-
-  If you don't understand what's going on, go with the default.
-
-Maximum number of SCSI tapes that can be loaded as modules
-CONFIG_ST_EXTRA_DEVS
-  This controls the amount of additional space allocated in tables for
-  drivers that are loaded as modules after the kernel is booted.  In
-  the event that the SCSI core itself was loaded as a module, this
-  value is the number of additional tapes that can be loaded after the
-  first host driver is loaded.
-
-  Admittedly this isn't pretty, but there are tons of race conditions
-  involved with resizing the internal arrays on the fly.  Someday this
-  flag will go away, and everything will work automatically.
-
-  If you don't understand what's going on, go with the default.
-
-SCSI tape support
-CONFIG_CHR_DEV_ST
-  If you want to use a SCSI tape drive under Linux, say Y and read the
-  SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, and
-  <file:drivers/scsi/README.st> in the kernel source.  This is NOT for
-  SCSI CD-ROMs.
-
-  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 st.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> and
-  <file:Documentation/scsi.txt>.
-
-OnStream SC-x0 SCSI tape support
-CONFIG_CHR_DEV_OSST
-  The OnStream SC-x0 SCSI tape drives can not be driven by the
-  standard st driver, but instead need this special osst driver and
-  use the  /dev/osstX char device nodes (major 206).  Via usb-storage
-  and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives
-  as well.  Note that there is also a second generation of OnStream
-  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
-  <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/>
-  Please also have a look at the standard st docu, as most of it
-  applies to osst as well.
-
-  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 osst.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> and
-  <file:Documentation/scsi.txt>.
-
-SCSI CD-ROM support
-CONFIG_BLK_DEV_SR
-  If you want to use a SCSI CD-ROM under Linux, say Y and read the
-  SCSI-HOWTO and the CD-ROM-HOWTO at
-  <http://www.linuxdoc.org/docs.html#howto>. Also make sure to say Y
-  or M to "ISO 9660 CD-ROM file system support" later.
-
-  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 sr_mod.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> and
-  <file:Documentation/scsi.txt>.
-
-Maximum number of CD-ROM devices that can be loaded as modules
-CONFIG_SR_EXTRA_DEVS
-  This controls the amount of additional space allocated in tables for
-  drivers that are loaded as modules after the kernel is booted. In
-  the event that the SCSI core itself was loaded as a module, this
-  value is the number of additional CD-ROMs that can be loaded after
-  the first host driver is loaded.
-
-  Admittedly this isn't pretty, but there are tons of race conditions
-  involved with resizing the internal arrays on the fly.  Someday this
-  flag will go away, and everything will work automatically.
-
-  If you don't understand what's going on, go with the default.
-
-Enable vendor-specific extensions (for SCSI CD-ROM)
-CONFIG_BLK_DEV_SR_VENDOR
-  This enables the usage of vendor specific SCSI commands. This is
-  required to support multisession CDs with old NEC/TOSHIBA cdrom
-  drives (and HP Writers). If you have such a drive and get the first
-  session only, try saying Y here; everybody else says N.
-
-SCSI generic support
-CONFIG_CHR_DEV_SG
-  If you want to use SCSI scanners, synthesizers or CD-writers or just
-  about anything having "SCSI" in its name other than hard disks,
-  CD-ROMs or tapes, say Y here. These won't be supported by the kernel
-  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 Cdrtools
-  (<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html>)
-  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.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> and
-  <file:Documentation/scsi.txt>. The module will be called sg.o. If unsure,
-  say N.
-
-Probe all LUNs on each SCSI device
-CONFIG_SCSI_MULTI_LUN
-  If you have a SCSI device that supports more than one LUN (Logical
-  Unit Number), e.g. a CD jukebox, and only one LUN is detected, you
-  can say Y here to force the SCSI driver to probe for multiple LUNs.
-  A SCSI device with multiple LUNs acts logically like multiple SCSI
-  devices. The vast majority of SCSI devices have only one LUN, and
-  so most people can say N here and should in fact do so, because it
-  is safer.
-
-Verbose SCSI error reporting (kernel size +=12K)
-CONFIG_SCSI_CONSTANTS
-  The error messages regarding your SCSI hardware will be easier to
-  understand if you say Y here; it will enlarge your kernel by about
-  12 KB. If in doubt, say Y.
-
-SCSI logging facility
-CONFIG_SCSI_LOGGING
-  This turns on a logging facility that can be used to debug a number
-  of SCSI related problems.
-
-  If you say Y here, no logging output will appear by default, but you
-  can enable logging by saying Y to "/proc file system support" and
-  "Sysctl support" below and executing the command
-
-     echo "scsi log token [level]" > /proc/scsi/scsi
-
-  at boot time after the /proc file system has been mounted.
-
-  There are a number of things that can be used for 'token' (you can
-  find them in the source: <file:drivers/scsi/scsi.c>), and this
-  allows you to select the types of information you want, and the
-  level allows you to select the level of verbosity.
-
-  If you say N here, it may be harder to track down some types of SCSI
-  problems. If you say Y here your kernel will be somewhat larger, but
-  there should be no noticeable performance impact as long as you have
-  logging turned off.
-
-SGI WD93C93 SCSI Driver
-CONFIG_SCSI_SGIWD93
-  Say Y here to support the on-board WD93C93 SCSI controller found (a)
-  on the Indigo2 and other MIPS-based SGI machines, and (b) on ARCS
-  ARM-based machines.
-
-DEC NCR53C94 SCSI Driver
-CONFIG_SCSI_DECNCR
-  Say Y here to support the NCR53C94 SCSI controller chips on IOASIC
-  based TURBOchannel DECstations and TURBOchannel PMAZ-A cards.
-
-AdvanSys SCSI support
-CONFIG_SCSI_ADVANSYS
-  This is a driver for all SCSI host adapters manufactured by
-  AdvanSys. It is documented in the kernel source in
-  <file:drivers/scsi/advansys.c>.
-
-  This driver is also available 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>.  The module will be called
-  advansys.o.
-
-Adaptec AHA152X/2825 support
-CONFIG_SCSI_AHA152X
-  This is a driver for the AHA-1510, AHA-1520, AHA-1522, and AHA-2825
-  SCSI host adapters. It also works for the AVA-1505, but the IRQ etc.
-  must be manually specified in this case.
-
-  It is explained in section 3.3 of the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. You might also want to
-  read the file <file:drivers/scsi/README.aha152x>.
-
-  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 aha152x.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Adaptec AHA1542 support
-CONFIG_SCSI_AHA1542
-  This is support for a SCSI host adapter.  It is explained in section
-  3.4 of the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  Note that Trantor was
-  purchased by Adaptec, and some former Trantor products are being
-  sold under the Adaptec name.  If it doesn't work out of the box, you
-  may have to change some settings in <file:drivers/scsi/aha1542.h>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called aha1542.o.
-
-Adaptec AHA1740 support
-CONFIG_SCSI_AHA1740
-  This is support for a SCSI host adapter.  It is explained in section
-  3.5 of the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  If it doesn't work out
-  of the box, you may have to change some settings in
-  <file:drivers/scsi/aha1740.h>.
-
-  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 aha1740.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Adaptec AIC7xxx support
-CONFIG_SCSI_AIC7XXX
-  This driver supports all of Adaptec's PCI based SCSI controllers
-  (not the hardware RAID controllers though) as well as the aic7770
-  based EISA and VLB SCSI controllers (the 274x and 284x series).
-  This is an Adaptec sponsored driver written by Justin Gibbs.  It is
-  intended to replace the previous aic7xxx driver maintained by Doug
-  Ledford since Doug is no longer maintaining that driver.
-
-Adaptec I2O RAID controllers
-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
-  driver by Deanna Bonds.  See <file:drivers/scsi/README.dpti>.
-
-  This driver is also available 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>.  The module will be called
-  dpt_i2o.o.
-
-Default number of TCQ commands per device
-CONFIG_AIC7XXX_CMDS_PER_DEVICE
-  Specify the number of commands you would like to allocate per SCSI
-  device when Tagged Command Queueing (TCQ) is enabled on that device.
-
-  This is an upper bound value for the number of tagged transactions
-  to be used for any device.  The aic7xxx driver will automatically
-  vary this number based on device behavior.  For devices with a
-  fixed maximum, the driver will eventually lock to this maximum
-  and display a console message inidicating this value.
-
-  Note: Unless you experience some type of device failure, the default
-	value, no enforced limit, should work for you.
-
-  Default: 253
-
-Delay in seconds after SCSI bus reset
-CONFIG_AIC7XXX_RESET_DELAY_MS
-  The number of milliseconds to delay after an initial bus reset.
-  The bus settle delay following all error recovery actions is
-  dictated by the SCSI layer and is not affected by this value.
-
-  Default: 15000 (15 seconds)
-
-Build Adapter Firmware with Kernel Build
-CONFIG_AIC7XXX_BUILD_FIRMWARE
-  This option should only be enabled if you are modifying the firmware
-  source to the aic7xxx driver and wish to have the generated firmware
-  include files updated during a normal kernel build.  The assembler
-  for the firmware requires lex and yacc or their equivalents, as well
-  as the db v1 library.  You may have to install additional packages
-  or modify the assembler make file or the files it includes if your
-  build environment is different than that of the author.
-
-Old Adaptec AIC7xxx support
-CONFIG_SCSI_AIC7XXX_OLD
-  WARNING This driver is an older aic7xxx driver and is no longer
-  under active development.  Adaptec, Inc. is writing a new driver to
-  take the place of this one, and it is recommended that whenever
-  possible, people should use the new Adaptec written driver instead
-  of this one.  This driver will eventually be phased out entirely.
-
-  This is support for the various aic7xxx based Adaptec SCSI
-  controllers. These include the 274x EISA cards; 284x VLB cards;
-  2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and
-  motherboard based SCSI controllers from Adaptec. It does not support
-  the AAA-13x RAID controllers from Adaptec, nor will it likely ever
-  support them. It does not support the 2920 cards from Adaptec that
-  use the Future Domain SCSI controller chip. For those cards, you
-  need the "Future Domain 16xx SCSI support" driver.
-
-  In general, if the controller is based on an Adaptec SCSI controller
-  chip from the aic777x series or the aic78xx series, this driver
-  should work. The only exception is the 7810 which is specifically
-  not supported (that's the RAID controller chip on the AAA-13x
-  cards).
-
-  Note that the AHA2920 SCSI host adapter is *not* supported by this
-  driver; choose "Future Domain 16xx SCSI support" instead if you have
-  one of those.
-
-  Information on the configuration options for this controller can be
-  found by checking the help file for each of the available
-  configuration options. You should read
-  <file:drivers/scsi/aic7xxx_old/README.aic7xxx> at a minimum before
-  contacting the maintainer with any questions.  The SCSI-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>, can also
-  be of great help.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called aic7xxx_old.o.
-
-Enable tagged command queueing (TCQ) by default
-CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
-  This option causes the aic7xxx driver to attempt to use Tagged
-  Command Queueing (TCQ) on all devices that claim to support it.
-
-  TCQ is a feature of SCSI-2 which improves performance: the host
-  adapter can send several SCSI commands to a device's queue even if
-  previous commands haven't finished yet.  Because the device is
-  intelligent, it can optimize its operations (like head positioning)
-  based on its own request queue.  Not all devices implement this
-  correctly.
-
-  If you say Y here, you can still turn off TCQ on troublesome devices
-  with the use of the tag_info boot parameter.  See the file
-  <file:drivers/scsi/README.aic7xxx> for more information on that and
-  other aic7xxx setup commands.  If this option is turned off, you may
-  still enable TCQ on known good devices by use of the tag_info boot
-  parameter.
-
-  If you are unsure about your devices then it is safest to say N
-  here.
-
-  However, TCQ can increase performance on some hard drives by as much
-  as 50% or more, so it is recommended that if you say N here, you
-  should at least read the <file:drivers/scsi/README.aic7xxx> file so
-  you will know how to enable this option manually should your drives
-  prove to be safe in regards to TCQ.
-
-  Conversely, certain drives are known to lock up or cause bus resets
-  when TCQ is enabled on them.  If you have a Western Digital
-  Enterprise SCSI drive for instance, then don't even bother to enable
-  TCQ on it as the drive will become unreliable, and it will actually
-  reduce performance.
-
-Default number of TCQ commands per device
-CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
-  Specify the number of commands you would like to allocate per SCSI
-  device when Tagged Command Queueing (TCQ) is enabled on that device.
-
-  Reasonable figures are in the range of 8 to 24 commands per device,
-  but depending on hardware could be increased or decreased from that
-  figure. If the number is too high for any particular device, the
-  driver will automatically compensate usually after only 10 minutes
-  of uptime. It will not hinder performance if some of your devices
-  eventually have their command depth reduced, but is a waste of
-  memory if all of your devices end up reducing this number down to a
-  more reasonable figure.
-
-  NOTE: Certain very broken drives are known to lock up when given
-  more commands than they like to deal with. Quantum Fireball drives
-  are the most common in this category. For the Quantum Fireball
-  drives it is suggested to use no more than 8 commands per device.
-
-  Default: 8
-
-Collect statistics to report in /proc
-CONFIG_AIC7XXX_OLD_PROC_STATS
-  This option tells the driver to keep track of how many commands have
-  been sent to each particular device and report that information to
-  the user via the /proc/scsi/aic7xxx/n file, where n is the number of
-  the aic7xxx controller you want the information on. This adds a
-  small amount of overhead to each and every SCSI command the aic7xxx
-  driver handles, so if you aren't really interested in this
-  information, it is best to leave it disabled. This will only work if
-  you also say Y to "/proc file system support", below.
-
-  If unsure, say N.
-
-IBM ServeRAID support
-CONFIG_SCSI_IPS
-  This is support for the IBM ServeRAID hardware RAID controllers.
-  See <http://www.developer.ibm.com/welcome/netfinity/serveraid.html>
-  for more information.  If this driver does not work correctly
-  without modification please contact the author by email at
-  ipslinux@us.ibm.com.
-
-  You can build this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  but only a single instance may be loaded. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-  The module will be called ips.o.
-
-BusLogic SCSI support
-CONFIG_SCSI_BUSLOGIC
-  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
-  <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),
-  but only a single instance may be loaded. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-  The module will be called BusLogic.o.
-
-Omit BusLogic SCSI FlashPoint support
-CONFIG_SCSI_OMIT_FLASHPOINT
-  This option allows you to omit the FlashPoint support from the
-  BusLogic SCSI driver. The FlashPoint SCCB Manager code is
-  substantial, so users of MultiMaster Host Adapters may wish to omit
-  it.
-
-Compaq Fibre Channel 64-bit/66Mhz HBA support
-CONFIG_SCSI_CPQFCTS
-  Say Y here to compile in support for the Compaq StorageWorks Fibre
-  Channel 64-bit/66Mhz Host Bus Adapter.
-
-DMX3191D SCSI support
-CONFIG_SCSI_DMX3191D
-  This is support for Domex DMX3191D SCSI Host Adapters.
-
-  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 dmx3191d.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-DTC3180/3280 SCSI support
-CONFIG_SCSI_DTC3280
-  This is support for DTC 3180/3280 SCSI Host Adapters.  Please read
-  the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, and the file
-  <file:drivers/scsi/README.dtc3x80>.
-
-  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 dtc.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support
-CONFIG_SCSI_EATA_DMA
-  This is support for the EATA-DMA protocol compliant SCSI Host
-  Adapters like the SmartCache III/IV, SmartRAID controller families
-  and the DPT PM2011B and PM2012B controllers.
-
-  Note that this driver is obsolete; if you have one of the above
-  SCSI Host Adapters, you should normally say N here and Y to "EATA
-  ISA/EISA/PCI support", below.  Please read the SCSI-HOWTO, available
-  from <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called eata_dma.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-EATA-PIO (old DPT PM2001, PM2012A) support
-CONFIG_SCSI_EATA_PIO
-  This driver supports all EATA-PIO protocol compliant SCSI Host
-  Adapters like the DPT PM2001 and the PM2012A.  EATA-DMA compliant
-  host adapters could also use this driver but are discouraged from
-  doing so, since this driver only supports hard disks and lacks
-  numerous features.  You might want to have a look at the SCSI-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called eata_pio.o.
-
-UltraStor 14F/34F support
-CONFIG_SCSI_U14_34F
-  This is support for the UltraStor 14F and 34F SCSI-2 host adapters.
-  The source at <file:drivers/scsi/u14-34f.c> contains some
-  information about this hardware.  If the driver doesn't work out of
-  the box, you may have to change some settings in
-  <file: drivers/scsi/u14-34f.c>.  Read the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  Note that there is also
-  another driver for the same hardware: "UltraStor SCSI support",
-  below.  You should say Y to both only if you want 24F support as
-  well.
-
-  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 u14-34f.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-enable elevator sorting
-CONFIG_SCSI_U14_34F_LINKED_COMMANDS
-  This option enables elevator sorting for all probed SCSI disks and
-  CD-ROMs. It definitely reduces the average seek distance when doing
-  random seeks, but this does not necessarily result in a noticeable
-  performance improvement: your mileage may vary...
-
-  The safe answer is N.
-
-maximum number of queued commands
-CONFIG_SCSI_U14_34F_MAX_TAGS
-  This specifies how many SCSI commands can be maximally queued for
-  each probed SCSI device. You should reduce the default value of 8
-  only if you have disks with buggy or limited tagged command support.
-  Minimum is 2 and maximum is 14. This value is also the window size
-  used by the elevator sorting option above. The effective value used
-  by the driver for each probed SCSI device is reported at boot time.
-
-Future Domain 16xx SCSI/AHA-2920A support
-CONFIG_SCSI_FUTURE_DOMAIN
-  This is support for Future Domain's 16-bit SCSI host adapters
-  (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and
-  other adapters based on the Future Domain chipsets (Quantum
-  ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board).
-  It is explained in section 3.7 of the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip
-  and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI
-  controller support"). This Future Domain driver works with the older
-  Adaptec AHA-2920A boards with a Future Domain chip on them.
-
-  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 fdomain.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Future Domain MCS-600/700 SCSI support
-CONFIG_SCSI_FD_MCS
-  This is support for Future Domain MCS 600/700 MCA SCSI adapters.
-  Some PS/2 computers are equipped with IBM Fast SCSI Adapter/A which
-  is identical to the MCS 700 and hence also supported by this driver.
-  This driver also supports the Reply SB16/SCSI card (the SCSI part).
-  It supports multiple adapters in the same system.
-
-  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 fd_mcs.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Generic NCR5380/53c400 SCSI support
-CONFIG_SCSI_GENERIC_NCR5380
-  This is the generic NCR family of SCSI controllers, not to be
-  confused with the NCR 53c7 or 8xx controllers.  It is explained in
-  section 3.8 of the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  If it doesn't work out
-  of the box, you may have to change some settings in
-  <file:drivers/scsi/g_NCR5380.h>.
-
-  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 g_NCR5380.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Enable NCR53c400 extensions
-CONFIG_SCSI_GENERIC_NCR53C400
-  This enables certain optimizations for the NCR53c400 SCSI cards.
-  You might as well try it out.  Note that this driver will only probe
-  for the Trantor T130B in its default configuration; you might have
-  to pass a command line option to the kernel at boot time if it does
-  not detect your card.  See the file
-  <file:drivers/scsi/README.g_NCR5380> for details.
-
-# Choice: ncr5380
-NCR5380/53c400 mapping method (use Port for T130B)
-CONFIG_SCSI_G_NCR5380_PORT
-  The NCR5380 and NCR53c400 SCSI controllers come in two varieties:
-  port or memory mapped. You should know what you have. The most
-  common card, Trantor T130B, uses port mapped mode.
-
-NCR Dual 700 MCA SCSI support
-CONFIG_SCSI_NCR_D700
-  This is a driver for the MicroChannel Dual 700 card produced by
-  NCR and commonly used in 345x/35xx/4100 class machines.  It always
-  tries to negotiate sync and uses tag command queueing.
-
-  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
-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
-  based on the 710 chip using 700 emulation mode.
-
-  Unless you know you have a 53c700 or 53c710 based lasi, say N here
-
-NCR53c7,8xx SCSI support
-CONFIG_SCSI_NCR53C7xx
-  This is a driver for the 53c7 and 8xx NCR family of SCSI
-  controllers, not to be confused with the NCR 5380 controllers.  It
-  is explained in section 3.8 of the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  If it doesn't work out
-  of the box, you may have to change some settings in
-  <file:drivers/scsi/53c7,8xx.h>.  Please read
-  <file:drivers/scsi/README.ncr53c7xx> for the available boot time
-  command line options.
-
-  Note: there is another driver for the 53c8xx family of controllers
-  ("NCR53C8XX SCSI support" below).  If you want to use them both, you
-  need to say M to both and build them as modules, but only one may be
-  active at a time. If you have a 53c8xx board, it's better to use the
-  other driver.
-
-  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 53c7,8xx.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Always negotiate synchronous transfers
-CONFIG_SCSI_NCR53C7xx_sync
-  In general, this is good; however, it is a bit dangerous since there
-  are some broken SCSI devices out there. Take your chances. Safe bet
-  is N.
-
-Allow FAST-SCSI [10MHz]
-CONFIG_SCSI_NCR53C7xx_FAST
-  This will enable 10MHz FAST-SCSI transfers with your host
-  adapter. Some systems have problems with that speed, so it's safest
-  to say N here.
-
-Allow DISCONNECT
-CONFIG_SCSI_NCR53C7xx_DISCONNECT
-  This enables the disconnect/reconnect feature of the NCR SCSI
-  controller. When you say Y here, a slow SCSI device will not lock
-  the SCSI bus while processing a request, allowing simultaneous use
-  of e.g. a SCSI hard disk and SCSI tape or CD-ROM drive, and
-  providing much better performance when using slow and fast SCSI
-  devices at the same time. Some devices, however, do not operate
-  properly with this option enabled, and will cause your SCSI system
-  to hang, which might cause a system crash. The safe answer
-  therefore is to say N.
-
-SYM53C8XX Version 2 SCSI support
-CONFIG_SCSI_SYM53C8XX_2
-  This driver supports the whole NCR53C8XX/SYM53C8XX family of 
-  PCI-SCSI controllers. It also supports the subset of LSI53C10XX 
-  Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS 
-  language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI 
-  controllers.
-
-  If your system has problems using this new major version of the
-  SYM53C8XX driver, you may switch back to driver version 1.
-
-  Please read <file:drivers/scsi/sym53c8xx_2/Documentation.txt> for more
-  information.
-
-PCI DMA addressing mode
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE
-  This option only applies to PCI-SCSI chip that are PCI DAC capable 
-  (875A, 895A, 896, 1010-33, 1010-66, 1000).
-
-  When set to 0, only PCI 32 bit DMA addressing (SAC) will be performed.
-  When set to 1, 40 bit DMA addressing (with upper 24 bits of address 
-  set to zero) is supported. The addressable range is here 1 TB.
-  When set to 2, full 64 bits of address for DMA are supported, but only
-  16 segments of 4 GB can be addressed. The addressable range is so 
-  limited to 64 GB.
-
-  The safest value is 0 (32 bit DMA addressing) that is guessed to still 
-  fit most of real machines.
-
-  The preferred value 1 (40 bit DMA addressing) should make happy 
-  properly engineered PCI DAC capable host bridges. You may configure
-  this option for Intel platforms with more than 4 GB of memory.
-
-  The still experimental value 2 (64 bit DMA addressing with 16 x 4GB 
-  segments limitation) can be used on systems that require PCI address 
-  bits past bit 39 to be set for the addressing of memory using PCI 
-  DAC cycles.
-
-use normal IO
-CONFIG_SCSI_SYM53C8XX_IOMAPPED
-  If you say Y here, the driver will preferently use normal IO rather than 
-  memory mapped IO.
-
-maximum number of queued commands
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS
-  This option allows you to specify the maximum number of commands
-  that can be queued to any device, when tagged command queuing is
-  possible. The driver supports up to 256 queued commands per device.
-  This value is used as a compiled-in hard limit.
-
-default tagged command queue depth
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS
-  This is the default value of the command queue depth the driver will 
-  announce to the generic SCSI layer for devices that support tagged 
-  command queueing. This value can be changed from the boot command line.
-  This is a soft limit that cannot exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS.
-
-NCR53C8XX SCSI support
-CONFIG_SCSI_NCR53C8XX
-  This is the BSD ncr driver adapted to Linux for the NCR53C8XX family
-  of PCI-SCSI controllers.  This driver supports parity checking,
-  tagged command queuing and fast synchronous data transfers up to 80
-  MB/s with wide FAST-40 LVD devices and controllers.
-
-  Recent versions of the 53C8XX chips are better supported by the
-  option "SYM53C8XX SCSI support", below.
-
-  Note: there is yet another driver for the 53c8xx family of
-  controllers ("NCR53c7,8xx SCSI support" above).  If you want to use
-  them both, you need to say M to both and build them as modules, but
-  only one may be active at a time.  If you have a 53c8xx board, you
-  probably do not want to use the "NCR53c7,8xx SCSI support".
-
-  Please read <file:drivers/scsi/README.ncr53c8xx> for more
-  information.
-
-SYM53C8XX Version 1 SCSI support
-CONFIG_SCSI_SYM53C8XX
-  This driver supports all the features of recent 53C8XX chips (used
-  in PCI SCSI controllers), notably the hardware phase mismatch
-  feature of the SYM53C896.
-
-  Older versions of the 53C8XX chips are not supported by this
-  driver.  If your system uses either a 810 rev. < 16, a 815, or a 825
-  rev. < 16 PCI SCSI processor, you must use the generic NCR53C8XX
-  driver ("NCR53C8XX SCSI support" above) or configure both the
-  NCR53C8XX and this SYM53C8XX drivers either as module or linked to
-  the kernel image.
-
-  When both drivers are linked into the kernel, the SYM53C8XX driver
-  is called first at initialization and you can use the 'excl=ioaddr'
-  driver boot option to exclude attachment of adapters by the
-  SYM53C8XX driver.  For example, entering
-  'sym53c8xx=excl:0xb400,excl=0xc000' at the lilo prompt prevents
-  adapters at io address 0xb400 and 0xc000 from being attached by the
-  SYM53C8XX driver, thus allowing the NCR53C8XX driver to attach them.
-  The 'excl' option is also supported by the NCR53C8XX driver.
-
-  Please read <file:drivers/scsi/README.ncr53c8xx> for more
-  information.
-
-Synchronous transfer frequency in MHz
-CONFIG_SCSI_NCR53C8XX_SYNC
-  The SCSI Parallel Interface-2 Standard defines 5 classes of transfer
-  rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80.  The numbers
-  are respectively the maximum data transfer rates in mega-transfers
-  per second for each class.  For example, a FAST-20 Wide 16 device is
-  able to transfer data at 20 million 16 bit packets per second for a
-  total rate of 40 MB/s.
-
-  You may specify 0 if you want to only use asynchronous data
-  transfers. This is the safest and slowest option. Otherwise, specify
-  a value between 5 and 80, depending on the capability of your SCSI
-  controller.  The higher the number, the faster the data transfer.
-  Note that 80 should normally be ok since the driver decreases the
-  value automatically according to the controller's capabilities.
-
-  Your answer to this question is ignored for controllers with NVRAM,
-  since the driver will get this information from the user set-up.  It
-  also can be overridden using a boot setup option, as follows
-  (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate
-  for FAST-20 synchronous data transfer (20 mega-transfers per
-  second).
-
-  The normal answer therefore is not to go with the default but to
-  select the maximum value 80 allowing the driver to use the maximum
-  value supported by each controller. If this causes problems with
-  your SCSI devices, you should come back and decrease the value.
-
-  There is no safe option other than using good cabling, right
-  terminations and SCSI conformant devices.
-
-Use normal IO
-CONFIG_SCSI_NCR53C8XX_IOMAPPED
-  If you say Y here, the driver will use normal IO, as opposed to
-  memory mapped IO. Memory mapped IO has less latency than normal IO
-  and works for most Intel-based hardware. Under Linux/Alpha only
-  normal IO is currently supported by the driver and so, this option
-  has no effect on those systems.
-
-  The normal answer therefore is N; try Y only if you encounter SCSI
-  related problems.
-
-Not allow targets to disconnect
-CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
-  This option is only provided for safety if you suspect some SCSI
-  device of yours to not support properly the target-disconnect
-  feature. In that case, you would say Y here. In general however, to
-  not allow targets to disconnect is not reasonable if there is more
-  than 1 device on a SCSI bus. The normal answer therefore is N.
-
-Default tagged command queue depth
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS
-  "Tagged command queuing" is a feature of SCSI-2 which improves
-  performance: the host adapter can send several SCSI commands to a
-  device's queue even if previous commands haven't finished yet.
-  Because the device is intelligent, it can optimize its operations
-  (like head positioning) based on its own request queue. Some SCSI
-  devices don't implement this properly; if you want to disable this
-  feature, enter 0 or 1 here (it doesn't matter which).
-
-  The default value is 8 and should be supported by most hard disks.
-  This value can be overridden from the boot command line using the
-  'tags' option as follows (example):
-  'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to
-  4, set queue depth to 16 for target 2 and target 3 on controller 0
-  and set queue depth to 10 for target 0 / lun 2 on controller 1.
-
-  The normal answer therefore is to go with the default 8 and to use
-  a boot command line option for devices that need to use a different
-  command queue depth.
-
-  There is no safe option other than using good SCSI devices.
-
-Maximum number of queued commands
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS
-  This option allows you to specify the maximum number of commands
-  that can be queued to any device, when tagged command queuing is
-  possible. The default value is 32. Minimum is 2, maximum is 64.
-  Modern hard disks are able to support 64 tags and even more, but
-  do not seem to be faster when more than 32 tags are being used.
-
-  So, the normal answer here is to go with the default value 32 unless
-  you are using very large hard disks with large cache (>= 1 MB) that
-  are able to take advantage of more than 32 tagged commands.
-
-  There is no safe option and the default answer is recommended.
-
-Assume boards are SYMBIOS compatible
-CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
-  This option allows you to enable some features depending on GPIO
-  wiring. These General Purpose Input/Output pins can be used for
-  vendor specific features or implementation of the standard SYMBIOS
-  features. Genuine SYMBIOS controllers use GPIO0 in output for
-  controller LED and GPIO3 bit as a flag indicating
-  singled-ended/differential interface. The Tekram DC-390U/F boards
-  uses a different GPIO wiring.
-
-  Your answer to this question is ignored if all your controllers have
-  NVRAM, since the driver is able to detect the board type from the
-  NVRAM format.
-
-  If all the controllers in your system are genuine SYMBIOS boards or
-  use BIOS and drivers from SYMBIOS, you would want to say Y here,
-  otherwise N. N is the safe answer.
-
-Enable traffic profiling
-CONFIG_SCSI_NCR53C8XX_PROFILE
-  This option allows you to enable profiling information gathering.
-  These statistics are not very accurate due to the low frequency
-  of the kernel clock (100 Hz on i386) and have performance impact
-  on systems that use very fast devices.
-
-  The normal answer therefore is N.
-
-Include support for the NCR PQS/PDS SCSI card
-CONFIG_SCSI_NCR53C8XX_PQS_PDS
-  Say Y here if you have a special SCSI adapter produced by NCR
-  corporation called a PCI Quad SCSI or PCI Dual SCSI. You do not need
-  this if you do not have one of these adapters. However, since this
-  device is detected as a specific PCI device, this option is quite
-  safe.
-
-  The common answer here is N, but answering Y is safe.
-
-IBMMCA SCSI support
-CONFIG_SCSI_IBMMCA
-  This is support for the IBM SCSI adapter found in many of the PS/2
-  series computers.  These machines have an MCA bus, so you need to
-  answer Y to "MCA support" as well and read
-  <file:Documentation/mca.txt>.
-
-  If the adapter isn't found during boot (a common problem for models
-  56, 57, 76, and 77) you'll need to use the 'ibmmcascsi=<pun>' kernel
-  option, where <pun> is the id of the SCSI subsystem (usually 7, but
-  if that doesn't work check your reference diskette).  Owners of
-  model 95 with a LED-matrix-display can in addition activate some
-  activity info like under OS/2, but more informative, by setting
-  'ibmmcascsi=display' as an additional kernel parameter.  Try "man
-  bootparam" or see the documentation of your boot loader about how to
-  pass options to the kernel.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called ibmmca.o.
-
-Standard SCSI-order
-CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-  In the PC-world and in most modern SCSI-BIOS-setups, SCSI-hard disks
-  are assigned to the drive letters, starting with the lowest SCSI-id
-  (physical number -- pun) to be drive C:, as seen from DOS and
-  similar operating systems. When looking into papers describing the
-  ANSI-SCSI-standard, this assignment of drives appears to be wrong.
-  The SCSI-standard follows a hardware-hierarchy which says that id 7
-  has the highest priority and id 0 the lowest. Therefore, the host
-  adapters are still today everywhere placed as SCSI-id 7 by default.
-  In the SCSI-standard, the drive letters express the priority of the
-  disk. C: should be the hard disk, or a partition on it, with the
-  highest priority. This must therefore be the disk with the highest
-  SCSI-id (e.g. 6) and not the one with the lowest! IBM-BIOS kept the
-  original definition of the SCSI-standard as also industrial- and
-  process-control-machines, like VME-CPUs running under realtime-OSes
-  (e.g. LynxOS, OS9) do.
-
-  If you like to run Linux on your MCA-machine with the same
-  assignment of hard disks as seen from e.g. DOS or OS/2 on your
-  machine, which is in addition conformant to the SCSI-standard, you
-  must say Y here. This is also necessary for MCA-Linux users who want
-  to keep downward compatibility to older releases of the
-  IBM-MCA-SCSI-driver (older than driver-release 2.00 and older than
-  June 1997).
-
-  If you like to have the lowest SCSI-id assigned as drive C:, as
-  modern SCSI-BIOSes do, which does not conform to the standard, but
-  is widespread and common in the PC-world of today, you must say N
-  here. If unsure, say Y.
-
-Reset SCSI-devices at boot time
-CONFIG_IBMMCA_SCSI_DEV_RESET
-  By default, SCSI-devices are reset when the machine is powered on.
-  However, some devices exist, like special-control-devices,
-  SCSI-CNC-machines, SCSI-printer or scanners of older type, that do
-  not reset when switched on. If you say Y here, each device connected
-  to your SCSI-bus will be issued a reset-command after it has been
-  probed, while the kernel is booting. This may cause problems with
-  more modern devices, like hard disks, which do not appreciate these
-  reset commands, and can cause your system to hang. So say Y only if
-  you know that one of your older devices needs it; N is the safe
-  answer.
-
-NCR MCA 53C9x SCSI support
-CONFIG_SCSI_MCA_53C9X
-  Some MicroChannel machines, notably the NCR 35xx line, use a SCSI
-  controller based on the NCR 53C94.  This driver will allow use of
-  the controller on the 3550, and very possibly others.
-
-  If you want to compile this as a module (= code which can be
-  inserted and removed from the running kernel whenever you want), say
-  M here and read <file:Documentation/modules.txt>.  The module will
-  be called mca_53c9x.o.
-
-Always IN2000 SCSI support
-CONFIG_SCSI_IN2000
-  This is support for an ISA bus SCSI host adapter.  You'll find more
-  information in <file:drivers/scsi/README.in2000>. If it doesn't work
-  out of the box, you may have to change the jumpers for IRQ or
-  address selection.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called in2000.o.
-
-Initio 91XXU(W) SCSI support
-CONFIG_SCSI_INITIO
-  This is support for the Initio 91XXU(W) SCSI host adapter.  Please
-  read the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called initio.o.
-
-PAS16 SCSI support
-CONFIG_SCSI_PAS16
-  This is support for a SCSI host adapter.  It is explained in section
-  3.10 of the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  If it doesn't work out
-  of the box, you may have to change some settings in
-  <file:drivers/scsi/pas16.h>.
-
-  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 pas16.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Initio INI-A100U2W SCSI support
-CONFIG_SCSI_INIA100
-  This is support for the Initio INI-A100U2W SCSI host adapter.
-  Please read the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called a100u2w.o.
-
-PCI2000 support
-CONFIG_SCSI_PCI2000
-  This is support for the PCI2000I EIDE interface card which acts as a
-  SCSI host adapter.  Please read the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module called pci2000.o ( = 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>.
-
-PCI2220i support
-CONFIG_SCSI_PCI2220I
-  This is support for the PCI2220i EIDE interface card which acts as a
-  SCSI host adapter.  Please read the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module called pci2220i.o ( = 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>.
-
-PSI240i support
-CONFIG_SCSI_PSI240I
-  This is support for the PSI240i EIDE interface card which acts as a
-  SCSI host adapter.  Please read the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module called psi240i.o ( = 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>.
-
-Qlogic FAS SCSI support
-CONFIG_SCSI_QLOGIC_FAS
-  This is a driver for the ISA, VLB, and PCMCIA versions of the Qlogic
-  FastSCSI! cards as well as any other card based on the FASXX chip
-  (including the Control Concepts SCSI/IDE/SIO/PIO/FDC cards).
-
-  This driver does NOT support the PCI versions of these cards. The
-  PCI versions are supported by the Qlogic ISP driver ("Qlogic ISP
-  SCSI support"), below.
-
-  Information about this driver is contained in
-  <file:drivers/scsi/README.qlogicfas>.  You should also read the
-  SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called qlogicfas.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Qlogic ISP SCSI support
-CONFIG_SCSI_QLOGIC_ISP
-  This driver works for all QLogic PCI SCSI host adapters (IQ-PCI,
-  IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card.  (This latter
-  card is supported by the "AM53/79C974 PCI SCSI" driver.)
-
-  If you say Y here, make sure to choose "BIOS" at the question "PCI
-  access mode".
-
-  Please read the file <file:drivers/scsi/README.qlogicisp>.  You
-  should also read the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called qlogicisp.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Qlogic ISP FC SCSI support
-CONFIG_SCSI_QLOGIC_FC
-  This is a driver for the QLogic ISP2100 SCSI-FCP host adapter.
-
-  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 qlogicfc.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Qlogic QLA 1280 SCSI support
-CONFIG_SCSI_QLOGIC_1280
-  Say Y if you have a QLogic ISP1x80/1x160 SCSI host adapter.
-
-  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 qla1280.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Seagate ST-02 and Future Domain TMC-8xx SCSI support
-CONFIG_SCSI_SEAGATE
-  These are 8-bit SCSI controllers; the ST-01 is also supported by
-  this driver.  It is explained in section 3.9 of the SCSI-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.  If it
-  doesn't work out of the box, you may have to change some settings in
-  <file:drivers/scsi/seagate.h>.
-
-  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 seagate.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Trantor T128/T128F/T228 SCSI support
-CONFIG_SCSI_T128
-  This is support for a SCSI host adapter. It is explained in section
-  3.11 of the SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  If it doesn't work out
-  of the box, you may have to change some settings in
-  <file:drivers/scsi/t128.h>.  Note that Trantor was purchased by
-  Adaptec, and some former Trantor products are being sold under the
-  Adaptec name.
-
-  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 t128.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-UltraStor SCSI support
-CONFIG_SCSI_ULTRASTOR
-  This is support for the UltraStor 14F, 24F and 34F SCSI-2 host
-  adapter family.  This driver is explained in section 3.12 of the
-  SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  If it doesn't work out
-  of the box, you may have to change some settings in
-  <file:drivers/scsi/ultrastor.h>.
-
-  Note that there is also another driver for the same hardware:
-  "UltraStor 14F/34F support", above.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called ultrastor.o.
-
-7000FASST SCSI support
-CONFIG_SCSI_7000FASST
-  This driver supports the Western Digital 7000 SCSI host adapter
-  family.  Some information is in the source:
-  <file:drivers/scsi/wd7000.c>.
-
-  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 wd7000.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-ACARD SCSI support
-CONFIG_SCSI_ACARD
-  This driver supports the ACARD 870U/W SCSI host adapter.
-
-  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 atp870u.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support
-CONFIG_SCSI_EATA
-  This driver supports all EATA/DMA-compliant SCSI host adapters.  DPT
-  ISA and all EISA I/O addresses are probed looking for the "EATA"
-  signature.  If you chose "BIOS" at the question "PCI access mode",
-  the addresses of all the PCI SCSI controllers reported by the PCI
-  subsystem are probed as well.
-
-  You want to read the start of <file:drivers/scsi/eata.c> and the
-  SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  Note that there is also another driver for the same hardware
-  available: "EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti,
-  Alphatronix) support". You should say Y to only one of them.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called eata.o.
-
-enable tagged command queueing
-CONFIG_SCSI_EATA_TAGGED_QUEUE
-  This is a feature of SCSI-2 which improves performance: the host
-  adapter can send several SCSI commands to a device's queue even if
-  previous commands haven't finished yet. Most EATA adapters negotiate
-  this feature automatically with the device, even if your answer is
-  N. The safe answer is N.
-
-enable elevator sorting
-CONFIG_SCSI_EATA_LINKED_COMMANDS
-  This option enables elevator sorting for all probed SCSI disks and
-  CD-ROMs. It definitely reduces the average seek distance when doing
-  random seeks, but this does not necessarily result in a noticeable
-  performance improvement: your mileage may vary...
-  The safe answer is N.
-
-maximum number of queued commands
-CONFIG_SCSI_EATA_MAX_TAGS
-  This specifies how many SCSI commands can be maximally queued for
-  each probed SCSI device. You should reduce the default value of 16
-  only if you have disks with buggy or limited tagged command support.
-  Minimum is 2 and maximum is 62. This value is also the window size
-  used by the elevator sorting option above. The effective value used
-  by the driver for each probed SCSI device is reported at boot time.
-
-NCR53c406a SCSI support
-CONFIG_SCSI_NCR53C406A
-  This is support for the NCR53c406a SCSI host adapter.  For user
-  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>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called NCR53c406.o.
-
-Symbios 53c416 SCSI support
-CONFIG_SCSI_SYM53C416
-  This is support for the sym53c416 SCSI host adapter, the SCSI
-  adapter that comes with some HP scanners. This driver requires that
-  the sym53c416 is configured first using some sort of PnP
-  configuration program (e.g. isapnp) or by a PnP aware BIOS. If you
-  are using isapnp then you need to compile this driver as a module
-  and then load it using insmod after isapnp has run. The parameters
-  of the configured card(s) should be passed to the driver. The format
-  is:
-
-    insmod sym53c416 sym53c416=<base>,<irq> [sym53c416_1=<base>,<irq>]
-
-  There is support for up to four adapters. If you want to compile
-  this driver as a module ( = code which can be inserted in and
-  removed from the running kernel whenever you want), say M here and
-  read <file:Documentation/modules.txt>. The module will be called
-  sym53c416.o.
-
-Simple 53c710 SCSI support (Compaq, NCR machines)
-CONFIG_SCSI_SIM710
-  This is a simple driver for NCR53c710 based SCSI host adapters.
-
-  More complex drivers for this chip are available ("NCR53c7,8xx SCSI
-  support", above), but they require that the scsi chip be able to do
-  DMA block moves between memory and on-chip registers, which can
-  cause problems under certain conditions.  This driver is designed to
-  avoid these problems and is intended to work with any Intel machines
-  using 53c710 chips, including various Compaq and NCR machines.
-
-  Please read the comments at the top of the file
-  <file:drivers/scsi/sim710.c> for more information.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called sim710.o.
-
-Tekram DC390(T) and Am53/79C974 SCSI support
-CONFIG_SCSI_DC390T
-  This driver supports PCI SCSI host adapters based on the Am53C974A
-  chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard
-  PCscsi/PCnet (Am53/79C974) solutions.
-
-  Documentation can be found in <file:drivers/scsi/README.tmscsim>.
-
-  Note that this driver does NOT support Tekram DC390W/U/F, which are
-  based on NCR/Symbios chips. Use "NCR53C8XX SCSI support" for those.
-  Also note that there is another generic Am53C974 driver,
-  "AM53/79C974 PCI SCSI support" below.  You can pick either one.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called tmscsim.o.
-
-Omit support for other Am53/79C974 based SCSI adapters
-CONFIG_SCSI_DC390T_NOGENSUPP
-  If you say N here, the DC390(T) SCSI driver relies on the DC390
-  EEPROM to get initial values for its settings, such as speed,
-  termination, etc.  If it can't find this EEPROM, it will use
-  defaults or the user supplied boot/module parameters.  For details
-  on driver configuration see <file:drivers/scsi/README.tmscsim>.
-
-  If you say Y here and if no EEPROM is found, the driver gives up and
-  thus only supports Tekram DC390(T) adapters.  This can be useful if
-  you have a DC390(T) and another Am53C974 based adapter, which, for
-  some reason, you want to drive with the other AM53C974 driver.
-
-  If unsure, say N.
-
-AM53/79C974 PCI SCSI support
-CONFIG_SCSI_AM53C974
-  This is support for the AM53/79C974 SCSI host adapters.  Please read
-  <file:drivers/scsi/README.AM53C974> for details.  Also, the
-  SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, is for you.
-
-  Note that there is another driver for AM53C974 based adapters:
-  "Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support", above.  You
-  can pick either one.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called AM53C974.o.
-
-AMI MegaRAID support
-CONFIG_SCSI_MEGARAID
-  This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490
-  and 467 SCSI host adapters.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called megaraid.o.
-
-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 <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).
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-IOMEGA parallel port (ppa - older drives)
-CONFIG_SCSI_PPA
-  This driver supports older versions of IOMEGA's parallel port ZIP
-  drive (a 100 MB removable media device).
-
-  Note that you can say N here if you have the SCSI version of the ZIP
-  drive: it will be supported automatically if you said Y to the
-  generic "SCSI disk support", above.
-
-  If you have the ZIP Plus drive or a more recent parallel port ZIP
-  drive (if the supplied cable with the drive is labeled "AutoDetect")
-  then you should say N here and Y to "IOMEGA parallel port (imm -
-  newer drives)", below.
-
-  For more information about this driver and how to use it you should
-  read the file <file:drivers/scsi/README.ppa>.  You should also read
-  the SCSI-HOWTO, which is available from
-  <http://www.linuxdoc.org/docs.html#howto>.  If you use this driver,
-  you will still be able to use the parallel port for other tasks,
-  such as a printer; it is safe to compile both drivers into the
-  kernel.
-
-  This driver is also available as a module which can be inserted in
-  and removed from the running kernel whenever you want.  To compile
-  this driver as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called ppa.o.
-
-IOMEGA parallel port (imm - newer drives)
-CONFIG_SCSI_IMM
-  This driver supports newer versions of IOMEGA's parallel port ZIP
-  drive (a 100 MB removable media device).
-
-  Note that you can say N here if you have the SCSI version of the ZIP
-  drive: it will be supported automatically if you said Y to the
-  generic "SCSI disk support", above.
-
-  If you have the ZIP Plus drive or a more recent parallel port ZIP
-  drive (if the supplied cable with the drive is labeled "AutoDetect")
-  then you should say Y here; if you have an older ZIP drive, say N
-  here and Y to "IOMEGA Parallel Port (ppa - older drives)", above.
-
-  For more information about this driver and how to use it you should
-  read the file <file:drivers/scsi/README.ppa>.  You should also read
-  the SCSI-HOWTO, which is available from
-  <http://www.linuxdoc.org/docs.html#howto>.  If you use this driver,
-  you will still be able to use the parallel port for other tasks,
-  such as a printer; it is safe to compile both drivers into the
-  kernel.
-
-  This driver is also available as a module which can be inserted in
-  and removed from the running kernel whenever you want.  To compile
-  this driver as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called imm.o.
-
-Force the Iomega ZIP drivers to use EPP-16
-CONFIG_SCSI_IZIP_EPP16
-  EPP (Enhanced Parallel Port) is a standard for parallel ports which
-  allows them to act as expansion buses that can handle up to 64
-  peripheral devices.
-
-  Some parallel port chipsets are slower than their motherboard, and
-  so we have to control the state of the chipset's FIFO queue every
-  now and then to avoid data loss. This will be done if you say Y
-  here.
-
-  Generally, saying Y is the safe option and slows things down a bit.
-
-Assume slow parallel port control register
-CONFIG_SCSI_IZIP_SLOW_CTR
-  Some parallel ports are known to have excessive delays between
-  changing the parallel port control register and good data being
-  available on the parallel port data/status register. This option
-  forces a small delay (1.0 usec to be exact) after changing the
-  control register to let things settle out. Enabling this option may
-  result in a big drop in performance but some very old parallel ports
-  (found in 386 vintage machines) will not work properly.
-
-  Generally, saying N is fine.
-
-SCSI debugging host simulator
-CONFIG_SCSI_DEBUG
-  This is a host adapter simulator that can be programmed to simulate
-  a large number of conditions that could occur on a real bus. The
-  advantage is that many hard to reproduce problems can be tested in a
-  controlled environment where there is reduced risk of losing
-  important data. This is primarily of use to people trying to debug
-  the middle and upper layers of the SCSI subsystem. If unsure, say N.
-
-Fibre Channel and FC4 SCSI support
-CONFIG_FC4
-  Fibre Channel is a high speed serial protocol mainly used to
-  connect large storage devices to the computer; it is compatible with
-  and intended to replace SCSI.
-
-  This is an experimental support for storage arrays connected to your
-  computer using optical fibre cables and the "X3.269-199X Fibre
-  Channel Protocol for SCSI" specification. If you want to use this,
-  you need to say Y here and to "SCSI support" as well as to the
-  drivers for the storage array itself and for the interface adapter
-  such as SOC or SOC+. This subsystem could even serve for IP
-  networking, with some code extensions.
-
-  If unsure, say N.
-
-Sun SOC/Sbus
-CONFIG_FC4_SOC
-  Serial Optical Channel is an interface card with one or two Fibre
-  Optic ports, each of which can be connected to a disk array. Note
-  that if you have older firmware in the card, you'll need the
-  microcode from the Solaris driver to make it work.
-
-  This support is also available as a module called soc.o ( = 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>.
-
-Sun SOC+ (aka SOCAL)
-CONFIG_FC4_SOCAL
-  Serial Optical Channel Plus is an interface card with up to two
-  Fibre Optic ports. This card supports FC Arbitrated Loop (usually
-  A5000 or internal FC disks in E[3-6]000 machines through the
-  Interface Board). You'll probably need the microcode from the
-  Solaris driver to make it work.
-
-  This support is also available as a module called socal.o ( = 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>.
-
-SparcSTORAGE Array 100 and 200 series
-CONFIG_SCSI_PLUTO
-  If you never bought a disk array made by Sun, go with N.
-
-  This support is also available as a module called pluto.o ( = 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>.
-
-Sun Enterprise Network Array (A5000 and EX500)
-CONFIG_SCSI_FCAL
-  This driver drives FC-AL disks connected through a Fibre Channel
-  card using the drivers/fc4 layer (currently only SOCAL). The most
-  common is either A5000 array or internal disks in E[3-6]000
-  machines.
-
-  This support is also available as a module called fcal.o ( = 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>. If unsure, say N.
-
-Acorn SCSI card (aka30) support
-CONFIG_SCSI_ACORNSCSI_3
-  This enables support for the Acorn SCSI card (aka30). If you have an
-  Acorn system with one of these, say Y. If unsure, say N.
-
-Support SCSI 2 Tagged queueing
-CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
-  Say Y here to enable tagged queuing support on the Acorn SCSI card.
-
-  This is a feature of SCSI-2 which improves performance: the host
-  adapter can send several SCSI commands to a device's queue even if
-  previous commands haven't finished yet. Some SCSI devices don't
-  implement this properly, so the safe answer is N.
-
-Support SCSI 2 Synchronous Transfers
-CONFIG_SCSI_ACORNSCSI_SYNC
-  Say Y here to enable synchronous transfer negotiation with all
-  targets on the Acorn SCSI card.
-
-  In general, this improves performance; however some SCSI devices
-  don't implement it properly, so the safe answer is N.
-
-ARXE SCSI support
-CONFIG_SCSI_ARXESCSI
-  Around 1991, Arxe Systems Limited released a high density floppy
-  disc interface for the Acorn Archimedes range, to allow the use of
-  HD discs from the then new A5000 on earlier models. This interface
-  was either sold on its own or with an integral SCSI controller.
-  Technical details on this NCR53c94-based device are available at
-  <http://www.cryton.demon.co.uk/acornbits/scsi_arxe.html>
-  Say Y here to compile in support for the SCSI controller.
-
-Oak SCSI support
-CONFIG_SCSI_OAK1
-  This enables support for the Oak SCSI card. If you have an Acorn
-  system with one of these, say Y. If unsure, say N.
-
-Cumana SCSI I support
-CONFIG_SCSI_CUMANA_1
-  This enables support for the Cumana SCSI I card. If you have an
-  Acorn system with one of these, say Y. If unsure, say N.
-
-Cumana SCSI II support
-CONFIG_SCSI_CUMANA_2
-  This enables support for the Cumana SCSI II card. If you have an
-  Acorn system with one of these, say Y. If unsure, say N.
-
-EcoSCSI support
-CONFIG_SCSI_ECOSCSI
-  This enables support for the EcoSCSI card -- a small card that sits
-  in the Econet socket. If you have an Acorn system with one of these,
-  say Y. If unsure, say N.
-
-EESOX SCSI support
-CONFIG_SCSI_EESOXSCSI
-  This enables support for the EESOX SCSI card. If you have an Acorn
-  system with one of these, say Y, otherwise say N.
-
-PowerTec SCSI support
-CONFIG_SCSI_POWERTECSCSI
-  This enables support for the Powertec SCSI card on Acorn systems. If
-  you have one of these, say Y. If unsure, say N.
-
-IEEE 1394 (FireWire) support
-CONFIG_IEEE1394
-  IEEE 1394 describes a high performance serial bus, which is also
-  known as FireWire(tm) or i.Link(tm) and is used for connecting all
-  sorts of devices (most notably digital video cameras) to your
-  computer.
-
-  If you have FireWire hardware and want to use it, say Y here.  This
-  is the core support only, you will also need to select a driver for
-  your IEEE 1394 adapter.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called ieee1394.o.
-
-Texas Instruments PCILynx support
-CONFIG_IEEE1394_PCILYNX
-  Say Y here if you have an IEEE-1394 controller with the Texas
-  Instruments PCILynx chip.  Note: this driver is written for revision
-  2 of this chip and may not work with revision 0.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called pcilynx.o.
-
-Use local RAM on PCILynx board
-CONFIG_IEEE1394_PCILYNX_LOCALRAM
-  This option makes the PCILynx driver use local RAM available on some
-  PCILynx setups for Packet Control Lists. Local RAM is random access
-  memory which resides on the PCILynx board as opposed to on your
-  computer's motherboard. Local RAM may speed up command processing
-  because no PCI transfers are necessary during use of the Packet
-  Control Lists.
-
-  Note that there are no known PCILynx systems providing local RAM
-  except for the evaluation boards by Texas Instruments and that the
-  PCILynx does not reliably report missing RAM. This means that it is
-  dangerous to say Y here if you are not absolutely sure that your
-  board provides 64KB of local RAM.
-
-  If unsure, say N.
-
-Support for non-IEEE1394 local ports
-CONFIG_IEEE1394_PCILYNX_PORTS
-  This option enables driver code to access the RAM, ROM and AUX ports
-  of the PCILynx through character devices in /dev.  If you don't know
-  what this is about then you won't need it.
-
-  If unsure, say N.
-
-#Adaptec AIC-5800 IEEE 1394 support
-#CONFIG_IEEE1394_AIC5800
-#  Say Y here if you have a IEEE 1394 controller using the Adaptec
-#  AIC-5800 chip.  All Adaptec host adapters (89xx series) use this
-#  chip, as well as miro's DV boards.
-#
-#  If you want to compile this as a module ( = code which can be
-#  inserted in and removed from the running kernel whenever you want),
-#  say M here and read <file:Documentation/modules.txt>.  The module
-#  will be called aic5800.o.
-#
-OHCI-1394 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
-  chipsets made by Texas Instruments and NEC. Most third-party vendors
-  use one of these chipsets.  It should work with any OHCI-1394
-  compliant card, however.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called ohci1394.o.
-
-OHCI-1394 Video support
-CONFIG_IEEE1394_VIDEO1394
-  This option enables video device usage for OHCI-1394 cards.  Enable
-  this option only if you have an IEEE 1394 video device connected to
-  an OHCI-1394 card.
-
-SBP-2 support (Harddisks etc.)
-CONFIG_IEEE1394_SBP2
-  This option enables you to use SBP-2 devices connected to your IEEE
-  1394 bus.  SBP-2 devices include harddrives and DVD devices.
-
-Raw IEEE 1394 I/O support
-CONFIG_IEEE1394_RAWIO
-  Say Y here if you want support for the raw device. This is generally
-  a good idea, so you should say Y here. The raw device enables
-  direct communication of user programs with the IEEE 1394 bus and
-  thus with the attached peripherals.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called raw1394.o.
-
-Excessive debugging output
-CONFIG_IEEE1394_VERBOSEDEBUG
-  If you say Y here, you will get very verbose debugging logs from the
-  subsystem which includes a dump of the header of every sent and
-  received packet.  This can amount to a high amount of data collected
-  in a very short time which is usually also saved to disk by the
-  system logging daemons.
-
-  Say Y if you really want or need the debugging output, everyone else
-  says N.
-
-Network device support
-CONFIG_NETDEVICES
-  You can say N here if you don't intend to connect your Linux box to
-  any other computer at all or if all your connections will be over a
-  telephone line with a modem either via UUCP (UUCP is a protocol to
-  forward mail and news between unix hosts over telephone lines; read
-  the UUCP-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
-  account or a BBS, even using term (term is a program which gives you
-  almost full Internet connectivity if you have a regular dial up
-  shell account on some Internet connected Unix computer. Read
-  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
-
-  You'll have to say Y if your computer contains a network card that
-  you want to use under Linux (make sure you know its name because you
-  will be asked for it and read the Ethernet-HOWTO (especially if you
-  plan to use more than one network card under Linux)) or if you want
-  to use SLIP (Serial Line Internet Protocol is the protocol used to
-  send Internet traffic over telephone lines or null modem cables) or
-  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
-  and newer replacement for SLIP) or PLIP (Parallel Line Internet
-  Protocol is mainly used to create a mini network by connecting the
-  parallel ports of two local machines) or AX.25/KISS (protocol for
-  sending Internet traffic over amateur radio links).
-
-  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
-  Olaf Kirch's excellent and free book "Network Administrator's
-  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
-  unsure, say Y.
-
-Dummy net driver support
-CONFIG_DUMMY
-  This is essentially a bit-bucket device (i.e. traffic you send to
-  this device is consigned into oblivion) with a configurable IP
-  address. It is most commonly used in order to make your currently
-  inactive SLIP address seem like a real address for local programs.
-  If you use SLIP or PPP, you might want to say Y here. Since this
-  thing often comes in handy, the default is Y. It won't enlarge your
-  kernel either. What a deal. Read about it in the Network
-  Administrator's Guide, available from
-  <http://www.linuxdoc.org/docs.html#guide>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called dummy.o.  If you want to use more than one dummy
-  device at a time, you need to compile this driver as a module.
-  Instead of 'dummy', the devices will then be called 'dummy0',
-  'dummy1' etc.
-
-Bonding driver support
-CONFIG_BONDING
-  Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet
-  Channels together. This is called 'Etherchannel' by Cisco,
-  'Trunking' by Sun, and 'Bonding' in Linux.
-
-  If you have two Ethernet connections to some other computer, you can
-  make them behave like one double speed connection using this driver.
-  Naturally, this has to be supported at the other end as well, either
-  with a similar Bonding Linux driver, a Cisco 5500 switch or a
-  SunTrunking SunSoft driver.
-
-  This is similar to the EQL driver, but it merges Ethernet segments
-  instead of serial lines.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called bonding.o.
-
-SLIP (serial line) support
-CONFIG_SLIP
-  Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
-  connect to your Internet service provider or to connect to some
-  other local Unix box or if you want to configure your Linux box as a
-  Slip/CSlip server for other people to dial in. SLIP (Serial Line
-  Internet Protocol) is a protocol used to send Internet traffic over
-  serial connections such as telephone lines or null modem cables;
-  nowadays, the protocol PPP is more commonly used for this same
-  purpose.
-
-  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 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
-  <http://www.linuxdoc.org/docs.html#howto>, explains how to
-  configure SLIP. Note that you don't need this option if you just
-  want to run term (term is a program which gives you almost full
-  Internet connectivity if you have a regular dial up shell account on
-  some Internet connected Unix computer. Read
-  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). SLIP
-  support will enlarge your kernel by about 4 KB. If unsure, say N.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>. The module will be
-  called slip.o.
-
-CSLIP compressed headers
-CONFIG_SLIP_COMPRESSED
-  This protocol is faster than SLIP because it uses compression on the
-  TCP/IP headers (not on the data itself), but it has to be supported
-  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://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
-  CSLIP. This won't enlarge your kernel.
-
-Keepalive and linefill
-CONFIG_SLIP_SMART
-  Adds additional capabilities to the SLIP driver to support the
-  RELCOM line fill and keepalive monitoring. Ideal on poor quality
-  analogue lines.
-
-Six bit SLIP encapsulation
-CONFIG_SLIP_MODE_SLIP6
-  Just occasionally you may need to run IP over hostile serial
-  networks that don't pass all control characters or are only seven
-  bit. Saying Y here adds an extra mode you can use with SLIP:
-  "slip6". In this mode, SLIP will only send normal ASCII symbols over
-  the serial device. Naturally, this has to be supported at the other
-  end of the link as well. It's good enough, for example, to run IP
-  over the async ports of a Camtec JNT Pad. If unsure, say N.
-
-PPP (point-to-point protocol) support
-CONFIG_PPP
-  PPP (Point to Point Protocol) is a newer and better SLIP.  It serves
-  the same purpose: sending Internet traffic over telephone (and other
-  serial) lines.  Ask your access provider if they support it, because
-  otherwise you can't use it; most Internet access providers these
-  days support PPP rather than SLIP.
-
-  To use PPP, you need an additional program called pppd as described
-  in the PPP-HOWTO, available at
-  <http://www.linuxdoc.org/docs.html#howto>.  Make sure that you have
-  the version of pppd recommended in <file:Documentation/Changes>.
-  The PPP option enlarges your kernel by about 16 KB.
-
-  There are actually two versions of PPP: the traditional PPP for
-  asynchronous lines, such as regular analog phone lines, and
-  synchronous PPP which can be used over digital ISDN lines for
-  example.  If you want to use PPP over phone lines or other
-  asynchronous serial lines, you need to say Y (or M) here and also to
-  the next option, "PPP support for async serial ports".  For PPP over
-  synchronous lines, you should say Y (or M) here and to "Support
-  synchronous PPP", below.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  If you said Y to "Version information on all symbols" above, then
-  you cannot compile the PPP driver into the kernel; you can then only
-  compile it as a module.  The module will be called ppp_generic.o.
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.
-
-PPP multilink support
-CONFIG_PPP_MULTILINK
-  PPP multilink is a protocol (defined in RFC 1990) which allows you
-  to combine several (logical or physical) lines into one logical PPP
-  connection, so that you can utilize your full bandwidth.
-
-  This has to be supported at the other end as well and you need a
-  version of the pppd daemon which understands the multilink protocol.
-
-  If unsure, say N.
-
-PPP filtering
-CONFIG_PPP_FILTER
-  Say Y here if you want to be able to filter the packets passing over
-  PPP interfaces.  This allows you to control which packets count as
-  activity (i.e. which packets will reset the idle timer or bring up
-  a demand-dialled link) and which packets are to be dropped entirely.
-  You need to say Y here if you wish to use the pass-filter and
-  active-filter options to pppd.
-
-  If unsure, say N.
-
-PPP support for async serial ports
-CONFIG_PPP_ASYNC
-  Say Y (or M) here if you want to be able to use PPP over standard
-  asynchronous serial ports, such as COM1 or COM2 on a PC.  If you use
-  a modem (not a synchronous or ISDN modem) to contact your ISP, you
-  need this option.
-
-  This code is also available as a module (code which can be inserted
-  into and removed from the running kernel).  If you want to compile
-  it as a module, say M here and read <file:Documentation/modules.txt>.
-
-  If unsure, say Y.
-
-PPP support for sync tty ports
-CONFIG_PPP_SYNC_TTY
-  Say Y (or M) here if you want to be able to use PPP over synchronous
-  (HDLC) tty devices, such as the SyncLink adapter. These devices
-  are often used for high-speed leased lines like T1/E1.
-
-  This code is also available as a module (code which can be inserted
-  into and removed from the running kernel).  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-PPP Deflate compression
-CONFIG_PPP_DEFLATE
-  Support for the Deflate compression method for PPP, which uses the
-  Deflate algorithm (the same algorithm that gzip uses) to compress
-  each PPP packet before it is sent over the wire.  The machine at the
-  other end of the PPP link (usually your ISP) has to support the
-  Deflate compression method as well for this to be useful.  Even if
-  they don't support it, it is safe to say Y here.
-
-  This code is also available as a module (code which can be inserted
-  into and removed from the running kernel).  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-PPP BSD-Compress compression
-CONFIG_PPP_BSDCOMP
-  Support for the BSD-Compress compression method for PPP, which uses
-  the LZW compression method to compress each PPP packet before it is
-  sent over the wire. The machine at the other end of the PPP link
-  (usually your ISP) has to support the BSD-Compress compression
-  method as well for this to be useful. Even if they don't support it,
-  it is safe to say Y here.
-
-  The PPP Deflate compression method ("PPP Deflate compression",
-  above) is preferable to BSD-Compress, because it compresses better
-  and is patent-free.
-
-  Note that the BSD compression code will always be compiled as a
-  module; it is called bsd_comp.o and will show up in the directory
-  modules once you have said "make modules". If unsure, say N.
-
-PPP over Ethernet
-CONFIG_PPPOE
-  Support for PPP over Ethernet.
-
-  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/>.
-
-Wireless LAN (non-hamradio)
-CONFIG_NET_RADIO
-  Support for wireless LANs and everything having to do with radio,
-  but not with amateur radio or FM broadcasting.
-
-  Saying Y here also enables the Wireless Extensions (creates
-  /proc/net/wireless and enables ifconfig access). The Wireless
-  Extension is a generic API allowing a driver to expose to the user
-  space configuration and statistics specific to common Wireless LANs.
-  The beauty of it is that a single set of tool can support all the
-  variations of Wireless LANs, regardless of their type (as long as
-  the driver supports Wireless Extension). Another advantage is that
-  these parameters may be changed on the fly without restarting the
-  driver (or Linux). If you wish to use Wireless Extensions with
-  wireless PCMCIA (PC-) cards, you need to say Y here; you can fetch
-  the tools from
-  <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
-  Some user-level drivers for scarab devices which don't require
-  special kernel support are available from
-  <ftp://shadow.cabi.net/pub/Linux/>.
-
-STRIP (Metricom Starmode radio IP)
-CONFIG_STRIP
-  Say Y if you have a Metricom radio and intend to use Starmode Radio
-  IP. STRIP is a radio protocol developed for the MosquitoNet project
-  (on the WWW at <http://mosquitonet.stanford.edu/>) to send Internet
-  traffic using Metricom radios.  Metricom radios are small, battery
-  powered, 100kbit/sec packet radio transceivers, about the size and
-  weight of a cellular telephone. (You may also have heard them called
-  "Metricom modems" but we avoid the term "modem" because it misleads
-  many people into thinking that you can plug a Metricom modem into a
-  phone line and use it as a modem.)
-
-  You can use STRIP on any Linux machine with a serial port, although
-  it is obviously most useful for people with laptop computers. If you
-  think you might get a Metricom radio in the future, there is no harm
-  in saying Y to STRIP now, except that it makes the kernel a bit
-  bigger.
-
-  You can also compile this as a module ( = code which can be inserted
-  in and removed from the running kernel whenever you want), say M
-  here and read <file:Documentation/modules.txt>.  The module will be
-  called strip.o.
-
-AT&T WaveLAN & DEC RoamAbout DS support
-CONFIG_WAVELAN
-  The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is
-  a Radio LAN (wireless Ethernet-like Local Area Network) using the
-  radio frequencies 900 MHz and 2.4 GHz.
-
-  This driver support the ISA version of the WaveLAN card.  A separate
-  driver for the PCMCIA (PC-card) hardware is available in David
-  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-  for location).
-
-  If you want to use an ISA WaveLAN card under Linux, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. Some more specific
-  information is contained in
-  <file:Documentation/networking/wavelan.txt> and in the source code
-  <file:drivers/net/wavelan.p.h>.
-
-  You will also need the wireless tools package available from
-  <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-  Please read the man pages contained therein.
-
-  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 wavelan.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-Aironet Arlan 655 & IC2200 DS support
-CONFIG_ARLAN
-  Aironet makes Arlan, a class of wireless LAN adapters. These use the
-  www.Telxon.com chip, which is also used on several similar cards.
-  This driver is tested on the 655 and IC2200 series cards. Look at
-  <http://www.ylenurme.ee/~elmer/655/> for the latest information.
-
-  The driver is built as two modules, arlan and arlan-proc. The latter
-  is the /proc interface and is not needed most of time.
-
-  On some computers the card ends up in non-valid state after some
-  time. Use a ping-reset script to clear it.
-
-Aironet 4500/4800 series adapters
-CONFIG_AIRONET4500
-  www.aironet.com (recently bought by Cisco) makes these 802.11 DS
-  adapters.  Driver by Elmer Joandi (elmer@ylenurme.ee).
-
-  Say Y here if you have such an adapter, and then say Y below to
-  the option that applies to your particular type of card (PCI, ISA,
-  or PCMCIA).
-
-  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 aironet4500_core.o. If you want to
-  compile it as a module, say M here and read
-  <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.
-
-  quick config parameters:
-	SSID=tsunami - "The Password"
-	adhoc=1  	there are no Access Points around
-	master=1 	Adhoc master (the one who creates network
-                        sync)
-	slave=1		Adhoc slave (btw, it is still forming own net
-			sometimes, and has problems with firmware...
-			change IbssJoinNetTimeout from /proc...)
-	channel=1..? 	meaningful in adhoc mode
-
-  If you have problems with screwing up card, both_bap_lock=1 is a
-  conservative value (performance hit 15%).
-
-  All other parameters can be set via the proc interface.
-
-Aironet 4500/4800 ISA/PCI/PNP/365 support
-CONFIG_AIRONET4500_NONCS
-  If you have an ISA, PCI or PCMCIA Aironet 4500/4800 wireless LAN
-  card, say Y here, and then also to the options below that apply
-  to you.
-
-  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 aironet4500_card.o.  If you want to
-  compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-Aironet 4500/4800 PNP support
-CONFIG_AIRONET4500_PNP
-  If you have an ISA Aironet 4500/4800 card which you want to use in
-  PnP (Plug and Play) mode, say Y here. This is the recommended mode
-  for ISA cards. Remember however to enable the PnP jumper on the
-  board if you say Y here.
-
-Aironet 4500/4800 PCI support
-CONFIG_AIRONET4500_PCI
-  If you have an PCI Aironet 4500/4800 card, say Y here.
-
-Aironet 4500/4800 ISA broken support
-CONFIG_AIRONET4500_ISA
-  If you have an ISA Aironet 4500/4800 card which you want to run in
-  non-PnP mode, say Y here. This is not recommended and does not work
-  correctly at this point. Say N.
-
-Aironet 4500/4800 I365 broken support
-CONFIG_AIRONET4500_I365
-  If you have a PCMCIA Aironet 4500/4800 card which you want to use
-  without the standard PCMCIA cardservices provided by the pcmcia-cs
-  package, say Y here. This is not recommended, so say N.
-
-Aironet 4500/4800 PCMCIA support
-CONFIG_AIRONET4500_CS
-  Say Y here if you have a PCMCIA Aironet 4500/4800 card which you
-  want to use with the standard PCMCIA cardservices provided by the
-  pcmcia-cs package.
-
-  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 aironet4500_cs.o. If you want to
-  compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-Aironet 4500/4800 PROC interface
-CONFIG_AIRONET4500_PROC
-  If you say Y here (and to the "/proc file system" below), you will
-  be able to configure your Aironet card via the
-  /proc/sys/aironet4500 interface.
-
-  Additional info: look in <file:drivers/net/aironet4500_rid.c>.
-
-  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 aironet4500_proc.o. If you want to
-  compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-  NOTE: the proc interface uses a lot of memory, so it is recommended
-        to compile it as a module and remove the module after
-        configuration.
-
-LAPB over Ethernet driver
-CONFIG_LAPBETHER
-  This is a driver for a pseudo device (typically called /dev/lapb0)
-  which allows you to open an LAPB point-to-point connection to some
-  other computer on your Ethernet network.  In order to do this, you
-  need to say Y or M to the driver for your Ethernet card as well as
-  to "LAPB Data Link Driver".
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called lapbether.o.  If unsure, say N.
-
-X.25 async driver
-CONFIG_X25_ASY
-  This is a driver for sending and receiving X.25 frames over regular
-  asynchronous serial lines such as telephone lines equipped with
-  ordinary modems.  Experts should note that this driver doesn't
-  currently comply with the asynchronous HDLS framing protocols in
-  CCITT recommendation X.25.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called x25_asy.o.  If unsure, say N.
-
-PCMCIA network device support
-CONFIG_NET_PCMCIA
-  Say Y if you would like to include support for any PCMCIA or CardBus
-  network adapters, then say Y to the driver for your particular card
-  below.  PCMCIA- or PC-cards are credit-card size devices often used
-  with laptops computers; CardBus is the newer and faster version of
-  PCMCIA.
-
-  To use your PC-cards, you will need supporting software from David
-  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-  for location).  You also want to check out the PCMCIA-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  If unsure, say N.
-
-3Com 3c589 PCMCIA support
-CONFIG_PCMCIA_3C589
-  Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA
-  (PC-card) Ethernet card to your computer.
-
-  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 3c589_cs.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>. If
-  unsure, say N.
-
-3Com 3c574 PCMCIA support
-CONFIG_PCMCIA_3C574
-  Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA
-  (PC-card) Fast Ethernet card to your computer.
-
-  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 3c574_cs.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.  If
-  unsure, say N.
-
-Fujitsu FMV-J18x PCMCIA support
-CONFIG_PCMCIA_FMVJ18X
-  Say Y here if you intend to attach a Fujitsu FMV-J18x or compatible
-  PCMCIA (PC-card) Ethernet card to your computer.
-
-  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 fmvj18x_cs.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-  If unsure, say N.
-
-NE2000 compatible PCMCIA support
-CONFIG_PCMCIA_PCNET
-  Say Y here if you intend to attach an NE2000 compatible PCMCIA
-  (PC-card) Ethernet or Fast Ethernet card to your computer.
-
-  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 pcnet_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
-  PCMCIA (PC-card) Ethernet card to your computer.
-
-  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 nmclan_cs.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.  If
-  unsure, say N.
-
-SMC 91Cxx PCMCIA support
-CONFIG_PCMCIA_SMC91C92
-  Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA
-  (PC-card) Ethernet or Fast Ethernet card to your computer.
-
-  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 smc91c92_cs.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-  If unsure, say N.
-
-Xircom 16-bit PCMCIA support
-CONFIG_PCMCIA_XIRC2PS
-  Say Y here if you intend to attach a Xircom 16-bit PCMCIA (PC-card)
-  Ethernet or Fast Ethernet card to your computer.
-
-  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 xirc2ps_cs.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-  If unsure, say N.
-
-COM20020 ARCnet PCMCIA support
-CONFIG_ARCNET_COM20020_CS
-  Say Y here if you intend to attach this type of ARCnet PCMCIA card
-  to your computer.
-
-  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 com20020_cs.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-  If unsure, say N.
-
-IBM PCMCIA Token Ring adapter support
-CONFIG_PCMCIA_IBMTR
-  Say Y here if you intend to attach this type of Token Ring PCMCIA
-  card to your computer. You then also need to say Y to "Token Ring
-  driver support".
-
-  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 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
-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
-  as with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and
-  ASIX.
-
-  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 xircom_tulip_cb.o.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>. If unsure, say N.
-
-PCMCIA Wireless LAN
-CONFIG_NET_PCMCIA_RADIO
-  Say Y here if you would like to use a PCMCIA (PC-card) device to
-  connect to a wireless local area network. Then say Y to the driver
-  for your particular card below.
-
-  To use your PC-cards, you will need supporting software from David
-  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-  for location). You also want to check out the PCMCIA-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-Hermes chipset 802.11b support (Orinoco/Prism2/Symbol cards)
-CONFIG_HERMES
-  A driver for 802.11b wireless cards based based on the "Hermes" or
-  Intersil HFA384x (Prism 2) MAC controller.  This includes the vast
-  majority of the PCMCIA 802.11b cards (which are nearly all rebadges)
-  - except for the Cisco/Aironet cards.  Cards supported include the
-  Apple Airport (not a PCMCIA card), WavelanIEEE/Orinoco,
-  Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya,
-  IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear
-  MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel
-  PRO/Wireless, and Symbol Spectrum24 High Rate amongst others.
-
-  This option includes the guts of the driver, but in order to
-  actually use a card you will also need to enable support for PCMCIA
-  Hermes cards, PLX9052 based PCI adaptors or the Apple Airport below.
-
-  You will also very likely also need the Wireless Tools in order to
-  configure your card and that /etc/pcmcia/wireless.opts works :
-  <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
-
-Hermes 802.11b in PLX9052 based PCI adaptor support
-CONFIG_PLX_HERMES
-  Enable support for PCMCIA cards supported by the "Hermes" (aka
-  orinoco_cs) driver when used in PLX9052 based PCI adaptors.  These
-  adaptors are not a full PCMCIA controller but act as a more limited
-  PCI <-> PCMCIA bridge.  Several vendors sell such adaptors so that
-  802.11b PCMCIA cards can be used in desktop machines.  The Netgear
-  MA301 is such an adaptor.
-
-  Support for these adaptors is so far still incomplete and buggy.
-  You have been warned.
-
-Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)
-CONFIG_PCMCIA_HERMES
-  A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
-  as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
-  EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and
-  others).  It should also be usable on various Prism II based cards
-  such as the Linksys, D-Link and Farallon Skyline.  It should also
-  work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN.
-
-  To use your PC-cards, you will need supporting software from David
-  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-  for location).  You also want to check out the PCMCIA-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  You will also very likely also need the Wireless Tools in order to
-  configure your card and that /etc/pcmcia/wireless.opts works:
-  <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
-Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards
-CONFIG_AIRO
-  This is the standard Linux driver to support Cisco/Aironet ISA and
-  PCI 802.11 wireless cards.
-  It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X
-  - with or without encryption) as well as card before the Cisco
-  aquisition (Aironet 4500, Aironet 4800, Aironet 4800B).
-
-  This driver support both the standard Linux Wireless Extensions
-  and Cisco proprietary API, so both the Linux Wireless Tools and the
-  Cisco Linux utilities can be used to configure the card.
-
-  The driver can be compiled as a module and will be named "airo.o".
-
-Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards
-CONFIG_AIRO_CS
-  This is the standard Linux driver to support Cisco/Aironet PCMCIA
-  802.11 wireless cards.  This driver is the same as the Aironet
-  driver part of the Linux Pcmcia package.
-  It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X
-  - with or without encryption) as well as card before the Cisco
-  aquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also
-  supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom
-  802.11b cards.
-
-  This driver support both the standard Linux Wireless Extensions
-  and Cisco proprietary API, so both the Linux Wireless Tools and the
-  Cisco Linux utilities can be used to configure the card.
-
-  To use your PC-cards, you will need supporting software from David
-  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-  for location).  You also want to check out the PCMCIA-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-Aviator/Raytheon 2.4MHz wireless support
-CONFIG_PCMCIA_RAYCS
-  Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
-  (PC-card) wireless Ethernet networking card to your computer.
-  Please read the file <file:Documentation/networking/ray_cs.txt> for
-  details.
-
-  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 ray_cs.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.  If
-  unsure, say N.
-
-Apple Airport support (built-in)
-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. This is essentially a Lucent Orinoco card with 
-  a non-standard interface
-
-Xircom Netwave AirSurfer wireless support
-CONFIG_PCMCIA_NETWAVE
-  Say Y here if you intend to attach this type of PCMCIA (PC-card)
-  wireless Ethernet networking card to your computer.
-
-  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 netwave_cs.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-  If unsure, say N.
-
-AT&T/Lucent Wavelan wireless support
-CONFIG_PCMCIA_WAVELAN
-  Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA
-  (PC-card) wireless Ethernet networking card to your computer.  This
-  driver is for the non-IEEE-802.11 Wavelan cards.
-
-  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 wavelan_cs.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-  If unsure, say N.
-
-PLIP (parallel port) support
-CONFIG_PLIP
-  PLIP (Parallel Line Internet Protocol) is used to create a
-  reasonably fast mini network consisting of two (or, rarely, more)
-  local machines.  A PLIP link from a Linux box is a popular means to
-  install a Linux distribution on a machine which doesn't have a
-  CD-ROM drive (a minimal system has to be transferred with floppies
-  first). The kernels on both machines need to have this PLIP option
-  enabled for this to work.
-
-  The PLIP driver has two modes, mode 0 and mode 1.  The parallel
-  ports (the connectors at the computers with 25 holes) are connected
-  with "null printer" or "Turbo Laplink" cables which can transmit 4
-  bits at a time (mode 0) or with special PLIP cables, to be used on
-  bidirectional parallel ports only, which can transmit 8 bits at a
-  time (mode 1); you can find the wiring of these cables in
-  <file:Documentation/networking/PLIP.txt>.  The cables can be up to
-  15m long.  Mode 0 works also if one of the machines runs DOS/Windows
-  and has some PLIP software installed, e.g. the Crynwr PLIP packet
-  driver (<http://oak.oakland.edu/simtel.net/msdos/pktdrvr-pre.html>)
-  and winsock or NCSA's telnet.
-
-  If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well
-  as the NET-3-HOWTO, both available from
-  <http://www.linuxdoc.org/docs.html#howto>.  Note that the PLIP
-  protocol has been changed and this PLIP driver won't work together
-  with the PLIP support in Linux versions 1.0.x.  This option enlarges
-  your kernel by about 8 KB.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  The module will be
-  called plip.o.  If unsure, say Y or M, in case you buy a laptop
-  later.
-
-EQL (serial line load balancing) support
-CONFIG_EQUALIZER
-  If you have two serial connections to some other computer (this
-  usually requires two modems and two telephone lines) and you use
-  SLIP (the protocol for sending Internet traffic over telephone
-  lines) or PPP (a better SLIP) on them, you can make them behave like
-  one double speed connection using this driver.  Naturally, this has
-  to be supported at the other end as well, either with a similar EQL
-  Linux driver or with a Livingston Portmaster 2e.
-
-  Say Y if you want this and read
-  <file:Documentation/networking/eql.txt>.  You may also want to read
-  section 6.2 of the NET-3-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called eql.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.  If
-  unsure, say N.
-
-Universal TUN/TAP device driver support
-CONFIG_TUN
-  TUN/TAP provides packet reception and transmission for user space
-  programs.  It can be viewed as a simple Point-to-Point or Ethernet
-  device, which instead of receiving packets from a physical media,
-  receives them from user space program and instead of sending packets
-  via physical media writes them to the user space program.
-
-  When a program opens /dev/net/tun, driver creates and registers
-  corresponding net device tunX or tapX.  After a program closed above
-  devices, driver will automatically delete tunXX or tapXX device and
-  all routes corresponding to it.
-
-  Please read <file:Documentation/networking/tuntap.txt> for more
-  information.
-
-  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 tun.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-  If you don't know what to use this for, you don't need it.
-
-Ethertap network tap (OBSOLETE)
-CONFIG_ETHERTAP
-  If you say Y here (and have said Y to "Kernel/User network link
-  driver", above) and create a character special file /dev/tap0 with
-  major number 36 and minor number 16 using mknod ("man mknod"), you
-  will be able to have a user space program read and write raw
-  Ethernet frames from/to that special file.  tap0 can be configured
-  with ifconfig and route like any other Ethernet device but it is not
-  connected to any physical LAN; everything written by the user to
-  /dev/tap0 is treated by the kernel as if it had come in from a LAN
-  to the device tap0; everything the kernel wants to send out over the
-  device tap0 can instead be read by the user from /dev/tap0: the user
-  mode program replaces the LAN that would be attached to an ordinary
-  Ethernet device. Please read the file
-  <file:Documentation/networking/ethertap.txt> for more information.
-
-  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 ethertap.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-  If you don't know what to use this for, you don't need it.
-
-Sealevel Systems 4021 support
-CONFIG_SEALEVEL_4021
-  This is a driver for the Sealevel Systems ACB 56 serial I/O adapter.
-
-  This driver can only be compiled as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  If you want to do that, say M here. The module will be called
-  sealevel.o.
-
-SyncLink HDLC/SYNCPPP support
-CONFIG_SYNCLINK_SYNCPPP
-  Enables HDLC/SYNCPPP support for the SyncLink WAN driver.
-  Normally the SyncLink WAN driver works with the main PPP
-  driver (ppp.c) and pppd program. HDLC/SYNCPPP support allows use
-  of the Cisco HDLC/PPP driver (syncppp.c).
-  The SyncLink WAN driver (in character devices) must also be enabled.
-
-FarSync T-Series support
-CONFIG_FARSYNC
-  This driver supports the FarSync T-Series X.21 (and V.35/V.24) cards
-  from FarSite Communications Ltd.
-  Synchronous communication is supported on all ports at speeds up to
-  8Mb/s (128K on V.24) using synchronous PPP or Cisco HDLC.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want)
-  say M here and read <file:Documentation/modules.txt>.
-  The module will be called farsync.o and if you want the module to be
-  automatically loaded when the interface is referenced then you
-  should add "alias syncX farsync" to /etc/modules.conf for each
-  interface, where X is 0, 1, 2, ...
-
-Frame Relay (DLCI) support
-CONFIG_DLCI
-  This is support for the frame relay protocol; frame relay is a fast
-  low-cost way to connect to a remote Internet access provider or to
-  form a private wide area network. The one physical line from your
-  box to the local "switch" (i.e. the entry point to the frame relay
-  network, usually at the phone company) can carry several logical
-  point-to-point connections to other computers connected to the frame
-  relay network. For a general explanation of the protocol, check out
-  <http://www.frforum.com/> on the WWW. To use frame relay, you need
-  supporting hardware (called FRAD) and certain programs from the
-  net-tools package as explained in
-  <file:Documentation/networking/framerelay.txt>.
-
-  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 dlci.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Max open DLCI
-CONFIG_DLCI_COUNT
-  This is the maximal number of logical point-to-point frame relay
-  connections (the identifiers of which are called DCLIs) that
-  the driver can handle. The default is probably fine.
-
-Max DLCI per device
-CONFIG_DLCI_MAX
-  You can specify here how many logical point-to-point frame relay
-  connections (the identifiers of which are called DCLIs) should be
-  handled by each of your hardware frame relay access devices. Go with
-  the default.
-
-SDLA (Sangoma S502/S508) support
-CONFIG_SDLA
-  Say Y here if you need a driver for the Sangoma S502A, S502E, and
-  S508 Frame Relay Access Devices. These are multi-protocol cards, but
-  only frame relay is supported by the driver at this time. Please
-  read <file:Documentation/framerelay.txt>.
-
-  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 sdla.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Acorn Econet/AUN protocols
-CONFIG_ECONET
-  Econet is a fairly old and slow networking protocol mainly used by
-  Acorn computers to access file and print servers. It uses native
-  Econet network cards. AUN is an implementation of the higher level
-  parts of Econet that runs over ordinary Ethernet connections, on
-  top of the UDP packet protocol, which in turn runs on top of the
-  Internet protocol IP.
-
-  If you say Y here, you can choose with the next two options whether
-  to send Econet/AUN traffic over a UDP Ethernet connection or over
-  a native Econet network card.
-
-  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 econet.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-AUN over UDP
-CONFIG_ECONET_AUNUDP
-  Say Y here if you want to send Econet/AUN traffic over a UDP
-  connection (UDP is a packet based protocol that runs on top of the
-  Internet protocol IP) using an ordinary Ethernet network card.
-
-Native Econet
-CONFIG_ECONET_NATIVE
-  Say Y here if you have a native Econet network card installed in
-  your computer.
-
-WAN router
-CONFIG_WAN_ROUTER
-  Wide Area Networks (WANs), such as X.25, frame relay and leased
-  lines, are used to interconnect Local Area Networks (LANs) over vast
-  distances with data transfer rates significantly higher than those
-  achievable with commonly used asynchronous modem connections.
-  Usually, a quite expensive external device called a `WAN router' is
-  needed to connect to a WAN.
-
-  As an alternative, WAN routing can be built into the Linux kernel.
-  With relatively inexpensive WAN interface cards available on the
-  market, a perfectly usable router can be built for less than half
-  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/>.
-  Read <file:Documentation/networking/wan-router.txt> for more
-  information.
-
-  The WAN routing support is also available as a module called
-  wanrouter.o ( = 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>.
-
-  If unsure, say N.
-
-Fast switching (read help!)
-CONFIG_NET_FASTROUTE
-  Saying Y here enables direct NIC-to-NIC (NIC = Network Interface
-  Card) data transfers on the local network, which is fast.
-
-  IMPORTANT NOTE: This option is NOT COMPATIBLE with "Network packet
-  filtering" (CONFIG_NETFILTER). Say N here if you say Y there.
-
-  However, it will work with all options in the "Advanced router"
-  section (except for "Use TOS value as routing key" and
-  "Use FWMARK value as routing key").
-
-  At the moment, few devices support fast switching (tulip is one of
-  them, a modified 8390 driver can be found at
-  <ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz>).
-
-  If unsure, say N.
-
-Forwarding between high speed interfaces
-CONFIG_NET_HW_FLOWCONTROL
-  This option enables NIC (Network Interface Card) hardware throttling
-  during periods of extremal congestion. At the moment only a couple
-  of device drivers support it (really only one -- tulip, a modified
-  8390 driver can be found at
-  <ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz>).
-
-  Really, this option is applicable to any machine attached to a fast
-  enough network, and even a 10 Mb NIC is able to kill a not very slow
-  box, such as a 120MHz Pentium.
-
-  However, do not say Y here if you did not experience any serious
-  problems.
-
-QoS and/or fair queueing
-CONFIG_NET_SCHED
-  When the kernel has several packets to send out over a network
-  device, it has to decide which ones to send first, which ones to
-  delay, and which ones to drop. This is the job of the packet
-  scheduler, and several different algorithms for how to do this
-  "fairly" have been proposed.
-
-  If you say N here, you will get the standard packet scheduler, which
-  is a FIFO (first come, first served). If you say Y here, you will be
-  able to choose from among several alternative algorithms which can
-  then be attached to different network devices. This is useful for
-  example if some of your network devices are real time devices that
-  need a certain minimum data flow rate, or if you need to limit the
-  maximum data flow rate for traffic which matches specified criteria.
-  This code is considered to be experimental.
-
-  To administer these schedulers, you'll need the user-level utilities
-  from the package iproute2+tc at <ftp://ftp.inr.ac.ru/ip-routing/>.
-  That package also contains some documentation; for more, check out
-  <http://snafu.freedom.org/linux2.2/iproute-notes.html>.
-
-  This Quality of Service (QoS) support will enable you to use
-  Differentiated Services (diffserv) and Resource Reservation Protocol
-  (RSVP) on your Linux router if you also say Y to "QoS support",
-  "Packet classifier API" and to some classifiers below. Documentation
-  and software is at <http://icawww1.epfl.ch/linux-diffserv/>.
-
-  If you say Y here and to "/proc file system" below, you will be able
-  to read status information about packet schedulers from the file
-  /proc/net/psched.
-
-  The available schedulers are listed in the following questions; you
-  can say Y to as many as you like. If unsure, say N now.
-
-CBQ packet scheduler
-CONFIG_NET_SCH_CBQ
-  Say Y here if you want to use the Class-Based Queueing (CBQ) packet
-  scheduling algorithm for some of your network devices.  This
-  algorithm classifies the waiting packets into a tree-like hierarchy
-  of classes; the leaves of this tree are in turn scheduled by
-  separate algorithms (called "disciplines" in this context).
-
-  See the top of <file:net/sched/sch_cbq.c> for references about the
-  CBQ algorithm.
-
-  CBQ is a commonly used scheduler, so if you're unsure, you should
-  say Y here. Then say Y to all the queueing algorithms below that you
-  want to use as CBQ disciplines.  Then say Y to "Packet classifier
-  API" and say Y to all the classifiers you want to use; a classifier
-  is a routine that allows you to sort your outgoing traffic into
-  classes based on a certain criterion.
-
-  This code is also available as a module called sch_cbq.o ( = 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>.
-
-CSZ packet scheduler
-CONFIG_NET_SCH_CSZ
-  Say Y here if you want to use the Clark-Shenker-Zhang (CSZ) packet
-  scheduling algorithm for some of your network devices.  At the
-  moment, this is the only algorithm that can guarantee service for
-  real-time applications (see the top of <file:net/sched/sch_csz.c>
-  for details and references about the algorithm).
-
-  Note: this scheduler is currently broken.
-
-  This code is also available as a module called sch_csz.o ( = 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>.
-
-ATM pseudo-scheduler
-CONFIG_NET_SCH_ATM
-  Say Y here if you want to use the ATM pseudo-scheduler.  This
-  provides a framework for invoking classifiers (aka "filters"), which
-  in turn select classes of this queuing discipline.  Each class maps
-  the flow(s) it is handling to a given virtual circuit (see the top of
-  <file:net/sched/sch_atm.c>).
-
-  This code is also available as a module called sch_atm.o ( = 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>.
-
-The simplest PRIO pseudo-scheduler
-CONFIG_NET_SCH_PRIO
-  Say Y here if you want to use an n-band priority queue packet
-  "scheduler" for some of your network devices or as a leaf discipline
-  for the CBQ scheduling algorithm. If unsure, say Y.
-
-  This code is also available as a module called sch_prio.o ( = 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>.
-
-Diffserv field marker
-CONFIG_NET_SCH_DSMARK
-  Say Y if you want to schedule packets avccording to the
-  Differentiated Services architecture proposed in RFC 2475.
-  Technical information on this method, with pointers to associated
-  RFCs, is available at <http://www.gta.ufrj.br/diffserv/>.
-
-  This code is also available as a module called sch_dsmark.o ( = 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>.
-
-GRED queue
-CONFIG_NET_SCH_GRED
-  Say Y here if you want to use the Generic Random Early Detection
-  (RED) packet scheduling algorithm for some of your network devices
-  (see the top of <file:net/sched/sch_red.c> for details and
-  references about the algorithm).
-
-  This code is also available as a module called sch_gred.o ( = 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>.
-
-RED queue
-CONFIG_NET_SCH_RED
-  Say Y here if you want to use the Random Early Detection (RED)
-  packet scheduling algorithm for some of your network devices (see
-  the top of <file:net/sched/sch_red.c> for details and references
-  about the algorithm).
-
-  This code is also available as a module called sch_red.o ( = 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>.
-
-SFQ queue
-CONFIG_NET_SCH_SFQ
-  Say Y here if you want to use the Stochastic Fairness Queueing (SFQ)
-  packet scheduling algorithm for some of your network devices or as a
-  leaf discipline for the CBQ scheduling algorithm (see the top of
-  <file:net/sched/sch_sfq.c> for details and references about the SFQ
-  algorithm).
-
-  This code is also available as a module called sch_sfq.o ( = 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>.
-
-TEQL queue
-CONFIG_NET_SCH_TEQL
-  Say Y here if you want to use the True Link Equalizer (TLE) packet
-  scheduling algorithm for some of your network devices or as a leaf
-  discipline for the CBQ scheduling algorithm. This queueing
-  discipline allows the combination of several physical devices into
-  one virtual device. (see the top of <file:net/sched/sch_teql.c> for
-  details).
-
-  This code is also available as a module called sch_teql.o ( = 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>.
-
-TBF queue
-CONFIG_NET_SCH_TBF
-  Say Y here if you want to use the Simple Token Bucket Filter (TBF)
-  packet scheduling algorithm for some of your network devices or as a
-  leaf discipline for the CBQ scheduling algorithm (see the top of
-  <file:net/sched/sch_tbf.c> for a description of the TBF algorithm).
-
-  This code is also available as a module called sch_tbf.o ( = 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>.
-
-Ingress Qdisc
-CONFIG_NET_SCH_INGRESS
-  If you say Y here, you will be able to police incoming bandwidth
-  and drop packets when this bandwidth exceeds your desired rate.
-  If unsure, say Y.
-
-  This code is also available as a module called cls_ingress.o
-  ( = 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>.
-
-QoS support
-CONFIG_NET_QOS
-  Say Y here if you want to include Quality Of Service scheduling
-  features, which means that you will be able to request certain
-  rate-of-flow limits for your network devices.
-
-  This Quality of Service (QoS) support will enable you to use
-  Differentiated Services (diffserv) and Resource Reservation Protocol
-  (RSVP) on your Linux router if you also say Y to "Packet classifier
-  API" and to some classifiers below. Documentation and software is at
-  <http://icawww1.epfl.ch/linux-diffserv/>.
-
-  Note that the answer to this question won't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about QoS support.
-
-Rate estimator
-CONFIG_NET_ESTIMATOR
-  In order for Quality of Service scheduling to work, the current
-  rate-of-flow for a network device has to be estimated; if you say Y
-  here, the kernel will do just that.
-
-Packet classifier API
-CONFIG_NET_CLS
-  The CBQ scheduling algorithm requires that network packets which are
-  scheduled to be sent out over a network device be classified
-  according to some criterion. If you say Y here, you will get a
-  choice of several different packet classifiers with the following
-  questions.
-
-  This will enable you to use Differentiated Services (diffserv) and
-  Resource Reservation Protocol (RSVP) on your Linux router.
-  Documentation and software is at
-  <http://icawww1.epfl.ch/linux-diffserv/>.
-
-Traffic policing (needed for in/egress)
-CONFIG_NET_CLS_POLICE
-  Say Y to support traffic policing (bandwidth limits).  Needed for
-  ingress and egress rate limiting.
-
-TC index classifier
-CONFIG_NET_CLS_TCINDEX
-  If you say Y here, you will be able to classify outgoing packets
-  according to the tc_index field of the skb. You will want this
-  feature if you want to implement Differentiated Services using
-  sch_dsmark. If unsure, say Y.
-
-  This code is also available as a module called cls_tcindex.o
-  ( = 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>.
-
-Routing tables based classifier
-CONFIG_NET_CLS_ROUTE4
-  If you say Y here, you will be able to classify outgoing packets
-  according to the route table entry they matched. If unsure, say Y.
-
-  This code is also available as a module called cls_route.o ( = 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>.
-
-Firewall based classifier
-CONFIG_NET_CLS_FW
-  If you say Y here, you will be able to classify outgoing packets
-  according to firewall criteria you specified.
-
-  This code is also available as a module called cls_fw.o ( = 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>.
-
-U32 classifier
-CONFIG_NET_CLS_U32
-  If you say Y here, you will be able to classify outgoing packets
-  according to their destination address. If unsure, say Y.
-
-  This code is also available as a module called cls_u32.o ( = 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>.
-
-Special RSVP classifier
-CONFIG_NET_CLS_RSVP
-  The Resource Reservation Protocol (RSVP) permits end systems to
-  request a minimum and maximum data flow rate for a connection; this
-  is important for real time data such as streaming sound or video.
-
-  Say Y here if you want to be able to classify outgoing packets based
-  on their RSVP requests.
-
-  This code is also available as a module called cls_rsvp.o ( = 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>.
-
-Special RSVP classifier for IPv6
-CONFIG_NET_CLS_RSVP6
-  The Resource Reservation Protocol (RSVP) permits end systems to
-  request a minimum and maximum data flow rate for a connection; this
-  is important for real time data such as streaming sound or video.
-
-  Say Y here if you want to be able to classify outgoing packets based
-  on their RSVP requests and you are using the new Internet Protocol
-  IPv6 as opposed to the older and more common IPv4.
-
-  This code is also available as a module called cls_rsvp6.o ( = 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>.
-
-Network code profiler
-CONFIG_NET_PROFILE
-  If you say Y here and to "/proc file system support" below, some
-  obscure and undocumented information about the network code's
-  performance will be written to /proc/net/profile. If you don't know
-  what it is about, you don't need it: say N.
-
-Wan interfaces support
-CONFIG_WAN
-  Wide Area Networks (WANs), such as X.25, frame relay and leased
-  lines, are used to interconnect Local Area Networks (LANs) over vast
-  distances with data transfer rates significantly higher than those
-  achievable with commonly used asynchronous modem connections.
-  Usually, a quite expensive external device called a `WAN router' is
-  needed to connect to a WAN.
-
-  As an alternative, a relatively inexpensive WAN interface card can
-  allow your Linux box to directly connect to a WAN. If you have one
-  of those cards and wish to use it under Linux, say Y here and also
-  to the WAN driver for your card, below.
-
-  If unsure, say N.
-
-Comtrol Hostess SV-11 support
-CONFIG_HOSTESS_SV11
-  This is a network card for low speed synchronous serial links, at
-  up to 256Kbps. It supports both PPP and Cisco HDLC.
-
-  At this point, the driver can only be compiled as a module.
-
-COSA/SRP sync serial board support
-CONFIG_COSA
-  This is a driver for COSA and SRP synchronous serial boards. These
-  boards allow to connect synchronous serial devices (for example
-  base-band modems, or any other device with the X.21, V.24, V.35 or
-  V.36 interface) to your Linux box. The cards can work as the
-  character device, synchronous PPP network device, or the Cisco HDLC
-  network device.
-
-  To actually use the COSA or SRP board, you will need user-space
-  utilities for downloading the firmware to the cards and to set them
-  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/wan/cosa.c> for details about the cards and the driver
-  itself.
-
-  The driver will be compiled as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called cosa.o. For general information about
-  modules read <file:Documentation/modules.txt>.
-
-Etinc PCISYNC serial board support
-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/>
-  for further informations about the driver and his configuration.
-
-  The driver will be compiled as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called dscc4.o. For general information about
-  modules read <file:Documentation/modules.txt>.
-
-LanMedia Corp. serial boards (SSI/V.35, T1/E1, HSSI, T3)
-CONFIG_LANMEDIA
-  This is a driver for the following Lan Media family of serial
-  boards.
-
-  LMC 1000 board allows you to connect synchronous serial devices (for
-  example base-band modems, or any other device with the X.21, V.24,
-  V.35 or V.36 interface) to your Linux box.
-
-  LMC 1200 with on board DSU board allows you to connect your Linux
-  box dirrectly to a T1 or E1 circuit.
-
-  LMC 5200 board provides a HSSI interface capable of running up to
-  52 mbits per second.
-
-  LMC 5245 board connects directly to a T3 circuit saving the
-  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/>.
-
-  This code is also available as a module called lmc.o ( = 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>.
-
-Fibre Channel driver support
-CONFIG_NET_FC
-  Fibre Channel is a high speed serial protocol mainly used to connect
-  large storage devices to the computer; it is compatible with and
-  intended to replace SCSI.
-
-  If you intend to use Fibre Channel, you need to have a Fibre channel
-  adaptor card in your computer; say Y here and to the driver for your
-  adaptor below. You also should have said Y to "SCSI support" and
-  "SCSI generic support".
-
-Interphase 5526 Tachyon chipset based adaptor support
-CONFIG_IPHASE5526
-  Say Y here if you have a Fibre Channel adaptor of this kind.
-
-  The 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 iph5526.o. For general information about
-  modules read <file:Documentation/modules.txt>.
-
-Red Creek Hardware VPN
-CONFIG_RCPCI
-  This is a driver for hardware which provides a Virtual Private
-  Network (VPN). Say Y if you have it.
-
-  This code is also available as a module called rcpci.o ( = 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>.
-
-Granch SBNI12 Leased Line adapter driver
-CONFIG_SBNI
-  This is a driver for ISA SBNI12-xx cards which are low cost
-  alternatives to leased line modems. Say Y if you want to insert
-  the driver into the kernel or say M to compile it as a module (the
-  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
-  can send email to sbni@granch.ru.
-
-  Say N if unsure.
-
-SBNI Adapters Multiline feature
-CONFIG_SBNI_MULTILINE
-  Schedule traffic for some parallel lines, via SBNI12 adapters.
-  If you have two computers connected with two parallel lines it's
-  possible to increase transfer rate nearly twice. You should have
-  a program named 'sbniconfig' to configure adapters.
-
-  Say N if unsure.
-
-WAN router drivers
-CONFIG_WAN_ROUTER_DRIVERS
-  If you have a WAN interface card and you want your Linux box to act
-  as a WAN router, thereby connecting you Local Area Network to the
-  outside world over the WAN connection, say Y here and then to the
-  driver for your card below. In addition, you need to say Y to "Wan
-  Router".
-
-  You will need the wan-tools package which is available from
-  <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
-  kernel: saying N will just cause the configurator to skip all
-  the questions about WAN router drivers. If unsure, say N.
-
-Sangoma WANPIPE(tm) multiprotocol cards
-CONFIG_VENDOR_SANGOMA
-  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
-  S508-ISA.  These cards support
-
-    - X.25, Frame Relay, PPP, Cisco HDLC protocols.
-
-    - API support for protocols like HDLC (LAPB),
-      HDLC Streaming, X.25, Frame Relay and BiSync.
-
-    - Ethernet Bridging over Frame Relay protocol.
-
-    - MULTILINK PPP
-
-    - Async PPP (Modem Dialup)
-
-  If you have one or more of these cards, say M to this option; you
-  may then also want to read the file
-  <file:Documentation/networking/wanpipe.txt>.  The next questions
-  will ask you about the protocols you want the driver to support.
-
-  The driver will be compiled as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called wanpipe.o.  For general information about
-  modules read <file:Documentation/modules.txt>.
-
-WANPIPE X.25 support
-CONFIG_WANPIPE_X25
-  Say Y to this option if you are planning to connect a WANPIPE card
-  to an X.25 network.  Note, this feature also includes the X.25 API
-  support used to develope custom applications over the X.25 protocol.
-  If you say N, the X.25 support will not be included in the driver.
-  The X.25 option is supported on S514-PCI and S508-ISA cards.
-
-WANPIPE Frame Relay support
-CONFIG_WANPIPE_FR
-  Say Y to this option if you are planning to connect a WANPIPE card
-  to a frame relay network, or use frame relay API to develope
-  custom applications over the Frame  Relay protocol.
-  This feature also contains the Ethernet Bridging over Frame Relay,
-  where a WANPIPE frame relay link can be directly connected to the
-  Linux kernel bridge.  If you say N, the frame relay support will
-  not be included in the driver. The Frame Relay option is
-  supported on S514-PCI and S508-ISA cards.
-
-WANPIPE PPP support
-CONFIG_WANPIPE_PPP
-  Say Y to this option if you are planning to connect a WANPIPE card
-  to a leased line using Point-to-Point protocol (PPP). If you say N,
-  the PPP support will not be included in the driver. The PPP option
-  is supported on S514-PCI/S508-ISA cards.
-
-WANPIPE Multi-Port PPP support
-CONFIG_WANPIPE_MULTPPP
-  Say Y to this option if you are planning to connect a WANPIPE card
-  to a leased line using Point-to-Point protocol (PPP).  Note, the
-  MultiPort PPP uses the Linux Kernel SyncPPP protocol over the
-  Sangoma HDLC Streaming adapter.  In this case each Sangoma adapter
-  port can support an independent PPP connection.  For example, a
-  single Quad-Port PCI adapter can support up to four independent
-  PPP links. If you say N,the PPP support will not be included in the
-  driver.  The PPP option is supported on S514-PCI/S508-ISA cards.
-
-WANPIPE Cisco HDLC support
-CONFIG_WANPIPE_CHDLC
-  Say Y to this option if you are planning to connect a WANPIPE card
-  to a leased line using the Cisco HDLC protocol. This now supports
-  Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards.
-  This support also allows user to build applications using the
-  HDLC streaming API.
-
-  CHDLC Streaming driver also supports MULTILINK PPP
-  support that can bind multiple WANPIPE T1 cards into
-  a single logical channel.
-
-  If you say  N, the Cisco HDLC support and
-  HDLC streaming API and MULTILINK PPP will not be
-  included in the driver.
-
-MultiGate (COMX) synchronous serial board support
-CONFIG_COMX
-  Say Y if you want to use any board from the MultiGate (COMX) family.
-  These boards are synchronous serial adapters for the PC,
-  manufactured by ITConsult-Pro Co, Hungary.
-
-  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>.
-
-  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
-  use this driver.
-
-  If you want to compile this as a module, say M and read
-  <file:Documentation/modules.txt>.  The module will be called comx.o.
-
-Support for COMX/CMX/HiCOMX boards
-CONFIG_COMX_HW_COMX
-  Hardware driver for the 'CMX', 'COMX' and 'HiCOMX' boards from the
-  MultiGate family. Say Y if you have one of these.
-
-  You will need additional firmware to use these cards, which are
-  downloadable from <ftp://ftp.itc.hu/>.
-
-  If you want to compile this as a module, say M and read
-  <file:Documentation/modules.txt>.  The module will be called
-  comx-hw-comx.o.
-
-Support for LoCOMX board
-CONFIG_COMX_HW_LOCOMX
-  Hardware driver for the 'LoCOMX' board from the MultiGate family.
-  Say Y if you have a board like this.
-
-  If you want to compile this as a module, say M and read
-  <file:Documentation/modules.txt>.  The module will be called
-  comx-hw-locomx.o.
-
-Support for MixCOM board
-CONFIG_COMX_HW_MIXCOM
-  Hardware driver for the 'MixCOM' board from the MultiGate family.
-  Say Y if you have a board like this.
-
-  If you want to use the watchdog device on this card, you should
-  select it in the Watchdog Cards section of the Character Devices
-  configuration. The ISDN interface of this card is Teles 16.3
-  compatible, you should enable it in the ISDN configuration menu. The
-  driver for the flash ROM of this card is available separately on
-  <ftp://ftp.itc.hu/>.
-
-  If you want to compile this as a module, say M and read
-  <file:Documentation/modules.txt>. The module will be called
-  comx-hw-mixcom.o.
-
-i810 TCO timer/watchdog support
-CONFIG_I810_TCO
-  Hardware driver for the TCO timer built into the Intel i810 and i815
-  chipset family.  The TCO (Total Cost of Ownership) timer is a
-  watchdog timer that will reboot the machine after its second
-  expiration. The expiration time can be configured by commandline
-  argument "i810_margin=<n>" where <n> is the counter initial value.
-  It is decremented every 0.6 secs, the default is 50 which gives a
-  timeout of 30 seconds and one minute until reset.
-
-  On some motherboards the driver may fail to reset the chipset's
-  NO_REBOOT flag which prevents the watchdog from rebooting the
-  machine. If this is the case you will get a kernel message like
-  "i810tco init: failed to reset NO_REBOOT flag".
-
-  If you want to compile this as a module, say M and read
-  <file:Documentation/modules.txt>.  The module will be called
-  i810-tco.o.
-
-Support for HDLC and syncPPP protocols on MultiGate boards
-CONFIG_COMX_PROTO_PPP
-  Cisco-HDLC and synchronous PPP protocol driver for all MultiGate
-  boards. Say Y if you want to use either protocol on your MultiGate
-  boards.
-
-  If you want to compile this as a module, say M and read
-  <file:Documentation/modules.txt>.  The module will be called
-  comx-proto-ppp.o.
-
-Support for LAPB protocol on MultiGate boards
-CONFIG_COMX_PROTO_LAPB
-  LAPB protocol driver for all MultiGate boards. Say Y if you
-  want to use this protocol on your MultiGate boards.
-
-  If you want to compile this as a module, say M and read
-  <file:Documentation/modules.txt>.  The module will be called
-  comx-proto-lapb.o.
-
-Support for Frame Relay on MultiGate boards
-CONFIG_COMX_PROTO_FR
-  Frame Relay protocol driver for all MultiGate boards. Say Y if you
-  want to use this protocol on your MultiGate boards.
-
-  If you want to compile this as a module, say M and read
-  <file:Documentation/modules.txt>.  The module will be called
-  comx-proto-fr.o.
-
-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
-  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
-  the protocols you want the driver to support (for now only X.25 is
-  supported).
-
-  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
-  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/>).
-
-  Feel free to contact me or the cycsyn-devel mailing list at
-  acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for
-  additional details, I hope to have documentation available as soon
-  as possible. (Cyclades Brazil is writing the Documentation).
-
-  The driver will be compiled as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called cyclomx.o. For general information about
-  modules read <file:Documentation/modules.txt>.
-
-Cyclom 2X X.25 support
-CONFIG_CYCLOMX_X25
-  Say Y to this option if you are planning to connect a Cyclom 2X card
-  to an X.25 network.
-
-  If you say N, the X.25 support will not be included in the driver
-  (saves about 11 KB of kernel memory).
-
-Generic HDLC driver
-CONFIG_HDLC
-  Say Y to this option if your Linux box contains a WAN card supported
-  by this driver and you are planning to connect the box to a WAN
-  ( = Wide Area Network). You will need supporting software from
-  <http://hq.pm.waw.pl/hdlc/>.
-  Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame
-  Relay, synchronous Point-to-Point Protocol (PPP) and X.25.
-
-  If unsure, say N here.
-
-Raw HDLC support
-CONFIG_HDLC_RAW
-  Say Y to this option if you want generic HDLC driver to support
-  raw HDLC over WAN (Wide Area Network) connections.
-
-  If unsure, say N here.
-
-Cisco HDLC support
-CONFIG_HDLC_CISCO
-  Say Y to this option if you want generic HDLC driver to support
-  Cisco HDLC over WAN (Wide Area Network) connections.
-
-  If unsure, say N here.
-
-Frame-Relay HDLC support
-CONFIG_HDLC_FR
-  Say Y to this option if you want generic HDLC driver to support
-  Frame-Relay protocol over WAN (Wide Area Network) connections.
-
-  If unsure, say N here.
-
-Frame-Relay bridging support
-CONFIG_HDLC_FR_BRIDGE
-  Say Y to this option if you want generic HDLC driver to support
-  bridging LAN frames over Frame-Relay links.
-
-  If unsure, say N here.
-
-Synchronous Point-to-Point Protocol (PPP) support
-CONFIG_HDLC_PPP
-  Say Y to this option if you want generic HDLC driver to support
-  PPP over WAN (Wide Area Network) connections.
-
-  If unsure, say N here.
-
-CCITT X.25 over HDLC support
-CONFIG_HDLC_X25
-  Say Y to this option if you want generic HDLC driver to support
-  X.25 protocol over WAN (Wide Area Network) connections.
-
-  If unsure, say N here.
-
-SDL RISCom/N2 support
-CONFIG_N2
-  This driver is for RISCom/N2 single or dual channel ISA cards
-  made by SDL Communications Inc.  If you have such a card,
-  say Y here and see <http://hq.pm.waw.pl/pub/hdlc/>.
-
-  Note that N2csu and N2dds cards are not supported by this driver.
-
-  If unsure, say N here.
-
-Moxa C101 support
-CONFIG_C101
-  This driver is for C101 SuperSync ISA cards made by Moxa
-  Technologies Co., Ltd. If you have such a card,
-  say Y here and see <http://hq.pm.waw.pl/pub/hdlc/>
-
-  If unsure, say N here.
-
-Ethernet (10 or 100Mbit)
-CONFIG_NET_ETHERNET
-  Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
-  type of Local Area Network (LAN) in universities and companies.
-
-  Common varieties of Ethernet are: 10BASE-2 or Thinnet (10 Mbps over
-  coaxial cable, linking computers in a chain), 10BASE-T or twisted
-  pair (10 Mbps over twisted pair cable, linking computers to central
-  hubs), 10BASE-F (10 Mbps over optical fiber links, using hubs),
-  100BASE-TX (100 Mbps over two twisted pair cables, using hubs),
-  100BASE-T4 (100 Mbps over 4 standard voice-grade twisted pair
-  cables, using hubs), 100BASE-FX (100 Mbps over optical fiber links)
-  [the 100BASE varieties are also known as Fast Ethernet], and Gigabit
-  Ethernet (1 Gbps over optical fiber or short copper links).
-
-  If your Linux machine will be connected to an Ethernet and you have
-  an Ethernet network interface card (NIC) installed in your computer,
-  say Y here and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. You will then also have
-  to say Y to the driver for your particular NIC.
-
-  Note that the answer to this question won't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about Ethernet network cards. If unsure, say N.
-
-Western Digital/SMC cards
-CONFIG_NET_VENDOR_SMC
-  If you have a network (Ethernet) card belonging to this class, say Y
-  and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  Note that the answer to this question doesn't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about Western Digital cards. If you say Y, you will be
-  asked for your specific card in the following questions.
-
-WD80*3 support
-CONFIG_WD80x3
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called wd.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-SMC Ultra MCA support
-CONFIG_ULTRAMCA
-  If you have a network (Ethernet) card of this type and are running
-  an MCA based system (PS/2), say Y and read the Ethernet-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called smc-mca.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-SMC Ultra support
-CONFIG_ULTRA
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  Important: There have been many reports that, with some motherboards
-  mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible,
-  such as some BusLogic models) causes corruption problems with many
-  operating systems. The Linux smc-ultra driver has a work-around for
-  this but keep it in mind if you have such a SCSI card and have
-  problems.
-
-  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 smc-ultra.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt> as
-  well as <file:Documentation/networking/net-modules.txt>.
-
-SMC Ultra32 EISA support
-CONFIG_ULTRA32
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called smc-ultra32.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt> as
-  well as <file:Documentation/networking/net-modules.txt>.
-
-SMC 9194 support
-CONFIG_SMC9194
-  This is support for the SMC9xxx based Ethernet cards. Choose this
-  option if you have a DELL laptop with the docking station, or
-  another SMC9192/9194 based chipset.  Say Y if you want it compiled
-  into the kernel, and read the file
-  <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called smc9194.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-PCI NE2000 and clones support
-CONFIG_NE2K_PCI
-  This driver is for NE2000 compatible PCI cards. It will not work
-  with ISA NE2000 cards (they have their own driver, "NE2000/NE1000
-  support" below). If you have a PCI NE2000 network (Ethernet) card,
-  say Y and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver also works for the following NE2000 clone cards:
-    RealTek RTL-8029  Winbond 89C940  Compex RL2000  KTI ET32P2
-    NetVin NV5000SC   Via 86C926      SureCom NE34   Winbond
-    Holtek HT80232    Holtek HT80229
-
-  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 ne2k-pci.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt> as
-  well as <file:Documentation/networking/net-modules.txt>.
-
-Racal-Interlan (Micom) NI cards
-CONFIG_NET_VENDOR_RACAL
-  If you have a network (Ethernet) card belonging to this class, such
-  as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  Note that the answer to this question doesn't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about NI cards. If you say Y, you will be asked for
-  your specific card in the following questions.
-
-NI5010 support
-CONFIG_NI5010
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. Note that this is still
-  experimental code.
-
-  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 ni5010.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-NI5210 support
-CONFIG_NI52
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ni52.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-NI6510 support
-CONFIG_NI65
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ni65.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-RealTek RTL-8139C+ 10/100 PCI Fast Ethernet Adapter support
-CONFIG_8139CP
-  This is a driver for the Fast Ethernet PCI network cards based on
-  the RTL8139C+ chips. If you have one of those, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. This is recommended.
-  The module will be called 8139cp.o.
-
-RealTek RTL-8139 PCI Fast Ethernet Adapter support
-CONFIG_8139TOO
-  This is a driver for the Fast Ethernet PCI network cards based on
-  the RTL8139 chips. If you have one of those, say Y and read
-  <file:Documentation/networking/8139too.txt> as well as the
-  Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called 8139too.o.
-
-Use PIO instead of MMIO
-CONFIG_8139TOO_PIO
-  This instructs the driver to use programmed I/O ports (PIO) instead
-  of PCI shared memory (MMIO).  This can possibly solve some problems
-  in case your mainboard has memory consistency issues.  If unsure,
-  say N.
-
-Support for automatic channel equalization
-CONFIG_8139TOO_TUNE_TWISTER
-  This implements a function which might come in handy in case you are
-  using low quality on long cabling. It tries to match the transceiver
-  to the cable characteristics. This is experimental since hardly
-  documented by the manufacturer.  If unsure, say N.
-
-Support for older RTL-8129/8130 boards
-CONFIG_8139TOO_8129
-  This enables support for the older and uncommon RTL-8129 and
-  RTL-8130 chips, which support MII via an external transceiver,
-  instead of an internal one.  Disabling this option will save some
-  memory by making the code size smaller.  If unsure, say Y.
-
-SiS 900/7016 PCI Fast Ethernet Adapter support
-CONFIG_SIS900
-  This is a driver for the Fast Ethernet PCI network cards based on
-  the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in
-  SiS 630 and SiS 540 chipsets.  If you have one of those, say Y and
-  read the Ethernet-HOWTO, available at
-  <http://www.linuxdoc.org/docs.html#howto>.  Please read
-  <file:Documentation/networking/sis900.txt> and comments at the
-  beginning of <file:drivers/net/sis900.c> for more information.
-
-  This driver also supports AMD 79C901 HomePNA so that you can use
-  your phone line as a network cable.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called sis900.o.
-
-Packet Engines Yellowfin Gigabit-NIC / Symbios 53c885 support
-CONFIG_YELLOWFIN
-  Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
-  adapter or the SYM53C885 Ethernet controller. The Gigabit adapter is
-  used by the Beowulf Linux cluster project.  See
-  <http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html> for more
-  information about this driver in particular and Beowulf in general.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called yellowfin.o.
-
-General Instruments Surfboard 1000
-CONFIG_NET_SB1000
-  This is a driver for the General Instrument (also known as
-  NextLevel) SURFboard 1000 internal
-  cable modem. This is an ISA card which is used by a number of cable
-  TV companies to provide cable modem access. It's a one-way
-  downstream-only cable modem, meaning that your upstream net link is
-  provided by your regular phone modem.
-
-  At present this driver only compiles as a module, so say M here if
-  you have this card. The module will be called sb1000.o. Then read
-  <file:Documentation/networking/README.sb1000> for information on how
-  to use this module, as it needs special ppp scripts for establishing
-  a connection. Further documentation and the necessary scripts can be
-  found at:
-
-  <http://www.jacksonville.net/~fventuri/>
-  <http://home.adelphia.net/~siglercm/sb1000.html>
-  <http://linuxpower.cx/~cable/>
-
-  If you don't have this card, of course say N.
-
-Adaptec Starfire support
-CONFIG_ADAPTEC_STARFIRE
-  Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network
-  adapter. The DuraLAN chip is used on the 64 bit PCI boards from
-  Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip
-  driver.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called starfire.o.
-
-Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support
-CONFIG_ACENIC
-  Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear
-  GA620, SGI Gigabit or Farallon PN9000-SX PCI Gigabit Ethernet
-  adapter. The driver allows for using the Jumbo Frame option (9000
-  bytes/frame) however it requires that your switches can handle this
-  as well. To enable Jumbo Frames, add `mtu 9000' to your ifconfig
-  line.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called acenic.o.
-
-Omit support for old Tigon I based AceNICs
-CONFIG_ACENIC_OMIT_TIGON_I
-  Say Y here if you only have Tigon II based AceNICs and want to leave
-  out support for the older Tigon I based cards which are no longer
-  being sold (ie. the original Alteon AceNIC and 3Com 3C985 (non B
-  version)).  This will reduce the size of the driver object by
-  app. 100KB.  If you are not sure whether your card is a Tigon I or a
-  Tigon II, say N here.
-
-  The safe and default value for this is N.
-
-SysKonnect SK-98xx support
-CONFIG_SK98LIN
-  Say Y here if you have a SysKonnect SK-98xx Gigabit Ethernet Server
-  Adapter. The following adapters are supported by this driver:
-  - SK-9841 (single link 1000Base-LX)
-  - SK-9842 (dual link   1000Base-LX)
-  - SK-9843 (single link 1000Base-SX)
-  - SK-9844 (dual link   1000Base-SX)
-  - SK-9821 (single link 1000Base-T)
-  - SK-9822 (dual link   1000Base-T)
-  - SK-9861 (single link Volition connector)
-  - SK-9862 (dual link   Volition connector)
-  The driver also supports the following adapters from Allied Telesyn:
-  - AT2970...
-
-  The dual link adapters support a link-failover feature.  Read
-  <file:Documentation/networking/sk98lin.txt> for information about
-  optional driver parameters.
-  Questions concerning this driver may be addressed to:
-    linux@syskonnect.de
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called sk98lin.o.
-
-Sun GEM support
-CONFIG_SUNGEM
-  Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0.  See also
-  <http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>.
-
-MyriCOM Gigabit Ethernet support
-CONFIG_MYRI_SBUS
-  This driver supports MyriCOM Sbus gigabit Ethernet cards.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called myri_sbus.o.
-
-D-Link 2000-based Gigabit Ethernet support
-CONFIG_DL2K
-  This driver supports D-Link 2000-based gigabit ethernet cards, which
-  includes
-       D-Link DGE-550T Gigabit Ethernet Adapter.
-       D-Link DL2000-based Gigabit Ethernet Adapter.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called dl2k.o.
-
-AMD LANCE and PCnet (AT1500 and NE2100) support
-CONFIG_LANCE
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. Some LinkSys cards are
-  of this type.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called lance.o.
-
-SGI IOC3 Ethernet
-CONFIG_SGI_IOC3_ETH
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-National Semiconductor DP83902AV support
-CONFIG_STNIC
-  Support for cards based on the National Semiconductor DP83902AV
-  ST-NIC Serial Network Interface Controller for Twisted Pair.  This
-  is a 10Mbit/sec Ethernet controller.  Product overview and specs at
-  <http://www.national.com/pf/DP/DP83902A.html>.
-
-  If unsure, say N.
-
-3COM cards
-CONFIG_NET_VENDOR_3COM
-  If you have a network (Ethernet) card belonging to this class, say Y
-  and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  Note that the answer to this question doesn't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about 3COM cards. If you say Y, you will be asked for
-  your specific card in the following questions.
-
-3c501 "EtherLink" support
-CONFIG_EL1
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  Also, consider buying a
-  new card, since the 3c501 is slow, broken, and obsolete: you will
-  have problems.  Some people suggest to ping ("man ping") a nearby
-  machine every minute ("man cron") when using this card.
-
-  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 3c501.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-3c503 "EtherLink II" support
-CONFIG_EL2
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called 3c503.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-3c505 "EtherLink Plus" support
-CONFIG_ELPLUS
-  Information about this network (Ethernet) card can be found in
-  <file:Documentation/networking/3c505.txt>.  If you have a card of
-  this type, say Y and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  The module will be
-  called 3c505.o.
-
-3c507 (EtherLink 16) support
-CONFIG_EL16
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called 3c507.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-3c523 "EtherlinkMC" support
-CONFIG_ELMC
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called 3c523.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-3c527 "EtherLink/MC 32" support
-CONFIG_ELMC_II
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called 3c527.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-3c509/3c529 (MCA)/3c579 "EtherLink III"  support
-CONFIG_EL3
-  If you have a network (Ethernet) card belonging to the 3Com
-  EtherLinkIII series, say Y and read the Ethernet-HOWTO, available
-  from <http://www.linuxdoc.org/docs.html#howto>.
-
-  If your card is not working you may need to use the DOS
-  setup disk to disable Plug & Play mode, and to select the default
-  media type.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  The module will be
-  called 3c509.o.
-
-3c515 ISA Fast EtherLink
-CONFIG_3C515
-  If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet
-  network card, say Y and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  The module will be
-  called 3c515.o.
-
-3c590/3c900 series (592/595/597) "Vortex/Boomerang/Cyclone" support
-CONFIG_VORTEX
-  This option enables driver support for a large number of 10mbps and
-  10/100mbps EISA, PCI and PCMCIA 3Com network cards:
-
-  "Vortex"    (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI
-  "Boomerang" (EtherLink XL 3c900 or 3c905)            PCI
-  "Cyclone"   (3c540/3c900/3c905/3c980/3c575/3c656)    PCI and Cardbus
-  "Tornado"   (3c905)                                  PCI
-  "Hurricane" (3c555/3cSOHO)                           PCI
-
-  If you have such a card, say Y and read the Ethernet-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>. More
-  specific information is in
-  <file:Documentation/networking/vortex.txt> and in the comments at
-  the beginning of <file:drivers/net/3c59x.c>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.
-
-Other ISA cards
-CONFIG_NET_ISA
-  If your network (Ethernet) card hasn't been mentioned yet and its
-  bus system (that's the way the cards talks to the other components
-  of your computer) is ISA (as opposed to EISA, VLB or PCI), say Y.
-  Make sure you know the name of your card. Read the Ethernet-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  If unsure, say Y.
-
-  Note that the answer to this question doesn't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the remaining ISA network card questions. If you say Y, you will be
-  asked for your specific card in the following questions.
-
-Generic ARCnet support
-CONFIG_ARCNET
-  If you have a network card of this type, say Y and check out the
-  (arguably) beautiful poetry in
-  <file:Documentation/networking/arcnet.txt>.
-
-  You need both this driver, and the driver for the particular ARCnet
-  chipset of your card. If you don't know, then it's probably a
-  COM90xx type card, so say Y (or M) to "ARCnet COM90xx chipset
-  support" below.
-
-  You might also want to have a look at the Ethernet-HOWTO, available
-  from <http://www.linuxdoc.org/docs.html#howto>(even though ARCnet
-  is not really Ethernet).
-
-  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 arcnet.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-Enable old ARCNet packet format (RFC 1051)
-CONFIG_ARCNET_1051
-  This allows you to use RFC1051 with your ARCnet card via the virtual
-  arc0s device. You only need arc0s if you want to talk to ARCnet
-  software complying with the "old" standard, specifically, the DOS
-  arcnet.com packet driver, Amigas running AmiTCP, and some variants
-  of NetBSD. You do not need to say Y here to communicate with
-  industry-standard RFC1201 implementations, like the arcether.com
-  packet driver or most DOS/Windows ODI drivers. RFC1201 is included
-  automatically as the arc0 device. Please read the ARCnet
-  documentation in <file:Documentation/networking/arcnet.txt> for more
-  information about using arc0e and arc0s.
-
-Enable standard ARCNet packet format (RFC 1201)
-CONFIG_ARCNET_1201
-  This allows you to use RFC1201 with your ARCnet card via the virtual
-  arc0 device.  You need to say Y here to communicate with
-  industry-standard RFC1201 implementations, like the arcether.com
-  packet driver or most DOS/Windows ODI drivers.  Please read the
-  ARCnet documentation in <file:Documentation/networking/arcnet.txt>
-  for more information about using arc0.
-
-Enable raw mode packet interface
-CONFIG_ARCNET_RAW
-  ARCnet "raw mode" packet encapsulation, no soft headers.  Unlikely
-  to work unless talking to a copy of the same Linux arcnet driver,
-  but perhaps marginally faster in that case.
-
-ARCnet COM90xx (normal) chipset driver
-CONFIG_ARCNET_COM90xx
-  This is the chipset driver for the standard COM90xx cards. If you
-  have always used the old ARCnet driver without knowing what type of
-  card you had, this is probably the one for you.
-
-  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 com90xx.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-ARCnet COM90xx (IO mapped) chipset driver
-CONFIG_ARCNET_COM90xxIO
-  This is the chipset driver for the COM90xx cards, using them in
-  IO-mapped mode instead of memory-mapped mode. This is slower than
-  the normal driver. Only use it if your card doesn't support shared
-  memory.
-
-  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 com90io.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-ARCnet COM90xx (RIM I) chipset driver
-CONFIG_ARCNET_RIM_I
-  This is yet another chipset driver for the COM90xx cards, but this
-  time only using memory-mapped mode, and no IO ports at all. This
-  driver is completely untested, so if you have one of these cards,
-  please mail dwmw2@infradead.org, especially if it works!
-
-  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 arc-rimi.o.  If you want to compile
-  it as a module, say M here and read <file:Documentation/modules.txt>
-  as  well as <file:Documentation/networking/net-modules.txt>.
-
-ARCnet COM20020 chipset driver
-CONFIG_ARCNET_COM20020
-  This is the driver for the new COM20020 chipset. It supports such
-  things as promiscuous mode, so packet sniffing is possible, and
-  extra diagnostic information.
-
-  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 com20020.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt> as
-  well as <file:Documentation/networking/net-modules.txt>.
-
-Cabletron E21xx support
-CONFIG_E2100
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called e2100.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-CS89x0 support (Daynaport CS and LC cards)
-CONFIG_CS89x0
-  Support for CS89x0 chipset based Ethernet cards. If you have a
-  network (Ethernet) card of this type, say Y and read the
-  Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto> as well as
-  <file:Documentation/networking/cs89x0.txt>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  The module will be
-  called cs89x.o.
-
-DEPCA, DE10x, DE200, DE201, DE202, DE422 support
-CONFIG_DEPCA
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto> as well as
-  <file:drivers/net/depca.c>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  The module will be
-  called
-  depca.o.
-
-EtherWORKS 3 (DE203, DE204, DE205) support
-CONFIG_EWRK3
-  This driver supports the DE203, DE204 and DE205 network (Ethernet)
-  cards. If this is for you, say Y and read
-  <file:Documentation/networking/ewrk3.txt> in the kernel source as
-  well as the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  The module will be
-  called ewrk3.o.
-
-SEEQ8005 support
-CONFIG_SEEQ8005
-  This is a driver for the SEEQ 8005 network (Ethernet) card.  If this
-  is for you, read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  The module will be
-  called ewrk3.o.
-
-AT1700/1720 support
-CONFIG_AT1700
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  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>.  The module will be
-  called at1700.o.
-
-FMV-181/182/183/184 support
-CONFIG_FMV18X
-  If you have a Fujitsu FMV-181/182/183/184 network (Ethernet) card,
-  say Y and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you use an FMV-183 or FMV-184 and it is not working, you may need
-  to disable Plug & Play mode of the card.
-
-  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 fmv18x.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-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
-  that the EtherExpress PRO/100 Ethernet card has its own separate
-  driver.  Please read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called eepro.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-EtherExpress 16 support
-CONFIG_EEXPRESS
-  If you have an EtherExpress16 network (Ethernet) card, say Y and
-  read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  Note that the Intel
-  EtherExpress16 card used to be regarded as a very poor choice
-  because the driver was very unreliable. We now have a new driver
-  that should do better.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  The module will be
-  called eexpress.o.
-
-Packet Engines Hamachi GNIC-II support
-CONFIG_HAMACHI
-  If you have a Gigabit Ethernet card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  The module will be
-  called hamachi.o.
-
-HP PCLAN+ (27247B and 27252A) support
-CONFIG_HPLAN_PLUS
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called hp-plus.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-HP PCLAN (27245 and other 27xxx series) support
-CONFIG_HPLAN
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called hp.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-HP 10/100VG PCLAN (ISA, EISA, PCI) support
-CONFIG_HP100
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  The module will be
-  called hp100.o.
-
-NE2000/NE1000 support
-CONFIG_NE2000
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  Many Ethernet cards
-  without a specific driver are compatible with NE2000.
-
-  If you have a PCI NE2000 card however, say N here and Y to "PCI
-  NE2000 support", above. If you have a NE2000 card and are running on
-  an MCA system (a bus system used on some IBM PS/2 computers and
-  laptops), say N here and Y to "NE/2 (ne2000 MCA version) support",
-  below.
-
-  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 ne.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-National Semiconductor DP8381x series PCI Ethernet support
-CONFIG_NATSEMI
-  This driver is for the National Semiconductor DP83810 series,
-  which is used in cards from PureData, NetGear, Linksys
-  and others, including the 83815 chip.
-  More specific information and updates are available from
-  <http://www.scyld.com/network/natsemi.html>.
-
-SK_G16 support
-CONFIG_SK_G16
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-NE/2 (ne2000 MCA version) support
-CONFIG_NE2_MCA
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ne2.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-SKnet MCA support
-CONFIG_SKMC
-  These are Micro Channel Ethernet adapters. You need to say Y to "MCA
-  support" in order to use this driver.  Supported cards are the SKnet
-  Junior MC2 and the SKnet MC2(+).  The driver automatically
-  distinguishes between the two cards. Note that using multiple boards
-  of different type hasn't been tested with this driver.  Say Y if you
-  have one of these Ethernet adapters.
-
-  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 is called sk_mca.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-IBM LAN Adapter/A support
-CONFIG_IBMLANA
-  This is a Micro Channel Ethernet adapter.  You need to set
-  CONFIG_MCA to use this driver.  It is both available as an in-kernel
-  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>. 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
-  boards with this driver should be possible, but has not been tested
-  up to now due to lack of hardware.
-
-EISA, VLB, PCI and on board controllers
-CONFIG_NET_PCI
-  This is another class of network cards which attach directly to the
-  bus. If you have one of those, say Y and read the Ethernet-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  Note that the answer to this question doesn't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about this class of network cards. If you say Y, you
-  will be asked for your specific card in the following questions. If
-  you are unsure, say Y.
-
-AMD PCnet32 (VLB and PCI) support
-CONFIG_PCNET32
-  If you have a PCnet32 or PCnetPCI based network (Ethernet) card,
-  answer Y here and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called pcnet32.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-Ansel Communications EISA 3200 support
-CONFIG_AC3200
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ac3200.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-Mylex EISA LNE390A/LNE390B support
-CONFIG_LNE390
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called lne390.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-Novell/Eagle/Microdyne NE3210 EISA support
-CONFIG_NE3210
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  Note that this driver
-  will NOT WORK for NE3200 cards as they are completely different.
-
-  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 ne3210.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-Apricot Xen-II on board Ethernet
-CONFIG_APRICOT
-  If you have a network (Ethernet) controller of this type, say Y and
-  read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  The module will be
-  called apricot.o.
-
-Generic DECchip & DIGITAL EtherWORKS PCI/EISA
-CONFIG_DE4X5
-  This is support for the DIGITAL series of PCI/EISA Ethernet cards.
-  These include the DE425, DE434, DE435, DE450 and DE500 models.  If
-  you have a network card of this type, say Y and read the
-  Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. More specific
-  information is contained in
-  <file:Documentation/networking/de4x5.txt>.
-
-  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 de4x5.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-DECchip Tulip (dc21x4x) PCI support
-CONFIG_TULIP
-  This driver is developed for the SMC EtherPower series Ethernet
-  cards and also works with cards based on the DECchip 
-  21040/21041/21140 (Tulip series) chips.  Some LinkSys PCI cards are
-  of this type.  (If your card is NOT SMC EtherPower 10/100 PCI
-  (smc9332dst), you can also try the driver for "Generic DECchip"
-  cards, above.  However, most people with a network card of this type
-  will say Y here.) Do read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  More specific
-  information is contained in 
-  <file:Documentation/networking/tulip.txt>.
-
-  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 tulip.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-New Tulip bus configuration
-CONFIG_TULIP_MWI 
-  This configures your Tulip card specifically for the card and
-  system cache line size type you are using.
-
-  This is experimental code, not yet tested on many boards.
-
-  If unsure, say N.
-
-Digi Intl. RightSwitch SE-X support
-CONFIG_DGRS
-  This is support for the Digi International RightSwitch series of
-  PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6
-  models.  If you have a network card of this type, say Y and read the
-  Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  More specific
-  information is contained in <file:Documentation/networking/dgrs.txt>.
-
-  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 dgrs.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-EtherExpress Pro/100 support
-CONFIG_EEPRO100
-  If you have an Intel EtherExpress PRO/100 PCI network (Ethernet)
-  card, say Y and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called eepro100.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt> as
-  well as <file:Documentation/networking/net-modules.txt>.
-
-Enable Power Management
-CONFIG_EEPRO100_PM
-  Many Intel EtherExpress PRO/100 PCI network cards are capable
-  of providing power management capabilities.  To make use of these
-  capabilities, say Y.
-
-  WARNING:  This option is intended for kernel developers and testers.
-  It is still very experimental, with some people reporting complete
-  lockups.
-
-  It is recommended to say N here.
-
-Myson MTD-8xx PCI Ethernet support
-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/>.
-
-ICL EtherTeam 16i/32 support
-CONFIG_ETH16I
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called eth16i.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-TI ThunderLAN support
-CONFIG_TLAN
-  If you have a PCI Ethernet network card based on the ThunderLAN chip
-  which is supported by this driver, say Y and read the
-  Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  Devices currently supported by this driver are Compaq Netelligent,
-  Compaq NetFlex and Olicom cards.  Please read the file
-  <file:Documentation/networking/tlan.txt> for more details.
-
-  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 tlan.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-  Please email feedback to  torben.mathiasen@compaq.com.
-
-VIA Rhine support
-CONFIG_VIA_RHINE
-  If you have a VIA "rhine" based network card (Rhine-I (3043) or
-  Rhine-2 (VT86c100A)), say Y here.
-
-  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 via-rhine.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt> as
-  well as <file:Documentation/networking/net-modules.txt>.
-
-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
-  (Ethernet) card, say Y.  Some information is contained in the file
-  <file:Documentation/networking/dmfe.txt>.
-
-  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 dmfe.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-Racal-Interlan EISA ES3210 support
-CONFIG_ES3210
-  If you have a network (Ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called es3210.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-SMC EtherPower II
-CONFIG_EPIC100
-  This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC,
-  which is based on the SMC83c17x (EPIC/100).
-  More specific information and updates are available from
-  <http://www.scyld.com/network/epic100.html>.
-
-DEC LANCE Ethernet controller support
-CONFIG_DECLANCE
-  This driver is for the series of Ethernet controllers produced by
-  DEC (now Compaq) based on the AMD Lance chipset, including the
-  DEPCA series.  (This chipset is better known via the NE2100 cards.)
-
-SGI Seeq Ethernet controller support
-CONFIG_SGISEEQ
-  Say Y here if you have an Seeq based Ethernet network card. This is
-  used in many Silicon Graphics machines.
-
-Sundance Alta PCI Ethernet support
-CONFIG_SUNDANCE
-  This driver is for the Sundance "Alta" chip.
-  More specific information and updates are available from
-  <http://www.scyld.com/network/sundance.html>.
-
-Sun3/Sun3x on-board LANCE support
-CONFIG_SUN3LANCE
-  Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80)
-  featured an AMD Lance 10Mbit Ethernet controller on board; say Y
-  here to compile in the Linux driver for this and enable Ethernet.
-  General Linux information on the Sun 3 and 3x series (now
-  discontinued) is at
-  <http://www.angelfire.com/ca2/tech68k/sun3.html>.
-
-  If you're not building a kernel for a Sun 3, say N.
-
-Sun3 on-board Intel 82586 support
-CONFIG_SUN3_82586
-  This driver enables support for the on-board Intel 82586 based
-  Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards.  Note
-  that this driver does not support 82586-based adapters on additional
-  VME boards.
-
-Winbond W89c840 PCI Ethernet support
-CONFIG_WINBOND_840
-  This driver is for the Winbond W89c840 chip.  It also works with
-  the TX9882 chip on the Compex RL100-ATX board.
-  More specific information and updates are available from
-  <http://www.scyld.com/network/drivers.html>.
-
-Zenith Z-Note support
-CONFIG_ZNET
-  The Zenith Z-Note notebook computer has a built-in network
-  (Ethernet) card, and this is the Linux driver for it. Note that the
-  IBM Thinkpad 300 is compatible with the Z-Note and is also supported
-  by this driver. Read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-Philips SAA9730 Ethernet support
-CONFIG_LAN_SAA9730
-  The SAA9730 is a combined multimedia and peripheral controller used
-  in thin clients, Internet access terminals, and diskless
-  workstations.
-  See <http://www.semiconductors.philips.com/pip/SAA9730_flyer_1>.
-
-Pocket and portable adapters
-CONFIG_NET_POCKET
-  Cute little network (Ethernet) devices which attach to the parallel
-  port ("pocket adapters"), commonly used with laptops. If you have
-  one of those, say Y and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to plug a network (or some other) card into the PCMCIA
-  (or PC-card) slot of your laptop instead (PCMCIA is the standard for
-  credit card size extension cards used by all modern laptops), you
-  need the pcmcia-cs package (location contained in the file
-  <file:Documentation/Changes>) and you can say N here.
-
-  Laptop users should read the Linux Laptop home page at
-  <http://www.cs.utexas.edu/users/kharker/linux-laptop/>.
-
-  Note that the answer to this question doesn't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about this class of network devices. If you say Y, you
-  will be asked for your specific device in the following questions.
-
-AT-LAN-TEC/RealTek pocket adapter support
-CONFIG_ATP
-  This is a network (Ethernet) device which attaches to your parallel
-  port. Read <file:drivers/net/atp.c> as well as the Ethernet-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>, if you
-  want to use this.  If you intend to use this driver, you should have
-  said N to the "Parallel printer support", because the two drivers
-  don't like each other.
-
-  If you want to compile this driver as a module however ( = 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 atp.o.
-
-D-Link DE600 pocket adapter support
-CONFIG_DE600
-  This is a network (Ethernet) device which attaches to your parallel
-  port. Read <file:Documentation/networking/DLINK.txt> as well as the
-  Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, if you want to use
-  this. It is possible to have several devices share a single parallel
-  port and it is safe to compile the corresponding drivers into the
-  kernel.
-
-  If you want to compile this driver as a module however ( = 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 de600.o.
-
-D-Link DE620 pocket adapter support
-CONFIG_DE620
-  This is a network (Ethernet) device which attaches to your parallel
-  port. Read <file:Documentation/networking/DLINK.txt> as well as the
-  Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, if you want to use
-  this. It is possible to have several devices share a single parallel
-  port and it is safe to compile the corresponding drivers into the
-  kernel.
-
-  If you want to compile this driver as a module however ( = 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 de620.o.
-
-Token Ring driver support
-CONFIG_TR
-  Token Ring is IBM's way of communication on a local network; the
-  rest of the world uses Ethernet. To participate on a Token Ring
-  network, you need a special Token ring network card. If you are
-  connected to such a Token Ring network and want to use your Token
-  Ring card under Linux, say Y here and to the driver for your
-  particular card below and read the Token-Ring mini-HOWTO, available
-  from <http://www.linuxdoc.org/docs.html#howto>. Most people can
-  say N here.
-
-IBM Tropic chipset based adapter support
-CONFIG_IBMTR
-  This is support for all IBM Token Ring cards that don't use DMA. If
-  you have such a beast, say Y and read the Token-Ring mini-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  Warning: this driver will almost definitely fail if more than one
-  active Token Ring card is present.
-
-  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 ibmtr.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-IBM Olympic chipset PCI adapter support
-CONFIG_IBMOL
-  This is support for all non-Lanstreamer IBM PCI Token Ring Cards.
-  Specifically this is all IBM PCI, PCI Wake On Lan, PCI II, PCI II
-  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>.
-
-  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 olympic.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-  Also read <file:Documentation/networking/olympic.txt> or check the
-  Linux Token Ring Project site for the latest information at
-  <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 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).
-  The modules will be called lanstreamer.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-Generic TMS380 Token Ring ISA/PCI/MCA/EISA adapter support
-CONFIG_TMS380TR
-  This driver provides generic support for token ring adapters
-  based on the Texas Instruments TMS380 series chipsets.  This
-  includes the SysKonnect TR4/16(+) ISA (SK-4190), SysKonnect
-  TR4/16(+) PCI (SK-4590), SysKonnect TR4/16 PCI (SK-4591),
-  Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and several
-  Madge adapters.  If you say Y here, you will be asked to select
-  which cards to support below.  If you're using modules, each
-  class of card will be supported by a separate module.
-
-  If you have such an adapter and would like to use it, say Y and
-  read the Token-Ring mini-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  Also read the file <file:Documentation/networking/tms380tr.txt> or
-  check <http://www.auk.cx/tms380tr/>.
-
-  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 tms380tr.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-Generic TMS380 PCI support
-CONFIG_TMSPCI
-  This tms380 module supports generic TMS380-based PCI cards.
-
-  These cards are known to work:
-     - Compaq 4/16 TR PCI
-     - SysKonnect TR4/16 PCI (SK-4590/SK-4591)
-     - Thomas-Conrad TC4048 PCI 4/16
-     - 3Com Token Link Velocity
-
-  This driver is available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called tmspci.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-Generic TMS380 ISA support
-CONFIG_TMSISA
-  This tms380 module supports generic TMS380-based ISA cards.
-
-  These cards are known to work:
-     - SysKonnect TR4/16 ISA (SK-4190)
-
-  This driver is available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called tmsisa.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-Madge Smart 16/4 PCI Mk2 support
-CONFIG_ABYSS
-  This tms380 module supports the Madge Smart 16/4 PCI Mk2
-  cards (51-02).
-
-  This driver is available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called abyss.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-Madge Smart 16/4 Ringnode MicroChannel
-CONFIG_MADGEMC
-  This tms380 module supports the Madge Smart 16/4 MC16 and MC32
-  MicroChannel adapters.
-
-  This driver is available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called madgemc.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-SMC ISA/MCA Token Ring adapter support
-CONFIG_SMCTR
-  This is support for the ISA and MCA SMC Token Ring cards,
-  specifically SMC TokenCard Elite (8115T) and SMC TokenCard Elite/A
-  (8115T/A) adapters.
-
-  If you have such an adapter and would like to use it, say Y or M and
-  read the Token-Ring mini-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto> and the file
-  <file:Documentation/networking/smctr.txt>.
-
-  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 smctr.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-Sun Happy Meal 10/100baseT support
-CONFIG_HAPPYMEAL
-  This driver supports the "hme" interface present on most Ultra
-  systems and as an option on older Sbus systems. This driver supports
-  both PCI and Sbus devices. This driver also supports the "qfe" quad
-  100baseT device available in both PCI and Sbus configurations.
-
-  This support is also available as a module called sunhme.o ( = 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>.
-
-Sun Lance support
-CONFIG_SUNLANCE
-  This driver supports the "le" interface present on all 32-bit Sparc
-  systems, on some older Ultra systems and as an Sbus option.  These
-  cards are based on the AMD Lance chipset, which is better known
-  via the NE2100 cards.
-
-  This support is also available as a module called sunlance.o ( =
-  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>.
-
-Sun BigMAC 10/100baseT support
-CONFIG_SUNBMAC
-  This driver supports the "be" interface available as an Sbus option.
-  This is Sun's older 100baseT Ethernet device.
-
-  This support is also available as a module called sunbmac.o ( = 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>.
-
-Sun QuadEthernet support
-CONFIG_SUNQE
-  This driver supports the "qe" 10baseT Ethernet device, available as
-  an Sbus option. Note that this is not the same as Quad FastEthernet
-  "qfe" which is supported by the Happy Meal driver instead.
-
-  This support is also available as a module called sunqe.o ( = 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>.
-
-Traffic Shaper
-CONFIG_SHAPER
-  The traffic shaper is a virtual network device that allows you to
-  limit the rate of outgoing data flow over some other network device.
-  The traffic that you want to slow down can then be routed through
-  these virtual devices. See
-  <file:Documentation/networking/shaper.txt> for more information.
-
-  An alternative to this traffic shaper is the experimental
-  Class-Based Queueing (CBQ) scheduling support which you get if you
-  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
-  shaper package.
-
-  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 shaper.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.  If
-  unsure, say N.
-
-FDDI driver support
-CONFIG_FDDI
-  Fiber Distributed Data Interface is a high speed local area network
-  design; essentially a replacement for high speed Ethernet. FDDI can
-  run over copper or fiber. If you are connected to such a network and
-  want a driver for the FDDI card in your computer, say Y here (and
-  then also Y to the driver for your FDDI card, below). Most people
-  will say N.
-
-Digital DEFEA and DEFPA adapter support
-CONFIG_DEFXX
-  This is support for the DIGITAL series of EISA (DEFEA) and PCI
-  (DEFPA) controllers which can connect you to a local FDDI network.
-
-SysKonnect FDDI PCI support
-CONFIG_SKFP
-  Say Y here if you have a SysKonnect FDDI PCI adapter.
-  The following adapters are supported by this driver:
-  - SK-5521 (SK-NET FDDI-UP)
-  - SK-5522 (SK-NET FDDI-UP DAS)
-  - SK-5541 (SK-NET FDDI-FP)
-  - SK-5543 (SK-NET FDDI-LP)
-  - SK-5544 (SK-NET FDDI-LP DAS)
-  - SK-5821 (SK-NET FDDI-UP64)
-  - SK-5822 (SK-NET FDDI-UP64 DAS)
-  - SK-5841 (SK-NET FDDI-FP64)
-  - SK-5843 (SK-NET FDDI-LP64)
-  - SK-5844 (SK-NET FDDI-LP64 DAS)
-  - Netelligent 100 FDDI DAS Fibre SC
-  - Netelligent 100 FDDI SAS Fibre SC
-  - Netelligent 100 FDDI DAS UTP
-  - Netelligent 100 FDDI SAS UTP
-  - Netelligent 100 FDDI SAS Fibre MIC
-
-  Read <file:Documentation/networking/skfp.txt> for information about
-  the driver.
-
-  Questions concerning this driver can be addressed to:
-    linux@syskonnect.de
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called skfp.o.
-
-HIgh Performance Parallel Interface (HIPPI) support
-CONFIG_HIPPI
-  HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and
-  1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI
-  can run over copper (25m) or fiber (300m on multi-mode or 10km on
-  single-mode). HIPPI networks are commonly used for clusters and to
-  connect to super computers. If you are connected to a HIPPI network
-  and have a HIPPI network card in your computer that you want to use
-  under Linux, say Y here (you must also remember to enable the driver
-  for your HIPPI card below). Most people will say N here.
-
-Essential RoadRunner HIPPI PCI adapter support
-CONFIG_ROADRUNNER
-  Say Y here if this is your PCI HIPPI network card.
-
-  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 rrunner.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.  If
-  unsure, say N.
-
-Use large TX/RX rings
-CONFIG_ROADRUNNER_LARGE_RINGS
-  If you say Y here, the RoadRunner driver will preallocate up to 2 MB
-  of additional memory to allow for fastest operation, both for
-  transmitting and receiving. This memory cannot be used by any other
-  kernel code or by user space programs. Say Y here only if you have
-  the memory.
-
-Acorn Ether1 support
-CONFIG_ARM_ETHER1
-  If you have an Acorn system with one of these (AKA25) network cards,
-  you should say Y to this option if you wish to use it with Linux.
-
-Acorn/ANT Ether3 support
-CONFIG_ARM_ETHER3
-  If you have an Acorn system with one of these network cards, you
-  should say Y to this option if you wish to use it with Linux.
-
-I-Cubed EtherH support
-CONFIG_ARM_ETHERH
-  If you have an Acorn system with one of these network cards, you
-  should say Y to this option if you wish to use it with Linux.
-
-EBSA-110 Ethernet interface (AM79C961A)
-CONFIG_ARM_AM79C961A
-  If you wish to compile a kernel for the EBSA-110, then you should
-  always answer Y to this.
-
-Support Thumb instructions
-CONFIG_ARM_THUMB
-  Say Y if you want to have kernel support for ARM Thumb instructions,
-  fault handlers, and system calls.
-
-  The Thumb instruction set is a compressed form of the standard ARM
-  instruction set resulting in smaller binaries at the expense of
-  slightly less efficient code.
-
-  If you don't know what this all is, saying Y is a safe choice.
-
-Support CD-ROM drives that are not SCSI or IDE/ATAPI
-CONFIG_CD_NO_IDESCSI
-  If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y
-  here, otherwise N. Read the CD-ROM-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  Note that the answer to this question doesn't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about these CD-ROM drives. If you are unsure what you
-  have, say Y and find out whether you have one of the following
-  drives.
-
-  For each of these drivers, a file Documentation/cdrom/{driver_name}
-  exists. Especially in cases where you do not know exactly which kind
-  of drive you have you should read there. Most of these drivers use a
-  file drivers/cdrom/{driver_name}.h where you can define your
-  interface parameters and switch some internal goodies.
-
-  All these CD-ROM drivers are also usable as a module ( = code which
-  can be inserted in and removed from the running kernel whenever you
-  want). If you want to compile them as module, say M instead of Y and
-  read <file:Documentation/modules.txt>.
-
-  If you want to use any of these CD-ROM drivers, you also have to
-  answer Y or M to "ISO 9660 CD-ROM file system support" below (this
-  answer will get "defaulted" for you if you enable any of the Linux
-  CD-ROM drivers).
-
-Sony CDU31A/CDU33A CD-ROM support
-CONFIG_CDU31A
-  These CD-ROM drives have a spring-pop-out caddyless drawer, and a
-  rectangular green LED centered beneath it.  NOTE: these CD-ROM
-  drives will not be auto detected by the kernel at boot time; you
-  have to provide the interface address as an option to the kernel at
-  boot time as described in <file:Documentation/cdrom/cdu31a> or fill
-  in your parameters into <file:drivers/cdrom/cdu31a.c>.  Try "man
-  bootparam" or see the documentation of your boot loader (lilo or
-  loadlin) about how to pass options to the kernel.
-
-  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-  file system support" below, because that's the file system used on
-  CD-ROMs.
-
-  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 cdu31a.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Standard Mitsumi [no XA/Multisession] CD-ROM support
-CONFIG_MCD
-  This is the older of the two drivers for the older Mitsumi models
-  LU-005, FX-001 and FX-001D. This is not the right driver for the
-  FX-001DE and the triple or quad speed models (all these are
-  IDE/ATAPI models). Please also the file
-  <file:Documentation/cdrom/mcd>.
-
-  With the old LU-005 model, the whole drive chassis slides out for cd
-  insertion. The FX-xxx models use a motorized tray type mechanism.
-  Note that this driver does not support XA or MultiSession CDs
-  (PhotoCDs). There is a new driver (next question) which can do
-  this. If you want that one, say N here.
-
-  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-  file system support" below, because that's the file system used on
-  CD-ROMs.
-
-  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 mcd.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-IRQ channel for Mitsumi CD-ROM
-CONFIG_MCD_IRQ
-  This allows you to specify the default value of the IRQ used by the
-  driver. This setting can be overridden by passing the "mcd="
-  parameter to the kernel at boot time (or at module load time if you
-  said M to "Standard Mitsumi CD-ROM support").
-
-I/O base address for Mitsumi CD-ROM
-CONFIG_MCD_BASE
-  This allows you to specify the default value of the I/O base address
-  used by the driver. This setting can be overridden by passing the
-  "mcd=" parameter to the kernel at boot time (or at module load time
-  if you said M to "Standard Mitsumi CD-ROM support").
-
-Mitsumi [XA/MultiSession] CD-ROM support
-CONFIG_MCDX
-  Use this driver if you want to be able to read XA or MultiSession
-  CDs (PhotoCDs) as well as ordinary CDs with your Mitsumi LU-005,
-  FX-001 or FX-001D CD-ROM drive. In addition, this driver uses much
-  less kernel memory than the old one, if that is a concern. This
-  driver is able to support more than one drive, but each drive needs
-  a separate interface card. Please read the file
-  <file:Documentation/cdrom/mcdx>.
-
-  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-  file system support" below, because that's the file system used on
-  CD-ROMs.
-
-  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 mcdx.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Matsushita/Panasonic/Creative, Longshine, TEAC CD-ROM support
-CONFIG_SBPCD
-  This driver supports most of the drives which use the Panasonic or
-  Sound Blaster interface.  Please read the file
-  <file:Documentation/cdrom/sbpcd>.
-
-  The Matsushita CR-521, CR-522, CR-523, CR-562, CR-563 drives
-  (sometimes labeled "Creative"), the Creative Labs CD200, the
-  Longshine LCS-7260, the "IBM External ISA CD-ROM" (in fact a CR-56x
-  model), the TEAC CD-55A fall under this category.  Some other
-  "electrically compatible" drives (Vertos, Genoa, some Funai models)
-  are currently not supported; for the Sanyo H94A drive currently a
-  separate driver (asked later) is responsible.  Most drives have a
-  uniquely shaped faceplate, with a caddyless motorized drawer, but
-  without external brand markings.  The older CR-52x drives have a
-  caddy and manual loading/eject, but still no external markings.  The
-  driver is able to do an extended auto-probing for interface
-  addresses and drive types; this can help to find facts in cases you
-  are not sure, but can consume some time during the boot process if
-  none of the supported drives gets found.  Once your drive got found,
-  you should enter the reported parameters into
-  <file:drivers/cdrom/sbpcd.h> and set "DISTRIBUTION 0" there.
-
-  This driver can support up to four CD-ROM controller cards, and each
-  card can support up to four CD-ROM drives; if you say Y here, you
-  will be asked how many controller cards you have.  If compiled as a
-  module, only one controller card (but with up to four drives) is
-  usable.
-
-  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-  file system support" below, because that's the file system used on
-  CD-ROMs.
-
-  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 sbpcd.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Matsushita/Panasonic, ... second CD-ROM controller support
-CONFIG_SBPCD2
-  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:drivers/cdrom/sbpcd.h> before compiling the new kernel.  Read
-  the file <file:Documentation/cdrom/sbpcd>.
-
-Matsushita/Panasonic, ... third CD-ROM controller support
-CONFIG_SBPCD3
-  Say Y here only if you have three CD-ROM controller cards of this
-  type (usually only if you have more than six 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 the file <file:Documentation/cdrom/sbpcd>.
-
-Matsushita/Panasonic, ... fourth CD-ROM controller support
-CONFIG_SBPCD4
-  Say Y here only if you have four CD-ROM controller cards of this
-  type (usually only if you have more than eight 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 the file <file:Documentation/cdrom/sbpcd>.
-
-Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CD-ROM support
-CONFIG_AZTCD
-  This is your driver if you have an Aztech CDA268-01A, Orchid
-  CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCD-ROM CR520 or
-  CR540 CD-ROM drive.  This driver -- just like all these CD-ROM
-  drivers -- is NOT for CD-ROM drives with IDE/ATAPI interfaces, such
-  as Aztech CDA269-031SE. Please read the file
-  <file:Documentation/cdrom/aztcd>.
-
-  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-  file system support" below, because that's the file system used on
-  CD-ROMs.
-
-  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 aztcd.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Sony CDU535 CD-ROM support
-CONFIG_CDU535
-  This is the driver for the older Sony CDU-535 and CDU-531 CD-ROM
-  drives. Please read the file <file:Documentation/cdrom/sonycd535>.
-
-  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-  file system support" below, because that's the file system used on
-  CD-ROMs.
-
-  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 sonycd535.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Goldstar R420 CD-ROM support
-CONFIG_GSCD
-  If this is your CD-ROM drive, say Y here.  As described in the file
-  <file:Documentation/cdrom/gscd>, you might have to change a setting
-  in the file <file:drivers/cdrom/gscd.h> before compiling the
-  kernel.  Please read the file <file:Documentation/cdrom/gscd>.
-
-  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-  file system support" below, because that's the file system used on
-  CD-ROMs.
-
-  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 gscd.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Philips/LMS CM206 CD-ROM support
-CONFIG_CM206
-  If you have a Philips/LMS CD-ROM drive cm206 in combination with a
-  cm260 host adapter card, say Y here. Please also read the file
-  <file:Documentation/cdrom/cm206>.
-
-  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-  file system support" below, because that's the file system used on
-  CD-ROMs.
-
-  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 cm206.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Optics Storage DOLPHIN 8000AT CD-ROM support
-CONFIG_OPTCD
-  This is the driver for the 'DOLPHIN' drive with a 34-pin Sony
-  compatible interface. It also works with the Lasermate CR328A. If
-  you have one of those, say Y. This driver does not work for the
-  Optics Storage 8001 drive; use the IDE-ATAPI CD-ROM driver for that
-  one. Please read the file <file:Documentation/cdrom/optcd>.
-
-  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
-  file system support" below, because that's the file system used on
-  CD-ROMs.
-
-  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 optcd.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Sanyo CDR-H94A CD-ROM support
-CONFIG_SJCD
-  If this is your CD-ROM drive, say Y here and read the file
-  <file:Documentation/cdrom/sjcd>. You should then also say Y or M to
-  "ISO 9660 CD-ROM file system support" below, because that's the
-  file system used on CD-ROMs.
-
-  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 sjcd.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-ISP16/MAD16/Mozart soft configurable cdrom interface support
-CONFIG_ISP16_CDI
-  These are sound cards with built-in cdrom interfaces using the OPTi
-  82C928 or 82C929 chips. Say Y here to have them detected and
-  possibly configured at boot time. In addition, You'll have to say Y
-  to a driver for the particular cdrom drive you have attached to the
-  card. Read <file:Documentation/cdrom/isp16> for details.
-
-  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 isp16.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-iSeries Virtual I/O CD Support
-CONFIG_VIOCD
-  If you are running Linux on an IBM iSeries system and you want to
-  read a CD drive owned by OS/400, say Y here.
-
-Quota support
-CONFIG_QUOTA
-  If you say Y here, you will be able to set per user limits for disk
-  usage (also called disk quotas). Currently, it works only for the
-  ext2 file system. You need additional software in order to use quota
-  support; for details, read the Quota mini-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. Probably the quota
-  support is only useful for multi user systems. If unsure, say N.
-
-Memory Technology Device (MTD) support
-CONFIG_MTD
-  Memory Technology Devices are flash, RAM and similar chips, often
-  used for solid state file systems on embedded devices. This option
-  will provide the generic support for MTD drivers to register
-  themselves with the kernel and for potential users of MTD devices
-  to enumerate the devices which are present and obtain a handle on
-  them. It will also allow you to select individual drivers for 
-  particular hardware and users of MTD devices. If unsure, say N.
-
-MTD debugging support
-CONFIG_MTD_DEBUG
-  This turns on low-level debugging for the entire MTD sub-system.
-  Normally, you should say 'N'.
-
-MTD partitioning support
-CONFIG_MTD_PARTITIONS
-  If you have a device which needs to divide its flash chip(s) up
-  into multiple 'partitions', each of which appears to the user as
-  a separate MTD device, you require this option to be enabled. If
-  unsure, say 'Y'.
-
-  Note, however, that you don't need this option for the DiskOnChip
-  devices. Partitioning on NFTL 'devices' is a different - that's the
-  'normal' form of partitioning used on a block device.
-
-RedBoot partition table parsing
-CONFIG_MTD_REDBOOT_PARTS
-  RedBoot is a ROM monitor and bootloader which deals with multiple
-  'images' in flash devices by putting a table in the last erase block
-  of the device, similar to a partition table, which gives the
-  offsets, lengths and names of all the images stored in the flash.
-
-  If you need code which can detect and parse this table, and register
-  MTD 'partitions' corresponding to each image in the table, enable
-  this option.
-
-  You will still need the parsing functions to be called by the driver
-  for your particular device. It won't happen automatically. The
-  SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
-  example.
-
-Compaq bootldr partition table parsing
-CONFIG_MTD_BOOTLDR_PARTS
-  The Compaq bootldr deals with multiple 'images' in flash devices
-  by putting a table in one of the first erase blocks of the device,
-  similar to a partition table, which gives the offsets, lengths and
-  names of all the images stored in the flash.
-
-  If you need code which can detect and parse this table, and register
-  MTD 'partitions' corresponding to each image in the table, enable
-  this option.
-
-  You will still need the parsing functions to be called by the driver
-  for your particular device. It won't happen automatically. The 
-  SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for 
-  example.
-
-ARM Firmware Suite flash layout / partition parsing
-CONFIG_MTD_AFS_PARTS
-  The ARM Firmware Suite allows the user to divide flash devices into
-  multiple 'images'. Each such image has a header containing its name
-  and offset/size etc.
-
-  If you need code which can detect and parse these tables, and
-  register MTD 'partitions' corresponding to each image detected,
-  enable this option.
-
-  You will still need the parsing functions to be called by the driver
-  for your particular device.  It won't happen automatically.  The 
-  'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
-
-MTD debugging verbosity (0 = quiet, 3 = noisy)
-CONFIG_MTD_DEBUG_VERBOSE
-  Determines the verbosity level of the MTD debugging messages.
-
-Direct chardevice access to MTD devices
-CONFIG_MTD_CHAR
-  This provides a character device for each MTD device present in
-  the system, allowing the user to read and write directly to the
-  memory chips, and also use ioctl() to obtain information about
-  the device, or to erase parts of it.
-
-Caching block device access to MTD devices
-CONFIG_MTD_BLOCK
-  Although most flash chips have an erase size too large to be useful
-  as block devices, it is possible to use MTD devices which are based
-  on RAM chips in this manner. This block device is a user of MTD
-  devices performing that function.
-
-  At the moment, it is also required for the Journalling Flash File
-  System(s) to obtain a handle on the MTD device when it's mounted
-  (although JFFS and JFFS2 don't actually use any of the functionality
-  of the mtdblock device).
-
-  Later, it may be extended to perform read/erase/modify/write cycles
-  on flash chips to emulate a smaller block size. Needless to say,
-  this is very unsafe, but could be useful for file systems which are
-  almost never written to.
-
-  You do not need this option for use with the DiskOnChip devices. For
-  those, enable NFTL support (CONFIG_NFTL) instead.
-
-Readonly block device access to MTD devices
-CONFIG_MTD_BLOCK_RO
-  This allows you to mount read-only file systems (such as cramfs)
-  from an MTD device, without the overhead (and danger) of the caching
-  driver.
-
-  You do not need this option for use with the DiskOnChip devices. For
-  those, enable NFTL support (CONFIG_NFTL) instead.
-
-FTL (Flash Translation Layer) support
-CONFIG_FTL
-  This provides support for the original Flash Translation Layer which
-  is part of the PCMCIA specification. It uses a kind of pseudo-
-  file system on a flash device to emulate a block device with
-  512-byte sectors, on top of which you put a 'normal' file system.
-
-  You may find that the algorithms used in this code are patented
-  unless you live in the Free World where software patents aren't
-  legal - in the USA you are only permitted to use this on PCMCIA
-  hardware, although under the terms of the GPL you're obviously
-  permitted to copy, modify and distribute the code as you wish. Just
-  not use it.
-
-NFTL (NAND Flash Translation Layer) support
-CONFIG_NFTL
-  This provides support for the NAND Flash Translation Layer which is
-  used on M-Systems' DiskOnChip devices. It uses a kind of pseudo-
-  file system on a flash device to emulate a block device with
-  512-byte sectors, on top of which you put a 'normal' file system.
-
-  You may find that the algorithms used in this code are patented
-  unless you live in the Free World where software patents aren't
-  legal - in the USA you are only permitted to use this on DiskOnChip
-  hardware, although under the terms of the GPL you're obviously
-  permitted to copy, modify and distribute the code as you wish. Just
-  not use it.
-
-Write support for NFTL (EXPERIMENTAL)
-CONFIG_NFTL_RW
-  If you're lucky, this will actually work. Don't whinge if it
-  doesn't.  Send mail to the MTD mailing list
-  <linux-mtd@lists.infradead.org> if you want to help to make it more
-  reliable.
-
-Common Flash Interface (CFI) support
-CONFIG_MTD_CFI
-  The Common Flash Interface specification was developed by Intel,
-  AMD and other flash manufactures that provides a universal method
-  for probing the capabilities of flash devices. If you wish to
-  support any device that is CFI-compliant, you need to enable this
-  option. Visit <http://www.amd.com/products/nvd/overview/cfi.html>
-  for more information on CFI.
-
-CFI Advanced configuration options
-CONFIG_MTD_CFI_ADV_OPTIONS
-  If you need to specify a specific endianness for access to flash
-  chips, or if you wish to reduce the size of the kernel by including
-  support for only specific arrangements of flash chips, say 'Y'. This
-  option does not directly affect the code, but will enable other 
-  configuration options which allow you to do so.
-
-  If unsure, say 'N'.
-
-Specific CFI Flash geometry selection
-CONFIG_MTD_CFI_GEOMETRY
-  This option does not affect the code directly, but will enable 
-  some other configuration options which would allow you to reduce
-  the size of the kernel by including support for only certain 
-  arrangements of CFI chips. If unsure, say 'N' and all options 
-  which are supported by the current code will be enabled.
-
-Support 8-bit buswidth
-CONFIG_MTD_CFI_B1
-  If you wish to support CFI devices on a physical bus which is
-  8 bits wide, say 'Y'.
-
-Support 16-bit buswidth
-CONFIG_MTD_CFI_B2
-  If you wish to support CFI devices on a physical bus which is
-  16 bits wide, say 'Y'.
-
-Support 32-bit buswidth
-CONFIG_MTD_CFI_B4
-  If you wish to support CFI devices on a physical bus which is
-  32 bits wide, say 'Y'.
-
-Support 1-chip flash interleave
-CONFIG_MTD_CFI_I1
-  If your flash chips are not interleaved - i.e. you only have one
-  flash chip addressed by each bus cycle, then say 'Y'.
-
-Support 2-chip flash interleave
-CONFIG_MTD_CFI_I2
-  If your flash chips are interleaved in pairs - i.e. you have two
-  flash chips addressed by each bus cycle, then say 'Y'.
-
-Support 4-chip flash interleave
-CONFIG_MTD_CFI_I4
-  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
-Flash cmd/query data swapping
-CONFIG_MTD_CFI_NOSWAP
-  This option defines the way in which the CPU attempts to arrange
-  data bits when writing the 'magic' commands to the chips. Saying
-  'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't
-  enabled, means that the CPU will not do any swapping; the chips
-  are expected to be wired to the CPU in 'host-endian' form. 
-  Specific arrangements are possible with the BIG_ENDIAN_BYTE and
-  LITTLE_ENDIAN_BYTE, if the bytes are reversed.
-
-  If you have a LART, on which the data (and address) lines were
-  connected in a fashion which ensured that the nets were as short
-  as possible, resulting in a bit-shuffling which seems utterly
-  random to the untrained eye, you need the LART_ENDIAN_BYTE option.
-
-  Yes, there really exists something sicker than PDP-endian :)
-
-CFI support for Intel/Sharp Extended Command Set chips
-CONFIG_MTD_CFI_INTELEXT
-  The Common Flash Interface defines a number of different command
-  sets which a CFI-compliant chip may claim to implement. This code
-  provides support for one of those command sets, used on Intel
-  StrataFlash and other parts.
-
-CFI support for AMD/Fujitsu Standard Command Set chips
-CONFIG_MTD_CFI_AMDSTD
-  The Common Flash Interface defines a number of different command
-  sets which a CFI-compliant chip may claim to implement. This code
-  provides support for one of those command sets, used on chips 
-  chips including the AMD Am29LV320.
-
-CFI support for Intel/Sharp Standard Commands
-CONFIG_MTD_CFI_INTELSTD
-  The Common Flash Interface defines a number of different command
-  sets which a CFI-compliant chip may claim to implement. This code
-  provides support for one of those command sets.
-
-pre-CFI Sharp chip support
-CONFIG_MTD_SHARP
-  This option enables support for flash chips using Sharp-compatible
-  commands, including some which are not CFI-compatible and hence 
-  cannot be used with the CONFIG_MTD_CFI_INTELxxx options.
-
-AMD compatible flash chip support (non-CFI)
-CONFIG_MTD_AMDSTD
-  This option enables support for flash chips using AMD-compatible
-  commands, including some which are not CFI-compatible and hence 
-  cannot be used with the CONFIG_MTD_CFI_AMDSTD option.
-
-  It also works on AMD compatible chips that do conform to CFI.
-
-Support for RAM chips in bus mapping
-CONFIG_MTD_RAM
-  This option enables basic support for RAM chips accessed through 
-  a bus mapping driver.
-
-Support for ROM chips in bus mapping
-CONFIG_MTD_ROM
-  This option enables basic support for ROM chips accessed through 
-  a bus mapping driver.
-
-JEDEC device support
-CONFIG_MTD_JEDEC
-  Enable older older JEDEC flash interface devices for self
-  programming flash.  It is commonly used in older AMD chips.  It is
-  only called JEDEC because the JEDEC association
-  <http://www.jedec.org/> distributes the identification codes for the
-  chips. WARNING!!!! This code does not compile and is incomplete as
-  are the specific JEDEC devices drivers.
-
-CFI Flash device mapped on StrongARM SA11x0
-CONFIG_MTD_SA1100
-  This enables access to the flash chips on most platforms based on
-  the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.
-  If you have such a board, say 'Y'.
-
-Support for Compaq bootldr partition tables on SA11x0
-CONFIG_MTD_SA1100_REDBOOT_PARTITIONS
-  Enabling this option will cause the kernel to look for a RedBoot 
-  FIS (Flash Image System) table in the last erase block of the flash
-  chips detected. If you are using RedBoot on your SA11x0-based board
-  and want Linux to present 'partitions' matching the images which
-  RedBoot has listed, say 'Y'.
-
-Support for Compaq bootldr partition tables on SA11x0
-CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS
-  Enabling this option will cause the kernel to look for a Compaq
-  bootldr partition table on the flash chips detected.  If you are
-  using the Compaq bootldr on your SA11x0-based board and want Linux 
-  to present 'partitions' matching the images which the bootldr has
-  listed, say 'Y'.
-
-Flash chip mapping in physical memory
-CONFIG_MTD_PHYSMAP
-  This provides a 'mapping' driver which allows the CFI probe and
-  command set driver code to communicate with flash chips which
-  are mapped physically into the CPU's memory. You will need to
-  configure the physical address and size of the flash chips on
-  your particular board as well as the bus width.
-
-Physical start location of flash chip mapping
-CONFIG_MTD_PHYSMAP_START
-  This is the physical memory location at which the flash chips
-  are mapped on your particular target board. Refer to the
-  memory map which should hopefully be in the documentation for
-  your board.
-
-Physical length of flash chip mapping
-CONFIG_MTD_PHYSMAP_LEN
-  This is the total length of the mapping of the flash chips on
-  your particular board. If there is space, or aliases, in the
-  physical memory map between the chips, this could be larger
-  than the total amount of flash present. Refer to the memory
-  map which should hopefully be in the documentation for your
-  board.
-
-Buswidth of flash in bytes
-CONFIG_MTD_PHYSMAP_BUSWIDTH
-  This is the total width of the data bus of the flash devices
-  in octets. For example, if you have a data bus width of 32
-  bits, you would set the bus width octect value to 4. This is
-  used internally by the CFI drivers.
-
-Flash chip mapping on Sun Microsystems boardsets
-CONFIG_MTD_SUN_UFLASH
-  This provides a 'mapping' driver which supports the way in 
-  which user-programmable flash chips are connected on various 
-  Sun Microsystems boardsets.  This driver will require CFI support 
-  in the kernel, so if you did not enable CFI previously, do that now.
-
-Flash chip mapping on Nora
-CONFIG_MTD_NORA
-  If you had to ask, you don't have one. Say 'N'.
-
-Flash chip mapping on Photron PNC-2000
-CONFIG_MTD_PNC2000
-  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
-CONFIG_MTD_RPXLITE
-  The RPXLite PowerPC board has CFI-compliant chips mapped in
-  a strange sparse mapping. This 'mapping' driver supports that
-  arrangement, allowing the CFI probe and command set driver code
-  to communicate with the chips on the RPXLite board. More at
-  <http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm>.
-
-Flash chip mapping on AMD SC520 CDP board
-CONFIG_MTD_SC520CDP
-  The SC520 CDP board has two banks of CFI-compliant chips and one
-  Dual-in-line JEDEC chip. This 'mapping' driver supports that
-  arrangement, implementing three MTD devices.
-
-Flash chip mapping on Arcom Control Systems SBC-MediaGX
-CONFIG_MTD_SBC_GXX
-  This provides a driver for the on-board flash of Arcom Control
-  Systems' SBC-GXn family of boards, formerly known as SBC-MediaGX.
-  By default the flash is split into 3 partitions which are accessed
-  as separate MTD devices.  This board utilizes Intel StrataFlash.
-  More info at
-  <http://www.arcomcontrols.com/products/icp/pc104/processors/>.
-
-CFI Flash device mapped on D-Box2
-CONFIG_MTD_DBOX2
-  This enables access routines for the flash chips on the Nokia/Sagem
-  D-Box 2 board. If you have one of these boards and would like to use
-  the flash chips on it, say 'Y'.
-
-CFI Flash device mapped on the XScale IQ80310 board
-CONFIG_MTD_IQ80310
-  This enables access routines for the flash chips on the Intel XScale
-  IQ80310 evaluation board. If you have one of these boards and would 
-  like to use the flash chips on it, say 'Y'.
-
-CFI Flash device mapped on AMD NetSc520
-CONFIG_MTD_NETSC520
-  This enables access routines for the flash chips on the AMD NetSc520
-  demonstration board. If you have one of these boards and would like 
-  to use the flash chips on it, say 'Y'.
-
-Flash chip mapping on Arcom Control Systems ELAN-104NC
-CONFIG_MTD_ELAN_104NC
-  This provides a driver for the on-board flash of the Arcom Control
-  System's ELAN-104NC development board. By default the flash
-  is split into 3 partitions which are accessed as separate MTD
-  devices. This board utilizes Intel StrataFlash. More info at
-  <http://www.arcomcontrols.com/products/icp/pc104/processors/>.
-
-Flash chip mapping on Compaq iPAQ/Bitsy
-CONFIG_MTD_BITSY
-  This provides a driver for the on-board flash found in Compaq's
-  iPAQ Palm PC and their research prototype the Itsy. iPAQ info at
-  <http://www5.compaq.com/products/handhelds/pocketpc/> and the
-  Itsy <http://www.research.digital.com/wrl/projects/Itsy/index.html>.
- 
-Flash chip mapping on Compaq iPAQ/Bitsy
-CONFIG_MTD_DC21285
-  This provides a driver for the flash accessed using Intel's
-  21285 bridge used with Intel's StrongARM processors. More info at
-  <http://developer.intel.com/design/bridge/quicklist/dsc-21285.htm>.
-
-Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board
-CONFIG_MTD_CSTM_MIPS_IXX
-  This provides a mapping driver for the Integrated Tecnology Express,
-  Inc (ITE) QED-4N-S01B eval board and the Globespan IVR Reference
-  Board.  It provides the necessary addressing, length, buswidth, vpp
-  code and addition setup of the flash device for these boards.  In
-  addition, this mapping driver can be used for other boards via
-  setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/LEN/BUSWIDTH
-  parameters.  This mapping will provide one mtd device using one
-  partition.  The start address can be offset from the beginning of
-  flash and the len can be less than the total flash device size to
-  allow a window into the flash.  Both CFI and JEDEC probes are
-  called.
-
-Physical start location of flash 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
-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
-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
-CONFIG_MTD_MIXMEM
-  This supports the paging arrangement for access to flash chips
-  on the MixCOM piggyback card, allowing the flash chip drivers
-  to get on with their job of driving the flash chips without
-  having to know about the paging. If you have one of these boards,
-  you probably want to enable this mapping driver. More info is at
-  <http://www.itc.hu/>.
-
-Flash chip mapping 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
-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
-  Board Computer. More information on the board is available at
-  <http://www.tempustech.com/tt301.htm>.
-
-Support for NAND flash devices
-CONFIG_MTD_NAND
-  This enables support for accessing all type of NAND flash
-  devices.
-
-Support for software ECC algorithm
-CONFIG_MTD_NAND_ECC
-  This enables software-based ECC for use with NAND flash chips. It
-  can detect and correct 1 bit errors per 256 byte blocks. This
-  should be used to increase the reliability of the data stored and
-  read on the device.
-
-Support for verify read after write
-CONFIG_MTD_NAND_VERIFY_WRITE
-  This adds an extra check when data is written to the flash. The
-  NAND flash device internally checks only bits transitioning
-  from 1 to 0. There is a rare possibility that even though the
-  device thinks the write was successful, a bit could have been
-  flipped accidentaly due to device wear, gamma rays, whatever.
-  Enable this if you are really paranoid.
-
-Support for the SPIA board
-CONFIG_MTD_NAND_SPIA
-  If you had to ask, you don't have one. Say 'N'.
-
-M-Systems Disk-On-Chip 1000 support
-CONFIG_MTD_DOC1000
-  This provides an MTD device driver for the M-Systems DiskOnChip
-  1000 devices, which are obsolete so you probably want to say 'N'.
-
-M-Systems Disk-On-Chip 2000 and Millennium support
-CONFIG_MTD_DOC2000
-  This provides an MTD device driver for the M-Systems DiskOnChip
-  2000 and Millennium devices.  Originally designed for the DiskOnChip
-  2000, it also now includes support for the DiskOnChip Millennium.
-  If you have problems with this driver and the DiskOnChip Millennium,
-  you may wish to try the alternative Millennium driver below. To use
-  the alternative driver, you will need to undefine DOC_SINGLE_DRIVER
-  in the <file:drivers/mtd/devices/docprobe.c> source code.
-
-  If you use this device, you probably also want to enable the NFTL
-  'NAND Flash Translation Layer' option below, which is used to
-  emulate a block device by using a kind of file system on the flash
-  chips.
-
-Alternative Disk-On-Chip Millennium support
-CONFIG_MTD_DOC2001
-  This provides an alternative MTD device driver for the M-Systems 
-  DiskOnChip Millennium devices.  Use this if you have problems with
-  the combined DiskOnChip 2000 and Millennium driver above.  To get
-  the DiskOnChip probe code to load and use this driver instead of
-  the other one, you will need to undefine DOC_SINGLE_DRIVER near
-  the beginning of <file:drivers/mtd/devices/docprobe.c>.
-
-  If you use this device, you probably also want to enable the NFTL
-  'NAND Flash Translation Layer' option below, which is used to
-  emulate a block device by using a kind of file system on the flash
-  chips.
-
-Probe for DiskOnChip devices
-CONFIG_MTD_DOCPROBE
-  This isn't a real config option, it's derived.
-
-Advanced detection options for DiskOnChip
-CONFIG_MTD_DOCPROBE_ADVANCED
-  This option allows you to specify nonstandard address at which to
-  probe for a DiskOnChip, or to change the detection options.  You
-  are unlikely to need any of this unless you are using LinuxBIOS.
-  Say 'N'.
-
-Probe for 0x55 0xAA BIOS Extension Signature
-CONFIG_MTD_DOCPROBE_55AA
-  Check for the 0x55 0xAA signature of a DiskOnChip, and do not
-  continue with probing if it is absent.  The signature will always be
-  present for a DiskOnChip 2000 or a normal DiskOnChip Millennium.
-  Only if you have overwritten the first block of a DiskOnChip
-  Millennium will it be  absent.  Enable this option if you are using
-  LinuxBIOS or if you need to recover a DiskOnChip Millennium on which
-  you have managed to wipe the first block.
-
-Physical address of DiskOnChip
-CONFIG_MTD_DOCPROBE_ADDRESS
-  By default, the probe for DiskOnChip devices will look for a
-  DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-  This option allows you to specify a single address at which to probe
-  for the device, which is useful if you have other devices in that
-  range which get upset when they are probed.
-
-  (Note that on PowerPC, the normal probe will only check at
-  0xE4000000.)
-
-  Normally, you should leave this set to zero, to allow the probe at
-  the normal addresses.
-
-Probe high addresses
-CONFIG_MTD_DOCPROBE_HIGH
-  By default, the probe for DiskOnChip devices will look for a
-  DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-  This option changes to make it probe between 0xFFFC8000 and
-  0xFFFEE000.  Unless you are using LinuxBIOS, this is unlikely to be
-  useful to you.  Say 'N'.
-
-Ramix PMC551 PCI Mezzanine ram card support
-CONFIG_MTD_PMC551
-  This provides a MTD device driver for the Ramix PMC551 RAM PCI card
-  from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>.
-  These devices come in memory configurations from 32M - 1G.  If you
-  have one, you probably want to enable this.
-
-  If this driver is compiled as a module you get the ability to select
-  the size of the aperture window pointing into the devices memory.
-  What this means is that if you have a 1G card, normally the kernel
-  will use a 1G memory map as its view of the device.  As a module,
-  you can select a 1M window into the memory and the driver will
-  "slide" the window around the PMC551's memory.  This was
-  particularly useful on the 2.2 kernels on PPC architectures as there
-  was limited kernel space to deal with.
-
-PMC551 256M DRAM Bugfix
-CONFIG_MTD_PMC551_BUGFIX
-  Some of Ramix's PMC551 boards with 256M configurations have invalid
-  column and row mux values.  This option will fix them, but will
-  break other memory configurations.  If unsure say N.
-
-PMC551 Debugging
-CONFIG_MTD_PMC551_DEBUG
-  This option makes the PMC551 more verbose during its operation and
-  is only really useful if you are developing on this driver or
-  suspect a possible hardware or driver bug.  If unsure say N.
-
-Use extra onboard system memory as MTD device
-CONFIG_MTD_SLRAM
-  If your CPU cannot cache all of the physical memory in your machine,
-  you can still use it for storage or swap by using this driver to
-  present it to the system as a Memory Technology Device.
-
-Debugging RAM test driver
-CONFIG_MTD_MTDRAM
-  This enables a test MTD device driver which uses vmalloc() to
-  provide storage.  You probably want to say 'N' unless you're
-  testing stuff.
-
-MTDRAM erase block size in KB
-CONFIG_MTDRAM_ERASE_SIZE
-  This allows you to configure the size of the erase blocks in the
-  device emulated by the MTDRAM driver.  If the MTDRAM driver is built
-  as a module, it is also possible to specify this as a parameter when
-  loading the module.
-
-MTDRAM device size in KB
-CONFIG_MTDRAM_TOTAL_SIZE
-  This allows you to configure the total size of the MTD device
-  emulated by the MTDRAM driver.  If the MTDRAM driver is built
-  as a module, it is also possible to specify this as a parameter when
-  loading the module.
-
-SRAM Hexadecimal Absolute position or 0
-CONFIG_MTDRAM_ABS_POS
-  If you have system RAM accessible by the CPU but not used by Linux
-  in normal operation, you can give the physical address at which the
-  available RAM starts, and the MTDRAM driver will use it instead of
-  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
-CONFIG_MTD_CFI_FLAGADM
-  Mapping for the Flaga digital module.  If you don´t have one, ignore
-  this setting.
-
-Momenco Ocelot boot flash device
-CONFIG_MTD_OCELOT
-  This enables access routines for the boot flash device and for the
-  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.
-
-Flash chip mapping 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
-  subsystem which offers higher speeds and more features than the
-  traditional PC serial port.  The bus supplies power to peripherals
-  and allows for hot swapping.  Up to 127 USB peripherals can be
-  connected to a single USB port in a tree structure.  The USB port is
-  the root of the tree, the peripherals are the leaves and the inner
-  nodes are special USB devices called hubs.  Many newer PC's have USB
-  ports and newer peripherals such as scanners, keyboards, mice,
-  modems, and printers support the USB protocol and can be connected
-  to the PC via those ports.
-
-  Say Y here if your computer has a USB port and you want to use USB
-  devices.  You then need to say Y to at least one of "UHCI support"
-  or "OHCI support" below (the type of interface that the USB hardware
-  in your computer provides to the operating system) and then choose
-  from among the drivers for USB peripherals.  You may want to check
-  out the information provided in <file:Documentation/usb/> and
-  especially the links given in <file:Documentation/usb/usb-help.txt>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called usbcore.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB verbose debug messages
-CONFIG_USB_DEBUG
-  Say Y here if you want the USB core & hub drivers to produce a bunch
-  of debug messages to the system log. Select this if you are having a
-  problem with USB support and want to see more of what is going on.
-
-USB fetch large config
-CONFIG_USB_LARGE_CONFIG
-  This option changes the initial request for a config descriptor so
-  that some poorly designed devices will still work.  Some APC UPSes
-  need it.  Basically, the usb subsystem sends a request for a short
-  (8 byte) config, just to find out how large the real config is.
-  Incorrectly implemented devices may choke on this small config
-  request.  This option make the initial request for a quite large
-  config (1009 bytes), and things just work.
-
-  If you have an APC UPS, say Y; otherwise say N.
-
-USB long timeout
-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
-  patient.  There should be no harm in selecting this, but it is
-  needed for some MGE Ellipse UPSes.
-
-  If you have an MGE Ellipse UPS, or you see timeouts in HID
-  transactions, say Y; otherwise say N.
-
-EHCI (USB 2.0) support
-CONFIG_USB_EHCI_HCD
-  The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
-  "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
-  If your USB host controller supports USB 2.0, you will likely want to
-  configure this Host Controller Driver.  At this writing, the primary
-  implementation of EHCI is a chip from NEC, widely available in add-on
-  PCI cards, but implementations are in the works from other vendors
-  including Intel and Philips.  Motherboard support is appearing.
-
-  EHCI controllers are packaged with "companion" host controllers (OHCI
-  or UHCI) to handle USB 1.1 devices connected to root hub ports.  Ports
-  will connect to EHCI if it the device is high speed, otherwise they
-  connect to a companion controller.  If you configure EHCI, you should
-  probably configure the OHCI (for NEC and some other vendors) USB Host
-  Controller Driver too.
-
-  You may want to read <file:Documentation/usb/ehci.txt>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ehci-hcd.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-UHCI (Intel PIIX4, VIA, ...) support
-CONFIG_USB_UHCI
-  The Universal Host Controller Interface is a standard by Intel for
-  accessing the USB hardware in the PC (which is also called the USB
-  host controller). If your USB host controller conforms to this
-  standard, you may want to say Y, but see below. All recent boards
-  with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
-  i810, i820) conform to this standard. Also all VIA PCI chipsets
-  (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
-  133).
-
-  Currently there exist two drivers for UHCI host controllers: this
-  one and the so-called JE driver, which you can get from
-  "UHCI alternate (JE) support", below. You need only one.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called usb-uhci.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-UHCI (Intel PIIX4, VIA, ...) alternate (JE) support
-CONFIG_USB_UHCI_ALT
-  The Universal Host Controller Interface is a standard by Intel for
-  accessing the USB hardware in the PC (which is also called the USB
-  host controller). If your USB host controller conforms to this
-  standard, you may want to say Y, but see below. All recent boards
-  with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
-  i810, i820) conform to this standard. Also all VIA PCI chipsets
-  (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
-  133). If unsure, say Y.
-
-  Currently there exist two drivers for UHCI host controllers: this
-  so-called JE driver, and the one you get from "UHCI support", above.
-  You need only one.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called uhci.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support
-CONFIG_USB_OHCI
-  The Open Host Controller Interface is a standard by
-  Compaq/Microsoft/National for accessing the USB PC hardware (also
-  called USB host controller). If your USB host controller conforms to
-  this standard, say Y. The USB host controllers on most non-Intel
-  architectures and on several x86 compatibles with non-Intel chipsets
-  -- like SiS (aktual 610, 610 and so on) or ALi (ALi IV, ALi V,
-  Aladdin Pro..) -- conform to this standard.
-
-  You may want to read <file:Documentation/usb/ohci.txt>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called usb-ohci.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-USB Human Interface Device (full HID) support
-CONFIG_USB_HID
-  Say Y here if you want full HID support to connect keyboards,
-  mice, joysticks, graphic tablets, or any other HID based devices
-  to your computer via USB. You can't use this driver and the
-  HIDBP (Boot Protocol) keyboard and mouse drivers at the same time.
-  More information is available: <file:Documentation/input/input.txt>.
-
-  If unsure, say Y.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called hid.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-/dev/usb/hiddev raw HID device support
-CONFIG_USB_HIDDEV
-  Say Y here if you want to support HID devices (from the USB
-  specification standpoint) that aren't strictly user interface
-  devices, like monitor controls and Uninterruptable Power Supplies.
-
-  This module supports these devices separately using a separate
-  event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
-  This driver requires CONFIG_USB_HID.
-
-  If unsure, say N.
-
-USB HIDBP Keyboard (basic) support
-CONFIG_USB_KBD
-  Say Y here if you don't want to use the generic HID driver for your
-  USB keyboard and prefer to use the keyboard in its limited Boot
-  Protocol mode instead. This driver is much smaller than the HID one.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called usbkbd.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-  If unsure, say N.
-
-USB HIDBP Mouse (basic) support
-CONFIG_USB_MOUSE
-  Say Y here if you don't want to use the generic HID driver for your
-  USB mouse and prefer to use the mouse in its limited Boot Protocol
-  mode instead. This driver is much smaller than the HID one.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called usbmouse.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-  If unsure, say N.
-
-Wacom Intuos/Graphire tablet support
-CONFIG_USB_WACOM
-  Say Y here if you want to use the USB version of the Wacom Intuos
-  or Graphire tablet.  Make sure to say Y to "Mouse support"
-  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-  (CONFIG_INPUT_EVDEV) as well.
-
-  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 wacom.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Aiptek 8000U tablet support
-CONFIG_USB_AIPTEK
-  Say Y here if you want to use the USB version of the Aiptek 8000U
-  tablet.  Make sure to say Y to "Event interface support"
-  (CONFIG_INPUT_EVDEV) as well.
-
-  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 <file:Documentation/modules.txt>.
-
-Use input layer for ADB devices
-CONFIG_INPUT_ADBHID
-  Say Y here if you want to have ADB (Apple Desktop Bus) HID devices
-  such as keyboards, mice, joysticks, or graphic tablets handled by
-  the input layer.  If you say Y here, make sure to say Y to the
-  corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV),
-  "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface
-  support" (CONFIG_INPUT_EVDEV) as well.
-
-  If you say N here, you still have the option of using the old ADB
-  keyboard and mouse drivers.
-
-  If unsure, say Y.
-
-Input core support
-CONFIG_INPUT
-  Say Y here if you want to enable any of the following options for
-  USB Human Interface Device (HID) support.
-
-  Say Y here if you want to enable any of the USB HID options in the
-  USB support section which require Input core support.
-
-  Otherwise, say N.
-
-Keyboard support
-CONFIG_INPUT_KEYBDEV
-  Say Y here if you want your USB HID keyboard (or an ADB keyboard
-  handled by the input layer) to be able to serve as a system
-  keyboard.
-
-  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 keybdev.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Mouse support
-CONFIG_INPUT_MOUSEDEV
-  Say Y here if you want your USB HID mouse (or ADB mouse handled by
-  the input layer) to be accessible as char devices 13:32+ -
-  /dev/input/mouseX and 13:63 - /dev/input/mice as an emulated ImPS/2
-  mouse.  That way, all user space programs will be able to use your
-  mouse.
-
-  If unsure, say Y.
-
-  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 mousedev.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Horizontal screen resolution
-CONFIG_INPUT_MOUSEDEV_SCREEN_X
-  If you're using a digitizer, or a graphic tablet, and want to use
-  it as a mouse then the mousedev driver needs to know the X window
-  screen resolution you are using to correctly scale the data. If
-  you're not using a digitizer, this value is ignored.
-
-Vertical screen resolution
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y
-  If you're using a digitizer, or a graphic tablet, and want to use
-  it as a mouse then the mousedev driver needs to know the X window
-  screen resolution you are using to correctly scale the data. If
-  you're not using a digitizer, this value is ignored.
-
-Joystick support
-CONFIG_INPUT_JOYDEV
-  Say Y here if you want your USB HID joystick or gamepad to be
-  accessible as char device 13:0+ - /dev/input/jsX device.
-
-  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 joydev.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Event interface support
-CONFIG_INPUT_EVDEV
-  Say Y here if you want your USB or ADB HID device events be
-  accessible under char device 13:64+ - /dev/input/eventX in a generic
-  way.  This is the future ...
-
-USB Scanner support
-CONFIG_USB_SCANNER
-  Say Y here if you want to connect a USB scanner to your computer's
-  USB port. Please read <file:Documentation/usb/scanner.txt> and
-  <file:Documentation/usb/scanner-hp-sane.txt> for more information.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called scanner.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-HP 5300C scanner support 
-CONFIG_USB_HP5300
-  Say Y here if you want to connect a HP5300C scanner to your
-  computer's USB port.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called hp5300.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-USB Audio support
-CONFIG_USB_AUDIO
-  Say Y here if you want to connect USB audio equipment such as
-  speakers to your computer's USB port.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called audio.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB Modem (CDC ACM) support
-CONFIG_USB_ACM
-  This driver supports USB modems and ISDN adapters which support the
-  Communication Device Class Abstract Control Model interface.
-  Please read <file:Documentation/usb/acm.txt> for details.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called acm.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB serial converter support
-CONFIG_USB_SERIAL
-  Say Y here if you have a USB device that provides normal serial
-  ports, or acts like a serial device, and you want to connect it to
-  your USB bus.
-
-  Please read <file:Documentation/usb/usb-serial.txt> for more
-  information on the specifics of the different devices that are
-  supported, and on how to use them.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called usbserial.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-USB Generic Serial Driver
-CONFIG_USB_SERIAL_GENERIC
-  Say Y here if you want to use the generic USB serial driver.  Please
-  read <file:Documentation/usb/usb-serial.txt> for more information on
-  using this driver.  It is recommended that the "USB Serial converter
-  support" be compiled as a module for this driver to be used
-  properly.
-
-USB ConnectTech WhiteHEAT Serial Driver
-CONFIG_USB_SERIAL_WHITEHEAT
-  Say Y here if you want to use a ConnectTech WhiteHEAT 4 port
-  USB to serial converter device.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called whiteheat.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-USB Handspring Visor Driver
-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
-  driver.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called visor.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB Compaq iPAQ Driver
-CONFIG_USB_SERIAL_IPAQ
-  Say Y here if you want to connect to your Compaq iPAQ running
-  Windows CE 3.0 using a USB autosync cable. For information on using
-  the driver, read <file:Documentation/usb/usb-serial.txt>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ipaq.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB IR Dongle Serial Driver
-CONFIG_USB_SERIAL_IR
-  Say Y here if you want to enable simple serial support for USB IrDA
-  devices.  This is useful if you do not want to use the full IrDA
-  stack.
-  
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ir-usb.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB IR Dongle Serial Driver
-CONFIG_USB_SERIAL_IR
-  Say Y here if you want to enable simple serial support for USB IrDA
-  devices.  This is useful if you do not want to use the full IrDA
-  stack.
-  
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ir-usb.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB Belkin and Paracom Single Port Serial Driver
-CONFIG_USB_SERIAL_BELKIN
-  Say Y here if you want to use a Belkin USB Serial single port
-  adaptor (F5U103 is one of the model numbers) or the Peracom single
-  port USB to serial adapter.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called belkin_sa.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-USB FTDI Single Port Serial Driver
-CONFIG_USB_SERIAL_FTDI_SIO
-  Say Y here if you want to use a FTDI SIO single port USB to serial
-  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
-  information on this driver and the device.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ftdi_sio.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-USB Keyspan PDA Single Port Serial Driver
-CONFIG_USB_SERIAL_KEYSPAN_PDA
-  Say Y here if you want to use a Keyspan PDA single port USB to
-  serial converter device.  This driver makes use of firmware
-  developed from scratch by Brian Warner.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called keyspan_pda.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-USB Xircom / Entregra Single Port Serial Driver
-CONFIG_USB_SERIAL_XIRCOM
-  Say Y here if you want to use a Xircom or Entregra single port USB to
-  serial converter device.  This driver makes use of firmware
-  developed from scratch by Brian Warner.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called keyspan_pda.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-USB Keyspan USA-xxx Serial Driver
-CONFIG_USB_SERIAL_KEYSPAN
-  Say Y here if you want to use Keyspan USB to serial converter
-  devices.  This driver makes use of Keyspan's official firmware
-  and was developed with their support.  You must also include
-  firmware to support your particular device(s).
-
-  See <http://misc.nu/hugh/keyspan.html> for more information.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called keyspan.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB Keyspan USA-28 Firmware
-CONFIG_USB_SERIAL_KEYSPAN_USA28
-  Say Y here to include firmware for the USA-28 converter.
-
-USB Keyspan USA-28X Firmware
-CONFIG_USB_SERIAL_KEYSPAN_USA28X
-  Say Y here to include firmware for the USA-28X converter.
-  Be sure you have a USA-28X, there are also 28XA and 28XB
-  models, the label underneath has the actual part number.
-
-USB Keyspan USA-28XA Firmware
-CONFIG_USB_SERIAL_KEYSPAN_USA28XA
-  Say Y here to include firmware for the USA-28XA converter.
-  Be sure you have a USA-28XA, there are also 28X and 28XB
-  models, the label underneath has the actual part number.
-
-USB Keyspan USA-28XB Firmware
-CONFIG_USB_SERIAL_KEYSPAN_USA28XB
-  Say Y here to include firmware for the USA-28XB converter.
-  Be sure you have a USA-28XB, there are also 28X and 28XA
-  models, the label underneath has the actual part number.
-
-USB Keyspan USA-19 Firmware
-CONFIG_USB_SERIAL_KEYSPAN_USA19
-  Say Y here to include firmware for the USA-19 converter.
-
-USB Keyspan USA-18X Firmware
-CONFIG_USB_SERIAL_KEYSPAN_USA18X
-  Say Y here to include firmware for the USA-18X converter.
-
-USB Keyspan USA-19W Firmware
-CONFIG_USB_SERIAL_KEYSPAN_USA19W
-  Say Y here to include firmware for the USA-19W converter.
-
-USB Keyspan USA-49W Firmware
-CONFIG_USB_SERIAL_KEYSPAN_USA49W
-  Say Y here to include firmware for the USA-49W converter.
-
-USB ZyXEL omni.net LCD Plus Driver
-CONFIG_USB_SERIAL_OMNINET
-  Say Y here if you want to use a ZyXEL omni.net LCD ISDN TA.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called omninet.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB Digi International AccelePort USB Serial Driver
-CONFIG_USB_SERIAL_DIGI_ACCELEPORT
-  Say Y here if you want to use Digi AccelePort USB 2 or 4 devices,
-  2 port (plus parallel port) and 4 port USB serial converters.  The
-  parallel port on the USB 2 appears as a third serial port on Linux.
-  The Digi Acceleport USB 8 is not yet supported by this driver.
-
-  This driver works under SMP with the usb-uhci driver.  It does not
-  work under SMP with the uhci driver.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called digi_acceleport.o.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-USB Empeg empeg-car Mark I/II Driver
-CONFIG_USB_SERIAL_EMPEG
-  Say Y here if you want to connect to your Empeg empeg-car Mark I/II
-  mp3 player via USB.  The driver uses a single ttyUSB{0,1,2,...}
-  device node.  See <file:Documentation/usb/usb-serial.txt> for more
-  tidbits of information.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called empeg.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB MCT Single Port Serial Driver
-CONFIG_USB_SERIAL_MCT_U232
-  Say Y here if you want to use a USB Serial single port adapter from
-  Magic Control Technology Corp. (U232 is one of the model numbers).
-
-  This driver also works with Sitecom U232-P25 and D-Link DU-H3SP USB
-  BAY devices.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called mct_u232.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-USB Prolific 2303 Single Port Serial Driver
-CONFIG_USB_SERIAL_PL2303
-  Say Y here if you want to use the PL2303 USB Serial single port
-  adapter from Prolific.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called pl2303.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-USB REINER SCT cyberJack pinpad/e-com chipcard reader
-CONFIG_USB_SERIAL_CYBERJACK
-  Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard
-  reader. This is an interface to ISO 7816 compatible contactbased
-  chipcards, e.g. GSM SIMs.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called cyberjack.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-  If unsure, say N.
-
-USB Edgeport Serial Driver
-CONFIG_USB_SERIAL_EDGEPORT
-  Say Y here if you want to use any of the following devices from
-  Inside Out Networks (Digi):
-       Edgeport/4
-       Rapidport/4
-       Edgeport/4t
-       Edgeport/2
-       Edgeport/4i
-       Edgeport/2i
-       Edgeport/421
-       Edgeport/21
-       Edgeport/8
-       Edgeport/8 Dual
-       Edgeport/2D8
-       Edgeport/4D8
-       Edgeport/8i
-       Edgeport/2 DIN
-       Edgeport/4 DIN
-       Edgeport/16 Dual
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called io_edgeport.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-USB PalmConnect (and other KL5KUSB105-based) Single Port Serial Driver
-CONFIG_USB_SERIAL_KLSI
-  Say Y here if you want to use a KL5KUSB105 - based single port
-  serial adapter. The most widely known -- and currently the only
-  tested -- device in this category is the PalmConnect USB Serial
-  adapter sold by Palm Inc. for use with their Palm III and Palm V
-  series PDAs.
-
-  Please read <file:Documentation/usb/usb-serial.txt> for more
-  information.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called kl5kusb105.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-USB Serial Converter verbose debug
-CONFIG_USB_SERIAL_DEBUG
-  Say Y here if you want verbose debug messages from the USB Serial
-  Drivers sent to the kernel debug log.
-
-USB Printer support
-CONFIG_USB_PRINTER
-  Say Y here if you want to connect a USB printer to your computer's
-  USB port.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called printer.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB IBM (Xirlink) C-It Camera support
-CONFIG_USB_IBMCAM
-  Say Y here if you want to connect a IBM "C-It" camera, also known as
-  "Xirlink PC Camera" to your computer's USB port.  For more
-  information, read <file:Documentation/usb/ibmcam.txt>.
-
-  This driver uses the Video For Linux API.  You must enable
-  (Y or M in config) Video For Linux (under Character Devices)
-  to use this driver.  Information on this API and pointers to
-  "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ibmcam.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>. This
-  camera has several configuration options which can be specified when
-  you load the module.  Read <file:Documentation/usb/ibmcam.txt> to
-  learn more.
-
-USB OV511 Camera support
-CONFIG_USB_OV511
-  Say Y here if you want to connect this type of camera to your
-  computer's USB port. See <file:Documentation/usb/ov511.txt> for more
-  information and for a list of supported cameras.
-
-  This driver uses the Video For Linux API. You must say Y or M to
-  "Video For Linux" (under Character Devices) to use this driver.
-  Information on this API and pointers to "v4l" programs may be found
-  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called 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
-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/>.
-
-  This driver should work with the following devices:
-        * Ericsson PipeRider (all variants)
-        * Motorola (DM100 and SB4100)
-        * Broadcom Cable Modem (reference design)
-        * Toshiba PCX1100U and possibly other cable modems
-
-  The device creates a network device (ethX, where X depends on what
-  other networking devices you have in use), as for a normal PCI
-  or ISA based ethernet network card.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called CDCEther.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-NetChip 1080-based USB Host-to-Host Link
-CONFIG_USB_NET1080
-  The NetChip 1080 is a USB 1.1 host controller.  NetChip has a web
-  site with technical information at <http://www.netchip.com/>.
-
-Philips webcam support
-CONFIG_USB_PWC
-  Say Y or M here if you want to use one of these Philips USB webcams:
-  PCA645, PCA646, PCVC675, PCVC680, PCVC690, PCVC730, PCVC740, or
-  the Askey VC010. The PCA635, PCVC665 and PCVC720 are not supported
-  by this driver and never will be.
-
-  This driver has an optional plugin, which is distributed as a binary
-  module only.  It contains code that allow you to use higher
-  resolutions and framerates but may not be distributed as source.
-  But even without this plugin you can these cams for most
-  applications.
-
-  See <file:Documentation/usb/philips.txt> for more information and
-  installation instructions.
-
-  The built-in microphone is enabled by selecting USB Audio support.
-
-  This driver uses the Video For Linux API. You must say Y or M to
-  "Video For Linux" (under Character Devices) to use this driver.
-  Information on this API and pointers to "v4l" programs may be found
-  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called pwc.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB SE401 Camera support
-CONFIG_USB_SE401
-  Say Y here if you want to connect this type of camera to your
-  computer's USB port. See <file:Documentation/usb/se401.txt> for more
-  information and for a list of supported cameras.
-
-  This driver uses the Video For Linux API. You must say Y or M to
-  "Video For Linux" (under Multimedia Devices) to use this driver.
-  Information on this API and pointers to "v4l" programs may be found
-  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called se401.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB STV680 (Pencam) Camera support
-CONFIG_USB_STV680
-  Say Y here if you want to connect this type of camera to your
-  computer's USB port. This includes the Pencam line of cameras.
-  See <file:Documentation/usb/stv680.txt> for more information and for
-  a list of supported cameras.
-
-  This driver uses the Video For Linux API. You must say Y or M to
-  "Video For Linux" (under Multimedia Devices) to use this driver.
-  Information on this API and pointers to "v4l" programs may be found
-  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called stv680.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Vicam
-CONFIG_USB_VICAM
-  Say Y here if you have 3com homeconnect camera (vicam).
-
-  This driver uses the Video For Linux API. You must say Y or M to
-  "Video For Linux" (under Multimedia Devices) to use this driver.
-  Information on this API and pointers to "v4l" programs may be found
-  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called vicam.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-
-Pegasus/Pegasus II based USB-Ethernet device support
-CONFIG_USB_PEGASUS
-  Say Y here if you know you have Pegasus or Pegasus II based adapter.
-  If in doubt then look at linux/drivers/usb/pegasus.h for the complete
-  list of supported devices.
-  If your particular adapter is not in the list and you are _sure_ it
-  is Pegasus or Pegasus II based then send me (pmanolov@lnxw.com) vendor
-  and device IDs.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called 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 '
-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:
-       3Com 3C19250
-       ADS USB-10BT
-       ATEN USB Ethernet
-       ASANTE USB To Ethernet Adapter
-       AOX Endpoints USB Ethernet
-       Correga K.K.
-       D-Link DSB-650C and DU-E10
-       Entrega / Portgear E45
-       I-O DATA USB-ET/T
-       Jaton USB Ethernet Device Adapter
-       Kingston Technology USB Ethernet Adapter
-       Linksys USB10T
-       Mobility USB-Ethernet Adapter
-       NetGear EA-101
-       Peracom Enet and Enet2
-       Portsmith Express Ethernet Adapter
-       Shark Pocket Adapter
-       SMC 2202USB
-       Sony Vaio port extender
-
-  This driver is likely to work with most 10Mbps only USB Ethernet
-  adapters, including some "no brand" devices. It does NOT work on
-  SmartBridges smartNIC or on Belkin F5U111 devices - you should use
-  the CATC NetMate driver for those. If you are not sure which one
-  you need, select both, and the correct one should be selected for
-  you.
-
-  This driver makes the adapter appear as a normal Ethernet interface,
-  typically on eth0, if it is the only ethernet device, or perhaps on
-  eth1, if you have a PCI or ISA ethernet card installed.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called kaweth.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB CATC NetMate-based Ethernet device support
-CONFIG_USB_CATC
-  Say Y if you want to use one of the following 10Mbps USB Ethernet
-  device based on the EL1210A chip. Supported devices are:
-    Belkin F5U111
-    CATC NetMate
-    CATC NetMate II
-    smartBridges smartNIC
-
-  This driver makes the adapter appear as a normal Ethernet interface,
-  typically on eth0, if it is the only ethernet device, or perhaps on
-  eth1, if you have a PCI or ISA ethernet card installed.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called catc.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB Kodak DC-2xx Camera support
-CONFIG_USB_DC2XX
-  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/>).
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called dc2xx.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB Mustek MDC800 Digital Camera support
-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/>).
-  To use it create a device node with "mknod /dev/mustek c 180 32" and
-  configure it in your software.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called mdc800.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB Mass Storage support
-CONFIG_USB_STORAGE
-  Say Y here if you want to connect USB mass storage devices to your
-  computer's USB port.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called usb-storage.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-USB Mass Storage verbose debug
-CONFIG_USB_STORAGE_DEBUG
-  Say Y here in order to have the USB Mass Storage code generate
-  verbose debugging messages.
-
-ISD-200 USB/ATA driver
-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.
-
-  Some of the products that use this chip are:
-
-    - Archos Jukebox 6000
-    - ISD SmartCable for Storage
-    - Taiwan Skymaster CD530U/DEL-0241 IDE bridge
-    - Sony CRX10U CD-R/RW drive
-    - CyQ've CQ8060A CDRW drive
-    - Planex eXtreme Drive RX-25HU USB-IDE cable (not model RX-25U)
-
-USS720 parport driver
-CONFIG_USB_USS720
-  This driver is for USB parallel port adapters that use the Lucent
-  Technologies USS-720 chip. These cables are plugged into your USB
-  port and provide USB compatibility to peripherals designed with
-  parallel port interfaces.
-
-  The chip has two modes: automatic mode and manual mode. In automatic
-  mode, it looks to the computer like a standard USB printer. Only
-  printers may be connected to the USS-720 in this mode. The generic
-  USB printer driver ("USB Printer support", above) may be used in
-  that mode, and you can say N here if you want to use the chip only
-  in this mode.
-
-  Manual mode is not limited to printers, any parallel port
-  device should work. This driver utilizes manual mode.
-  Note however that some operations are three orders of magnitude
-  slower than on a PCI/ISA Parallel Port, so timing critical
-  applications might not work.
-
-  Say Y here if you own an USS-720 USB->Parport cable and intend to
-  connect anything other than a printer to it.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called uss720.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-USB device file system
-CONFIG_USB_DEVICEFS
-  If you say Y here (and to "/proc file system support" in the "File
-  systems section, above), you will get a file /proc/bus/usb/devices
-  which lists the devices currently connected to your USB bus or
-  busses, a file /proc/bus/usb/drivers which lists the USB kernel
-  client drivers currently loaded, and for every connected device a
-  file named  "/proc/bus/usb/xxx/yyy", where xxx is the bus number and
-  yyy the device number; the latter files can be used by user space
-  programs to talk directly to the device. These files are "virtual",
-  meaning they are generated on the fly and not stored on the hard
-  drive.
-
-  You may need to mount the usbdevfs file system to see the files, use
-   mount -t usbdevfs none /proc/bus/usb
-
-  For the format of the various /proc/bus/usb/ files, please read
-  <file:Documentation/usb/proc_usb_info.txt>.
-
-  Please note that this code is completely unrelated to devfs, the
-  "/dev file system support".
-
-  Most users want to say Y here.
-
-Enforce USB bandwidth allocation
-CONFIG_USB_BANDWIDTH
-  If you say Y here, the USB subsystem enforces USB bandwidth
-  allocation and will prevent some device opens from succeeding
-  if they would cause USB bandwidth usage to go above 90% of
-  the bus bandwidth.
-
-  If you say N here, these conditions will cause warning messages
-  about USB bandwidth usage to be logged and some devices or
-  drivers may not work correctly.
-
-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
-  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>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called dabusb.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Host-to-Host USB networking
-CONFIG_USB_USBNET
-  This driver supports network links over USB with USB "Network"
-  or "data transfer" cables, often used to network laptops to PCs.
-  Such cables have chips from suppliers such as Belkin/eTEK, GeneSys
-  (GeneLink), NetChip and Prolific. Intelligent USB devices could also
-  use this approach to provide Internet access, using standard USB
-  cabling. You can find these chips also on some motherboards with
-  USB PC2PC support.
-
-  These links will have names like "usb0", "usb1", etc.  They act
-  like two-node Ethernets, so you can use 802.1d Ethernet Bridging
-  (CONFIG_BRIDGE) to simplify your network routing.
-
-  This code is also available as a kernel module (code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called usbnet.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Freecom USB/ATAPI Bridge support
-CONFIG_USB_STORAGE_FREECOM
-  Support for the Freecom USB to IDE/ATAPI adaptor.
-  Freecom has a web page at <http://www.freecom.de/>.
-
-Microtech CompactFlash/SmartMedia reader
-CONFIG_USB_STORAGE_DPCM
-  Say Y here to support the Microtech ZiO! CompactFlash/SmartMedia
-  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
-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.
-
-USB Diamond Rio500 support
-CONFIG_USB_RIO500
-  Say Y here if you want to connect a USB Rio500 mp3 player to your
-  computer's USB port. Please read <file:Documentation/usb/rio.txt>
-  for more information.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called rio500.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-USB Auerswald ISDN device support
-CONFIG_USB_AUERSWALD
-  Say Y here if you want to connect an Auerswald USB ISDN Device
-  to your computer's USB port.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called auerswald.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-D-Link DSB-R100 FM radio support
-CONFIG_USB_DSBR
-  Say Y here if you want to connect this type of radio to your
-  computer's USB port. Note that the audio is not digital, and
-  you must connect the line out connector to a sound card or a
-  set of speakers.
-
-  This driver uses the Video For Linux API.  You must enable
-  (Y or M in config) Video For Linux (under Character Devices)
-  to use this driver.  Information on this API and pointers to
-  "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called dsbr100.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Always do synchronous disk IO for UBD
-CONFIG_BLK_DEV_UBD_SYNC
-  The User-Mode Linux port includes a driver called UBD which will let
-  you access arbitrary files on the host computer as block devices.
-  Writes to such a block device are not immediately written to the
-  host's disk; this may cause problems if, for example, the User-Mode
-  Linux 'Virtual Machine' uses a journalling file system and the host
-  computer crashes.
-
-  Synchronous operation (i.e. always writing data to the host's disk
-  immediately) is configurable on a per-UBD basis by using a special
-  kernel command line option.  Alternatively, you can say Y here to
-  turn on synchronous operation by default for all block.
-
-  If you're running a journalling file system (like reiserfs, for
-  example) in your virtual machine, you will want to say Y here.  If
-  you care for the safety of the data in your virtual machine, Y is a
-  wise choice too.  In all other cases (for example, if you're just
-  playing around with User-Mode Linux) you can choose N.
-
-Enable ptrace proxy
-CONFIG_PT_PROXY
-  This option enables a debugging interface which allows gdb to debug
-  the kernel without needing to actually attach to kernel threads.
-  If you want to do kernel debugging, say Y here; otherwise say N.
-
-Management console
-CONFIG_MCONSOLE
-  The user mode linux management console is a low-level interface to
-  the kernel, somewhat like the i386 SysRq interface.  Since there is
-  a full-blown operating system running under every user mode linux
-  instance, there is much greater flexibility possible than with the
-  SysRq mechanism.
-
-  If you answer 'Y' to this option, to use this feature, you need the
-  mconsole client (called uml_mconsole) which is present in CVS in
-  2.4.5-9um and later (path /tools/mconsole), and is also in the
-  distribution RPM package in 2.4.6 and later.
-
-  It is safe to say 'Y' here.
-
-Enable kernel debugging symbols
-CONFIG_DEBUGSYM
-  When this is enabled, the User-Mode Linux binary will include
-  debugging symbols.  This enlarges the binary by a few megabytes,
-  but aids in tracking down kernel problems in UML.  It is required
-  if you intend to do any kernel development.
-
-  If you're truly short on disk space or don't expect to report any
-  bugs back to the UML developers, say N, otherwise say Y.
-
-Enable gcov support
-CONFIG_GCOV
-  This option allows developers to retrieve coverage data from a UML
-  session.
-
-  See <http://user-mode-linux.sourceforge.net/gcov.html> for more
-  details.
-
-  If you're involved in UML kernel development and want to use gcov,
-  say Y.  If you're unsure, say N.
-
-Enable gprof support
-CONFIG_GPROF
-  This allows profiling of a User-Mode Linux kernel with the gprof
-  utility.
-
-  See <http://user-mode-linux.sourceforge.net/gprof.html> for more
-  details.
-
-  If you're involved in UML kernel development and want to use gprof,
-  say Y.  If you're unsure, say N.
-
-Host filesystem
-CONFIG_HOSTFS
-  While the User-Mode Linux port uses its own root file system for
-  booting and normal file access, this module lets the UML user
-  access files stored on the host.  It does not require any
-  network connection between the Host and UML.  An example use of
-  this might be:
-
-  mount none /tmp/fromhost -t hostfs -o /tmp/umlshare
-
-  where /tmp/fromhost is an empty directory inside UML and
-  /tmp/umlshare is a directory on the host with files the UML user
-  wishes to access.
-
-  For more information, see
-  <http://user-mode-linux.sourceforge.net/hostfs.html>.
-
-  If you'd like to be able to work with files stored on the host, 
-  say Y or M here; otherwise say N.
-
-Example IO Memory driver
-CONFIG_MMAPPER
-  The User-Mode Linux port can provide support for IO Memory
-  emulation with this option.  This allows a host file to be
-  specified as an I/O region on the kernel command line. That file
-  will be mapped into UML's kernel address space where a driver can
-  locate it and do whatever it wants with the memory, including
-  providing an interface to it for UML processes to use.
-
-  For more information, see
-  <http://user-mode-linux.sourceforge.net/iomem.html>.
-
-  If you'd like to be able to provide a simulated IO port space for
-  User-Mode Linux processes, say Y.  If unsure, say N.
-
-Virtual Serial Line
-CONFIG_SSL
-  The User-Mode Linux environment allows you to create virtual serial
-  lines on the UML that are usually made to show up on the host as
-  ttys or ptys.
-
-  See <http://user-mode-linux.sourceforge.net/input.html> for more
-  information and command line examples of how to use this facility.
-
-  Unless you have a specific reason for disabling this, say Y.
-
-Virtual network device
-CONFIG_UML_NET
-  While the User-Mode port cannot directly talk to any physical
-  hardware devices, this choice and the following transport options
-  provide one or more virtual network devices through which the UML
-  kernels can talk to each other, the host, and with the host's help,
-  machines on the outside world.
-
-  For more information, including explations of the networking and
-  sample configurations, see
-  <http://user-mode-linux.sourceforge.net/networking.html>.
-
-  If you'd like to be able to enable networking in the User-Mode
-  linux environment, say Y; otherwise say N.  Note that you must
-  enable at least one of the following transport options to actually
-  make use of UML networking.
-
-Daemon transport
-CONFIG_UML_NET_DAEMON
-  This User-Mode Linux network transport allows one or more running
-  UMLs on a single host to communicate with each other, but not to
-  the host.
-
-  To use this form of networking, you'll need to run the UML
-  networking daemon on the host.
-
-  For more information, see
-  <http://user-mode-linux.sourceforge.net/networking.html>  That site
-  has examples of the UML command line to use to enable Daemon
-  networking.
-
-  If you'd like to set up a network with other UMLs on a single host,
-  say Y.  If you need a network between UMLs on multiple physical
-  hosts, choose the Multicast Transport.  To set up a network with
-  the host and/or other IP machines, say Y to the Ethertap or Slip
-  transports.  You'll need at least one of them, but may choose
-  more than one without conflict.  If you don't need UML networking,
-  say N.
-
-Ethertap transport
-CONFIG_UML_NET_ETHERTAP
-  The Ethertap User-Mode Linux network transport allows a single
-  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 it's on a (multi-device, broadcast) virtual
-  Ethernet network, it's in fact communicating over a point-to-point
-  link with the host.
-
-  To use this, your host kernel must have support for Ethertap
-  devices.  Also, if your host kernel is 2.4.x, it must have 
-  CONFIG_NETLINK_DEV configured as Y or M.
-
-  For more information, see
-  <http://user-mode-linux.sourceforge.net/networking.html>  That site
-  has examples of the UML command line to use to enable Ethertap
-  networking.
-
-  If you'd like to set up an IP network with the host and/or the
-  outside world, say Y to this, the Daemon Transport and/or the 
-  Slip Transport.  You'll need at least one of them, but may choose
-  more than one without conflict.  If you don't need UML networking,
-  say N.
-
-TUN/TAP transport
-CONFIG_UML_NET_TUNTAP
-  The UML TUN/TAP network transport allows a UML instance to exchange
-  packets with the host over a TUN/TAP device.  This option will only
-  work with a 2.4 host, unless you've applied the TUN/TAP patch to
-  your 2.2 host kernel.
-
-  To use this transport, your host kernel must have support for TUN/TAP
-  devices, either built-in or as a module.
-
-Multicast transport
-CONFIG_UML_NET_MCAST
-  This Multicast User-Mode Linux network transport allows multiple
-  UMLs (even ones running on different host machines!) to talk to
-  each other over a virtual ethernet network.  However, it requires
-  at least one UML with one of the other transports to act as a
-  bridge if any of them need to be able to talk to their hosts or any
-  other IP machines.
-
-  To use this, your host kernel(s) must support IP Multicasting.
-
-  For more information, see
-  <http://user-mode-linux.sourceforge.net/networking.html>  That site
-  has examples of the UML command line to use to enable Multicast
-  networking, and notes about the security of this approach.
-
-  If you need UMLs on multiple physical hosts to communicate as if
-  they shared an Ethernet network, say Y.  If you need to communicate
-  with other IP machines, make sure you select one of the other
-  transports (possibly in addition to Multicast; they're not
-  exclusive).  If you don't need to network UMLs say N to each of
-  the transports.
-
-SLIP transport
-CONFIG_UML_NET_SLIP
-  The Slip User-Mode Linux network transport allows a running UML to
-  network with its host over a point-to-point link.  Unlike Ethertap,
-  which can carry any Ethernet frame (and hence even non-IP packets),
-  the Slip transport can only carry IP packets.
-
-  To use this, your host must support Slip devices.
-
-  For more information, see
-  <http://user-mode-linux.sourceforge.net/networking.html>.  That site
-  has examples of the UML command line to use to enable Slip
-  networking, and details of a few quirks with it.
-
-  The Ethertap Transport is preferred over Slip because of its
-  limitation.  If you prefer Slip, however, say Y here.  Otherwise
-  choose the Multicast transport (to network multiple UMLs on 
-  multiple hosts), Ethertap (to network with the host and the
-  outside world), and/or the Daemon transport (to network multiple
-  UMLs on a single host).  You may choose more than one without
-  conflict.  If you don't need UML networking, say N.
-
-Microtek USB scanner support
-CONFIG_USB_MICROTEK
-  Say Y here if you want support for the Microtek X6USB and
-  possibly the Phantom 336CX, Phantom C6 and ScanMaker V6U(S)L.
-  Support for anything but the X6 is experimental.
-  Please report failures and successes.
-  The scanner will appear as a scsi generic device to the rest
-  of the system. Scsi support is required for this driver to compile
-  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
-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.
-  The scanner will be accessible as a SCSI device.
-
-USB Bluetooth support
-CONFIG_USB_BLUETOOTH
-  Say Y here if you want to connect a USB Bluetooth device to your
-  computer's USB port. You will need the Bluetooth stack (available
-  at <http://developer.axis.com/software/index.shtml>) to fully use
-  the device.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called bluetooth.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Minix fs support
-CONFIG_MINIX_FS
-  Minix is a simple operating system used in many classes about OS's.
-  The minix file system (method to organize files on a hard disk
-  partition or a floppy disk) was the original file system for Linux,
-  but has been superseded by the second extended file system ext2fs.
-  You don't want to use the minix file system on your hard disk
-  because of certain built-in restrictions, but it is sometimes found
-  on older Linux floppy disks.  This option will enlarge your kernel
-  by about 28 KB. If unsure, say N.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>. The module
-  will be called minix.o.  Note that the file system of your root
-  partition (the one containing the directory /) cannot be compiled as
-  a module.
-
-Reiserfs support
-CONFIG_REISERFS_FS
-  Stores not just filenames but the files themselves in a balanced
-  tree.  Uses journaling.
-
-  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.
-
-  It is more easily extended to have features currently found in
-  database and keyword search systems than block allocation based file
-  systems are.  The next version will be so extended, and will support
-  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.
-
-  Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com.
-
-  If you like it, you can pay us to add new features to it that you
-  need, buy a support contract, or pay us to port it to another OS.
-
-Enable extra Reiserfs consistency checks
-CONFIG_REISERFS_CHECK
-  If you set this to Y, then ReiserFS will perform every check it can
-  possibly imagine of its internal consistency throughout its
-  operation.  It will also go substantially slower.  More than once we
-  have forgotten that this was on, and then gone despondent over the
-  latest benchmarks.:-) Use of this option allows our team to go all
-  out in checking for consistency when debugging without fear of its
-  effect on end users.  If you are on the verge of sending in a bug
-  report, say Y and you might get a useful error message.  Almost
-  everyone 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 (+8 KB).  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 N.
-
-Second extended fs support
-CONFIG_EXT2_FS
-  This is the de facto standard Linux file system (method to organize
-  files on a storage device) for hard disks.
-
-  You want to say Y here, unless you intend to use Linux exclusively
-  from inside a DOS partition using the UMSDOS file system. The
-  advantage of the latter is that you can get away without
-  repartitioning your hard drive (which often implies backing
-  everything up and restoring afterwards); the disadvantage is that
-  Linux becomes susceptible to DOS viruses and that UMSDOS is somewhat
-  slower than ext2fs. Even if you want to run Linux in this fashion,
-  it might be a good idea to have ext2fs around: it enables you to
-  read more floppy disks and facilitates the transition to a *real*
-  Linux partition later. Another (rare) case which doesn't require
-  ext2fs is a diskless Linux box which mounts all files over the
-  network using NFS (in this case it's sufficient to say Y to "NFS
-  file system support" below). Saying Y here will enlarge your kernel
-  by about 44 KB.
-
-  The Ext2fs-Undeletion mini-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, gives information about
-  how to retrieve deleted files on ext2fs file systems.
-
-  To change the behavior of ext2 file systems, you can use the tune2fs
-  utility ("man tune2fs"). To modify attributes of files and
-  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 from
-  <ftp://ibiblio.org/pub/Linux/system/filesystems/ext2/>) and from
-  within Windows NT using the ext2nt command line tool package from
-  <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
-  <http://jnewbigin-pc.it.swin.edu.au/Linux/Explore2fs.htm>.
-
-  If you want to compile this file system 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 ext2.o.  Be aware however that the file system
-  of your root partition (the one containing the directory /) cannot
-  be compiled as a module, and so this could be dangerous.  Most
-  everyone wants to say Y here.
-
-Ext3 journaling 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
-  (method to organize files on a storage device) for hard disks.
-
-  The journaling 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
-  is consistent without the need for a lengthy check.
-
-  Other than adding the journal to the file system, the on-disk format
-  of ext3 is identical to ext2.  It is possible to freely switch
-  between using the ext3 driver and the ext2 driver, as long as the
-  file system has been cleanly unmounted, or e2fsck is run on the file
-  system.
-
-  To add a journal on an existing ext2 file system or change the
-  behavior of ext3 file systems, you can use the tune2fs utility ("man
-  tune2fs").  To modify attributes of files and directories on ext3
-  file systems, use chattr ("man chattr").  You need to be using
-  e2fsprogs version 1.20 or later in order to create ext3 journals
-  (available at <http://sourceforge.net/projects/e2fsprogs/>).
-
-  If you want to compile this file system 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 ext3.o.  Be aware however that the file system
-  of your root partition (the one containing the directory /) cannot
-  be compiled as a module, and so this may be dangerous.
-
-Journal Block Device support (JBD for ext3) (EXPERIMENTAL)
-CONFIG_JBD
-  This is a generic journaling 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.
-
-  If you are using the ext3 file system, you need to say Y here. If
-  you are not using ext3 then you will probably want to say N.
-
-  If you want to compile this device 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 jbd.o.  If you are compiling ext3 into the kernel,
-  you cannot compile this code as a module.
-
-JBD (ext3) debugging support
-CONFIG_JBD_DEBUG
-  If you are using the ext3 journaled file system (or potentially any
-  other file system/device using JBD), this option allows you to
-  enable debugging output while the system is running, in order to
-  help track down any problems you are having.  By default the
-  debugging output will be turned off.
-
-  If you select Y here, then you will be able to turn on debugging
-  with "echo N > /proc/sys/fs/jbd-debug", where N is a number between
-  1 and 5, the higher the number, the more debugging output is
-  generated.  To turn debugging off again, do
-  "echo 0 > /proc/sys/fs/jbd-debug".
-
-Buffer Head tracing (DEBUG)
-CONFIG_BUFFER_DEBUG
-  If you are a kernel developer working with file systems or in the
-  block device layer, this buffer head tracing may help you to track
-  down bugs in your code.  This enables some debugging macros
-  (BUFFER_TRACE, etc.) which allow you to track the state of a buffer
-  through various layers of code.  The debugging code is used
-  primarily by ext3 and JBD code.
-
-  Because this option adds considerably to the size of each buffer,
-  most people will want to say N here.
-
-BFS file system support
-CONFIG_BFS_FS
-  Boot File System (BFS) is a file system used under SCO UnixWare to
-  allow the bootloader access to the kernel image and other important
-  files during the boot process.  It is usually mounted under /stand
-  and corresponds to the slice marked as "STAND" in the UnixWare
-  partition.  You should say Y if you want to read or write the files
-  on your /stand slice from within Linux.  You then also need to say Y
-  to "UnixWare slices support", below.  More information about the BFS
-  file system is contained in the file
-  <file:Documentation/filesystems/bfs.txt>.
-
-  If you don't know what this is about, say N.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called bfs.o.  Note that the file system of your root
-  partition (the one containing the directory /) cannot be compiled as
-  a module.
-
-Compressed ROM file system support
-CONFIG_CRAMFS
-  Saying Y here includes support for CramFs (Compressed ROM File
-  System).  CramFs is designed to be a simple, small, and compressed
-  file system for ROM based embedded systems.  CramFs is read-only,
-  limited to 256MB file systems (with 16MB files), and doesn't support
-  16/32 bits uid/gid, hard links and timestamps.
-
-  See <file:Documentation/filesystems/cramfs.txt> and
-  <file:fs/cramfs/README> for further information.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called cramfs.o.  Note that the root file system (the one
-  containing the directory /) cannot be compiled as a module.
-
-  If unsure, say N.
-
-CMS file system support
-CONFIG_CMS_FS
-  Read only support for CMS minidisk file systems found on IBM
-  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.
-
-Virtual memory file system support
-CONFIG_TMPFS
-  Tmpfs is a file system which keeps all files in virtual memory.
-
-  In contrast to RAM disks, which get allocated a fixed amount of
-  physical RAM, tmpfs grows and shrinks to accommodate the files it
-  contains and is able to swap unneeded pages out to swap space.
-
-  Everything is "virtual" in the sense that no files will be created
-  on your hard drive; if you reboot, everything in tmpfs will be
-  lost.
-
-  You should mount the file system somewhere to be able to use
-  POSIX shared memory. Adding the following line to /etc/fstab should
-  take care of things:
-
-  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).
-
-  You can set limits for the number of blocks and inodes used by the
-  file system with the mount options "size", "nr_blocks" and
-  "nr_inodes". These parameters accept a suffix k, m or g for kilo,
-  mega and giga and can be changed on remount.
-
-  The initial permissions of the root directory can be set with the
-  mount option "mode".
-
-Simple RAM-based file system support
-CONFIG_RAMFS
-  Ramfs is a file system which keeps all files in RAM. It allows
-  read and write access.
-
-  It is more of an programming example than a useable file system.  If
-  you need a file system which lives in RAM with limit checking use
-  tmpfs.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called ramfs.o.
-
-ISO 9660 CD-ROM file system support
-CONFIG_ISO9660_FS
-  This is the standard file system used on CD-ROMs.  It was previously
-  known as "High Sierra File System" and is called "hsfs" on other
-  Unix systems.  The so-called Rock-Ridge extensions which allow for
-  long Unix filenames and symbolic links are also supported by this
-  driver.  If you have a CD-ROM drive and want to do more with it than
-  just listen to audio CDs and watch its LEDs, say Y (and read
-  <file:Documentation/filesystems/isofs.txt> and the CD-ROM-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>), thereby
-  enlarging your kernel by about 27 KB; otherwise say N.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called isofs.o.
-
-Microsoft Joliet CD-ROM extensions
-CONFIG_JOLIET
-  Joliet is a Microsoft extension for the ISO 9660 CD-ROM file system
-  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
-  want to be able to read Joliet CD-ROMs under Linux.
-
-Transparent decompression extension
-CONFIG_ZISOFS
-  This is a Linux-specific extension to RockRidge which lets you store
-  data in compressed form on a CD-ROM and have it transparently
-  decompressed when the CD-ROM is accessed.  See
-  <http://www.kernel.org/pub/linux/utils/fs/zisofs/> for the tools
-  necessary to create such a filesystem.  Say Y here if you want to be
-  able to read such compressed CD-ROMs.
-
-UDF file system support (read-only)
-CONFIG_UDF_FS
-  This is the new file system used on some CD-ROMs and DVDs. Say Y if
-  you intend to mount DVD discs or CDRW's written in packet mode, or
-  if written to by other UDF utilities, such as DirectCD. This UDF
-  file system support is read-only. If you want to write to UDF
-  file systems on some media, you need to say Y to "UDF read-write
-  support" below in addition. Please read
-  <file:Documentation/filesystems/udf.txt>.
-
-  This file system support 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 udf.o. If you want to
-  compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-  If unsure, say N.
-
-UDF write support (DANGEROUS)
-CONFIG_UDF_RW
-  Say Y if you want to test write support for UDF file systems.
-  Due to lack of support for writing to CDR/CDRW's, this option
-  is only supported for hard discs, DVD-RAM, and loopback files.
-
-DOS FAT fs support
-CONFIG_FAT_FS
-  If you want to use one of the FAT-based file systems (the MS-DOS,
-  VFAT (Windows 95) and UMSDOS (used to run Linux on top of an
-  ordinary DOS partition) file systems), then you must say Y or M here
-  to include FAT support. You will then be able to mount partitions or
-  diskettes with FAT-based file systems and transparently access the
-  files on them, i.e. MSDOS files will look and behave just like all
-  other Unix files.
-
-  This FAT support is not a file system in itself, it only provides
-  the foundation for the other file systems. You will have to say Y or
-  M to at least one of "MSDOS fs support" or "VFAT fs support" in
-  order to make use of it.
-
-  Another way to read and write MSDOS floppies and hard drive
-  partitions from within Linux (but not transparently) is with the
-  mtools ("man mtools") program suite. You don't need to say Y here in
-  order to do that.
-
-  If you need to move large files on floppies between a DOS and a
-  Linux box, say Y here, mount the floppy under Linux with an MSDOS
-  file system and use GNU tar's M option. GNU tar is a program
-  available for Unix and DOS ("man tar" or "info tar").
-
-  It is now also becoming possible to read and write compressed FAT
-  file systems; read <file:Documentation/filesystems/fat_cvf.txt> for
-  details.
-
-  The FAT support will enlarge your kernel by about 37 KB. If unsure,
-  say Y.
-
-  If you want to compile this as a module however ( = 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 fat.o.  Note that if you compile the FAT
-  support as a module, you cannot compile any of the FAT-based file
-  systems into the kernel -- they will have to be modules as well.
-  The file system of your root partition (the one containing the
-  directory /) cannot be a module, so don't say M here if you intend
-  to use UMSDOS as your root file system.
-
-MSDOS fs support
-CONFIG_MSDOS_FS
-  This allows you to mount MSDOS partitions of your hard drive (unless
-  they are compressed; to access compressed MSDOS partitions under
-  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://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
-  other Unix files.
-
-  If you want to use UMSDOS, the Unix-like file system on top of a
-  DOS file system, which allows you to run Linux from within a DOS
-  partition without repartitioning, you'll have to say Y or M here.
-
-  If you have Windows 95 or Windows NT installed on your MSDOS
-  partitions, you should use the VFAT file system (say Y to "VFAT fs
-  support" below), or you will not be able to see the long filenames
-  generated by Windows 95 / Windows NT.
-
-  This option will enlarge your kernel by about 7 KB. If unsure,
-  answer Y. This will only work if you said Y to "DOS FAT fs support"
-  as well. If you want to compile this as a module however ( = 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 msdos.o.
-
-VFAT (Windows-95) fs support
-CONFIG_VFAT_FS
-  This option provides support for normal Windows file systems with
-  long filenames.  That includes non-compressed FAT-based file systems
-  used by Windows 95, Windows 98, Windows NT 4.0, and the Unix
-  programs from the mtools package.
-
-  You cannot use the VFAT file system for your Linux root partition
-  (the one containing the directory /); use UMSDOS instead if you
-  want to run Linux from within a DOS partition (i.e. say Y to
-  "Unix like fs on top of std MSDOS fs", below).
-
-  The VFAT support enlarges your kernel by about 10 KB and it only
-  works if you said Y to the "DOS FAT fs support" above.  Please read
-  the file <file:Documentation/filesystems/vfat.txt> for details.  If
-  unsure, say Y.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called vfat.o.
-
-Unix-like file system on top of standard MSDOS fs
-CONFIG_UMSDOS_FS
-  Say Y here if you want to run Linux from within an existing DOS
-  partition of your hard drive. The advantage of this is that you can
-  get away without repartitioning your hard drive (which often implies
-  backing everything up and restoring afterwards) and hence you're
-  able to quickly try out Linux or show it to your friends; the
-  disadvantage is that Linux becomes susceptible to DOS viruses and
-  that UMSDOS is somewhat slower than ext2fs.  Another use of UMSDOS
-  is to write files with long unix filenames to MSDOS floppies; it
-  also allows Unix-style soft-links and owner/permissions of files on
-  MSDOS floppies.  You will need a program called umssync in order to
-  make use of UMSDOS; read
-  <file:Documentation/filesystems/umsdos.txt>.
-
-  To get utilities for initializing/checking UMSDOS file system, or
-  latest patches and/or information, visit the UMSDOS home page at
-  <http://www.voyager.hr/~mnalis/umsdos/>.
-
-  This option enlarges your kernel by about 28 KB and it only works if
-  you said Y to both "DOS FAT fs support" and "MSDOS fs support"
-  above.  If you want to compile this as a module ( = code which can
-  be inserted in and removed from the running kernel whenever you
-  want), say M here and read <file:Documentation/modules.txt>.  The
-  module will be called umsdos.o.  Note that the file system of your
-  root partition (the one containing the directory /) cannot be a
-  module, so saying M could be dangerous.  If unsure, say N.
-
-/proc file system support
-CONFIG_PROC_FS
-  This is a virtual file system providing information about the status
-  of the system. "Virtual" means that it doesn't take up any space on
-  your hard disk: the files are created on the fly by the kernel when
-  you try to access them. Also, you cannot read the files with older
-  version of the program less: you need to use more or cat.
-
-  It's totally cool; for example, "cat /proc/interrupts" gives
-  information about what the different IRQs are used for at the moment
-  (there is a small number of Interrupt ReQuest lines in your computer
-  that are used by the attached devices to gain the CPU's attention --
-  often a source of trouble if two devices are mistakenly configured
-  to use the same IRQ). The program procinfo to display some
-  information about your system gathered from the /proc file system.
-
-  Before you can use the /proc file system, it has to be mounted,
-  meaning it has to be given a location in the directory hierarchy.
-  That location should be /proc. A command such as "mount -t proc proc
-  /proc" or the equivalent line in /etc/fstab does the job.
-
-  The /proc file system is explained in the file
-  <file:Documentation/filesystems/proc.txt> and on the proc(5) manpage
-  ("man 5 proc").
-
-  This option will enlarge your kernel by about 67 KB. Several
-  programs depend on this, so everyone should say Y here.
-
-Support for PReP Residual Data
-CONFIG_PREP_RESIDUAL
-  Some PReP systems have residual data passed to the kernel by the
-  firmware.  This allows detection of memory size, devices present and
-  other useful pieces of information.  Sometimes this information is
-  not present or incorrect.
-
-  Unless you expect to boot on a PReP system, there is not need to
-  select Y.
-
-/dev file system support
-CONFIG_DEVFS_FS
-  This is support for devfs, a virtual file system (like /proc) which
-  provides the file system interface to device drivers, normally found
-  in /dev. Devfs does not depend on major and minor number
-  allocations. Device drivers register entries in /dev which then
-  appear automatically, which means that the system administrator does
-  not have to create character and block special device files in the
-  /dev directory using the mknod command (or MAKEDEV script) anymore.
-
-  This is work in progress. If you want to use this, you *must* read
-  the material in <file:Documentation/filesystems/devfs/>, especially
-  the file README there.
-
-  If unsure, say N.
-
-Automatically mount devfs at boot time
-CONFIG_DEVFS_MOUNT
-  This option appears if you have CONFIG_DEVFS_FS enabled. Setting
-  this to 'Y' will make the kernel automatically mount devfs onto /dev
-  when the system is booted, before the init thread is started.
-  You can override this with the "devfs=nomount" boot option.
-
-  If unsure, say N.
-
-Debug devfs
-CONFIG_DEVFS_DEBUG
-  If you say Y here, then the /dev file system code will generate
-  debugging messages. See the file
-  <file:Documentation/filesystems/devfs/boot-options> for more
-  details.
-
-  If unsure, say N.
-
-NFS file system support
-CONFIG_NFS_FS
-  If you are connected to some other (usually local) Unix computer
-  (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing
-  on that computer (the NFS server) using the Network File Sharing
-  protocol, say Y. "Mounting files" means that the client can access
-  the files with usual UNIX commands as if they were sitting on the
-  client's hard disk. For this to work, the server must run the
-  programs nfsd and mountd (but does not need to have NFS file system
-  support enabled in its kernel). NFS is explained in the Network
-  Administrator's Guide, available from
-  <http://www.linuxdoc.org/docs.html#guide>, on its man page: "man
-  nfs", and in the NFS-HOWTO.
-
-  A superior but less widely used alternative to NFS is provided by
-  the Coda file system; see "Coda file system support" below.
-
-  If you say Y here, you should have said Y to TCP/IP networking also.
-  This option would enlarge your kernel by about 27 KB.
-
-  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 nfs.o. If you want to compile it as a module,
-  say M here and read <file:Documentation/modules.txt>.
-
-  If you are configuring a diskless machine which will mount its root
-  file system over NFS at boot time, say Y here and to "Kernel
-  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, 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.
-
-Provide NFSv3 client support
-CONFIG_NFS_V3
-  Say Y here if you want your NFS client to be able to speak the newer
-  version 3 of the NFS protocol.
-
-  If unsure, say N.
-
-Root file system on NFS
-CONFIG_ROOT_NFS
-  If you want your Linux box to mount its whole root file system (the
-  one containing the directory /) from some other computer over the
-  net via NFS (presumably because your box doesn't have a hard disk),
-  say Y. Read <file:Documentation/nfsroot.txt> for details. It is
-  likely that in this case, you also want to say Y to "Kernel level IP
-  autoconfiguration" so that your box can discover its network address
-  at boot time.
-
-  Most people say N here.
-
-NFS server support
-CONFIG_NFSD
-  If you want your Linux box to act as an NFS *server*, so that other
-  computers on your local network which support NFS can access certain
-  directories on your box transparently, you have two options: you can
-  use the self-contained user space program nfsd, in which case you
-  should say N here, or you can say Y and use the kernel based NFS
-  server. The advantage of the kernel based solution is that it is
-  faster.
-
-  In either case, you will need support software; the respective
-  locations are given in the file <file:Documentation/Changes> in the
-  NFS section.
-
-  If you say Y here, you will get support for version 2 of the NFS
-  protocol (NFSv2). If you also want NFSv3, say Y to the next question
-  as well.
-
-  Please read the NFS-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  The NFS server is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module is called nfsd.o.  If you want to compile it as a module,
-  say M here and read <file:Documentation/modules.txt>.  If unsure,
-  say N.
-
-Provide NFSv3 server support
-CONFIG_NFSD_V3
-  If you would like to include the NFSv3 server as well as the NFSv2
-  server, say Y here.  If unsure, say Y.
-
-Provide NFS over TCP server support DEVELOPER ONLY
-CONFIG_NFSD_TCP
-  If you are a developer and want to work on fixing problems with
-  NFS server over TCP support, say Y here.  If unsure, say N.
-
-  Some problems can be found by looking for FIXME in
-  <file:net/sunrpc/svcsock.c>.
-
-OS/2 HPFS file system support
-CONFIG_HPFS_FS
-  OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS
-  is the file system used for organizing files on OS/2 hard disk
-  partitions. Say Y if you want to be able to read files from and
-  write files to an OS/2 HPFS partition on your hard drive. OS/2
-  floppies however are in regular MSDOS format, so you don't need this
-  option in order to be able to read them. Read
-  <file:Documentation/filesystems/hpfs.txt>.
-
-  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 hpfs.o.  If you want to compile it as a module,
-  say M here and read <file:Documentation/modules.txt>.  If unsure,
-  say N.
-
-NTFS file system support (read-only)
-CONFIG_NTFS_FS
-  NTFS is the file system of Microsoft Windows NT. Say Y if you want
-  to get read access to files on NTFS partitions of your hard drive.
-  The Linux NTFS driver supports most of the mount options of the VFAT
-  driver, see <file:Documentation/filesystems/ntfs.txt>. Saying Y here
-  will give you read-only access to NTFS partitions.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ntfs.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-NTFS write support (DANGEROUS)
-CONFIG_NTFS_RW
-  If you say Y here, you will (maybe) be able to write to NTFS file
-  systems as well as read from them. The read-write support in NTFS
-  is far from being complete and is not well tested. If you say Y
-  here, back up your NTFS volume first, since it will probably get
-  damaged. Also, download the Linux-NTFS project distribution from
-  Sourceforge at <http://linux-ntfs.sf.net/> and always run the
-  included ntfsfix utility after writing to an NTFS partition from
-  Linux to fix some of the damage done by the driver. You should run
-  ntfsfix _after_ unmounting the partition in Linux but _before_
-  rebooting into Windows. When Windows next boots, chkdsk will be
-  run automatically to fix the remaining damage.
-  Please note that write support is limited to Windows NT4 and
-  earlier versions.
-
-  If unsure, say N.
-
-System V/Xenix/V7/Coherent file system support
-CONFIG_SYSV_FS
-  SCO, Xenix and Coherent are commercial Unix systems for Intel
-  machines, and Version 7 was used on the DEC PDP-11. Saying Y
-  here would allow you to read from their floppies and hard disk
-  partitions.
-
-  If you have floppies or hard disk partitions like that, it is likely
-  that they contain binaries from those other Unix systems; in order
-  to run these binaries, you will want to install linux-abi which is a
-  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/>).
-  NOTE: that will work only for binaries from Intel-based systems;
-  PDP ones will have to wait until somebody ports Linux to -11 ;-)
-
-  If you only intend to mount files from some other Unix over the
-  network using NFS, you don't need the System V file system support
-  (but you need NFS file system support obviously).
-
-  Note that this option is generally not needed for floppies, since a
-  good portable way to transport files and directories between unixes
-  (and even other operating systems) is given by the tar program ("man
-  tar" or preferably "info tar").  Note also that this option has
-  nothing whatsoever to do with the option "System V IPC". Read about
-  the System V file system in
-  <file:Documentation/filesystems/sysv-fs.txt>.
-  Saying Y here will enlarge your kernel by about 27 KB.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called sysv.o.
-
-  If you haven't heard about all of this before, it's safe to say N.
-
-Amiga FFS file system support
-CONFIG_AFFS_FS
-  The Fast File System (FFS) is the common file system used on hard
-  disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20).  Say Y
-  if you want to be able to read and write files from and to an Amiga
-  FFS partition on your hard drive.  Amiga floppies however cannot be
-  read with this driver due to an incompatibility of the floppy
-  controller used in an Amiga and the standard floppy controller in
-  PCs and workstations. Read <file:Documentation/filesystems/affs.txt>
-  and <file:fs/affs/Changes>.
-
-  With this driver you can also mount disk files used by Bernd
-  Schmidt's Un*X Amiga Emulator
-  (<http://www.freiburg.linux.de/~uae/>).
-  If you want to do this, you will also need to say Y or M to "Loop
-  device support", above.
-
-  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 affs.o.  If you want to compile it as a module,
-  say M here and read <file:Documentation/modules.txt>.  If unsure,
-  say N.
-
-Apple Macintosh file system support
-CONFIG_HFS_FS
-  If you say Y here, you will be able to mount Macintosh-formatted
-  floppy disks and hard drive partitions with full read-write access.
-  Please read <file:fs/hfs/HFS.txt> to learn about the available mount
-  options.
-
-  This file system support 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 hfs.o.  If you want to
-  compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-ROM file system support
-CONFIG_ROMFS_FS
-  This is a very small read-only file system mainly intended for
-  initial ram disks of installation disks, but it could be used for
-  other read-only media as well.  Read
-  <file:Documentation/filesystems/romfs.txt> for details.
-
-  This file system support 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 romfs.o.  If you want to
-  compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  Note that the file system of your
-  root partition (the one containing the directory /) cannot be a
-  module.
-
-  If you don't know whether you need it, then you don't need it:
-  answer N.
-
-QNX4 file system support (read only)
-CONFIG_QNX4FS_FS
-  This is the file system used by the operating system QNX 4. Say Y if
-  you intend to mount QNX hard disks or floppies. Unless you say Y to
-  "QNX4FS read-write support" below, you will only be able to read
-  these file systems.
-
-  This file system support 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 qnx4.o. If you want to
-  compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-  If you don't know whether you need it, then you don't need it:
-  answer N.
-
-QNX4FS write support (DANGEROUS)
-CONFIG_QNX4FS_RW
-  Say Y if you want to test write support for QNX4 file systems.
-
-Kernel automounter support
-CONFIG_AUTOFS_FS
-  The automounter is a tool to automatically mount remote file systems
-  on demand. This implementation is partially kernel-based to reduce
-  overhead in the already-mounted case; this is unlike the BSD
-  automounter (amd), which is a pure user space daemon.
-
-  To use the automounter you need the user-space tools from the autofs
-  package; you can find the location in <file:Documentation/Changes>.
-  You also want to answer Y to "NFS file system support", below.
-
-  If you want to use the newer version of the automounter with more
-  features, say N here and say Y to "Kernel automounter v4 support",
-  below.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called autofs.o.
-
-  If you are not a part of a fairly large, distributed network, you
-  probably do not need an automounter, and can say N here.
-
-Kernel automounter version 4 support (also supports v3)
-CONFIG_AUTOFS4_FS
-  The automounter is a tool to automatically mount remote file systems
-  on demand. This implementation is partially kernel-based to reduce
-  overhead in the already-mounted case; this is unlike the BSD
-  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
-  want to answer Y to "NFS file system support", below.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called autofs4.o.  You will need to add "alias autofs
-  autofs4" to your modules configuration file.
-
-  If you are not a part of a fairly large, distributed network or
-  don't have a laptop which needs to dynamically reconfigure to the
-  local network, you probably do not need an automounter, and can say
-  N here.
-
-EFS file system support (read-only)
-CONFIG_EFS_FS
-  EFS is an older file system used for non-ISO9660 CD-ROMs and hard
-  disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer
-  uses the XFS file system for hard disk partitions however).
-
-  This implementation only offers read-only access. If you don't know
-  what all this is about, it's safe to say N. For more information
-  about EFS see its home page at <http://aeschi.ch.eu.org/efs/>.
-
-  If you want to compile the EFS file system 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 efs.o.
-
-Journalling Flash File System (JFFS) support
-CONFIG_JFFS_FS
-  JFFS is the Journaling 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/>).
-
-JFFS debugging verbosity (0 = quiet, 3 = noisy)
-CONFIG_JFFS_FS_VERBOSE
-  Determines the verbosity level of the JFFS debugging messages.
-
-Journalling Flash File System v2 (JFFS2) support
-CONFIG_JFFS2_FS
-  JFFS2 is the second generation of the Journalling Flash File System
-  for use on diskless embedded devices. It provides improved wear
-  levelling, compression and support for hard links. You cannot use
-  this on normal block devices, only on 'MTD' devices.
-
-  Further information should be made available soon at
-  <http://sources.redhat.com/jffs2/>.
-
-JFFS2 debugging verbosity (0 = quiet, 2 = noisy)
-CONFIG_JFFS2_FS_DEBUG
-  This controls the amount of debugging messages produced by the JFFS2
-  code. Set it to zero for use in production systems. For evaluation,
-  testing and debugging, it's advisable to set it to one. This will
-  enable a few assertions and will print debugging messages at the
-  KERN_DEBUG loglevel, where they won't normally be visible. Level 2
-  is unlikely to be useful - it enables extra debugging in certain
-  areas which at one point needed debugging, but when the bugs were
-  located and fixed, the detailed messages were relegated to level 2.
-
-  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,
-  OpenBSD and NeXTstep) use a file system called UFS. Some System V
-  Unixes can create and mount hard disk partitions and diskettes using
-  this file system as well. Saying Y here will allow you to read from
-  these partitions; if you also want to write to them, say Y to the
-  experimental "UFS file system write support", below. Please read the
-  file <file:Documentation/filesystems/ufs.txt> for more information.
-
-  If you only intend to mount files from some other Unix over the
-  network using NFS, you don't need the UFS file system support (but
-  you need NFS file system support obviously).
-
-  Note that this option is generally not needed for floppies, since a
-  good portable way to transport files and directories between unixes
-  (and even other operating systems) is given by the tar program ("man
-  tar" or preferably "info tar").
-
-  When accessing NeXTstep files, you may need to convert them from the
-  NeXT character set to the Latin1 character set; use the program
-  recode ("info recode") for this purpose.
-
-  If you want to compile the UFS file system 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 ufs.o.
-
-  If you haven't heard about all of this before, it's safe to say N.
-
-UFS file system write support (DANGEROUS)
-CONFIG_UFS_FS_WRITE
-  Say Y here if you want to try writing to UFS partitions. This is
-  experimental, so you should back up your UFS partitions beforehand.
-
-Advanced partition selection
-CONFIG_PARTITION_ADVANCED
-  Say Y here if you would like to use hard disks under Linux which
-  were partitioned under an operating system running on a different
-  architecture than your Linux system.
-
-  Note that the answer to this question won't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about foreign partitioning schemes.
-
-  If unsure, say N.
-
-Acorn partition support
-CONFIG_ACORN_PARTITION
-  Support hard disks partitioned under Acorn operating systems.
-
-Native filecore partition support
-CONFIG_ACORN_PARTITION_ADFS
-  The Acorn Disc Filing System is the standard file system of the
-  RiscOS operating system which runs on Acorn's ARM-based Risc PC
-  systems and the Acorn Archimedes range of machines.  If you say
-  `Y' here, Linux will support disk partitions created under ADFS.
-
-PowerTec partition support
-CONFIG_ACORN_PARTITION_POWERTEC
-  Support reading partition tables created on Acorn machines using
-  the PowerTec SCSI drive.
-
-RISCiX partition support
-CONFIG_ACORN_PARTITION_RISCIX
-  Once upon a time, there was a native Unix port for the Acorn series
-  of machines called RISCiX.  If you say 'Y' here, Linux will be able
-  to read disks partitioned under RISCiX.
-
-ICS partition support
-CONFIG_ACORN_PARTITION_ICS
-  Say Y here if you would like to use hard disks under Linux which
-  were partitioned using the ICS interface on Acorn machines.
-
-Alpha OSF partition support
-CONFIG_OSF_PARTITION
-  Say Y here if you would like to use hard disks under Linux which
-  were partitioned on an Alpha machine.
-
-Macintosh partition map support
-CONFIG_MAC_PARTITION
-  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)
-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.
-  They are also known as "Dynamic Disks".
-
-  Windows 2000 introduced the concept of Dynamic Disks to get around
-  the limitations of the PC's partitioning scheme.  The Logical Disk
-  Manager allows the user to repartion a disk and create spanned,
-  mirrored, striped or RAID volumes, all without the need for
-  rebooting.
-
-  Normal partitions are now called Basic Disks under Windows 2000 and
-  XP.
-
-  Technical documentation to accompany this driver is available from:
-  <http://linux-ntfs.sf.net/ldm/>.
-
-  If unsure, say N.
-
-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
-  report a bug.
-
-  If unsure, say N.
-
-PC BIOS (MSDOS partition tables) support
-CONFIG_MSDOS_PARTITION
-  Say Y here if you would like to use hard disks under Linux which
-  were partitioned on an x86 PC (not necessarily by DOS).
-
-Amiga partition table support
-CONFIG_AMIGA_PARTITION
-  Say Y here if you would like to use hard disks under Linux which
-  were partitioned under AmigaOS.
-
-Atari partition table support
-CONFIG_ATARI_PARTITION
-  Say Y here if you would like to use hard disks under Linux which
-  were partitioned under the Atari OS.
-
-BSD disklabel (FreeBSD partition tables) support
-CONFIG_BSD_DISKLABEL
-  FreeBSD uses its own hard disk partition scheme on your PC. It
-  requires only one entry in the primary partition table of your disk
-  and manages it similarly to DOS extended partitions, putting in its
-  first sector a new partition table in BSD disklabel format. Saying Y
-  here allows you to read these disklabels and further mount FreeBSD
-  partitions from within Linux if you have also said Y to "UFS
-  file system support", above. If you don't know what all this is
-  about, say N.
-
-Minix subpartition support
-CONFIG_MINIX_SUBPARTITION
-  Minix 2.0.0/2.0.2 subpartition table support for Linux.
-  Say Y here if you want to mount and use Minix 2.0.0/2.0.2
-  subpartitions.
-
-Sun partition table support
-CONFIG_SUN_PARTITION
-  Like most systems, SunOS uses its own hard disk partition table
-  format, incompatible with all others. Saying Y here allows you to
-  read these partition tables and further mount SunOS partitions from
-  within Linux if you have also said Y to "UFS file system support",
-  above. This is mainly used to carry data from a SPARC under SunOS to
-  your Linux box via a removable medium like magneto-optical or ZIP
-  drives; note however that a good portable way to transport files and
-  directories between unixes (and even other operating systems) is
-  given by the tar program ("man tar" or preferably "info tar"). If
-  you don't know what all this is about, say N.
-
-Solaris (x86) partition table support
-CONFIG_SOLARIS_X86_PARTITION
-  Like most systems, Solaris x86 uses its own hard disk partition
-  table format, incompatible with all others. Saying Y here allows you
-  to read these partition tables and further mount Solaris x86
-  partitions from within Linux if you have also said Y to "UFS
-  file system support", above.
-
-SGI partition support
-CONFIG_SGI_PARTITION
-  Say Y here if you would like to be able to read the hard disk
-  partition table format used by SGI machines.
-
-Ultrix partition table support
-CONFIG_ULTRIX_PARTITION
-  Say Y here if you would like to be able to read the hard disk
-  partition table format used by DEC (now Compaq) Ultrix machines.
-  Otherwise, say N.
-
-IBM disk label and partition support
-CONFIG_IBM_PARTITION
-  Say Y here if you would like to be able to read the hard disk
-  partition table format used by IBM DASD disks operating under CMS.
-  Otherwise, say N.
-
-ADFS file system support
-CONFIG_ADFS_FS
-  The Acorn Disc Filing System is the standard file system of the
-  RiscOS operating system which runs on Acorn's ARM-based Risc PC
-  systems and the Acorn Archimedes range of machines. If you say Y
-  here, Linux will be able to read from ADFS partitions on hard drives
-  and from ADFS-formatted floppy discs. If you also want to be able to
-  write to those devices, say Y to "ADFS write support" below.
-
-  The ADFS partition should be the first partition (i.e.,
-  /dev/[hs]d?1) on each of your drives. Please read the file
-  <file:Documentation/filesystems/adfs.txt> for further details.
-
-  This code is also available as a module called adfs.o ( = 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>.
-
-  If unsure, say N.
-
-ADFS write support (DANGEROUS)
-CONFIG_ADFS_FS_RW
-  If you say Y here, you will be able to write to ADFS partitions on
-  hard drives and ADFS-formatted floppy disks. This is experimental
-  codes, so if you're unsure, say N.
-
-/dev/pts file system for Unix98 PTYs
-CONFIG_DEVPTS_FS
-  You should say Y here if you said Y to "Unix98 PTY support" above.
-  You'll then get a virtual file system which can be mounted on
-  /dev/pts with "mount -t devpts". This, together with the pseudo
-  terminal master multiplexer /dev/ptmx, is used for pseudo terminal
-  support as described in The Open Group's Unix98 standard: in order
-  to acquire a pseudo terminal, a process opens /dev/ptmx; the number
-  of the pseudo terminal is then made available to the process and the
-  pseudo terminal slave can be accessed as /dev/pts/<number>. What was
-  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
-
-  The GNU C library glibc 2.1 contains the requisite support for this
-  mode of operation; you also need client programs that use the Unix98
-  API. Please read <file:Documentation/Changes> for more information
-  about the Unix98 pty devices.
-
-  Note that the experimental "/dev file system support"
-  (CONFIG_DEVFS_FS)  is a more general facility.
-
-FreeVxFS file system support (VERITAS VxFS(TM) compatible)
-CONFIG_VXFS_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 file system 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
-  partition (VTOC - Virtual Table of Contents). Its format is
-  incompatible with all other OSes. Saying Y here allows you to read
-  VTOC and further mount UnixWare partitions read-only from within
-  Linux if you have also said Y to "UFS file system support" or
-  "System V and Coherent file system support", above.
-
-  This is mainly used to carry data from a UnixWare box to your
-  Linux box via a removable medium like magneto-optical, ZIP or
-  removable IDE drives. Note, however, that a good portable way to
-  transport files and directories between unixes (and even other
-  operating systems) is given by the tar program ("man tar" or
-  preferably "info tar").
-
-  If you don't know what all this is about, say N.
-
-SMB file system support (to mount Windows shares etc.)
-CONFIG_SMB_FS
-  SMB (Server Message Block) is the protocol Windows for Workgroups
-  (WfW), Windows 95/98, Windows NT and OS/2 Lan Manager use to share
-  files and printers over local networks.  Saying Y here allows you to
-  mount their file systems (often called "shares" in this context) and
-  access them just like any other Unix directory.  Currently, this
-  works only if the Windows machines use TCP/IP as the underlying
-  transport protocol, and not NetBEUI.  For details, read
-  <file:Documentation/filesystems/smbfs.txt> and the SMB-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  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 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>.
-
-  If you want to compile the SMB 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 smbfs.o.  Most people say N, however.
-
-Use a default NLS
-CONFIG_SMB_NLS_DEFAULT
-  Enabling this will make smbfs use nls translations by default. You
-  need to specify the local charset (CONFIG_NLS_DEFAULT) in the nls
-  settings and you need to give the default nls for the SMB server as
-  CONFIG_SMB_NLS_REMOTE.
-
-  The nls settings can be changed at mount time, if your smbmount
-  supports that, using the codepage and iocharset parameters.
-
-  smbmount from samba 2.2.0 or later supports this.
-
-Default Remote NLS Option
-CONFIG_SMB_NLS_REMOTE
-  This setting allows you to specify a default value for which
-  codepage the server uses. If this field is left blank no
-  translations will be done by default. The local codepage/charset
-  default to CONFIG_NLS_DEFAULT.
-
-  The nls settings can be changed at mount time, if your smbmount
-  supports that, using the codepage and iocharset parameters.
-
-  smbmount from samba 2.2.0 or later supports this.
-
-Coda file system support (advanced network fs)
-CONFIG_CODA_FS
-  Coda is an advanced network file system, similar to NFS in that it
-  enables you to mount file systems of a remote server and access them
-  with regular Unix commands as if they were sitting on your hard
-  disk.  Coda has several advantages over NFS: support for
-  disconnected operation (e.g. for laptops), read/write server
-  replication, security model for authentication and encryption,
-  persistent client caches and write back caching.
-
-  If you say Y here, your Linux box will be able to act as a Coda
-  *client*.  You will need user level code as well, both for the
-  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/>.
-
-  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)
-CONFIG_INTERMEZZO_FS
-  InterMezzo is a networked file system with disconnected operation
-  and kernel level write back caching.  It is most often used for
-  replicating potentially large trees or keeping laptop/desktop copies
-  in sync.
-
-  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/>.
-
-NCP file system support (to mount NetWare volumes)
-CONFIG_NCP_FS
-  NCP (NetWare Core Protocol) is a protocol that runs over IPX and is
-  used by Novell NetWare clients to talk to file servers.  It is to
-  IPX what NFS is to TCP/IP, if that helps.  Saying Y here allows you
-  to mount NetWare file server volumes and to access them just like
-  any other Unix directory.  For details, please read the file
-  <file:Documentation/filesystems/ncpfs.txt> in the kernel source and
-  the IPX-HOWTO from <http://www.linuxdoc.org/docs.html#howto>.
-
-  You do not have to say Y here if you want your Linux box to act as a
-  file *server* for Novell NetWare clients.
-
-  General information about how to connect Linux, Windows machines and
-  Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called ncpfs.o.  Say N unless you are connected to a Novell
-  network.
-
-Packet signatures
-CONFIG_NCPFS_PACKET_SIGNING
-  NCP allows packets to be signed for stronger security. If you want
-  security, say Y.  Normal users can leave it off.  To be able to use
-  packet signing you must use ncpfs > 2.0.12.
-
-Proprietary file locking
-CONFIG_NCPFS_IOCTL_LOCKING
-  Allows locking of records on remote volumes.  Say N unless you have
-  special applications which are able to utilize this locking scheme.
-
-Clear remove/delete inhibit when needed
-CONFIG_NCPFS_STRONG
-  Allows manipulation of files flagged as Delete or Rename Inhibit.
-  To use this feature you must mount volumes with the ncpmount
-  parameter "-s" (ncpfs-2.0.12 and newer).  Say Y unless you are not
-  mounting volumes with -f 444.
-
-Use NFS namespace if available
-CONFIG_NCPFS_NFS_NS
-  Allows you to utilize NFS namespace on NetWare servers.  It brings
-  you case sensitive filenames.  Say Y.  You can disable it at
-  mount-time with the `-N nfs' parameter of ncpmount.
-
-Use LONG (OS/2) namespace if available
-CONFIG_NCPFS_OS2_NS
-  Allows you to utilize OS2/LONG namespace on NetWare servers.
-  Filenames in this namespace are limited to 255 characters, they are
-  case insensitive, and case in names is preserved.  Say Y.  You can
-  disable it at mount time with the -N os2 parameter of ncpmount.
-
-Lowercase DOS filenames on LONG namespace volume
-CONFIG_NCPFS_SMALLDOS
-  If you say Y here, every filename on a NetWare server volume using
-  the OS2/LONG namespace and created under DOS or on a volume using
-  DOS namespace will be converted to lowercase characters.
-  Saying N here will give you these filenames in uppercase.
-
-  This is only a cosmetic option since the OS2/LONG namespace is case
-  insensitive. The only major reason for this option is backward
-  compatibility when moving from DOS to OS2/LONG namespace support.
-  Long filenames (created by Win95) will not be affected.
-
-  This option does not solve the problem that filenames appear
-  differently under Linux and under Windows, since Windows does an
-  additional conversions on the client side. You can achieve similar
-  effects by saying Y to "Allow using of Native Language Support"
-  below.
-
-Use Native Language Support
-CONFIG_NCPFS_NLS
-  Allows you to use codepages and I/O charsets for file name
-  translation between the server file system and input/output. This
-  may be useful, if you want to access the server with other operating
-  systems, e.g. Windows 95. See also NLS for more Information.
-
-  To select codepages and I/O charsets use ncpfs-2.2.0.13 or newer.
-
-Symbolic links and mode permission bits
-CONFIG_NCPFS_EXTRAS
-  This enables the use of symbolic links and an execute permission
-  bit on NCPFS. The file server need not have long name space or NFS
-  name space loaded for these to work.
-
-  To use the new attributes, it is recommended to use the flags
-  '-f 600 -d 755' on the ncpmount command line.
-
-Default NLS Option
-CONFIG_NLS_DEFAULT
-  The default NLS used when mounting file system. Note, that this is
-  the NLS used by your console, not the NLS used by a specific file
-  system (if different) to store data (filenames) on a disk.
-  Currently, the valid values are:
-  big5, cp437, cp737, cp775, cp850, cp852, cp855, cp857, cp860, cp861,
-  cp862, cp863, cp864, cp865, cp866, cp869, cp874, cp932, cp936,
-  cp949, cp950, cp1251, cp1255, euc-jp, euc-kr, gb2312, iso8859-1,
-  iso8859-2, iso8859-3, iso8859-4, iso8859-5, iso8859-6, iso8859-7,
-  iso8859-8, iso8859-9, iso8859-13, iso8859-14, iso8859-15,
-  koi8-r, koi8-ru, koi8-u, sjis, tis-620, utf8.
-  If you specify a wrong value, it will use the built-in NLS;
-  compatible with iso8859-1.
-
-  If unsure, specify it as "iso8859-1".
-
-Codepage 437 (United States, Canada)
-CONFIG_NLS_CODEPAGE_437
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored
-  in so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage that is used in
-  the United States and parts of Canada. This is recommended.
-
-Codepage 737 (Greek)
-CONFIG_NLS_CODEPAGE_737
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored
-  in so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage that is used for
-  Greek. If unsure, say N.
-
-Codepage 775 (Baltic Rim)
-CONFIG_NLS_CODEPAGE_775
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored
-  in so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage that is used
-  for the Baltic Rim Languages (Latvian and Lithuanian). If unsure,
-  say N.
-
-Codepage 850 (Europe)
-CONFIG_NLS_CODEPAGE_850
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage that is used for
-  much of Europe -- United Kingdom, Germany, Spain, Italy, and [add
-  more countries here]. It has some characters useful to many European
-  languages that are not part of the US codepage 437.
-
-  If unsure, say Y.
-
-Codepage 852 (Central/Eastern Europe)
-CONFIG_NLS_CODEPAGE_852
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the Latin 2 codepage used by DOS
-  for much of Central and Eastern Europe. It has all the required
-  characters for these languages: Albanian, Croatian, Czech, English,
-  Finnish, Hungarian, Irish, German, Polish, Romanian, Serbian (Latin
-  transcription), Slovak, Slovenian, and Sorbian.
-
-Codepage 855 (Cyrillic)
-CONFIG_NLS_CODEPAGE_855
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Cyrillic.
-
-Codepage 857 (Turkish)
-CONFIG_NLS_CODEPAGE_857
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Turkish.
-
-Codepage 860 (Portuguese)
-CONFIG_NLS_CODEPAGE_860
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Portuguese.
-
-Codepage 861 (Icelandic)
-CONFIG_NLS_CODEPAGE_861
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Icelandic.
-
-Codepage 862 (Hebrew)
-CONFIG_NLS_CODEPAGE_862
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Hebrew.
-
-Codepage 863 (Canadian French)
-CONFIG_NLS_CODEPAGE_863
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Canadian
-  French.
-
-Codepage 864 (Arabic)
-CONFIG_NLS_CODEPAGE_864
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Arabic.
-
-Codepage 865 (Norwegian, Danish)
-CONFIG_NLS_CODEPAGE_865
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for the Nordic
-  European countries.
-
-Codepage 866 (Cyrillic/Russian)
-CONFIG_NLS_CODEPAGE_866
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for
-  Cyrillic/Russian.
-
-Codepage 869 (Greek)
-CONFIG_NLS_CODEPAGE_869
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Greek.
-
-Thai charset (CP874, TIS-620)
-CONFIG_NLS_CODEPAGE_874
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Thai.
-
-Windows CP1251 (Bulgarian, Belarusian)
-CONFIG_NLS_CODEPAGE_1251
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Russian and
-  Bulgarian and Belarusian.
-
-Japanese charsets (Shift-JIS, EUC-JP)
-CONFIG_NLS_CODEPAGE_932
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Shift-JIS
-  or EUC-JP. To use EUC-JP, you can use 'euc-jp' as mount option or
-  NLS Default value during kernel configuration, instead of 'cp932'.
-
-Simplified Chinese charset (CP936, GB2312)
-CONFIG_NLS_CODEPAGE_936
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Simplified
-  Chinese(GBK).
-
-Korean charset (CP949, EUC-KR)
-CONFIG_NLS_CODEPAGE_949
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for UHC.
-
-Traditional Chinese charset (Big5)
-CONFIG_NLS_CODEPAGE_950
-  The Microsoft FAT file system family can deal with filenames in
-  native language character sets. These character sets are stored in
-  so-called DOS codepages. You need to include the appropriate
-  codepage if you want to be able to read/write these filenames on
-  DOS/Windows partitions correctly. This does apply to the filenames
-  only, not to the file contents. You can include several codepages;
-  say Y here if you want to include the DOS codepage for Traditional
-  Chinese(Big5).
-
-NLS ISO 8859-1 (Latin 1; Western European Languages)
-CONFIG_NLS_ISO8859_1
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for the Latin 1 character
-  set, which covers most West European languages such as Albanian,
-  Catalan, Danish, Dutch, English, Faeroese, Finnish, French, German,
-  Galician, Irish, Icelandic, Italian, Norwegian, Portuguese, Spanish,
-  and Swedish. It is also the default for the US. If unsure, say Y.
-
-NLS ISO 8859-2 (Latin 2; Slavic/Central European Languages)
-CONFIG_NLS_ISO8859_2
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for the Latin 2 character
-  set, which works for most Latin-written Slavic and Central European
-  languages: Czech, German, Hungarian, Polish, Rumanian, Croatian,
-  Slovak, Slovene.
-
-NLS ISO 8859-3 (Latin 3; Esperanto, Galician, Maltese, Turkish)
-CONFIG_NLS_ISO8859_3
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for the Latin 3 character
-  set, which is popular with authors of Esperanto, Galician, Maltese,
-  and Turkish.
-
-NLS ISO 8859-4 (Latin 4; old Baltic charset)
-CONFIG_NLS_ISO8859_4
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for the Latin 4 character
-  set which introduces letters for Estonian, Latvian, and
-  Lithuanian. It is an incomplete predecessor of Latin 7.
-
-NLS ISO 8859-5 (Cyrillic)
-CONFIG_NLS_ISO8859_5
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for ISO8859-5, a Cyrillic
-  character set with which you can type Bulgarian, Belarusian,
-  Macedonian, Russian, Serbian, and Ukrainian. Note that the charset
-  KOI8-R is preferred in Russia.
-
-NLS ISO 8859-6 (Arabic)
-CONFIG_NLS_ISO8859_6
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for ISO8859-6, the Arabic
-  character set.
-
-NLS ISO 8859-7 (Modern Greek)
-CONFIG_NLS_ISO8859_7
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for ISO8859-7, the Modern
-  Greek character set.
-
-Hebrew charsets (ISO-8859-8, CP1255)
-CONFIG_NLS_ISO8859_8
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for ISO8859-8, the Hebrew
-  character set.
-
-NLS ISO 8859-9 (Latin 5; Turkish)
-CONFIG_NLS_ISO8859_9
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for the Latin 5 character
-  set, and it replaces the rarely needed Icelandic letters in Latin 1
-  with the Turkish ones. Useful in Turkey.
-
-NLS ISO 8859-10 (Latin 6; Nordic)
-CONFIG_NLS_ISO8859_10
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for the Latin 6 character
-  set, which adds the last Inuit (Greenlandic) and Sami (Lappish)
-  letters that were missing in Latin 4 to cover the entire Nordic
-  area.
-
-NLS ISO 8859-13 (Latin 7; Baltic)
-CONFIG_NLS_ISO8859_13
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for the Latin 7 character
-  set, which supports modern Baltic languages including Latvian
-  and Lithuanian.
-
-NLS ISO 8859-14 (Latin 8; Celtic)
-CONFIG_NLS_ISO8859_14
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for the Latin 8 character
-  set, which adds the last accented vowels for Welsh (aka Cymraeg)
-  (and Manx Gaelic) that were missing in Latin 1.
-  <http://linux.speech.cymru.org/> has further information.
-
-NLS ISO 8859-15 (Latin 9; Western European languages with Euro)
-CONFIG_NLS_ISO8859_15
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for the Latin 9 character
-  set, which covers most West European languages such as Albanian,
-  Catalan, Danish, Dutch, English, Estonian, Faeroese, Finnish,
-  French, German, Galician, Irish, Icelandic, Italian, Norwegian,
-  Portuguese, Spanish, and Swedish. Latin 9 is an update to
-  Latin 1 (ISO 8859-1) that removes a handful of rarely used
-  characters and instead adds support for Estonian, corrects the
-  support for French and Finnish, and adds the new Euro character.
-  If unsure, say Y.
-
-NLS KOI8-R (Russian)
-CONFIG_NLS_KOI8_R
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for the preferred Russian
-  character set.
-
-NLS KOI8-U/RU (Ukrainian, Belarusian)
-CONFIG_NLS_KOI8_U
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for the preferred Ukrainian
-  (koi8-u) and Belarusian (koi8-ru) character sets.
-
-NLS UTF8
-CONFIG_NLS_UTF8
-  If you want to display filenames with native language characters
-  from the Microsoft FAT file system family or from JOLIET CD-ROMs
-  correctly on the screen, you need to include the appropriate
-  input/output character sets. Say Y here for the UTF-8 encoding of
-  the Unicode/ISO9646 universal character set.
-
-Virtual terminal
-CONFIG_VT
-  If you say Y here, you will get support for terminal devices with
-  display and keyboard devices. These are called "virtual" because you
-  can run several virtual terminals (also called virtual consoles) on
-  one physical terminal. This is rather useful, for example one
-  virtual terminal can collect system messages and warnings, another
-  one can be used for a text-mode user session, and a third could run
-  an X session, all in parallel. Switching between virtual terminals
-  is done with certain key combinations, usually Alt-<function key>.
-
-  The setterm command ("man setterm") can be used to change the
-  properties (such as colors or beeping) of a virtual terminal. The
-  man page console_codes(4) ("man console_codes") contains the special
-  character sequences that can be used to change those properties
-  directly. The fonts used on virtual terminals can be changed with
-  the setfont ("man setfont") command and the key bindings are defined
-  with the loadkeys ("man loadkeys") command.
-
-  You need at least one virtual terminal device in order to make use
-  of your keyboard and monitor. Therefore, only people configuring an
-  embedded system would want to say N here in order to save some
-  memory; the only way to log into such a system is then via a serial
-  or network connection.
-
-  If unsure, say Y, or else you won't be able to do much with your new
-  shiny Linux system :-)
-
-Support for console on virtual terminal
-CONFIG_VT_CONSOLE
-  The system console is the device which receives all kernel messages
-  and warnings and which allows logins in single user mode. If you
-  answer Y here, a virtual terminal (the device used to interact with
-  a physical terminal) can be used as system console. This is the most
-  common mode of operations, so you should say Y here unless you want
-  the kernel messages be output only to a serial port (in which case
-  you should say Y to "Console on serial port", below).
-
-  If you do say Y here, by default the currently visible virtual
-  terminal (/dev/tty0) will be used as system console. You can change
-  that with a kernel command line option such as "console=tty3" which
-  would use the third virtual terminal as system console. (Try "man
-  bootparam" or see the documentation of your boot loader (lilo or
-  loadlin) about how to pass options to the kernel at boot time.)
-
-  If unsure, say Y.
-
-STI console
-CONFIG_STI_CONSOLE
-  The STI console is the builtin display/keyboard on HP-PARISC
-  machines.  Say Y here to build support for it into your kernel.
-  The alternative is to use your primary serial port as a console.
-
-Use MDIO for PHY configuration
-CONFIG_USE_MDIO
-  On some boards the hardware configuration of the ethernet PHY can be
-  used without any software interaction over the MDIO interface, so
-  all MII code can be omitted. Say N here if unsure or if you don't
-  need link status reports.
-
-860T FEC Ethernet
-CONFIG_FEC_ENET
-  Enable Ethernet support via the Fast Ethernet Controller (FCC) on
-  the Motorola MPC8260.
-
-Ethernet on FCC1
-CONFIG_FCC1_ENET
-  Use MPC8260 fast Ethernet controller 1 to drive Ethernet (default).
-
-Ethernet on FCC2
-CONFIG_FCC2_ENET
-  Use MPC8260 fast Ethernet controller 2 to drive Ethernet.
-
-Ethernet on FCC3
-CONFIG_FCC3_ENET
-  Use MPC8260 fast Ethernet controller 3 to drive Ethernet.
-
-CPM SCC Ethernet
-CONFIG_SCC_ENET
-  Enable Ethernet support via the Motorola MPC8xx serial
-  commmunications controller.
-
-Ethernet on SCC1
-CONFIG_SCC1_ENET
-  Use MPC8xx serial communications controller 1 to drive Ethernet
-  (default).
-
-Ethernet on SCC2
-CONFIG_SCC2_ENET
-  Use MPC8xx serial communications controller 2 to drive Ethernet.
-
-Ethernet on SCC3
-CONFIG_SCC3_ENET
-  Use MPC8xx serial communications controller 3 to drive Ethernet.
-
-Use Big CPM Ethernet Buffers
-CONFIG_ENET_BIG_BUFFERS
-  Allocate large buffers for MPC8xx Etherenet.  Increases throughput
-  and decreases the likelihood of dropped packets, but costs memory.
-
-Apple Desktop Bus (ADB) support
-CONFIG_ADB
-  Apple Desktop Bus (ADB) support is for support of devices which
-  are connected to an ADB port.  ADB devices tend to have 4 pins.
-  If you have an Apple Macintosh prior to the iMac, or a
-  "Blue and White G3", you probably want to say Y here.  Otherwise
-  say N.
-
-Support for CUDA based PowerMacs
-CONFIG_ADB_CUDA
-  This provides support for CUDA based Power Macintosh systems.  This
-  includes most OldWorld PowerMacs, the first generation iMacs, the
-  Blue&White G3 and the Yikes G4 (PCI Graphics).  All later models
-  should use CONFIG_ADB_PMU instead.
-
-  If unsure say Y.
-
-Support for PMU-based PowerMacs
-CONFIG_ADB_PMU
-  On the PowerBook 3400 and 2400, the PMU is a 6805 microprocessor
-  core whose primary function is to control battery charging and
-  system power.  The PMU also controls the ADB (Apple Desktop Bus)
-  which connects to the keyboard and mouse, as well as the
-  non-volatile RAM and the RTC (real time clock) chip.  Say Y to
-  enable support for this device; you should do so if your machine
-  is one of these PowerBooks.
-
-Include MacIO ADB driver
-CONFIG_ADB_MACIO
-  Say Y here to include direct support for the ADB controller in the
-  Hydra chip used on PowerPC Macintoshes of the CHRP type.  (The Hydra
-  also includes a MESH II SCSI controller, DBDMA controller, VIA chip,
-  OpenPIC controller and two RS422/Geoports.)
-
-Support for ADB keyboard (old driver)
-CONFIG_ADB_KEYBOARD
-  This option allows you to use an ADB keyboard attached to your
-  machine. Note that this disables any other (ie. PS/2) keyboard
-  support, even if your machine is physically capable of using both at
-  the same time.
-
-  If you use an ADB keyboard (4 pin connector), say Y here.
-  If you use a PS/2 keyboard (6 pin connector), say N here.
-
-HIL keyboard support
-CONFIG_HIL
-  The "Human Interface Loop" is a older, 8-channel USB-like controller
-  used in Hewlette Packard PA-RISC based machines.  There are a few
-  cases where it is seen on PC/MAC architectures as well, usually also
-  manufactured by HP.  This driver is based off MACH and BSD drivers,
-  and implements support for a keyboard attached to the HIL port.
-  Full support for the USB-like functions and non-keyboard channels of
-  the HIL is not provided for in this driver.  There are vestiges of
-  mouse support in the driver, but it is probably not working.  The
-  necessary hardware documentation to fully support the HIL controller
-  and interface it to the linux-input API is lacking.
-
-  Enable this option if you intend to use a HIL keyboard.
-
-Include IOP (IIfx/Quadra 9x0) ADB driver
-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
-  support for it, say 'Y' here.
-
-Mac II style Apple Desktop Bus support
-CONFIG_ADB_MACII
-  Say Y here if want your kernel to support Macintosh systems that use
-  the Mac II style ADB.  This includes the II, IIx, IIcx, SE/30, IIci,
-  Quadra 610, Quadra 650, Quadra 700, Quadra 800, Centris 610 and
-  Centris 650.
-
-Mac IIsi style Apple Desktop Bus support
-CONFIG_ADB_MACIISI
-  Say Y here if want your kernel to support Macintosh systems that use
-  the Mac IIsi style ADB.  This includes the IIsi, IIvi, IIvx, Classic
-  II, LC, LC II, LC III, Performa 460, and the Performa 600.
-
-Apple 68K PowerBook Power Management and Desktop Bus support
-CONFIG_ADB_PMU68K
-  Say Y here if want your kernel to support the m68k based Powerbooks.
-  This includes the PowerBook 140, PowerBook 145, PowerBook 150,
-  PowerBook 160, PowerBook 165, PowerBook 165c, PowerBook 170,
-  PowerBook 180, PowerBook, 180c, PowerBook 190cs, PowerBook 520,
-  PowerBook Duo 210, PowerBook Duo 230, PowerBook Duo 250,
-  PowerBook Duo 270c, PowerBook Duo 280 and PowerBook Duo 280c.
-
-Macintosh IIfx/Quadra 900/Quadra 950 floppy support
-CONFIG_BLK_DEV_SWIM_IOP
-  Say Y here to support the SWIM (Super Woz Integrated Machine) IOP
-  floppy controller on the Macintosh IIfx and Quadra 900/950.
-
-Macintosh NS8390 based Ethernet support
-CONFIG_MAC8390
-  If you want to include a driver to support Nubus or LC-PDS
-  Ethernet cards using an NS8390 chipset or its equivalent, say Y
-  and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-Macintosh CS89x0 based Ethernet support
-CONFIG_MAC89x0
-  Support for CS89x0 chipset based Ethernet cards.  If you have a
-  Nubus or LC-PDS network (Ethernet) card of this type, say Y and
-  read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  This module will
-  be called mac89x0.o.
-
-Macintosh onboard AMD 79C940 MACE based Ethernet support
-CONFIG_MACMACE
-  Support for the onboard AMD 79C940 MACE Ethernet controller used in
-  the 660AV and 840AV Macintosh.  If you have one of these Macintoshes
-  say Y and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-Macintosh SONIC based Ethernet support (onboard, NuBus, LC, CS)
-CONFIG_MACSONIC
-  Support for NatSemi SONIC based Ethernet devices.  This includes
-  the onboard Ethernet in many Quadras as well as some LC-PDS,
-  a few Nubus and all known Comm Slot Ethernet cards.  If you have
-  one of these say Y and read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.  This module will
-  be called macsonic.o.
-
-Macintosh NCR5380 SCSI support
-CONFIG_MAC_SCSI
-  This is the NCR 5380 SCSI controller included on most of the 68030
-  based Macintoshes.  If you have one of these say Y and read the
-  SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-Macintosh NCR53c9[46] SCSI support
-CONFIG_SCSI_MAC_ESP
-  This is the NCR 53c9x SCSI controller found on most of the 68040
-  based Macintoshes.  If you have one of these say Y and read the
-  SCSI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called mac_esp.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Standard/generic (8250/16550 and compatible UARTs) serial support
-CONFIG_SERIAL
-  This selects whether you want to include the driver for the standard
-  serial ports.  The standard answer is Y.  People who might say N
-  here are those that are setting up dedicated Ethernet WWW/FTP
-  servers, or users that have one of the various bus mice instead of a
-  serial mouse and don't intend to use their machine's standard serial
-  port for anything.  (Note that the Cyclades and Stallion multi
-  serial port drivers do not need this driver built in for them to
-  work.)
-
-  If you want to compile this driver as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called
-  serial.o.
-  [WARNING: Do not compile this driver as a module if you are using
-  non-standard serial ports, since the configuration information will
-  be lost when the driver is unloaded.  This limitation may be lifted
-  in the future.]
-
-  BTW1: If you have a mouseman serial mouse which is not recognized by
-  the X window system, try running gpm first.
-
-  BTW2: If you intend to use a software modem (also called Winmodem)
-  under Linux, forget it.  These modems are crippled and require
-  proprietary drivers which are only available under Windows.
-
-  Most people will say Y or M here, so that they can use serial mice,
-  modems and similar devices connecting to the standard serial ports.
-
-Support for console on serial port
-CONFIG_SERIAL_CONSOLE
-  If you say Y here, it will be possible to use a serial port as the
-  system console (the system console is the device which receives all
-  kernel messages and warnings and which allows logins in single user
-  mode). This could be useful if some terminal or printer is connected
-  to that serial port.
-
-  Even if you say Y here, the currently visible virtual console
-  (/dev/tty0) will still be used as the system console by default, but
-  you can alter that using a kernel command line option such as
-  "console=ttyS1". (Try "man bootparam" or see the documentation of
-  your boot loader (lilo or loadlin) about how to pass options to the
-  kernel at boot time.)
-
-  If you don't have a VGA card installed and you say Y here, the
-  kernel will automatically use the first serial line, /dev/ttyS0, as
-  system console.
-
-  If unsure, say N.
-
-Support for PowerMac serial ports
-CONFIG_MAC_SERIAL
-  If you have Macintosh style serial ports (8 pin mini-DIN), say Y
-  here. If you also have regular serial ports and enable the driver
-  for them, you can't currently use the serial console feature.
-
-Comtrol Rocketport support
-CONFIG_ROCKETPORT
-  This is a driver for the Comtrol Rocketport cards which provide
-  multiple serial ports. You would need something like this to connect
-  more than two modems to your Linux box, for instance in order to
-  become a dial-in server.
-
-  If you want to compile this driver as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called
-  rocket.o.
-
-Digiboard Intelligent async support
-CONFIG_DIGIEPCA
-  This is a driver for Digi International's Xx, Xeve, and Xem series
-  of cards which provide multiple serial ports. You would need
-  something like this to connect more than two modems to your Linux
-  box, for instance in order to become a dial-in server. This driver
-  supports the original PC (ISA) boards as well as PCI, and EISA. If
-  you have a card like this, say Y here and read the file
-  <file:Documentation/digiepca.txt>.
-
-  NOTE: There is another, separate driver for the Digiboard PC boards:
-  "Digiboard PC/Xx Support" below. You should (and can) only select
-  one of the two drivers.
-
-  If you want to compile this driver as a module, say M here and read
-  <file:Documentation/modules.txt>. The module will be called epca.o.
-
-Digiboard PC/Xx Support
-CONFIG_DIGI
-  This is a driver for the Digiboard PC/Xe, PC/Xi, and PC/Xeve cards
-  that give you many serial ports. You would need something like this
-  to connect more than two modems to your Linux box, for instance in
-  order to become a dial-in server. If you have a card like that, say
-  Y here and read the file <file:Documentation/digiboard.txt>.
-
-  If you want to compile this driver as a module, say M here and read
-  <file:Documentation/modules.txt>. The module will be called pcxx.o.
-
-SDL RISCom/8 card support
-CONFIG_RISCOM8
-  This is a driver for the SDL Communications RISCom/8 multiport card,
-  which gives you many serial ports. You would need something like
-  this to connect more than two modems to your Linux box, for instance
-  in order to become a dial-in server. If you have a card like that,
-  say Y here and read the file <file:Documentation/riscom8.txt>.
-
-  Also it's possible to say M here and compile this driver as kernel
-  loadable module; the module will be called riscom8.o.
-
-Computone IntelliPort Plus serial support
-CONFIG_COMPUTONE
-  This driver supports the entire family of Intelliport II/Plus
-  controllers with the exception of the MicroChannel controllers and
-  products previous to the Intelliport II. These are multiport cards,
-  which give you many serial ports. You would need something like this
-  to connect more than two modems to your Linux box, for instance in
-  order to become a dial-in server. If you have a card like that, say
-  Y here and read <file:Documentation/computone.txt>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>. You will get
-  two modules called ip2.o and ip2main.o.
-
-Specialix IO8+ card support
-CONFIG_SPECIALIX
-  This is a driver for the Specialix IO8+ multiport card (both the
-  ISA and the PCI version) which gives you many serial ports. You
-  would need something like this to connect more than two modems to
-  your Linux box, for instance in order to become a dial-in server.
-
-  If you have a card like that, say Y here and read the file
-  <file:Documentation/specialix.txt>. Also it's possible to say M here
-  and compile this driver as kernel loadable module which will be
-  called specialix.o.
-
-Specialix DTR/RTS pin is RTS
-CONFIG_SPECIALIX_RTSCTS
-  The Specialix IO8+ card can only support either RTS or DTR. If you
-  say N here, the driver will use the pin as "DTR" when the tty is in
-  software handshake mode.  If you say Y here or hardware handshake is
-  on, it will always be RTS.  Read the file
-  <file:Documentation/specialix.txt> for more information.
-
-Specialix RIO system support
-CONFIG_RIO
-  This is a driver for the Specialix RIO, a smart serial card which
-  drives an outboard box that can support up to 128 ports.  Product
-  information is at <http://www.sphinxcst.co.uk/perle/multi.htm>.
-  There are both ISA and PCI versions.
-
-Support really old RIO/PCI cards
-CONFIG_RIO_OLDPCI
-  Older RIO PCI cards need some initialization-time configuration to
-  determine the IRQ and some control addresses.  If you have a RIO and
-  this doesn't seem to work, try setting this to Y.
-
-Cyclades async mux support
-CONFIG_CYCLADES
-  This is a driver for a card that gives you many serial ports. You
-  would need something like this to connect more than two modems to
-  your Linux box, for instance in order to become a dial-in server.
-  For information about the Cyclades-Z card, read
-  <file:drivers/char/README.cycladesZ>.
-
-  As of 1.3.9x kernels, this driver's minor numbers start at 0 instead
-  of 32.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called cyclades.o.
-
-  If you haven't heard about it, it's safe to say N.
-
-Cyclades-Z interrupt mode operation
-CONFIG_CYZ_INTR
-  The Cyclades-Z family of multiport cards allows 2 (two) driver op
-  modes: polling and interrupt. In polling mode, the driver will check
-  the status of the Cyclades-Z ports every certain amount of time
-  (which is called polling cycle and is configurable). In interrupt
-  mode, it will use an interrupt line (IRQ) in order to check the
-  status of the Cyclades-Z ports. The default op mode is polling. If
-  unsure, say N.
-
-Stallion multiport serial support
-CONFIG_STALDRV
-  Stallion cards give you many serial ports.  You would need something
-  like this to connect more than two modems to your Linux box, for
-  instance in order to become a dial-in server.  If you say Y here,
-  you will be asked for your specific card model in the next
-  questions.  Make sure to read <file:Documentation/stallion.txt> in
-  this case.  If you have never heard about all this, it's safe to
-  say N.
-
-Stallion EasyIO or EC8/32 support
-CONFIG_STALLION
-  If you have an EasyIO or EasyConnection 8/32 multiport Stallion
-  card, then this is for you; say Y.  Make sure to read
-  <file:Documentation/stallion.txt>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called stallion.o.
-
-Stallion EC8/64, ONboard, Brumby support
-CONFIG_ISTALLION
-  If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
-  serial multiport card, say Y here. Make sure to read
-  <file:Documentation/stallion.txt>.
-
-  To compile it 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
-  istallion.o.
-
-Microgate SyncLink adapter support
-CONFIG_SYNCLINK
-  Provides support for the SyncLink ISA and PCI multiprotocol serial
-  adapters. These adapters support asynchronous and HDLC bit
-  synchronous communication up to 10Mbps (PCI adapter).
-
-  This driver can only be built as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called synclink.o.  If you want to do that, say M
-  here.
-
-Synchronous HDLC line discipline support
-CONFIG_N_HDLC
-  Allows synchronous HDLC communications with tty device drivers that
-  support synchronous HDLC such as the Microgate SyncLink adapter.
-
-  This driver can only be built as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called n_hdlc.o. If you want to do that, say M
-  here.
-
-Specialix SX (and SI) card support
-CONFIG_SX
-  This is a driver for the SX and SI multiport serial cards.
-  Please read the file <file:Documentation/sx.txt> for details.
-
-  This driver can only be built as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called sx.o. If you want to do that, say M here.
-
-Hayes ESP serial port support
-CONFIG_ESPSERIAL
-  This is a driver which supports Hayes ESP serial ports.  Both single
-  port cards and multiport cards are supported.  Make sure to read
-  <file:Documentation/hayes-esp.txt>.
-
-  To compile this driver as a module ( = code which can be inserted in
-  and removed from the running kernel whenever you want), say M here
-  and read <file:Documentation/modules.txt>.  The module will be
-  called esp.o.  If unsure, say N.
-
-Moxa Intellio support
-CONFIG_MOXA_INTELLIO
-  Say Y here if you have a Moxa Intellio multiport serial card.
-
-  This driver can also be built as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called moxa.o. If you want to do that, say M
-  here.
-
-Moxa SmartIO support
-CONFIG_MOXA_SMARTIO
-  Say Y here if you have a Moxa SmartIO multiport serial card.
-
-  This driver can also be built as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called mxser.o. If you want to do that, say M
-  here.
-
-Multi-Tech multiport card support
-CONFIG_ISI
-  This is a driver for the Multi-Tech cards which provide several
-  serial ports.  The driver is experimental and can currently only be
-  built as a module ( = code which can be inserted in and removed from
-  the running kernel whenever you want).  Please read
-  <file:Documentation/modules.txt>.  The module will be called
-  isicom.o.
-
-Unix98 PTY support
-CONFIG_UNIX98_PTYS
-  A pseudo terminal (PTY) is a software device consisting of two
-  halves: a master and a slave. The slave device behaves identical to
-  a physical terminal; the master device is used by a process to
-  read data from and write data to the slave, thereby emulating a
-  terminal. Typical programs for the master side are telnet servers
-  and xterms.
-
-  Linux has traditionally used the BSD-like names /dev/ptyxx for
-  masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
-  has a number of problems. The GNU C library glibc 2.1 and later,
-  however, supports the Unix98 naming standard: in order to acquire a
-  pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
-  terminal is then made available to the process and the pseudo
-  terminal slave can be accessed as /dev/pts/<number>. What was
-  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
-
-  The entries in /dev/pts/ are created on the fly by a virtual
-  file system; therefore, if you say Y here you should say Y to
-  "/dev/pts file system for Unix98 PTYs" as well.
-
-  If you want to say Y here, you need to have the C library glibc 2.1
-  or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
-  Read the instructions in <file:Documentation/Changes> pertaining to
-  pseudo terminals. It's safe to say N.
-
-Maximum number of Unix98 PTYs in use (0-2048)
-CONFIG_UNIX98_PTY_COUNT
-  The maximum number of Unix98 PTYs that can be used at any one time.
-  The default is 256, and should be enough for desktop systems. Server
-  machines which support incoming telnet/rlogin/ssh connections and/or
-  serve several X terminals may want to increase this: every incoming
-  connection and every xterm uses up one PTY.
-
-  When not in use, each additional set of 256 PTYs occupy
-  approximately 8 KB of kernel memory on 32-bit architectures.
-
-Parallel printer support
-CONFIG_PRINTER
-  If you intend to attach a printer to the parallel port of your Linux
-  box (as opposed to using a serial printer; if the connector at the
-  printer has 9 or 25 holes ["female"], then it's serial), say Y.
-  Also read the Printing-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  It is possible to share one parallel port among several devices
-  (e.g. printer and ZIP drive) and it is safe to compile the
-  corresponding drivers into the kernel.  If you want to compile this
-  driver as a module however ( = code which can be inserted in and
-  removed from the running kernel whenever you want), say M here and
-  read <file:Documentation/modules.txt> and
-  <file:Documentation/parport.txt>.  The module will be called lp.o.
-
-  If you have several parallel ports, you can specify which ports to
-  use with the "lp" kernel command line option.  (Try "man bootparam"
-  or see the documentation of your boot loader (lilo or loadlin) about
-  how to pass options to the kernel at boot time.)  The syntax of the
-  "lp" command line option can be found in <file:drivers/char/lp.c>.
-
-  If you have more than 8 printers, you need to increase the LP_NO
-  macro in lp.c and the PARPORT_MAX macro in parport.h.
-
-Support for console on line printer
-CONFIG_LP_CONSOLE
-  If you want kernel messages to be printed out as they occur, you
-  can have a console on the printer. This option adds support for
-  doing that; to actually get it to happen you need to pass the
-  option "console=lp0" to the kernel at boot time.
-
-  If the printer is out of paper (or off, or unplugged, or too
-  busy..) the kernel will stall until the printer is ready again.
-  By defining CONSOLE_LP_STRICT to 0 (at your own risk) you
-  can make the kernel continue when this happens,
-  but it'll lose the kernel messages.
-
-  If unsure, say N.
-
-Support for user-space parallel port device drivers
-CONFIG_PPDEV
-  Saying Y to this adds support for /dev/parport device nodes.  This
-  is needed for programs that want portable access to the parallel
-  port, for instance deviceid (which displays Plug-and-Play device
-  IDs).
-
-  This is the parallel port equivalent of SCSI generic support (sg).
-  It is safe to say N to this -- it is not needed for normal printing
-  or parallel port CD-ROM/disk support.
-
-  This support is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called
-  ppdev.o.
-
-  If unsure, say N.
-
-Cobalt Networks support
-CONFIG_COBALT
-  Support for Cobalt Networks x86-based servers.
-
-Gen III (3000 series) system support
-CONFIG_COBALT_GEN_III
-  This option enables support for the 3000 series of Cobalt Networks
-  systems. This includes the RaQ 3, RaQ 4, and Qube 3 product lines.
-
-  This platform uses an AMD K6-2 processor, an ALI M1541/1533 chipset,
-  an optional NCR 53c875 SCSI controller, and two Intel 82559ER or
-  National Semiconductor DP83815 NICs.
-
-  Getting this option wrong will likely result in a kernel that does
-  not boot. Selecting support for more than 1 system series will add
-  bloat to your kernel, but will not cause anything bad to happen.
-
-  If you have a Cobalt Networks System, but aren't sure what kind,
-  say Y here.
-
-Gen V (5000 series) system support
-CONFIG_COBALT_GEN_V
-  This option enables support for the 5000 series of Cobalt Networks
-  systems. This includes the RaQ XTR product line.
-
-  This platform uses Intel Pentium III Coppermine FCPGA CPUs, the
-  ServerWorks LE chipset (with registered ECC DIMMs only!), two
-  HighPoint HPT370 IDE controllers, and two National Semiconductor
-  DP83815 NICs.
-
-  Getting this option wrong will likely result in a kernel that does
-  not boot. Selecting support for more than 1 system series will add
-  bloat to your kernel, but will not cause anything bad to happen.
-
-  If you have a Cobalt Networks System, but aren't sure what kind,
-  say Y here.
-
-Create legacy /proc files
-CONFIG_COBALT_OLDPROC
-  This option forces some Cobalt Networks drivers to support legacy
-  files in /proc.  Older versions of these drivers exported files
-  directly in /proc, as opposed to the newer /proc/cobalt.  If you say
-  N to this option, the old filenames will no longer be exported.
-  Regardless of your selection here, files in /proc/cobalt will be
-  exported.  Of course, you have to include support for /proc fs, too.
-
-  It is safe to say Y here.
-
-Front panel LCD support
-CONFIG_COBALT_LCD
-  This enables support for the Cobalt Networks front panel.  This is
-  for the LCD panel and buttons.  The primary method for connection is
-  via the parallel port (IO base 0x370), but newer systems use an
-  I2C bus.
-
-  If you have a Cobalt Networks system, you should say Y here.
-
-Software controlled LED support
-CONFIG_COBALT_LED
-  This enables support for the software-controlled LEDs on Cobalt
-  Networks systems.  This includes the fault light and front panel
-  LEDs on the RaQ XTR, the lightbar on the Qube 3, and others.
-
-  If you have a Cobalt Networks system, you should say Y here.
-
-Silicon serial number support
-CONFIG_COBALT_SERNUM
-  This enables support for the on-board serial number on Cobalt
-  Networks systems.  This is a universally-unique 64-bit serial
-  number.  Some systems use a Dallas DS2401 chip, others have an I2C
-  based EEPROM.
-
-  If you select Y here, the files /proc/cobalt/hostid and
-  /proc/cobalt/serialnumber will be created.  The hostid file contains
-  a 32 bit integer generated from the serial number, in binary form.
-  The serialnumber file contains the hexadecimal representation of the
-  serial number, in ASCII.
-
-  If you have a Cobalt Networks system, you should say Y here.
-
-Chipset watchdog timer support
-CONFIG_COBALT_WDT
-  This enables support for the watchdog timer built into Cobalt
-  chipsets.  The timer wakes up periodically, to make find out if
-  system has hung, or disabled interrupts too long.  The result of
-  detecting a hang is a hard reboot.
-
-  If you have a Cobalt Networks system, you should say Y here.
-
-Thermal sensor support
-CONFIG_COBALT_THERMAL
-  This enables support for the thermal sensor(s) built into Cobalt
-  Networks systems.  This driver exports /proc/cobalt/thermal_sensors.
-
-  If you have a Cobalt Networks system, you should say Y here.
-
-Fan tachometer support
-CONFIG_COBALT_FANS
-  This enables support for the fan tachometers built into some Cobalt
-  Networks systems.  This driver exports /proc/cobalt/faninfo.  Some
-  Cobalt software depends on this feature, and enabling it does not
-  cause any risks.
-
-  If you have a Cobalt Networks system, you should say Y here, unless
-  you are absolutely sure.
-
-Disk drive ruler support
-CONFIG_COBALT_RULER
-  This enables support for the cobalt hard drive ruler, found on some
-  Cobalt systems, including the RaQ XTR.  This is the device that
-  enables swapping of drives.  It is not needed for basic disk
-  operation. Enabling this on a system with no ruler will have no
-  adverse effects.
-
-  If you have a Cobalt Networks system, you should say Y here,
-  unless you are absolutely sure.
-
-I2C support
-CONFIG_I2C
-  I2C (pronounce: I-square-C) is a slow serial bus protocol used in
-  many micro controller applications and developed by Philips.  SMBus,
-  or System Management Bus is a subset of the I2C protocol.  More
-  information is contained in the directory <file:Documentation/i2c/>,
-  especially in the file called "summary" there.
-
-  Both I2C and SMBus are supported here. You will need this for
-  hardware sensors support, and also for Video For Linux support.
-  Specifically, if you want to use a BT848 based frame grabber/overlay
-  boards under Linux, say Y here and also to "I2C bit-banging
-  interfaces", below.
-
-  If you want I2C support, you should say Y here and also to the
-  specific driver for your bus adapter(s) below.  If you say Y to
-  "/proc file system" below, you will then get a /proc interface which
-  is documented in <file:Documentation/i2c/proc-interface>.
-
-  This I2C support is also available as a module.  If you want to
-  compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-  The module will be called i2c-core.o.
-
-UltraSPARC-III bootbus i2c controller driver
-CONFIG_BBC_I2C
-  The BBC devices on the UltraSPARC III have two I2C controllers.  The
-  first I2C controller connects mainly to configuration PROMs (NVRAM,
-  CPU configuration, DIMM types, etc.).  The second I2C controller
-  connects to environmental control devices such as fans and
-  temperature sensors.  The second controller also connects to the
-  smartcard reader, if present.  Say Y to enable support for these.
-
-I2C bit-banging interfaces
-CONFIG_I2C_ALGOBIT
-  This allows you to use a range of I2C adapters called bit-banging
-  adapters.  Say Y if you own an I2C adapter belonging to this class
-  and then say Y to the specific driver for you adapter below.
-
-  This support is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-  The module will be called i2c-algo-bit.o.
-
-Philips style parallel port adapter
-CONFIG_I2C_PHILIPSPAR
-  This supports parallel-port I2C adapters made by Philips.  Say Y if
-  you own such an adapter.
-
-  This driver is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-  The module will be called i2c-philips-par.o.
-
-  Note that if you want support for different parallel port devices,
-  life will be much easier if you compile them all as modules.
-
-ELV adapter
-CONFIG_I2C_ELV
-  This supports parallel-port I2C adapters called ELV.  Say Y if you
-  own such an adapter.
-
-  This driver is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-  The module will be called i2c-elv.o.
-
-Velleman K9000 adapter
-CONFIG_I2C_VELLEMAN
-  This supports the Velleman K9000 parallel-port I2C adapter.  Say Y
-  if you own such an adapter.
-
-  This driver is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-  The module will be called i2c-velleman.o.
-
-I2C PCF 8584 interfaces
-CONFIG_I2C_ALGOPCF
-  This allows you to use a range of I2C adapters called PCF adapters.
-  Say Y if you own an I2C adapter belonging to this class and then say
-  Y to the specific driver for you adapter below.
-
-  This support is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-  The module will be called i2c-algo-pcf.o.
-
-Elektor ISA card
-CONFIG_I2C_ELEKTOR
-  This supports the PCF8584 ISA bus I2C adapter.  Say Y if you own
-  such an adapter.
-
-  This driver is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-  The module will be called i2c-elektor.o.
-
-I2C device interface
-CONFIG_I2C_CHARDEV
-  Say Y here to use i2c-* device files, usually found in the /dev
-  directory on your system.  They make it possible to have user-space
-  programs use the I2C bus.  Information on how to do this is
-  contained in the file <file:Documentation/i2c/dev-interface>.
-
-  This code is also available as a module.  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-  The module will be called i2c-dev.o.
-
-I2C /proc support
-CONFIG_I2C_PROC
-  This provides support for i2c device entries in the /proc filesystem.
-  The entries will be found in /proc/sys/dev/sensors.
-
-  This code is also available as a module. If you want to compile
-  it as a module, say M here and read <file:Documentation/modules.txt>.
-  The module will be called i2c-proc.o.
-
-Bus Mouse Support
-CONFIG_BUSMOUSE
-  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 a laptop, you either have to check the documentation or
-  experiment a bit to find out whether the trackball is a serial mouse
-  or not; it's best to say Y here for you.
-
-  This is the generic bus mouse driver code. If you have a bus mouse,
-  you will have to say Y here and also to the specific driver for your
-  mouse below.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called busmouse.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Mouse Support (not serial and bus mice)
-CONFIG_MOUSE
-  This is for machines with a mouse which is neither a serial nor a
-  bus mouse. Examples are PS/2 mice (such as the track balls on some
-  laptops) and some digitizer pads. 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>. This HOWTO contains
-  information about all non-serial mice, not just bus mice.
-
-  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
-  or not; it's best to say Y here for you.
-
-  Note that the answer to this question won't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about non-serial mice. If unsure, say Y.
-
-Logitech busmouse support
-CONFIG_LOGIBUSMOUSE
-  Logitech mouse connected to a proprietary interface card.  It's
-  generally a round connector with 9 pins. Note that the newer mice
-  made by Logitech don't use the Logitech protocol anymore; for those,
-  you don't need this option.  You want to read the Busmouse-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called busmouse.o.  If you are unsure, say N and read the
-  HOWTO nevertheless: it will tell you what you have.
-
-PS/2 mouse (aka "auxiliary device") support
-CONFIG_PSMOUSE
-  The PS/2 mouse connects to a special mouse port that looks much like
-  the keyboard port (small circular connector with 6 pins). This way,
-  the mouse does not use any serial ports. This port can also be used
-  for other input devices like light pens, tablets, keypads. Compaq,
-  AST and IBM all use this as their mouse port on currently shipping
-  machines. The trackballs of some laptops are PS/2 mice also. In
-  particular, the C&T 82C710 mouse on TI Travelmates is a PS/2 mouse.
-
-  Although PS/2 mice are not technically bus mice, they are explained
-  in detail in the Busmouse-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  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://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
-  This is a certain kind of PS/2 mouse used on the TI Travelmate. If
-  you are unsure, try first to say N here and come back if the mouse
-  doesn't work. Read the Busmouse-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-PC110 digitizer pad support
-CONFIG_PC110_PAD
-  This drives the digitizer pad on the IBM PC110 palmtop.  It can turn
-  the digitizer pad into a PS/2 mouse emulation with tap gestures or
-  into an absolute pad.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called pc110pad.o.
-
-Microsoft busmouse support
-CONFIG_MS_BUSMOUSE
-  These animals (also called Inport mice) are connected to an
-  expansion board using a round connector with 9 pins. If this is what
-  you have, say Y and read the Busmouse-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you are unsure, say N and read the HOWTO nevertheless: it will
-  tell you what you have. Also be aware that several vendors talk
-  about 'Microsoft busmouse' and actually mean PS/2 busmouse -- so
-  count the pins on the connector.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called msbusmouse.o.
-
-Apple Desktop Bus mouse support
-CONFIG_ADBMOUSE
-  Say Y here if you have this type of bus mouse (4 pin connector) as
-  is common on Macintoshes.  You may want to read the Busmouse-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called adbmouse.o.
-
-ATIXL busmouse support
-CONFIG_ATIXL_BUSMOUSE
-  This is a rare type of busmouse that is connected to the back of an
-  ATI video card.  Say Y if you have one of those. Note however that
-  most mice by ATI are actually Microsoft busmice; you should say Y to
-  "Microsoft busmouse support" above if you have one of those.  Read
-  the Busmouse-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called atixlmouse.o.
-
-  If you are unsure, say N and read the HOWTO nevertheless: it will
-  tell you what you have.
-
-QIC-02 tape support
-CONFIG_QIC02_TAPE
-  If you have a non-SCSI tape drive like that, say Y. Or, if you want
-  to compile this driver as a module ( = code which can be inserted in
-  and removed from the running kernel whenever you want), say M here
-  and read <file:Documentation/modules.txt>. The module will be called
-  tpqic02.o.
-
-iSeries Virtual Tape Support
-CONFIG_VIOTAPE
-  If you are running Linux on an iSeries system and you want Linux
-  to read and/or write a tape drive owned by OS/400, say Y here.
-
-Do you want runtime configuration for QIC-02
-CONFIG_QIC02_DYNCONF
-  You can either configure this driver once and for all by editing a
-  header file (<file:include/linux/tpqic02.h>), in which case you
-  should say N, or you can fetch a program via anonymous FTP which is
-  able to configure this driver during runtime.  The program to do
-  this is called 'qic02conf' and it is part of the
-  tpqic02-support-X.Y.tar.gz support package.
-
-  If you want to use the qic02conf program, say Y.
-
-Floppy tape drive (QIC-80/40/3010/3020/TR-1/TR-2/TR-3) support
-CONFIG_FTAPE
-  If you have a tape drive that is connected to your floppy
-  controller, say Y here.
-
-  Some tape drives (like the Seagate "Tape Store 3200" or the Iomega
-  "Ditto 3200" or the Exabyte "Eagle TR-3") come with a "high speed"
-  controller of their own. These drives (and their companion
-  controllers) are also supported if you say Y here.
-
-  If you have a special controller (such as the CMS FC-10, FC-20,
-  Mountain Mach-II, or any controller that is based on the Intel 82078
-  FDC like the high speed controllers by Seagate and Exabyte and
-  Iomega's "Ditto Dash") you must configure it by selecting the
-  appropriate entries from the "Floppy tape controllers" sub-menu
-  below and possibly modify the default values for the IRQ and DMA
-  channel and the IO base in ftape's configuration menu.
-
-  If you want to use your floppy tape drive on a PCI-bus based system,
-  please read the file <file:drivers/char/ftape/README.PCI>.
-
-  The ftape kernel driver is also available as a runtime loadable
-  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>. The
-  module will be called ftape.o.
-
-  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.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
-  changed quite a bit compared to previous versions of ftape.  Please
-  read <file:Documentation/ftape.txt>.
-
-VFS interface for ftape
-CONFIG_ZFTAPE
-  Normally, you want to say Y or M. DON'T say N here or you
-  WON'T BE ABLE TO USE YOUR FLOPPY TAPE DRIVE.
-
-  The ftape module itself no longer contains the routines necessary
-  to interface with the kernel VFS layer (i.e. to actually write data
-  to and read data from the tape drive).  Instead the file system
-  interface (i.e. the hardware independent part of the driver) has
-  been moved to a separate module.
-
-  If you say M zftape will be compiled as a runtime loadable
-  module ( = code which can be inserted in and removed from the
-  running kernel whenever you want).  In this case you should read
-  <file:Documentation/modules.txt>.  The module will be called
-  zftape.o.
-
-  Regardless of whether you say Y or M here, an additional runtime
-  loadable module called `zft-compressor.o' which contains code to
-  support user transparent on-the-fly compression based on Ross
-  William's lzrw3 algorithm will be produced.  If you have enabled the
-  kernel module loader (i.e. have said Y to "Kernel module loader
-  support", above) then `zft-compressor.o' will be loaded
-  automatically by zftape when needed.
-
-  Despite its name, zftape does NOT use compression by default.  The
-  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.instmath.rwth-aachen.de/~heine/ftape/> contains
-  further information.
-
-  IMPORTANT NOTE: zftape can read archives created by previous
-  versions of ftape and provide file mark support (i.e. fast skipping
-  between tape archives) but previous version of ftape will lack file
-  mark support when reading archives produced by zftape.
-
-Default block size for zftape
-CONFIG_ZFT_DFLT_BLK_SZ
-  If unsure leave this at its default value, i.e. 10240. Note that
-  you specify only the default block size here. The block size can be
-  changed at run time using the MTSETBLK tape operation with the
-  MTIOCTOP ioctl (i.e. with "mt -f /dev/qft0 setblk #BLKSZ" from the
-  shell command line).
-
-  The probably most striking difference between zftape and previous
-  versions of ftape is the fact that all data must be written or read
-  in multiples of a fixed block size. The block size defaults to
-  10240 which is what GNU tar uses. The values for the block size
-  should be either 1 or multiples of 1024 up to a maximum value of
-  63488 (i.e. 62 K). If you specify `1' then zftape's builtin
-  compression will be disabled.
-
-  Reasonable values are `10240' (GNU tar's default block size),
-  `5120' (afio's default block size), `32768' (default block size some
-  backup programs assume for SCSI tape drives) or `1' (no restriction
-  on block size, but disables builtin compression).
-
-Number of DMA buffers
-CONFIG_FT_NR_BUFFERS
-  Please leave this at `3' unless you REALLY know what you are doing.
-  It is not necessary to change this value. Values below 3 make the
-  proper use of ftape impossible, values greater than 3 are a waste of
-  memory. You can change the amount of DMA memory used by ftape at
-  runtime with "mt -f /dev/qft0 setdrvbuffer #NUMBUFFERS". Each buffer
-  wastes 32 KB of memory. Please note that this memory cannot be
-  swapped out.
-
-Enable procfs status report (+2kb)
-CONFIG_FT_PROC_FS
-  Optional. Saying Y will result in creation of a directory
-  `/proc/ftape' under the /proc file system. The files can be viewed
-  with your favorite pager (i.e. use "more /proc/ftape/history" or
-  "less /proc/ftape/history" or simply "cat /proc/ftape/history"). The
-  file will contain some status information about the inserted
-  cartridge, the kernel driver, your tape drive, the floppy disk
-  controller and the error history for the most recent use of the
-  kernel driver. Saying Y will enlarge the size of the ftape driver
-  by approximately 2 KB.
-
-  WARNING: When compiling ftape as a module (i.e. saying M to "Floppy
-  tape drive") it is dangerous to use ftape's /proc file system
-  interface. Accessing `/proc/ftape' while the module is unloaded will
-  result in a kernel Oops. This cannot be fixed from inside ftape.
-
-# Choice: ftdebug
-Controlling the amount of debugging output of ftape
-CONFIG_FT_NORMAL_DEBUG
-  This option controls the amount of debugging output the ftape driver
-  is ABLE to produce; it does not increase or diminish the debugging
-  level itself. If unsure, leave this at its default setting,
-  i.e. choose "Normal".
-
-  Ftape can print lots of debugging messages to the system console
-  resp. kernel log files. Reducing the amount of possible debugging
-  output reduces the size of the kernel module by some KB, so it might
-  be a good idea to use "None" for emergency boot floppies.
-
-  If you want to save memory then the following strategy is
-  recommended: leave this option at its default setting "Normal" until
-  you know that the driver works as expected, afterwards reconfigure
-  the kernel, this time specifying "Reduced" or "None" and recompile
-  and install the kernel as usual. Note that choosing "Excessive"
-  debugging output does not increase the amount of debugging output
-  printed to the console but only makes it possible to produce
-  "Excessive" debugging output.
-
-  Please read <file:Documentation/ftape.txt> for a short description
-  how to control the amount of debugging output.
-
-Excessive
-CONFIG_FT_FULL_DEBUG
-  Extremely verbose output for driver debugging purposes.
-
-Reduced
-CONFIG_FT_NO_TRACE
-  Reduced tape driver debugging output.
-
-None
-CONFIG_FT_NO_TRACE_AT_ALL
-  Suppress all debugging output from the tape drive.
-
-# Choice: ftcontroller
-The floppy drive controller for ftape
-CONFIG_FT_STD_FDC
-  Only change this setting if you have a special controller. If you
-  didn't plug any add-on card into your computer system but just
-  plugged the floppy tape cable into the already existing floppy drive
-  controller then you don't want to change the default setting,
-  i.e. choose "Standard".
-
-  Choose "MACH-2" if you have a Mountain Mach-2 controller.
-  Choose "FC-10/FC-20" if you have a Colorado FC-10 or FC-20
-  controller.
-  Choose "Alt/82078" if you have another controller that is located at
-  an IO base address different from the standard floppy drive
-  controller's base address of `0x3f0', or uses an IRQ (interrupt)
-  channel different from `6', or a DMA channel different from
-  `2'. This is necessary for any controller card that is based on
-  Intel's 82078 FDC such as Seagate's, Exabyte's and Iomega's "high
-  speed" controllers.
-
-  If you choose something other than "Standard" then please make
-  sure that the settings for the IO base address and the IRQ and DMA
-  channel in the configuration menus below are correct. Use the manual
-  of your tape drive to determine the correct settings!
-
-  If you are already successfully using your tape drive with another
-  operating system then you definitely should use the same settings
-  for the IO base, the IRQ and DMA channel that have proven to work
-  with that other OS.
-
-  Note that this menu lets you specify only the default setting for
-  the hardware setup. The hardware configuration can be changed at
-  boot time (when ftape is compiled into the kernel, i.e. if you
-  have said Y to "Floppy tape drive") or module load time (i.e. if you
-  have said M to "Floppy tape drive").
-
-  Please read also the file <file:Documentation/ftape.txt> which
-  contains a short description of the parameters that can be set at
-  boot or load time. If you want to use your floppy tape drive on a
-  PCI-bus based system, please read the file
-  <file:drivers/char/ftape/README.PCI>.
-
-IO base for the floppy disk controller used with Ftape
-CONFIG_FT_FDC_BASE
-  You don't need to specify a value if the following default
-  settings for the base IO address are correct:
-  <<< MACH-2     : 0x1E0 >>>
-  <<< FC-10/FC-20: 0x180 >>>
-  <<< Secondary  : 0x370 >>>
-  Secondary refers to a secondary FDC controller like the "high speed"
-  controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash.
-  Please make sure that the setting for the IO base address
-  specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR
-  CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already
-  successfully using the tape drive with another operating system then
-  you definitely should use the same settings for the IO base that has
-  proven to work with that other OS.
-
-  Note that this menu lets you specify only the default setting for
-  the IO base. The hardware configuration can be changed at boot time
-  (when ftape is compiled into the kernel, i.e. if you specified Y to
-  "Floppy tape drive") or module load time (i.e. if you have said M to
-  "Floppy tape drive").
-
-  Please read also the file <file:Documentation/ftape.txt> which
-  contains a short description of the parameters that can be set at
-  boot or load time.
-
-IRQ channel for the floppy disk controller used with Ftape
-CONFIG_FT_FDC_IRQ
-  You don't need to specify a value if the following default
-  settings for the interrupt channel are correct:
-  <<< MACH-2     : 6 >>>
-  <<< FC-10/FC-20: 9 >>>
-  <<< Secondary  : 6 >>>
-  Secondary refers to secondary a FDC controller like the "high speed"
-  controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash.
-  Please make sure that the setting for the IO base address
-  specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR
-  CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already
-  successfully using the tape drive with another operating system then
-  you definitely should use the same settings for the IO base that has
-  proven to work with that other OS.
-
-  Note that this menu lets you specify only the default setting for
-  the IRQ channel. The hardware configuration can be changed at boot
-  time (when ftape is compiled into the kernel, i.e. if you said Y to
-  "Floppy tape drive") or module load time (i.e. if you said M to
-  "Floppy tape drive").
-
-  Please read also the file <file:Documentation/ftape.txt> which
-  contains a short description of the parameters that can be set at
-  boot or load time.
-
-DMA channel for the floppy disk controller used with Ftape
-CONFIG_FT_FDC_DMA
-  You don't need to specify a value if the following default
-  settings for the DMA channel are correct:
-  <<< MACH-2     : 2 >>>
-  <<< FC-10/FC-20: 3 >>>
-  <<< Secondary  : 2 >>>
-  Secondary refers to a secondary FDC controller like the "high speed"
-  controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash.
-  Please make sure that the setting for the IO base address
-  specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR
-  CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already
-  successfully using the tape drive with another operating system then
-  you definitely should use the same settings for the IO base that has
-  proven to work with that other OS.
-
-  Note that this menu lets you specify only the default setting for
-  the DMA channel. The hardware configuration can be changed at boot
-  time (when ftape is compiled into the kernel, i.e. if you said Y to
-  "Floppy tape drive") or module load time (i.e. if you said M to
-  "Floppy tape drive").
-
-  Please read also the file <file:Documentation/ftape.txt> which
-  contains a short description of the parameters that can be set at
-  boot or load time.
-
-FDC FIFO Threshold before requesting DMA service
-CONFIG_FT_FDC_THR
-  Set the FIFO threshold of the FDC. If this is higher the DMA
-  controller may serve the FDC after a higher latency time. If this is
-  lower, fewer DMA transfers occur leading to less bus contention.
-  You may try to tune this if ftape annoys you with "reduced data
-  rate because of excessive overrun errors" messages. However, this
-  doesn't seem to have too much effect.
-
-  If unsure, don't touch the initial value, i.e. leave it at "8".
-
-FDC maximum data rate
-CONFIG_FT_FDC_MAX_RATE
-  With some motherboard/FDC combinations ftape will not be able to
-  run your FDC/tape drive combination at the highest available
-  speed. If this is the case you'll encounter "reduced data rate
-  because of excessive overrun errors" messages and lots of retries
-  before ftape finally decides to reduce the data rate.
-
-  In this case it might be desirable to tell ftape beforehand that
-  it need not try to run the tape drive at the highest available
-  speed. If unsure, leave this disabled, i.e. leave it at 2000
-  bits/sec.
-
-Direct Rendering Manager (XFree86 DRI support)
-CONFIG_DRM
-  Kernel-level support for the Direct Rendering Infrastructure (DRI)
-  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
-  details.  You should also select and configure AGP
-  (/dev/agpgart) support.
-
-Build drivers for new (XFree 4.1) DRM
-CONFIG_DRM_NEW
-  If you set this option, the new DRM version needed by XFree86 4.1
-  will be used.  Otherwise, the old DRM version will be used,
-  appropriate for XFree86 4.0.
-
-3dfx Banshee/Voodoo3+
-CONFIG_DRM_TDFX
-  Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
-  graphics card.  If M is selected, the module will be called tdfx.o.
-
-3dlabs GMX 2000
-CONFIG_DRM_GAMMA
-  Choose this option if you have a 3dlabs GMX 2000 graphics card.
-  If M is selected, the module will be called gamma.o.
-
-ATI Rage 128
-CONFIG_DRM_R128
-  Choose this option if you have an ATI Rage 128 graphics card.  If M
-  is selected, the module will be called r128.o.  AGP support for
-  this card is strongly suggested (unless you have a PCI version).
-
-ATI Radeon
-CONFIG_DRM_RADEON
-  Choose this option if you have an ATI Radeon graphics card.  There
-  are both PCI and AGP versions.  You don't need to choose this to
-  run the Radeon in plain VGA mode.  There is a product page at
-  <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
-  If M is selected, the module will be called radeon.o.
-
-Intel I810
-CONFIG_DRM_I810
-  Choose this option if you have an Intel I810 graphics card.  If M is
-  selected, the module will be called i810.o.  AGP support is required
-  for this driver to work.
-
-Matrox G200/G400/G450
-CONFIG_DRM_MGA
-  Choose this option if you have a Matrox G200, G400 or G450 graphics
-  card.  If M is selected, the module will be called mga.o.  AGP
-  support is required for this driver to work.
-
-3dfx Banshee/Voodoo3+
-CONFIG_DRM40_TDFX
-  Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
-  graphics card.  If M is selected, the module will be called tdfx.o.
-
-3dlabs GMX 2000
-CONFIG_DRM40_GAMMA
-  Choose this option if you have a 3dlabs GMX 2000 graphics card.
-  If M is selected, the module will be called gamma.o.
-
-ATI Rage 128
-CONFIG_DRM40_R128
-  Choose this option if you have an ATI Rage 128 graphics card.  If M
-  is selected, the module will be called r128.o.  AGP support for
-  this card is strongly suggested (unless you have a PCI version).
-
-ATI Radeon
-CONFIG_DRM40_RADEON
-  Choose this option if you have an ATI Radeon graphics card.  There
-  are both PCI and AGP versions.  You don't need to choose this to
-  run the Radeon in plain VGA mode.  There is a product page at
-  <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
-  If M is selected, the module will be called radeon.o.
-
-Intel I810
-CONFIG_DRM40_I810
-  Choose this option if you have an Intel I810 graphics card.  If M is
-  selected, the module will be called i810.o.  AGP support is required
-  for this driver to work.
-
-Matrox G200/G400/G450
-CONFIG_DRM40_MGA
-  Choose this option if you have a Matrox G200, G400 or G450 graphics
-  card.  If M is selected, the module will be called mga.o.  AGP
-  support is required for this driver to work.
-
-Creator/Creator3D/Elite3D
-CONFIG_DRM_FFB
-  Choose this option if you have one of Sun's Creator3D-based graphics
-  and frame buffer cards.  Product page at
-  <http://www.sun.com/desktop/products/Graphics/creator3d.html>.
-
-MTRR (Memory Type Range Register) support
-CONFIG_MTRR
-  On Intel P6 family processors (Pentium Pro, Pentium II and later)
-  the Memory Type Range Registers (MTRRs) may be used to control
-  processor access to memory ranges. This is most useful if you have
-  a video (VGA) card on a PCI or AGP bus. Enabling write-combining
-  allows bus write transfers to be combined into a larger transfer
-  before bursting over the PCI/AGP bus. This can increase performance
-  of image write operations 2.5 times or more. Saying Y here creates a
-  /proc/mtrr file which may be used to manipulate your processor's
-  MTRRs. Typically the X server should use this.
-
-  This code has a reasonably generic interface so that similar
-  control registers on other processors can be easily supported
-  as well:
-
-  The Cyrix 6x86, 6x86MX and M II processors have Address Range
-  Registers (ARRs) which provide a similar functionality to MTRRs. For
-  these, the ARRs are used to emulate the MTRRs.
-  The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
-  MTRRs. The Centaur C6 (WinChip) has 8 MCRs, allowing
-  write-combining. All of these processors are supported by this code
-  and it makes sense to say Y here if you have one of them.
-
-  Saying Y here also fixes a problem with buggy SMP BIOSes which only
-  set the MTRRs for the boot CPU and not for the secondary CPUs. This
-  can lead to all sorts of problems, so it's good to say Y here.
-
-  You can safely say Y even if your machine doesn't have MTRRs, you'll
-  just add about 9 KB to your kernel.
-
-  See <file:Documentation/mtrr.txt> for more information.
-
-CPU clock frequency of your DEC Alpha
-CONFIG_FT_ALPHA_CLOCK
-  On some DEC Alpha machines the CPU clock frequency cannot be
-  determined automatically, so you need to specify it here ONLY if
-  running a DEC Alpha, otherwise this setting has no effect.
-
-Double Talk PC internal speech card support
-CONFIG_DTLK
-  This driver is for the DoubleTalk PC, a speech synthesizer
-  manufactured by RC Systems (<http://www.rcsys.com/>).  It is also
-  called the `internal DoubleTalk'.  If you want to compile this as a
-  module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
-  <file:Documentation/modules.txt>. The module will be called dtlk.o.
-
-Siemens R3964 serial protocol support
-CONFIG_R3964
-  This driver allows synchronous communication with devices using the
-  Siemens R3964 packet protocol. Unless you are dealing with special
-  hardware like PLCs, you are unlikely to need this.
-
-  To compile this driver as a module ( = code which can be inserted in
-  and removed from the running kernel whenever you want), say M here
-  and read <file:Documentation/modules.txt>. The module will be called
-  n_r3964.o.
-
-  If unsure, say N.
-
-Applicom intelligent fieldbus card support
-CONFIG_APPLICOM
-  This driver provides the kernel-side support for the intelligent
-  fieldbus cards made by Applicom International. More information
-  about these cards can be found on the WWW at the address
-  <http://www.applicom-int.com/>, or by email from David Woodhouse
-  <dwmw2@infradead.org>.
-
-  To compile this driver as a module ( = code which can be inserted in
-  and removed from the running kernel whenever you want), say M here
-  and read <file:Documentation/modules.txt>. The module will be called
-  applicom.o.
-
-  If unsure, say N.
-
-Sony Vaio Programmable I/O Control Device support
-CONFIG_SONYPI
-  This driver enables access to the Sony Programmable I/O Control
-  Device which can be found in many (all ?) Sony Vaio laptops.
-
-  If you have one of those laptops, read
-  <file:Documentation/sonypi.txt>, and say Y or M here.
-
-  If you want to compile the driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called sonypi.o.
-
-Intel Random Number Generator support
-CONFIG_INTEL_RNG
-  This driver provides kernel-side support for the Random Number
-  Generator hardware found on Intel i8xx-based motherboards.
-
-  Both a character driver, used to read() entropy data, and a timer
-  function which automatically adds entropy directly into the
-  kernel pool, are exported by this driver.
-
-  To compile this driver as a module ( = code which can be inserted in
-  and removed from the running kernel whenever you want), say M here
-  and read <file:Documentation/modules.txt>. The module will be called
-  i810_rng.o.
-
-  If unsure, say N.
-
-Power Management support
-CONFIG_PM
-  "Power Management" means that parts of your computer are shut
-  off or put into a power conserving "sleep" mode if they are not
-  being used.  There are two competing standards for doing this: APM
-  and ACPI.  If you want to use either one, say Y here and then also
-  to the requisite support below.
-
-  Power Management is most important for battery powered laptop
-  computers; if you have a laptop, check out the Linux Laptop home
-  page on the WWW at
-  <http://www.cs.utexas.edu/users/kharker/linux-laptop/> and the
-  Battery Powered Linux mini-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  Note that, even if you say N here, Linux on the x86 architecture
-  will issue the hlt instruction if nothing is to be done, thereby
-  sending the processor to sleep and saving power.
-
-ACPI support
-CONFIG_ACPI
-  ACPI/OSPM support for Linux is currently under development. As such,
-  this support is preliminary and EXPERIMENTAL.  Configuring ACPI
-  support enables kernel interfaces that allow higher level software
-  (OSPM) to manipulate ACPI defined hardware and software interfaces,
-  including the evaluation of ACPI control methods.  If unsure, choose
-  N here.  Note, this option will enlarge your kernel by about 120K.
-
-  This support requires an ACPI compliant platform (hardware/firmware).
-  If both ACPI and Advanced Power Management (APM) support are
-  configured, whichever is loaded first shall be used.
-
-  This code DOES NOT currently provide a complete OSPM implementation
-  -- it has not yet reached APM's level of functionality.  When fully
-  implemented, Linux ACPI/OSPM will provide a more robust functional
-  replacement for legacy configuration and power management
-  interfaces, including the Plug-and-Play BIOS specification (PnP
-  BIOS), the Multi-Processor Specification (MPS), and the Advanced
-  Power Management specification (APM).
-
-  Linux support for ACPI/OSPM is based on Intel Corporation's ACPI
-  Component Architecture (ACPI CA). The latest ACPI CA source code,
-  documentation, debug builds, and implementation status information
-  can be downloaded from:
-  <http://developer.intel.com/technology/iapc/acpi/downloads.htm>.
-
-  The ACPI Sourceforge project may also be of interest:
-  <http://sf.net/projects/acpi/>
-
-Enable ACPI 2.0 with errata 1.3
-CONFIG_ACPI20
-  Enable support for the 2.0 version of the ACPI interpreter.  See the
-  help for ACPI for caveats and discussion.
-
-ACPI kernel configuration manager
-CONFIG_ACPI_KERNEL_CONFIG
-  If you say `Y' here, Linux's ACPI support will use the
-  hardware-level system descriptions found on IA64 machines.
-
-ACPI Debug Statements
-CONFIG_ACPI_DEBUG
-  The ACPI driver can optionally report errors with a great deal
-  of verbosity. Saying Y enables these statements. This will increase
-  your kernel size by around 50K.
-
-ACPI Bus Manager
-CONFIG_ACPI_BUSMGR
-  The ACPI Bus Manager enumerates devices in the ACPI namespace, and
-  handles PnP messages.  All ACPI devices use its services, so using
-  them requires saying Y here.
-
-ACPI System Driver
-CONFIG_ACPI_SYS
-  This driver will enable your system to shut down using ACPI, and
-  dump your ACPI DSDT table using /proc/acpi/dsdt.
-
-ACPI Processor Driver
-CONFIG_ACPI_CPU
-  This driver installs ACPI as the idle handler for Linux, and uses
-  ACPI C2 and C3 processor states to save power, on systems that
-  support it.
-
-ACPI Button
-CONFIG_ACPI_BUTTON
-  This driver registers for events based on buttons, such as the
-  power, sleep, and lid switch.  In the future, a daemon will read
-  /proc/acpi/event and perform user-defined actions such as shutting
-  down the system.  Until then, you can cat it, and see output when
-  a button is pressed.
-
-ACPI AC Adapter
-CONFIG_ACPI_AC
-  This driver adds support for the AC Adapter object, which indicates
-  whether a system is on AC, or not.  Typically, only laptops have
-  this object, since desktops are always on AC.
-
-ACPI Embedded Controller
-CONFIG_ACPI_EC
-  This driver is required on some systems for the proper operation of
-  the battery and thermal drivers.  If you are compiling for a laptop,
-  say Y.
-
-ACPI Control Method Battery
-CONFIG_ACPI_CMBATT
-  This driver adds support for battery information through
-  /proc/acpi/battery. If you have a laptop with a battery, say Y.
-
-ACPI Thermal
-CONFIG_ACPI_THERMAL
-  This driver handles overheating conditions on laptops. It is HIGHLY
-  recommended, as your laptop CPU may be damaged without it.
-
-Advanced Power Management BIOS support
-CONFIG_APM
-  APM is a BIOS specification for saving power using several different
-  techniques. This is mostly useful for battery powered laptops with
-  APM compliant BIOSes. If you say Y here, the system time will be
-  reset after a RESUME operation, the /proc/apm device will provide
-  battery status information, and user-space programs will receive
-  notification of APM "events" (e.g. battery status change).
-
-  If you select "Y" here, you can disable actual use of the APM
-  BIOS by passing the "apm=off" option to the kernel at boot time.
-
-  Note that the APM support is almost completely disabled for
-  machines with more than one CPU.
-
-  In order to use APM, you will need supporting software. For location
-  and more information, read <file:Documentation/pm.txt> and the
-  Battery Powered Linux mini-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  This driver does not spin down disk drives (see the hdparm(8)
-  manpage ("man 8 hdparm") for that), and it doesn't turn off
-  VESA-compliant "green" monitors.
-
-  This driver does not support the TI 4000M TravelMate and the ACER
-  486/DX4/75 because they don't have compliant BIOSes. Many "green"
-  desktop machines also don't have compliant BIOSes, and this driver
-  may cause those machines to panic during the boot phase.
-
-  Generally, if you don't have a battery in your machine, there isn't
-  much point in using this driver and you should say N. If you get
-  random kernel OOPSes or reboots that don't seem to be related to
-  anything, try disabling/enabling this option (or disabling/enabling
-  APM in your BIOS).
-
-  Some other things you should try when experiencing seemingly random,
-  "weird" problems:
-
-   1) make sure that you have enough swap space and that it is
-      enabled.
-   2) pass the "no-hlt" option to the kernel
-   3) switch on floating point emulation in the kernel and pass
-      the "no387" option to the kernel
-   4) pass the "floppy=nodma" option to the kernel
-   5) pass the "mem=4M" option to the kernel (thereby disabling
-      all but the first 4 MB of RAM)
-   6) make sure that the CPU is not over clocked.
-   7) read the sig11 FAQ at <http://www.bitwizard.nl/sig11/>
-   8) disable the cache from your BIOS settings
-   9) install a fan for the video card or exchange video RAM
-   10) install a better fan for the CPU
-   11) exchange RAM chips
-   12) exchange the motherboard.
-
-  To compile this driver as a module ( = code which can be inserted in
-  and removed from the running kernel whenever you want), say M here
-  and read <file:Documentation/modules.txt>. The module will be called
-  apm.o.
-
-Ignore USER SUSPEND
-CONFIG_APM_IGNORE_USER_SUSPEND
-  This option will ignore USER SUSPEND requests. On machines with a
-  compliant APM BIOS, you want to say N. However, on the NEC Versa M
-  series notebooks, it is necessary to say Y because of a BIOS bug.
-
-Enable APM at boot time
-CONFIG_APM_DO_ENABLE
-  Enable APM features at boot time. From page 36 of the APM BIOS
-  specification: "When disabled, the APM BIOS does not automatically
-  power manage devices, enter the Standby State, enter the Suspend
-  State, or take power saving steps in response to CPU Idle calls."
-  This driver will make CPU Idle calls when Linux is idle (unless this
-  feature is turned off -- see "Do CPU IDLE calls", below). This
-  should always save battery power, but more complicated APM features
-  will be dependent on your BIOS implementation. You may need to turn
-  this option off if your computer hangs at boot time when using APM
-  support, or if it beeps continuously instead of suspending. Turn
-  this off if you have a NEC UltraLite Versa 33/C or a Toshiba
-  T400CDT. This is off by default since most machines do fine without
-  this feature.
-
-Make CPU Idle calls when idle
-CONFIG_APM_CPU_IDLE
-  Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop.
-  On some machines, this can activate improved power savings, such as
-  a slowed CPU clock rate, when the machine is idle. These idle calls
-  are made after the idle loop has run for some length of time (e.g.,
-  333 mS). On some machines, this will cause a hang at boot time or
-  whenever the CPU becomes idle. (On machines with more than one CPU,
-  this option does nothing.)
-
-Enable console blanking using APM
-CONFIG_APM_DISPLAY_BLANK
-  Enable console blanking using the APM. Some laptops can use this to
-  turn off the LCD backlight when the screen blanker of the Linux
-  virtual console blanks the screen. Note that this is only used by
-  the virtual console screen blanker, and won't turn off the backlight
-  when using the X Window system. This also doesn't have anything to
-  do with your VESA-compliant power-saving monitor. Further, this
-  option doesn't work for all laptops -- it might not turn off your
-  backlight at all, or it might print a lot of errors to the console,
-  especially if you are using gpm.
-
-RTC stores time in GMT
-CONFIG_APM_RTC_IS_GMT
-  Say Y here if your RTC (Real Time Clock a.k.a. hardware clock)
-  stores the time in GMT (Greenwich Mean Time). Say N if your RTC
-  stores localtime.
-
-  It is in fact recommended to store GMT in your RTC, because then you
-  don't have to worry about daylight savings time changes. The only
-  reason not to use GMT in your RTC is if you also run a broken OS
-  that doesn't understand GMT.
-
-Allow interrupts during APM BIOS calls
-CONFIG_APM_ALLOW_INTS
-  Normally we disable external interrupts while we are making calls to
-  the APM BIOS as a measure to lessen the effects of a badly behaving
-  BIOS implementation.  The BIOS should reenable interrupts if it
-  needs to.  Unfortunately, some BIOSes do not -- especially those in
-  many of the newer IBM Thinkpads.  If you experience hangs when you
-  suspend, try setting this to Y.  Otherwise, say N.
-
-Use real mode APM BIOS call to power off
-CONFIG_APM_REAL_MODE_POWER_OFF
-  Use real mode APM BIOS calls to switch off the computer. This is
-  a work-around for a number of buggy BIOSes. Switch this option on if
-  your computer crashes instead of powering off properly.
-
-Watchdog Timer Support
-CONFIG_WATCHDOG
-  If you say Y here (and to one of the following options) and create a
-  character special file /dev/watchdog with major number 10 and minor
-  number 130 using mknod ("man mknod"), you will get a watchdog, i.e.:
-  subsequently opening the file and then failing to write to it for
-  longer than 1 minute will result in rebooting the machine. This
-  could be useful for a networked machine that needs to come back
-  online as fast as possible after a lock-up. There's both a watchdog
-  implementation entirely in software (which can sometimes fail to
-  reboot the machine) and a driver for hardware watchdog boards, which
-  are more robust and can also keep track of the temperature inside
-  your computer. For details, read <file:Documentation/watchdog.txt>
-  in the kernel source.
-
-  The watchdog is usually used together with the watchdog daemon
-  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.
-
-Disable watchdog shutdown on close
-CONFIG_WATCHDOG_NOWAYOUT
-  The default watchdog behaviour (which you get if you say N here) is
-  to stop the timer if the process managing it closes the file
-  /dev/watchdog. It's always remotely possible that this process might
-  get killed. If you say Y here, the watchdog cannot be stopped once
-  it has been started.
-
-WDT Watchdog timer
-CONFIG_WDT
-  If you have a WDT500P or WDT501P watchdog board, say Y here,
-  otherwise N. It is not possible to probe for this board, which means
-  that you have to inform the kernel about the IO port and IRQ using
-  the "wdt=" kernel option (try "man bootparam" or see the
-  documentation of your boot loader (lilo or loadlin) about how to
-  pass options to the kernel at boot time).
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called wdt.o.
-
-WDT PCI Watchdog timer
-CONFIG_WDTPCI
-  If you have a PCI WDT500/501 watchdog board, say Y here, otherwise
-  N.  It is not possible to probe for this board, which means that you
-  have to inform the kernel about the IO port and IRQ using the "wdt="
-  kernel option (try "man bootparam" or see the documentation of your
-  boot loader (lilo or loadlin) about how to pass options to the
-  kernel at boot time).
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called wdt_pci.o.
-
-WDT501 features
-CONFIG_WDT_501
-  Saying Y here and creating a character special file /dev/temperature
-  with major number 10 and minor number 131 ("man mknod") will give
-  you a thermometer inside your computer: reading from
-  /dev/temperature yields one byte, the temperature in degrees
-  Fahrenheit. This works only if you have a WDT501P watchdog board
-  installed.
-
-Fan Tachometer
-CONFIG_WDT_501_FAN
-  Enable the Fan Tachometer on the WDT501. Only do this if you have a
-  fan tachometer actually set up.
-
-Software Watchdog
-CONFIG_SOFT_WATCHDOG
-  A software monitoring watchdog. This will fail to reboot your system
-  from some situations that the hardware watchdog will recover
-  from. Equally it's a lot cheaper to install.
-
-  This driver is also available 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>. The module will be called
-   softdog.o.
-
-Berkshire Products PC Watchdog
-CONFIG_PCWATCHDOG
-  This is the driver for the Berkshire Products PC Watchdog card.
-  This card simply watches your kernel to make sure it doesn't freeze,
-  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/>.
-
-  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 is called pcwd.o. If you want to compile it as a module,
-  say M here and read <file:Documentation/modules.txt>.
-
-  Most people will say N.
-
-Acquire SBC Watchdog Timer
-CONFIG_ACQUIRE_WDT
-  This is the driver for the hardware watchdog on the PSC-6x86 Single
-  Board Computer produced by Acquire Inc (and others).  This watchdog
-  simply watches your kernel to make sure it doesn't freeze, 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.
-  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 is called pscwdt.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.  Most
-  people will say N.
-
-Advantech SBC Watchdog Timer
-CONFIG_ADVANTECH_WDT
-  If you are configuring a Linux kernel for the Advantech single-board
-  computer, say `Y' here to support its built-in watchdog timer
-  feature.  See the help for CONFIG_WATCHDOG for discussion.
-
-W83877F Watchdog Timer
-CONFIG_W83877F_WDT
-  This is the driver for the hardware watchdog on the W83877F chipset
-  as used in EMACS PC-104 motherboards (and likely others).  This
-  watchdog simply watches your kernel to make sure it doesn't freeze,
-  and if it does, it reboots your computer after a certain amount of
-  time.
-
-  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 is called mixcomwd.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.  Most
-  people will say N.
-
-IB700 SBC Watchdog Timer
-CONFIG_IB700_WDT
-  This is the driver for the hardware watchdog on the IB700 Single
-  Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog
-  simply watches your kernel to make sure it doesn't freeze, and if
-  it does, it reboots your computer after a certain amount of time.
-
-  This driver is like the WDT501 driver but for slightly different hardware.
-
-  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 is called ib700wdt.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt. Most people
-  will say N.
-
-Mixcom Watchdog
-CONFIG_MIXCOMWD
-  This is a driver for the Mixcom hardware watchdog cards.  This
-  watchdog simply watches your kernel to make sure it doesn't freeze,
-  and if it does, it reboots your computer after a certain amount of
-  time.
-
-  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 is called mixcomwd.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.  Most
-  people will say N.
-
-ZF MachZ Watchdog
-CONFIG_MACHZ_WDT
-  If you are using a ZF Micro MachZ processor, say Y here, otherwise
-  N.  This is the driver for the watchdog timer builtin on that
-  processor using ZF-Logic interface.  This watchdog simply watches
-  your kernel to make sure it doesn't freeze, and if it does, it
-  reboots your computer after a certain amount of time.
-
-  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 is called machzwd.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-SuperH 3/4 Watchdog
-CONFIG_SH_WDT
-  This driver adds watchdog support for the integrated watchdog in the
-  SuperH 3 and 4 processors. If you have one of these processors, say Y,
-  otherwise say N.
-
-  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 is called shwdt.o. If you want to compile it as a module,
-  say M here and read Documentation/modules.txt.
-	      
-Toshiba Laptop support
-CONFIG_TOSHIBA
-  This adds a driver to safely access the System Management Mode of
-  the CPU on Toshiba portables with a genuine Toshiba BIOS. It does
-  not work on models with a Pheonix BIOS. The System Management Mode
-  is used to set the BIOS and power saving options on Toshiba portables.
-
-  For information on utilities to make use of this driver see the
-  Toshiba Linux utilities web site at:
-  <http://www.buzzard.org.uk/toshiba/>.
-
-  Say Y if you intend to run this kernel on a Toshiba portable.
-  Say N otherwise.
-
-Dell Inspiron 8000 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/>
-
-  Say Y if you intend to run this kernel on a Dell Inspiron 8000.
-  Say N otherwise.
-
-/dev/cpu/microcode - Intel IA32 CPU microcode support
-CONFIG_MICROCODE
-  If you say Y here and also to "/dev file system support" in the
-  'File systems' section, you will be able to update the microcode on
-  Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II,
-  Pentium III, Pentium 4, Xeon etc.  You will obviously need the
-  actual microcode binary data itself which is not shipped with the
-  Linux kernel.
-
-  For latest news and information on obtaining all the required
-  ingredients for this driver, check:
-  <http://www.urbanmyth.org/microcode/>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called microcode.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.  If
-  you use modprobe or kmod you may also want to add the line
-  'alias char-major-10-184 microcode' to your /etc/modules.conf file.
-
-/dev/cpu/*/msr - Model-specific register support
-CONFIG_X86_MSR
-  This device gives privileged processes access to the x86
-  Model-Specific Registers (MSRs).  It is a character device with
-  major 202 and minors 0 to 31 for /dev/cpu/0/msr to /dev/cpu/31/msr.
-  MSR accesses are directed to a specific CPU on multi-processor
-  systems.
-
-/dev/cpu/*/cpuid - CPU information support
-CONFIG_X86_CPUID
-  This device gives processes access to the x86 CPUID instruction to
-  be executed on a specific processor.  It is a character device
-  with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to
-  /dev/cpu/31/cpuid.
-
-SBC-60XX Watchdog Timer
-CONFIG_60XX_WDT
- This driver can be used with the watchdog timer found on some
- single board computers, namely the 6010 PII based computer.
- It may well work with other cards.  It reads port 0x443 to enable
- and re-set the watchdog timer, and reads port 0x45 to disable
- the watchdog.  If you have a card that behave in similar ways,
- you can probably make this driver work with your card as well.
-
- You can compile this driver directly into the kernel, or use
- it as a module.  The module will be called sbc60xxwdt.o.
-
-Enhanced Real Time Clock Support
-CONFIG_RTC
-  If you say Y here and create a character special file /dev/rtc with
-  major number 10 and minor number 135 using mknod ("man mknod"), you
-  will get access to the real time clock (or hardware clock) built
-  into your computer.
-
-  Every PC has such a clock built in. It can be used to generate
-  signals from as low as 1Hz up to 8192Hz, and can also be used
-  as a 24 hour alarm. It reports status information via the file
-  /proc/driver/rtc and its behaviour is set by various ioctls on
-  /dev/rtc.
-
-  If you run Linux on a multiprocessor machine and said Y to
-  "Symmetric Multi Processing" above, you should say Y here to read
-  and set the RTC in an SMP compatible fashion.
-
-  If you think you have a use for such a device (such as periodic data
-  sampling), then say Y here, and read <file:Documentation/rtc.txt>
-  for details.
-
-  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 is called rtc.o. If you want to compile it as a module,
-  say M here and read <file:Documentation/modules.txt>.
-
-Tadpole ANA H8 Support
-CONFIG_H8
-  The Hitachi H8/337 is a microcontroller used to deal with the power
-  and thermal environment. If you say Y here, you will be able to
-  communicate with it via a character special device.
-
-  If unsure, say N.
-
-/dev/nvram support
-CONFIG_NVRAM
-  If you say Y here and create a character special file /dev/nvram
-  with major number 10 and minor number 144 using mknod ("man mknod"),
-  you get read and write access to the 50 bytes of non-volatile memory
-  in the real time clock (RTC), which is contained in every PC and
-  most Ataris.
-
-  This memory is conventionally called "CMOS RAM" on PCs and "NVRAM"
-  on Ataris. /dev/nvram may be used to view settings there, or to
-  change them (with some utility). It could also be used to frequently
-  save a few bits of very important data that may not be lost over
-  power-off and for which writing to disk is too insecure. Note
-  however that most NVRAM space in a PC belongs to the BIOS and you
-  should NEVER idly tamper with it. See Ralf Brown's interrupt list
-  for a guide to the use of CMOS bytes by your BIOS.
-
-  On Atari machines, /dev/nvram is always configured and does not need
-  to be selected.
-
-  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 nvram.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Joystick support
-CONFIG_JOYSTICK
-  If you have a joystick, 6dof controller, gamepad, steering wheel,
-  weapon control system or something like that you can say Y here to
-  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/input/joystick.txt> which
-  contains more information and the location of the joystick package
-  that you'll need.
-
-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/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.
-
-  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 gameport.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Classic ISA/PnP gameports
-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/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).
-  The module will be called ns558.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-PDPI Lightning 4 gamecard
-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/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).
-  The module will be called lightning.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Crystal SoundFusion gameports
-CONFIG_INPUT_CS461X
-  Say Y here if you have a Cirrus CS461x aka "Crystal SoundFusion"
-  PCI audio accelerator.  A product page for the CS4614 is at
-  <http://www.cirrus.com/design/products/overview/index.cfm?ProductID=40>.
-
-  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 cs461x.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Aureal Vortex and Trident 4DWave gameports
-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/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).
-  The module will be called pcigame.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-SoundBlaster Live! gameports
-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/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).
-  The module will be called emu10k1-gp.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Classic PC analog joysticks and gamepads
-CONFIG_INPUT_ANALOG
-  Say Y here if you have a controller that connects to the PC
-  gameport.  This supports many different types, including joysticks
-  with throttle control, with rudders, or with extensions like
-  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/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).
-  The module will be called analog.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Assassin 3D and MadCatz Panther devices
-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/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).
-  The module will be called a3d.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Logitech ADI digital joysticks and gamepads
-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/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).
-  The module will be called adi.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Creative Labs Blaster Cobra gamepad
-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/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).
-  The module will be called cobra.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Genius Flight2000 Digital joysticks and gamepads
-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/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).
-  The module will be called gf2k.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Gravis GrIP joysticks and gamepads
-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/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).
-  The module will be called grip.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-InterAct digital joysticks and gamepads
-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/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).
-  The module will be called interact.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-ThrustMaster DirectConnect joysticks and gamepads
-CONFIG_INPUT_TMDC
-  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/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).
-  The module will be called tmdc.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Microsoft SideWinder digital joysticks and gamepads
-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/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).
-  The module will be called sidewinder.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-Serial port device support
-CONFIG_INPUT_SERIO
-  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/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).
-  The module will be called sidewinder.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-Serial port input line discipline
-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/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).
-  The module will be called serport.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Logitech WingMan Warrior joystick
-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/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).
-  The module will be called warrior.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-LogiCad3d Magellan/SpaceMouse 6dof controller
-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/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).
-  The module will be called magellan.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-SpaceTec SpaceOrb/Avenger 6dof controller
-CONFIG_INPUT_SPACEORB
-  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/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).
-  The module will be called spaceorb.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-SpaceTec SpaceBall 4000 FLX 6dof controller
-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/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).
-  The module will be called spaceball.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Gravis Stinger gamepad
-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/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).
-  The module will be called stinger.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-I-Force joysticks/wheels
-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/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).
-  The module will be called iforce.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-I-Force joysticks/wheels
-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/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).
-  The module will be called iforce.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Multisystem, Sega Genesis, Saturn joysticks and gamepads
-CONFIG_INPUT_DB9
-  Say Y here if you have a Sega Master System gamepad, Sega Genesis
-  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/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).
-  The module will be called db9.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Multisystem, NES, SNES, N64, PSX joysticks and gamepads
-CONFIG_INPUT_GAMECON
-  Say Y here if you have a Nintendo Entertainment System gamepad,
-  Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
-  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/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).
-  The module will be called gamecon.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Multisystem joysticks via TurboGraFX device
-CONFIG_INPUT_TURBOGRAFX
-  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/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).
-  The module will be called turbografx.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-Amiga joysticks
-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/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).
-  The module will be called joy-amiga.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Atomwide serial port support
-CONFIG_ATOMWIDE_SERIAL
-  If you have an Atomwide Serial card for an Acorn system, say Y to
-  this option.  The driver can handle 1, 2, or 3 port cards.
-  If unsure, say N.
-
-Dual serial port support
-CONFIG_DUALSP_SERIAL
-  If you have the Serial Port's dual serial card for an Acorn system,
-  say Y to this option.  If unsure, say N.
-
-NetWinder Button
-CONFIG_NWBUTTON
-  If you say Y here and create a character device node /dev/nwbutton
-  with major and minor numbers 10 and 158 ("man mknod"), then every
-  time the orange button is pressed a number of times, the number of
-  times the button was pressed will be written to that device.
-
-  This is most useful for applications, as yet unwritten, which
-  perform actions based on how many times the button is pressed in a
-  row.
-
-  Do not hold the button down for too long, as the driver does not
-  alter the behaviour of the hardware reset circuitry attached to the
-  button; it will still execute a hard reset if the button is held
-  down for longer than approximately five seconds.
-
-  This driver is also available 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>.  The module will be called
-  nwbutton.o.
-
-  Most people will answer Y to this question and "Reboot Using Button"
-  below to be able to initiate a system shutdown from the button.
-
-Reboot Using Button
-CONFIG_NWBUTTON_REBOOT
-  If you say Y here, then you will be able to initiate a system
-  shutdown and reboot by pressing the orange button a number of times.
-  The number of presses to initiate the shutdown is two by default,
-  but this can be altered by modifying the value of NUM_PRESSES_REBOOT
-  in nwbutton.h and recompiling the driver or, if you compile the
-  driver as a module, you can specify the number of presses at load
-  time with "insmod button reboot_count=<something>".
-
-Sound card support
-CONFIG_SOUND
-  If you have a sound card in your computer, i.e. if it can say more
-  than an occasional beep, say Y.  Be sure to have all the information
-  about your sound card and its configuration down (I/O port,
-  interrupt and DMA channel), because you will be asked for it.
-
-  You want to read the Sound-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. General information about
-  the modular sound system is contained in the files
-  <file:Documentation/sound/Introduction>.  The file
-  <file:Documentation/sound/README.OSS> contains some slightly
-  outdated but still useful information as well.
-
-  If you have a PnP sound card and you want to configure it at boot
-  time using the ISA PnP tools (read
-  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
-  compile the sound card support as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want)
-  and load that module after the PnP configuration is finished.  To do
-  this, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/sound/README.modules>; the module will be
-  called soundcore.o.
-
-  I'm told that even without a sound card, you can make your computer
-  say more than an occasional beep, by programming the PC speaker.
-  Kernel patches and supporting utilities to do that are in the pcsp
-  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
-
-OSS sound modules
-CONFIG_SOUND_OSS
-  OSS is the Open Sound System suite of sound card drivers.  They make
-  sound programming easier since they provide a common API.  Say Y or
-  M here (the module will be called sound.o) if you haven't found a
-  driver for your sound card above, then pick your driver from the
-  list below.
-
-Persistent DMA buffers
-CONFIG_SOUND_DMAP
-  Linux can often have problems allocating DMA buffers for ISA sound
-  cards on machines with more than 16MB of RAM. This is because ISA
-  DMA buffers must exist below the 16MB boundary and it is quite
-  possible that a large enough free block in this region cannot be
-  found after the machine has been running for a while. If you say Y
-  here the DMA buffers (64Kb) will be allocated at boot time and kept
-  until the shutdown. This option is only useful if you said Y to
-  "OSS sound modules", above. If you said M to "OSS sound modules"
-  then you can get the persistent DMA buffer functionality by passing
-  the command-line argument "dmabuf=1" to the sound.o module.
-
-  Say Y unless you have 16MB or more RAM or a PCI sound card.
-
-Support for Aztech Sound Galaxy (non-PnP) cards
-CONFIG_SOUND_SGALAXY
-  This module initializes the older non Plug and Play sound galaxy
-  cards from Aztech. It supports the Waverider Pro 32 - 3D and the
-  Galaxy Washington 16.
-
-  If you compile the driver into the kernel, you have to add
-  "sgalaxy=<io>,<irq>,<dma>,<dma2>,<sgbase>" to the kernel command
-  line.
-
-Support for AD1816(A) based cards
-CONFIG_SOUND_AD1816
-  Say M here if you have a sound card based on the Analog Devices
-  AD1816(A) chip.
-
-  If you compile the driver into the kernel, you have to add
-  "ad1816=<io>,<irq>,<dma>,<dma2>" to the kernel command line.
-
-Yamaha OPL3-SA1 audio controller
-CONFIG_SOUND_OPL3SA1
-  Say Y or M if you have a Yamaha OPL3-SA1 sound chip, which is
-  usually built into motherboards. Read
-  <file:Documentation/sound/OPL3-SA> for details.
-
-  If you compile the driver into the kernel, you have to add
-  "opl3sa=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the kernel
-  command line.
-
-ProAudioSpectrum 16 support
-CONFIG_SOUND_PAS
-  Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio
-  16 or Logitech SoundMan 16 sound card. Answer N if you have some
-  other card made by Media Vision or Logitech since those are not
-  PAS16 compatible. Please read <file:Documentation/sound/PAS16>.
-  It is not necessary to add Sound Blaster support separately; it
-  is included in PAS support.
-
-  If you compile the driver into the kernel, you have to add
-  "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2>
-  to the kernel command line.
-
-Enable PAS16 joystick port
-CONFIG_PAS_JOYSTICK
-  Say Y here to enable the Pro Audio Spectrum 16's auxiliary joystick
-  port.
-
-100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support
-CONFIG_SOUND_SB
-  Answer Y if you have an original Sound Blaster card made by Creative
-  Labs or a 100% hardware compatible clone (like the Thunderboard or
-  SM Games). For an unknown card you may answer Y if the card claims
-  to be Sound Blaster-compatible.
-
-  Please read the file <file:Documentation/sound/Soundblaster>.
-
-  You should also say Y here for cards based on the Avance Logic
-  ALS-007 and ALS-1X0 chips (read <file:Documentation/sound/ALS>) and
-  for cards based on ESS chips (read
-  <file:Documentation/sound/ESS1868> and
-  <file:Documentation/sound/ESS>). If you have an SB AWE 32 or SB AWE
-  64, say Y here and also to "AWE32 synth" below and read
-  <file:Documentation/sound/INSTALL.awe>. If you have an IBM Mwave
-  card, say Y here and read <file:Documentation/sound/mwave>.
-
-  If you compile the driver into the kernel and don't want to use
-  isapnp, you have to add "sb=<io>,<irq>,<dma>,<dma2>" to the kernel
-  command line.
-
-  You can say M here to compile this driver as a module; the module is
-  called sb.o.
-
-Gravis Ultrasound support
-CONFIG_SOUND_GUS
-  Say Y here for any type of Gravis Ultrasound card, including the GUS
-  or GUS MAX.  See also <file:Documentation/sound/ultrasound> for more
-  information on configuring this card with modules.
-
-  If you compile the driver into the kernel, you have to add
-  "gus=<io>,<irq>,<dma>,<dma2>" to the kernel command line.
-
-MPU-401 support (NOT for SB16)
-CONFIG_SOUND_MPU401
-  Be careful with this question.  The MPU401 interface is supported by
-  all sound cards.  However, some natively supported cards have their
-  own driver for MPU401.  Enabling this MPU401 option with these cards
-  will cause a conflict.  Also, enabling MPU401 on a system that
-  doesn't really have a MPU401 could cause some trouble.  If your card
-  was in the list of supported cards, look at the card specific
-  instructions in the <file:Documentation/sound/README.OSS> file.  It
-  is safe to answer Y if you have a true MPU401 MIDI interface card.
-
-  If you compile the driver into the kernel, you have to add
-  "mpu401=<io>,<irq>" to the kernel command line.
-
-6850 UART support
-CONFIG_SOUND_UART6850
-  This option enables support for MIDI interfaces based on the 6850
-  UART chip. This interface is rarely found on sound cards. It's safe
-  to answer N to this question.
-
-  If you compile the driver into the kernel, you have to add
-  "uart6850=<io>,<irq>" to the kernel command line.
-
-PSS (AD1848, ADSP-2115, ESC614) support
-CONFIG_SOUND_PSS
-  Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven
-  ADSP-16 or some other card based on the PSS chipset (AD1848 codec +
-  ADSP-2115 DSP chip + Echo ESC614 ASIC CHIP). For more information on
-  how to compile it into the kernel or as a module see the file
-  <file:Documentation/sound/PSS>.
-
-  If you compile the driver into the kernel, you have to add
-  "pss=<io>,<mssio>,<mssirq>,<mssdma>,<mpuio>,<mpuirq>" to the kernel
-  command line.
-
-Enable PSS mixer (Beethoven ADSP-16 and other compatible)
-CONFIG_PSS_MIXER
-  Answer Y for Beethoven ADSP-16. You may try to say Y also for other
-  cards if they have master volume, bass, treble, and you can't
-  control it under Linux. If you answer N for Beethoven ADSP-16, you
-  can't control master volume, bass, treble and synth volume.
-
-  If you said M to "PSS support" above, you may enable or disable this
-  PSS mixer with the module parameter pss_mixer. For more information
-  see the file <file:Documentation/sound/PSS>.
-
-Have DSPxxx.LD firmware file
-CONFIG_PSS_HAVE_BOOT
-  If you have the DSPxxx.LD file or SYNTH.LD file for you card, say Y
-  to include this file. Without this file the synth device (OPL) may
-  not work.
-
-Full pathname of DSPxxx.LD firmware file
-CONFIG_PSS_BOOT_FILE
-  Enter the full pathname of your DSPxxx.LD file or SYNTH.LD file,
-  starting from /.
-
-Microsoft Sound System support
-CONFIG_SOUND_MSS
-  Again think carefully before answering Y to this question.  It's
-  safe to answer Y if you have the original Windows Sound System card
-  made by Microsoft or Aztech SG 16 Pro (or NX16 Pro).  Also you may
-  say Y in case your card is NOT among these:
-
-     ATI Stereo F/X, AdLib, Audio Excell DSP16, Cardinal DSP16,
-     Ensoniq SoundScape (and compatibles made by Reveal and Spea),
-     Gravis Ultrasound, Gravis Ultrasound ACE, Gravis Ultrasound Max,
-     Gravis Ultrasound with 16 bit option, Logitech Sound Man 16,
-     Logitech SoundMan Games, Logitech SoundMan Wave, MAD16 Pro (OPTi
-     82C929), Media Vision Jazz16, MediaTriX AudioTriX Pro, Microsoft
-     Windows Sound System (MSS/WSS), Mozart (OAK OTI-601), Orchid
-     SW32, Personal Sound System (PSS), Pro Audio Spectrum 16, Pro
-     Audio Studio 16, Pro Sonic 16, Roland MPU-401 MIDI interface,
-     Sound Blaster 1.0, Sound Blaster 16, Sound Blaster 16ASP, Sound
-     Blaster 2.0, Sound Blaster AWE32, Sound Blaster Pro, TI TM4000M
-     notebook, ThunderBoard, Turtle Beach Tropez, Yamaha FM
-     synthesizers (OPL2, OPL3 and OPL4), 6850 UART MIDI Interface.
-
-  For cards having native support in VoxWare, consult the card
-  specific instructions in <file:Documentation/sound/README.OSS>.
-  Some drivers have their own MSS support and saying Y to this option
-  will cause a conflict.
-
-  If you compile the driver into the kernel, you have to add
-  "ad1848=<io>,<irq>,<dma>,<dma2>[,<type>]" to the kernel command
-  line.
-
-SGI Visual Workstation on-board audio
-CONFIG_SOUND_VWSND
-  Say Y or M if you have an SGI Visual Workstation and you want to be
-  able to use its on-board audio.  Read
-  <file:Documentation/sound/vwsnd> for more info on this driver's
-  capabilities.
-
-Ensoniq SoundScape support
-CONFIG_SOUND_SSCAPE
-  Answer Y if you have a sound card based on the Ensoniq SoundScape
-  chipset. Such cards are being manufactured at least by Ensoniq, Spea
-  and Reveal (Reveal makes also other cards).
-
-  If you compile the driver into the kernel, you have to add
-  "sscape=<io>,<irq>,<dma>,<mpuio>,<mpuirq>" to the kernel command
-  line.
-
-MediaTriX AudioTriX Pro support
-CONFIG_SOUND_TRIX
-  Answer Y if you have the AudioTriX Pro sound card manufactured
-  by MediaTrix.
-
-Have TRXPRO.HEX firmware file
-CONFIG_TRIX_HAVE_BOOT
-  The MediaTrix AudioTrix Pro has an on-board microcontroller which
-  needs to be initialized by downloading the code from the file
-  TRXPRO.HEX in the DOS driver directory. If you don't have the
-  TRXPRO.HEX file handy you may skip this step. However, the SB and
-  MPU-401 modes of AudioTrix Pro will not work without this file!
-
-Full pathname of TRXPRO.HEX firmware file
-CONFIG_TRIX_BOOT_FILE
-  Enter the full pathname of your TRXPRO.HEX file, starting from /.
-
-Support for OPTi MAD16 and/or Mozart based cards
-CONFIG_SOUND_MAD16
-  Answer Y if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi
-  82C928 or 82C929 or 82C931) audio interface chip. These chips are
-  quite common so it's possible that many no-name cards have one of
-  them. In addition the MAD16 chip is used in some cards made by known
-  manufacturers such as Turtle Beach (Tropez), Reveal (some models)
-  and Diamond (latest ones). Note however that the Tropez sound cards
-  have their own driver; if you have one of those, say N here and Y or
-  M to "Full support for Turtle Beach WaveFront", below.
-
-  If you compile the driver into the kernel, you have to add
-  "mad16=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the
-  kernel command line.
-
-  See also <file:Documentation/sound/Opti> and
-  <file:Documentation/sound/MAD16> for more information on setting
-  these cards up as modules.
-
-Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/sound cards
-CONFIG_SOUND_WAVEFRONT
-  Answer Y or M if you have a Tropez Plus, Tropez or Maui sound card
-  and read the files <file:Documentation/sound/Wavefront> and
-  <file:Documentation/sound/Tropez+>.
-
-Support MIDI in older MAD16 based cards (requires SB)
-CONFIG_MAD16_OLDCARD
-  Answer Y (or M) if you have an older card based on the C928 or
-  Mozart chipset and you want to have MIDI support. If you enable this
-  option you also need to enable support for Sound Blaster.
-
-Support for Crystal CS4232 based (PnP) cards
-CONFIG_SOUND_CS4232
-  Say Y here if you have a card based on the Crystal CS4232 chip set,
-  which uses its own Plug and Play protocol.
-
-  If you compile the driver into the kernel, you have to add
-  "cs4232=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the kernel
-  command line.
-
-  See <file:Documentation/sound/CS4232> for more information on
-  configuring this card.
-
-Support for Yamaha OPL3-SA2 and SA3 based PnP cards
-CONFIG_SOUND_OPL3SA2
-  Say Y or M if you have a card based on one of these Yamaha sound
-  chipsets or the "SAx", which is actually a SA3. Read
-  <file:Documentation/sound/OPL3-SA2> for more information on
-  configuring these cards.
-
-  If you compile the driver into the kernel and do not also
-  configure in the optional ISA PnP support, you will have to add
-  "opl3sa2=<io>,<irq>,<dma>,<dma2>,<mssio>,<mpuio>" to the kernel
-  command line.
-
-Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers
-CONFIG_SOUND_MAUI
-  Say Y here if you have a Turtle Beach Wave Front, Maui, or Tropez
-  sound card.
-
-  If you compile the driver into the kernel, you have to add
-  "maui=<io>,<irq>" to the kernel command line.
-
-Have OSWF.MOT firmware file
-CONFIG_MAUI_HAVE_BOOT
-  Turtle Beach Maui and Tropez sound cards have a microcontroller
-  which needs to be initialized prior to use. OSWF.MOT is a file
-  distributed with the card's DOS/Windows drivers. Answer Y if you
-  have this file.
-
-Full pathname of OSWF.MOT firmware file
-CONFIG_MAUI_BOOT_FILE
-  Enter the full pathname of your OSWF.MOT file, starting from /.
-
-Support for Turtle Beach MultiSound Classic, Tahiti, Monterey
-CONFIG_SOUND_MSNDCLAS
-  Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
-  Monterey (not for the Pinnacle or Fiji).
-
-  See <file:Documentation/sound/MultiSound> for important information
-  about this driver.  Note that it has been discontinued, but the
-  Voyetra Turtle Beach knowledge base entry for it is still available
-  at <http://www.voyetra-turtle-beach.com/site/kb_ftp/790.asp>.
-
-MSND Classic I/O
-CONFIG_MSNDCLAS_IO
-  I/O port address for the MultiSound Classic and related cards.
-
-MSND Classic IRQ
-CONFIG_MSNDCLAS_IRQ
-  Interrupt Request line for the MultiSound Classic and related cards.
-
-MSND Classic memory address
-CONFIG_MSNDCLAS_MEM
-  Memory-mapped I/O base address for the MultiSound Classic and
-  related cards.
-
-Full pathname of MSNDINIT.BIN firmware file
-CONFIG_MSNDCLAS_INIT_FILE
-  The MultiSound cards have two firmware files which are required for
-  operation, and are not currently included. These files can be
-  obtained from Turtle Beach. See
-  <file:Documentation/sound/MultiSound> for information on how to
-  obtain this.
-
-Full pathname of MSNDPERM.BIN firmware file
-CONFIG_MSNDCLAS_PERM_FILE
-  The MultiSound cards have two firmware files which are required for
-  operation, and are not currently included. These files can be
-  obtained from Turtle Beach. See
-  <file:Documentation/sound/MultiSound> for information on how to
-  obtain this.
-
-Support for Turtle Beach MultiSound Pinnacle, Fiji
-CONFIG_SOUND_MSNDPIN
-  Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji.
-  See <file:Documentation/sound/MultiSound> for important information
-  about this driver. Note that it has been discontinued, but the
-  Voyetra Turtle Beach knowledge base entry for it is still available
-  at <http://www.voyetra-turtle-beach.com/site/kb_ftp/600.asp>.
-
-MSND Pinnacle IDE I/O 0
-CONFIG_MSNDPIN_IDE_IO0
-  CD-ROM drive 0 memory-mapped I/O base address for the MultiSound
-  Pinnacle and Fiji sound cards.
-
-MSND Pinnacle IDE I/O 1
-CONFIG_MSNDPIN_IDE_IO1
-  CD-ROM drive 1 memory-mapped I/O base address for the MultiSound
-  Pinnacle and Fiji sound cards.
-
-MSND Pinnacle IDE IRQ
-CONFIG_MSNDPIN_IDE_IRQ
-  Interrupt request number for the IDE CD-ROM interface on the
-  MultiSound Pinnacle and Fiji sound cards.
-
-MSND Pinnacle I/O
-CONFIG_MSNDPIN_IO
-  Memory-mapped I/O base address for the primary synthesizer on
-  MultiSound Pinnacle and Fiji sound cards.
-
-MSND Pinnacle MPU I/O
-CONFIG_MSNDPIN_MPU_IO
-  Memory-mapped I/O base address for the Kurzweil daughterboard
-  synthesizer on MultiSound Pinnacle and Fiji sound cards.
-
-MSND Pinnacle MPU IRQ
-CONFIG_MSNDPIN_MPU_IRQ
-  Iinterrupt request number for the Kurzweil daughterboard
-  synthesizer on MultiSound Pinnacle and Fiji sound cards.
-
-MSND Pinnacle IRQ
-CONFIG_MSNDPIN_IRQ
-  Interrupt request line for the primary synthesizer on MultiSound
-  Pinnacle and Fiji sound cards.
-
-MSND Pinnacle joystick I/O
-CONFIG_MSNDPIN_JOYSTICK_IO
-  Memory-mapped I/O base address for the joystick port on MultiSound
-  Pinnacle and Fiji sound cards.
-
-MSND Pinnacle memory
-CONFIG_MSNDPIN_MEM
-  Memory-mapped I/O base address for the primary synthesizer on
-  MultiSound Pinnacle and Fiji sound cards.
-
-Full pathname of PNDSPINI.BIN firmware file
-CONFIG_MSNDPIN_INIT_FILE
-  The MultiSound cards have two firmware files which are required
-  for operation, and are not currently included. These files can be
-  obtained from Turtle Beach. See
-  <file:Documentation/sound/MultiSound> for information on how to
-  obtain this.
-
-Full pathname of PNDSPERM.BIN firmware file
-CONFIG_MSNDPIN_PERM_FILE
-  The MultiSound cards have two firmware files which are required for
-  operation, and are not currently included. These files can be
-  obtained from Turtle Beach. See
-  <file:Documentation/sound/MultiSound> for information on how to
-  obtain this.
-
-MSND Pinnacle has S/PDIF I/O
-CONFIG_MSNDPIN_DIGITAL
-  If you have the S/PDIF daughter board for the Pinnacle or Fiji,
-  answer Y here; otherwise, say N. If you have this, you will be able
-  to play and record from the S/PDIF port (digital signal). See
-  <file:Documentation/sound/MultiSound> for information on how to make
-  use of this capability.
-
-MSND Pinnacle non-PnP Mode
-CONFIG_MSNDPIN_NONPNP
-  The Pinnacle and Fiji card resources can be configured either with
-  PnP, or through a configuration port. Say Y here if your card is NOT
-  in PnP mode. For the Pinnacle, configuration in non-PnP mode allows
-  use of the IDE and joystick peripherals on the card as well; these
-  do not show up when the card is in PnP mode. Specifying zero for any
-  resource of a device will disable the device. If you are running the
-  card in PnP mode, you must say N here and use isapnptools to
-  configure the card's resources.
-
-MSND Pinnacle config port
-CONFIG_MSNDPIN_CFG
-  This is the port which the Pinnacle and Fiji uses to configure the
-  card's resources when not in PnP mode. If your card is in PnP mode,
-  then be sure to say N to the previous option, "MSND Pinnacle Non-PnP
-  Mode".
-
-MSND buffer size (kB)
-CONFIG_MSND_FIFOSIZE
-  Configures the size of each audio buffer, in kilobytes, for
-  recording and playing in the MultiSound drivers (both the Classic
-  and Pinnacle). Larger values reduce the chance of data overruns at
-  the expense of overall latency. If unsure, use the default.
-
-Yamaha FM synthesizer (YM3812/OPL-3) support
-CONFIG_SOUND_YM3812
-  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
-  Answering Y is usually a safe and recommended choice, however some
-  cards may have software (TSR) FM emulation. Enabling FM support with
-  these cards may cause trouble (I don't currently know of any such
-  cards, however). Please read the file
-  <file:Documentation/sound/OPL3> if your card has an OPL3 chip.
-
-  If you compile the driver into the kernel, you have to add
-  "opl3=<io>" to the kernel command line.
-
-  If unsure, say Y.
-
-ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio)
-CONFIG_SOUND_ACI_MIXER
-  ACI (Audio Command Interface) is a protocol used to communicate with
-  the microcontroller on some sound cards produced by miro and
-  Cardinal Technologies.  The main function of the ACI is to control
-  the mixer and to get a product identification.
-
-  This VoxWare ACI driver currently supports the ACI functions on the
-  miroSOUND PCM1-pro, PCM12 and PCM20 radio. On the PCM20 radio, ACI
-  also controls the radio tuner. This is supported in the video4linux
-  miropcm20 driver (say M or Y here and go back to "Multimedia
-  devices" -> "Radio Adapters").
-
-  This driver is also available as a module and will be called aci.o.
-
-SB32/AWE support
-CONFIG_SOUND_AWE32_SYNTH
-  Say Y here if you have a Sound Blaster SB32, AWE32-PnP, SB AWE64 or
-  similar sound card. See <file:Documentation/sound/README.awe>,
-  <file:Documentation/sound/AWE32> and the Soundblaster-AWE
-  mini-HOWTO, available from <http://www.linuxdoc.org/docs.html#howto>
-  for more info.
-
-Gallant Audio Cards (SC-6000 and SC-6600 based)
-CONFIG_SOUND_AEDSP16
-  Answer Y if you have a Gallant's Audio Excel DSP 16 card. This
-  driver supports Audio Excel DSP 16 but not the III nor PnP versions
-  of this card.
-
-  The Gallant's Audio Excel DSP 16 card can emulate either an SBPro or
-  a Microsoft Sound System card, so you should have said Y to either
-  "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support"
-  or "Microsoft Sound System support", above, and you need to answer
-  the "MSS emulation" and "SBPro emulation" questions below
-  accordingly. You should say Y to one and only one of these two
-  questions.
-
-  Read the <file:Documentation/sound/README.OSS> file and the head of
-  <file:drivers/sound/aedsp16.c> as well as
-  <file:Documentation/sound/AudioExcelDSP16> to get more information
-  about this driver and its configuration.
-
-Audio Excel DSP 16 (SBPro emulation)
-CONFIG_AEDSP16_SBPRO
-  Answer Y if you want your audio card to emulate Sound Blaster Pro.
-  You should then say Y to "100% Sound Blaster compatibles
-  (SB16/32/64, ESS, Jazz16) support" and N to "Audio Excel DSP 16 (MSS
-  emulation)".
-
-  If you compile the driver into the kernel, you have to add
-  "aedsp16=<io>,<irq>,<dma>,<mssio>,<mpuio>,<mouirq>" to the kernel
-  command line.
-
-Audio Excel DSP 16 (MSS emulation)
-CONFIG_AEDSP16_MSS
-  Answer Y if you want your audio card to emulate Microsoft Sound
-  System. You should then say Y to "Microsoft Sound System support"
-  and say N to "Audio Excel DSP 16 (SBPro emulation)".
-
-SC-6600 based audio cards (new Audio Excel DSP 16)
-CONFIG_SC6600
-  The SC6600 is the new version of DSP mounted on the Audio Excel DSP
-  16 cards. Find in the manual the FCC ID of your audio card and
-  answer Y if you have an SC6600 DSP.
-
-SC-6600 Joystick Interface
-CONFIG_SC6600_JOY
-  Say Y here in order to use the joystick interface of the Audio Excel
-  DSP 16 card.
-
-SC-6600 CD-ROM Interface
-CONFIG_SC6600_CDROM  (4=None, 3=IDE, 1=Panasonic, 0=Sony)
-  This is used to activate the CD-ROM interface of the Audio Excel
-  DSP 16 card. Enter: 0 for Sony, 1 for Panasonic, 2 for IDE, 4 for no
-  CD-ROM present.
-
-SC-6600 CD-ROM Interface I/O Address
-CONFIG_SC6600_CDROMBASE
-  Base I/O port address for the CD-ROM interface of the Audio Excel
-  DSP 16 card.
-
-Audio Excel DSP 16 (MPU401 emulation)
-CONFIG_AEDSP16_MPU401
-  Answer Y if you want your audio card to emulate the MPU-401 midi
-  interface. You should then also say Y to "MPU-401 support".
-
-  Note that the I/O base for MPU-401 support of aedsp16 is the same
-  you have selected for "MPU-401 support". If you are using this
-  driver as a module you have to specify the MPU I/O base address with
-  the parameter 'mpu_base=0xNNN'.
-
-C-Media PCI (CMI8338/8378)
-CONFIG_SOUND_CMPCI
-  Say Y or M if you have a PCI sound card using the CMI8338
-  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
-  the CMI8338 or the CMI8738 chipset.  Data on these chips are
-  available at <http://www.cmedia.com.tw/>.
-
-Number of speakers (2, 4, 5, 6)
-CONFIG_SOUND_CMPCI_SPEAKERS
-  Specify the number of speaker channels you want the card to drive,
-  as an integer.
-
-Enable S/PDIF loop for CMI8738
-CONFIG_SOUND_CMPCI_SPDIFLOOP
-  Enable loopback from SPDIF in to SPDIF out.  For discussion, see
-  "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/>.
-
-  It is now possible to load dsp microcode patches into the EMU10K1
-  chip.  These patches are used to implement real time sound
-  processing effects which include for example: signal routing,
-  bass/treble control, AC3 passthrough, ...
-  Userspace tools to create new patches and load/unload them can be
-  found at <http://opensource.creative.com/dist.html>.
-
-Creative 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.
-
-Crystal SoundFusion (CS4280/461x)
-CONFIG_SOUND_FUSION
-  This module drives the Crystal SoundFusion devices (CS4280/46xx
-  series) when wired as native sound drivers with AC97 codecs.  If
-  this driver does not work try the CS4232 driver.
-
-Ensoniq AudioPCI (ES1370) based PCI sound cards
-CONFIG_SOUND_ES1370
-  Say Y or M if you have a PCI sound card utilizing the Ensoniq
-  ES1370 chipset, such as Ensoniq's AudioPCI (non-97). To find
-  out if your sound card uses an ES1370 without removing your
-  computer's cover, use lspci -n and look for the PCI ID
-  1274:5000. Since Ensoniq was bought by Creative Labs,
-  Sound Blaster 64/PCI models are either ES1370 or ES1371 based.
-  This driver differs slightly from OSS/Free, so PLEASE READ
-  <file:Documentation/sound/es1370>.
-
-Ensoniq AudioPCI 97 (ES1371) based sound cards
-CONFIG_SOUND_ES1371
-  Say Y or M if you have a PCI sound card utilizing the Ensoniq
-  ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if
-  your sound card uses an ES1371 without removing your computer's
-  cover, use lspci -n and look for the PCI ID 1274:1371. Since
-  Ensoniq was bought by Creative Labs, Sound Blaster 64/PCI
-  models are either ES1370 or ES1371 based. This driver differs
-  slightly from OSS/Free, so PLEASE READ
-  <file:Documentation/sound/es1371>.
-
-ESS Solo1 based PCI sound cards (eg. SC1938)
-CONFIG_SOUND_ESSSOLO1
-  Say Y or M if you have a PCI sound card utilizing the ESS Technology
-  Solo1 chip. To find out if your sound card uses a
-  Solo1 chip without removing your computer's cover, use
-  lspci -n and look for the PCI ID 125D:1969. This driver
-  differs slightly from OSS/Free, so PLEASE READ
-  <file:Documentation/sound/solo1>.
-
-S3 SonicVibes based PCI sound cards
-CONFIG_SOUND_SONICVIBES
-  Say Y or M if you have a PCI sound card utilizing the S3
-  SonicVibes chipset. To find out if your sound card uses a
-  SonicVibes chip without removing your computer's cover, use
-  lspci -n and look for the PCI ID 5333:CA00. This driver
-  differs slightly from OSS/Free, so PLEASE READ
-  <file:Documentation/sound/sonicvibes>.
-
-Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core
-CONFIG_SOUND_TRIDENT
-  Say Y or M if you have a PCI sound card utilizing the Trident
-  4DWave-DX/NX chipset or your mother board chipset has SiS 7018
-  or ALi 5451 built-in. The SiS 7018 PCI Audio Core is embedded
-  in SiS960 Super South Bridge and SiS540/630 Single Chipset.
-  The ALi 5451 PCI Audio Core is embedded in ALi M1535, M1535D,
-  M1535+ or M1535D+ South Bridge.
-
-  Use lspci -n to find out if your sound card or chipset uses
-  Trident 4DWave or SiS 7018. PCI ID 1023:2000 or 1023:2001 stands
-  for Trident 4Dwave. PCI ID 1039:7018 stands for SiS7018. PCI ID
-  10B9:5451 stands for ALi5451.
-
-  This driver supports S/PDIF in/out (record/playback) for ALi 5451
-  embedded in ALi M1535+ and M1535D+. Note that they aren't all
-  enabled by default; you can enable them by saying Y to "/proc file
-  system support" and "Sysctl support", and after the /proc file
-  system has been mounted, executing the command
-
-	command			what is enabled
-
-  echo 0>/proc/ALi5451	pcm out is also set to S/PDIF out. (Default).
-
-  echo 1>/proc/ALi5451	use S/PDIF out to output pcm data.
-
-  echo 2>/proc/ALi5451	use S/PDIF out to output non-pcm data.
-                        (AC3...).
-
-  echo 3>/proc/ALi5451	record from Ac97 in(MIC, Line in...).
-                        (Default).
-
-  echo 4>/proc/ALi5451	no matter Ac97 settings, record from S/PDIF
-                        in.
-
-
-  This driver differs slightly from OSS/Free, so PLEASE READ the
-  comments at the top of <file:drivers/sound/trident.c>.
-
-Rockwell WaveArtist
-CONFIG_SOUND_WAVEARTIST
-  Say Y here to include support for the Rockwell WaveArtist sound
-  system.  This driver is mainly for the NetWinder.
-
-VIA 82Cxxx Audio Codec
-CONFIG_SOUND_VIA82CXXX
-  Say Y here to include support for the audio codec found on VIA
-  82Cxxx-based chips. Typically these are built into a motherboard.
-
-  DO NOT select Sound Blaster or Adlib with this driver, unless
-  you have a Sound Blaster or Adlib card in addition to your VIA
-  audio chip.
-
-VIA 82C686 MIDI
-CONFIG_MIDI_VIA82CXXX
-  Answer Y to use the MIDI interface of the Via686. You may need to
-  enable this in the BIOS before it will work. This is for connection
-  to external MIDI hardware, and is not required for software playback
-  of MIDI files.
-
-NeoMagic 256AV/256ZX sound chipsets
-CONFIG_SOUND_NM256
-  Say M here to include audio support for the NeoMagic 256AV/256ZX
-  chipsets. These are the audio chipsets found in the Sony
-  Z505S/SX/DX, some Sony F-series, and the Dell Latitude CPi and CPt
-  laptops. It includes support for an AC97-compatible mixer and an
-  apparently proprietary sound engine.
-
-  See <file:Documentation/sound/NM256> for further information.
-
-ESS Maestro, Maestro2, Maestro2E driver
-CONFIG_SOUND_MAESTRO
-  Say Y or M if you have a sound system driven by ESS's Maestro line
-  of PCI sound chips.  These include the Maestro 1, Maestro 2, and
-  Maestro 2E.  See <file:Documentation/sound/Maestro> for more
-  details.
-
-ESS Maestro3/Allegro driver
-CONFIG_SOUND_MAESTRO3
-  Say Y or M if you have a sound system driven by ESS's Maestro 3
-  PCI sound chip.
-
-Adlib Cards
-CONFIG_SOUND_ADLIB
-  Includes ASB 64 4D. Information on programming AdLib cards is
-  available at <http://www.itsnet.com/home/ldragon/Specs/adlib.html>.
-
-Crystal Sound CS4281
-CONFIG_SOUND_CS4281
-  Picture and feature list at
-  <http://www.pcbroker.com/crystal4281.html>.
-
-16 bit sampling option of GUS (_NOT_ GUS MAX)
-CONFIG_SOUND_GUS16
-  Support for Gravis Ulstrasound (GUS) cards (other than the GUS),
-  sampling at 16-bit width.
-
-GUS MAX support
-CONFIG_SOUND_GUSMAX
-  Support for Gravis Ulstrasound MAX.
-
-Intel ICH audio support
-CONFIG_SOUND_ICH
-  Support for integral audio in Intel's I/O Controller Hub (ICH)
-  chipset, as used on the 810/820/840 motherboards.
-
-Verbose initialization
-CONFIG_SOUND_TRACEINIT
-  Verbose soundcard initialization -- affects the format of autoprobe
-  and initialization messages at boot time.
-
-TV card (bt848) mixer support
-CONFIG_SOUND_TVMIXER
-  Support for audio mixer facilities on the BT848 TV frame-grabber
-  card.
-
-VIDC 16-bit sound
-CONFIG_SOUND_VIDC
-  16-bit support for the VIDC onboard sound hardware found on Acorn
-  machines.
-
-Loopback MIDI device support
-CONFIG_SOUND_VMIDI
-  Support for MIDI loopback on port 1 or 2.
-
-Yamaha YMF7xx PCI audio (native mode)
-CONFIG_SOUND_YMFPCI
-  Support for Yamaha cards including the YMF711, YMF715, YMF718,
-  YMF719, YMF724, Waveforce 192XG, and Waveforce 192 Digital.
-
-Yamaha PCI legacy ports support
-CONFIG_SOUND_YMFPCI_LEGACY
-  Support for YMF7xx PCI cards emulating an MP401.
-
-RME Hammerfall (RME96XX) support
-CONFIG_SOUND_RME96XX
-  Say Y or M if you have a Hammerfall, Hammerfall light or Hammerfall
-  DSP card from RME.
-
-Are you using a crosscompiler
-CONFIG_CROSSCOMPILE
-  Say Y here if you are compiling the kernel on a different
-  architecture than the one it is intended to run on.
-
-Kernel support for Linux/MIPS 32-bit binary compatibility
-CONFIG_MIPS32_COMPAT
-  Select this option if you want Linux/MIPS 32-bit binary
-  compatibility. Since all software available for Linux/MIPS is
-  currently 32-bit you should say Y here.
-
-Build fp exception handler module
-CONFIG_MIPS_FPE_MODULE
-  Build the floating point exception handler module. This option is
-  only useful for people working on the floating point exception
-  handler. If you don't, say N.
-
-Galileo EV64120 Evaluation board
-CONFIG_MIPS_EV64120
-  This is an evaluation board based on the Galileo GT-64120
-  single-chip system controller that contains a MIPS R5000 compatible
-  core running at 75/100MHz.  Their website is located at
-  <http://www.galileot.com/>.  Say Y here if you wish to build a
-  kernel for this platform.
-
-Galileo EV96100 Evaluation board
-CONFIG_MIPS_EV96100
-  This is an evaluation board based on the Galielo GT-96100 LAN/WAN
-  communications controllers containing a MIPS R5000 compatible core
-  running at 83MHz. Their website is <http://www.galileot.com/>. Say Y
-  here if you wish to build a kernel for this platform.
-
-Support for ITE 8172G board
-CONFIG_MIPS_ITE8172
-  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
-  a kernel for this platform.
-
-Support for Globespan IVR board
-CONFIG_MIPS_IVR
-  This is an evaluation board built by Globespan to showcase thir
-  iVR (Internet Video Recorder) design. It utilizes a QED RM5231
-  R5000 MIPS core. More information can be found out their website
-  located at <http://www.globespan.net/products/product4.html>P. Say Y
-  here if you wish to build a kernel for this platform.
-
-Support for Alchemy Semi PB1000 board
-CONFIG_MIPS_PB1000
-  This is an evaluation board built by Alchemy Semiconducttor to
-  showcase their Au1000 Internet Edge Processor. It is SOC design
-  containing a MIPS32 core running at 266/400/500MHz with many
-  integrated peripherals. Further information can be found at their
-  website, <http://www.alchemysemi.com/>. Say Y here if you wish to
-  build a kernel for this platform.
-
-Support for Philips Nino
-CONFIG_NINO
-  Say Y here to select a kernel for the Philips Nino Palm PC. The
-  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).
-
-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-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
-  Enable low-level debugging assertion macros in the kernel code.
-  Currently used only by the time services code in the MIPS port.
-  Don't turn this on unless you know what you are doing.
-
-Remote GDB kernel debugging
-CONFIG_REMOTE_DEBUG
-  If you say Y here, it will be possible to remotely debug the MIPS
-  kernel using gdb. This enlarges your kernel image disk size by
-  several megabytes and requires a machine with more than 16 MB,
-  better 32 MB RAM to avoid excessive linking time. This is only
-  useful for kernel hackers. If unsure, say N.
-
-Run uncached
-CONFIG_MIPS_UNCACHED
-  If you say Y here there kernel will disable all CPU caches.  This will
-  reduce the system's performance dramatically but can help finding
-  otherwise hard to track bugs.  It can also useful if you're doing
-  hardware debugging with a logic analyzer and need to see all traffic
-  on the bus.
-
-Magic System Request Key support
-CONFIG_MAGIC_SYSRQ
-  If you say Y here, you will have some control over the system even
-  if the system crashes for example during kernel debugging (e.g., you
-  will be able to flush the buffer cache to disk, reboot the system
-  immediately or dump some status information). This is accomplished
-  by pressing various keys while holding SysRq (Alt+PrintScreen). It
-  also works on a serial console (on PC hardware at least), if you
-  send a BREAK and then within 5 seconds a command keypress. The
-  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
-  unless you really know what this hack does.
-
-ISDN support
-CONFIG_ISDN
-  ISDN ("Integrated Services Digital Networks", called RNIS in France)
-  is a special type of fully digital telephone service; it's mostly
-  used to connect to your Internet service provider (with SLIP or
-  PPP).  The main advantage is that the speed is higher than ordinary
-  modem/telephone connections, and that you can have voice
-  conversations while downloading stuff.  It only works if your
-  computer is equipped with an ISDN card and both you and your service
-  provider purchased an ISDN line from the phone company.  For
-  details, read <http://alumni.caltech.edu/~dank/isdn/> on the WWW.
-
-  This driver allows you to use an ISDN-card for networking
-  connections and as dialin/out device.  The isdn-tty's have a built
-  in AT-compatible modem emulator.  Network devices support autodial,
-  channel-bundling, callback and caller-authentication without having
-  a daemon running.  A reduced T.70 protocol is supported with tty's
-  suitable for German BTX.  On D-Channel, the protocols EDSS1
-  (Euro-ISDN) and 1TR6 (German style) are supported.  See
-  <file:Documentation/isdn/README> for more information.
-
-  If you want to compile the ISDN code 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 isdn.o. If unsure, say N.
-
-Support synchronous PPP
-CONFIG_ISDN_PPP
-  Over digital connections such as ISDN, there is no need to
-  synchronize sender and recipient's clocks with start and stop bits
-  as is done over analog telephone lines. Instead, one can use
-  "synchronous PPP". Saying Y here will include this protocol. This
-  protocol is used by Cisco and Sun for example. So you want to say Y
-  here if the other end of your ISDN connection supports it. You will
-  need a special version of pppd (called ipppd) for using this
-  feature. See <file:Documentation/isdn/README.syncppp> and
-  <file:Documentation/isdn/syncPPP.FAQ> for more information.
-
-Support generic MP (RFC 1717)
-CONFIG_ISDN_MPP
-  With synchronous PPP enabled, it is possible to increase throughput
-  by bundling several ISDN-connections, using this protocol. See
-  <file:Documentation/isdn/README.syncppp> for more information.
-
-Use VJ-compression with synchronous PPP
-CONFIG_ISDN_PPP_VJ
-  This enables Van Jacobson header compression for synchronous PPP.
-  Say Y if the other end of the connection supports it.
-
-Support BSD compression
-CONFIG_ISDN_PPP_BSDCOMP
-  Support for the BSD-Compress compression method for PPP, which uses
-  the LZW compression method to compress each PPP packet before it is
-  sent over the wire. The machine at the other end of the PPP link
-  (usually your ISP) has to support the BSD-Compress compression
-  method as well for this to be useful. Even if they don't support it,
-  it is safe to say Y here.
-
-Support audio via ISDN
-CONFIG_ISDN_AUDIO
-  If you say Y here, the modem-emulator will support a subset of the
-  EIA Class 8 Voice commands. Using a getty with voice-support
-  (mgetty+sendfax by gert@greenie.muc.de with an extension, available
-  with the ISDN utility package for example), you will be able to use
-  your Linux box as an ISDN-answering machine. Of course, this must be
-  supported by the lowlevel driver also. Currently, the HiSax driver
-  is the only voice-supporting driver. See
-  <file:Documentation/isdn/README.audio> for more information.
-
-X.25 PLP on top of ISDN
-CONFIG_ISDN_X25
-  This feature provides the X.25 protocol over ISDN connections.
-  See <file:Documentation/isdn/README.x25> for more information
-  if you are thinking about using this.
-
-ISDN diversion services support
-CONFIG_ISDN_DIVERSION
-  This option allows you to use some supplementary diversion
-  services in conjunction with the HiSax driver on an EURO/DSS1
-  line.
-
-  Supported options are CD (call deflection), CFU (Call forward
-  unconditional), CFB (Call forward when busy) and CFNR (call forward
-  not reachable). Additionally the actual CFU, CFB and CFNR state may
-  be interrogated.
-
-  The use of CFU, CFB, CFNR and interrogation may be limited to some
-  countries. The keypad protocol is still not implemented. CD should
-  work in all countries if the service has been subscribed to.
-
-  Please read the file <file:Documentation/isdn/README.diversion>.
-
-ICN 2B and 4B support
-CONFIG_ISDN_DRV_ICN
-  This enables support for two kinds of ISDN-cards made by a German
-  company called ICN.  2B is the standard version for a single ISDN
-  line with two B-channels, 4B supports two ISDN lines.  For running
-  this card, additional firmware is necessary, which has to be
-  downloaded into the card using a utility which is distributed
-  separately.  See <file:Documentation/isdn/README> and
-  <file:Documentation/isdn/README.icn> for more
-  information.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called icn.o.
-
-isdnloop support
-CONFIG_ISDN_DRV_LOOP
-  This driver provides a virtual ISDN card. Its primary purpose is
-  testing of linklevel features or configuration without getting
-  charged by your service-provider for lots of phone calls.
-  You need will need the loopctrl utility from the latest isdn4k-utils
-  package to set up this driver.
-
-HiSax SiemensChipSet driver support
-CONFIG_ISDN_DRV_HISAX
-  This is a driver supporting the Siemens chipset on various
-  ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, Teles
-  S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many
-  compatibles).
-
-  HiSax is just the name of this driver, not the name of any hardware.
-
-  If you have a card with such a chipset, you should say Y here and
-  also to the configuration option of the driver for your particular
-  card, below.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called hisax.o.  See <file:Documentation/isdn/README.HiSax>
-  for more information on using this driver.
-
-HiSax Support for EURO/DSS1
-CONFIG_HISAX_EURO
-  Say Y or N according to the D-channel protocol which your local
-  telephone service company provides.
-
-  The call control protocol E-DSS1 is used in most European countries.
-  If unsure, say Y.
-
-Support for German chargeinfo
-CONFIG_DE_AOC
-  If you want that the HiSax hardware driver sends messages to the
-  upper level of the isdn code on each AOCD (Advice Of Charge, During
-  the call -- transmission of the fee information during a call) and
-  on each AOCE (Advice Of Charge, at the End of the call --
-  transmission of fee information at the end of the call), say Y here.
-  This works only in Germany.
-
-Disable sending complete
-CONFIG_HISAX_NO_SENDCOMPLETE
-  If you have trouble with some ugly exchanges or you live in
-  Australia select this option.
-
-Disable sending low layer compatibility
-CONFIG_HISAX_NO_LLC
-  If you have trouble with some ugly exchanges try to select this
-  option.
-
-Disable keypad protocol option
-CONFIG_HISAX_NO_KEYPAD
-  If you like to send special dial strings including * or # without
-  using the keypad protocol, select this option.
-
-HiSax Support for German 1TR6
-CONFIG_HISAX_1TR6
-  Say Y or N according to the D-channel protocol which your local
-  telephone service company provides.
-
-  1TR6 is an old call control protocol which was used in Germany
-  before E-DSS1 was established. Nowadays, all new lines in Germany
-  use E-DSS1.
-
-HiSax Support for US NI1
-CONFIG_HISAX_NI1
-  Enable this if you like to use ISDN in US on a NI1 basic rate
-  interface.
-
-Teles 16.0/8.0
-CONFIG_HISAX_16_0
-  This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8
-  and many compatibles.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using the different cards, a different D-channel protocol, or
-  non-standard IRQ/port/shmem settings.
-
-Teles 16.3 or PNP or PCMCIA
-CONFIG_HISAX_16_3
-  This enables HiSax support for the Teles ISDN-cards S0-16.3 the
-  Teles/Creatix PnP and the Teles PCMCIA.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using the different cards, a different D-channel protocol, or
-  non-standard IRQ/port settings.
-
-Teles PCI
-CONFIG_HISAX_TELESPCI
-  This enables HiSax support for the Teles PCI.
-  See <file:Documentation/isdn/README.HiSax> on how to configure it.
-
-Teles S0Box
-CONFIG_HISAX_S0BOX
-  This enables HiSax support for the Teles/Creatix parallel port
-  S0BOX.  See <file:Documentation/isdn/README.HiSax> on how to
-  configure it.
-
-AVM A1 (Fritz)
-CONFIG_HISAX_AVM_A1
-  This enables HiSax support for the AVM A1 (aka "Fritz").
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using the different cards, a different D-channel protocol, or
-  non-standard IRQ/port settings.
-
-AVM PnP/PCI (Fritz!PnP/PCI)
-CONFIG_HISAX_FRITZPCI
-  This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI".
-  See <file:Documentation/isdn/README.HiSax> on how to configure it.
-
-AVM A1 PCMCIA (Fritz)
-CONFIG_HISAX_AVM_A1_PCMCIA
-  This enables HiSax support for the AVM A1 "Fritz!PCMCIA").
-  See <file:Documentation/isdn/README.HiSax> on how to configure it.
-
-Elsa cards
-CONFIG_HISAX_ELSA
-  This enables HiSax support for the Elsa Mircolink ISA cards, for the
-  Elsa Quickstep series cards and Elsa PCMCIA.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using the different cards, a different D-channel protocol, or
-  non-standard IRQ/port settings.
-
-ITK ix1-micro Revision 2
-CONFIG_HISAX_IX1MICROR2
-  This enables HiSax support for the ITK ix1-micro Revision 2 card.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using the different cards, a different D-channel protocol, or
-  non-standard IRQ/port settings.
-
-Eicon.Diehl Diva cards
-CONFIG_HISAX_DIEHLDIVA
-  This enables HiSax support for the Eicon.Diehl Diva none PRO
-  versions passive ISDN cards.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using the different cards, a different D-channel protocol, or
-  non-standard IRQ/port settings.
-
-ASUSCOM ISA cards
-CONFIG_HISAX_ASUSCOM
-  This enables HiSax support for the AsusCom and their OEM versions
-  passive ISDN ISA cards.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using the different cards, a different D-channel protocol, or
-  non-standard IRQ/port settings.
-
-TELEINT cards
-CONFIG_HISAX_TELEINT
-  This enables HiSax support for the TELEINT SA1 semiactiv ISDN card.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using the different cards, a different D-channel protocol, or
-  non-standard IRQ/port settings.
-
-HFC-S based cards
-CONFIG_HISAX_HFCS
-  This enables HiSax support for the HFC-S 2BDS0 based cards, like
-  teles 16.3c.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using the different cards, a different D-channel protocol, or
-  non-standard IRQ/port settings.
-
-Sedlbauer cards
-CONFIG_HISAX_SEDLBAUER
-  This enables HiSax support for the Sedlbauer passive ISDN cards.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using the different cards, a different D-channel protocol, or
-  non-standard IRQ/port settings.
-
-USR Sportster internal TA
-CONFIG_HISAX_SPORTSTER
-  This enables HiSax support for the USR Sportster internal TA card.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using a different D-channel protocol, or non-standard IRQ/port
-  settings.
-
-MIC card
-CONFIG_HISAX_MIC
-  This enables HiSax support for the ITH MIC card.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using a different D-channel protocol, or non-standard IRQ/port
-  settings.
-
-NETjet card
-CONFIG_HISAX_NETJET
-  This enables HiSax support for the NetJet from Traverse
-  Technologies.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using a different D-channel protocol, or non-standard IRQ/port
-  settings.
-
-NETspider U card
-CONFIG_HISAX_NETJET_U
-  This enables HiSax support for the Netspider U interface ISDN card
-  from Traverse Technologies.
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using a different D-channel protocol, or non-standard IRQ/port
-  settings.
-
-Niccy PnP/PCI card
-CONFIG_HISAX_NICCY
-  This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using a different D-channel protocol, or non-standard IRQ/port
-  settings.
-
-Siemens I-Surf card
-CONFIG_HISAX_ISURF
-  This enables HiSax support for the Siemens I-Talk/I-Surf card with
-  ISAR chip.
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using a different D-channel protocol, or non-standard IRQ/port
-  settings.
-
-HST Saphir card
-CONFIG_HISAX_HSTSAPHIR
-  This enables HiSax support for the HST Saphir card.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using a different D-channel protocol, or non-standard IRQ/port
-  settings.
-
-Telekom A4T card
-CONFIG_HISAX_BKM_A4T
-  This enables HiSax support for the Telekom A4T card.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using a different D-channel protocol, or non-standard IRQ/port
-  settings.
-
-Scitel Quadro card
-CONFIG_HISAX_SCT_QUADRO
-  This enables HiSax support for the Scitel Quadro card.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using a different D-channel protocol, or non-standard IRQ/port
-  settings.
-
-Gazel cards
-CONFIG_HISAX_GAZEL
-  This enables HiSax support for the Gazel cards.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using a different D-channel protocol, or non-standard IRQ/port
-  settings.
-
-HFC PCI-Bus cards
-CONFIG_HISAX_HFC_PCI
-  This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
-
-  For more informations see under
-  <file:Documentation/isdn/README.hfc-pci>.
-
-Winbond W6692 based cards
-CONFIG_HISAX_W6692
-  This enables HiSax support for Winbond W6692 based PCI ISDN cards.
-
-  See <file:Documentation/isdn/README.HiSax> on how to configure it
-  using a different D-channel protocol, or non-standard IRQ/port
-  settings.
-
-HFC-S+, HFC-SP, HFC-PCMCIA cards
-CONFIG_HISAX_HFC_SX
-  This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA
-  cards. This code is not finished yet.
-
-Am7930
-CONFIG_HISAX_AMD7930
-  This enables HiSax support for the AMD7930 chips on some SPARCs.
-  This code is not finished yet.
-
-HiSax debugging
-CONFIG_HISAX_DEBUG
-  This enables debugging code in the new-style HiSax drivers, i.e.
-  the ST5481 USB driver currently. 
-  If in doubt, say yes.
-
-ELSA PCMCIA MicroLink cards
-CONFIG_HISAX_ELSA_CS
-  This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink
-  card.
-
-Sedlbauer PCMCIA cards
-CONFIG_HISAX_SEDLBAUER_CS
-  This enables the PCMCIA client driver for the Sedlbauer Speed Star
-  and Speed Star II cards.
-
-ST5481 USB ISDN adapter
-CONFIG_HISAX_ST5481
-  This enables the driver for ST5481 based USB ISDN adapters,
-  e.g. the BeWan Gazel 128 USB
-
-PCBIT-D support
-CONFIG_ISDN_DRV_PCBIT
-  This enables support for the PCBIT ISDN-card.  This card is
-  manufactured in Portugal by Octal.  For running this card,
-  additional firmware is necessary, which has to be downloaded into
-  the card using a utility which is distributed separately.  See
-  <file:Documentation/isdn/README> and
-  <file:Documentation/isdn/README.pcbit> for more information.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called pcbit.o.
-
-Spellcaster support
-CONFIG_ISDN_DRV_SC
-  This enables support for the Spellcaster BRI ISDN boards.  This
-  driver currently builds only in a modularized version ( = code which
-  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.
-
-Eicon active card support
-CONFIG_ISDN_DRV_EICON
-  Say Y here if you have an Eicon active ISDN card. In order to use
-  this card, additional firmware is necessary, which has to be loaded
-  into the card using the eiconctrl utility which is part of the
-  latest isdn4k-utils package. Please read the file
-  <file:Documentation/isdn/README.eicon> for more information.
-
-Legacy Eicon driver
-CONFIG_ISDN_DRV_EICON_OLD
-  Say Y here to use your Eicon active ISDN card with ISDN4Linux
-  isdn module.
-
-Eicon PCI DIVA Server BRI/PRI/4BRI support
-CONFIG_ISDN_DRV_EICON_PCI
-  Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN
-  card.  Please read <file:Documentation/isdn/README.eicon> for more
-  information.
-
-Eicon old-type (S,SX,SCOM,Quadro,S2M) card support
-CONFIG_ISDN_DRV_EICON_ISA
-  Say Y here if you have an old-type Eicon active ISDN card. In order
-  to use this card, additional firmware is necessary, which has to be
-  loaded into the card using the eiconctrl utility which is part of
-  the latest isdn4k-utils package. Please read the file
-  <file:Documentation/isdn/README.eicon> for more information.
-
-Eicon driver type standalone
-CONFIG_ISDN_DRV_EICON_DIVAS
-  Enable this option if you want the eicon driver as standalone
-  version with no interface to the ISDN4Linux isdn module. If you
-  say Y here, the eicon module only supports the Diva Server PCI
-  cards and will provide its own IDI interface. You should say N
-  here.
-
-Support AT-Fax Class 1 and 2 commands
-CONFIG_ISDN_TTY_FAX
-  If you say Y here, the modem-emulator will support a subset of the
-  Fax Class 1 and 2 commands. Using a getty with fax-support
-  (mgetty+sendfax, hylafax), you will be able to use your Linux box as
-  an ISDN-fax-machine. This must be supported by the lowlevel driver
-  also. See <file:Documentation/isdn/README.fax> for more information.
-
-CAPI2.0 support
-CONFIG_ISDN_CAPI
-  This provides the CAPI (Common ISDN Application Programming
-  Interface, a standard making it easy for programs to access ISDN
-  hardware, see <http://www.capi.org/>.  This is needed for AVM's set
-  of active ISDN controllers like B1, T1, M1.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The modules will be called capi.o and kernelcapi.o. If you want to
-  compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-CAPI2.0 /dev/capi20 support
-CONFIG_ISDN_CAPI_CAPI20
-  This option will provide the CAPI 2.0 interface to userspace
-  applications via /dev/capi20. Applications should use the
-  standardized libcapi20 to access this functionality.  You should say
-  Y/M here.
-
-CAPI2.0 Middleware support
-CONFIG_ISDN_CAPI_MIDDLEWARE
-  This option will enhance the capabilities of the /dev/capi20
-  interface.  It will provide a means of moving a data connection,
-  established via the usual /dev/capi20 interface to a special tty
-  device.  If you want to use pppd with pppdcapiplugin to dial up to
-  your ISP, say Y here.
-
-CAPI2.0 filesystem support
-CONFIG_ISDN_CAPI_CAPIFS
-  This option provides a special file system, similar to /dev/pts with
-  device nodes for the special ttys established by using the
-  middleware extension above. If you want to use pppd with
-  pppdcapiplugin to dial up to your ISP, say Y here.
-
-CAPI2.0 capidrv interface support
-CONFIG_ISDN_CAPI_CAPIDRV
-  This option provides the glue code to hook up CAPI driven cards to
-  the legacy isdn4linux link layer.  If you have a card which is
-  supported by a CAPI driver, but still want to use old features like
-  ippp interfaces or ttyI emulation, say Y/M here.
-
-AVM B1 ISA support
-CONFIG_ISDN_DRV_AVMB1_B1ISA
-  Enable support for the ISA version of the AVM B1 card.
-
-AVM B1 PCI support
-CONFIG_ISDN_DRV_AVMB1_B1PCI
-  Enable support for the PCI version of the AVM B1 card.
-
-AVM B1 PCI V4 support
-CONFIG_ISDN_DRV_AVMB1_B1PCIV4
-  Enable support for the V4 version of AVM B1 PCI card.
-
-AVM T1/T1-B ISA support
-CONFIG_ISDN_DRV_AVMB1_T1ISA
-  Enable support for the AVM T1 T1B card.
-  Note: This is a PRI card and handle 30 B-channels.
-
-AVM B1/M1/M2 PCMCIA support
-CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
-  Enable support for the PCMCIA version of the AVM B1 card.
-
-AVM B1/M1/M2 PCMCIA cs module
-CONFIG_ISDN_DRV_AVMB1_AVM_CS
-  Enable the PCMCIA client driver for the AVM B1/M1/M2
-  PCMCIA cards.
-
-AVM T1/T1-B PCI support
-CONFIG_ISDN_DRV_AVMB1_T1PCI
-  Enable support for the AVM T1 T1B card.
-  Note: This is a PRI card and handle 30 B-channels.
-
-AVM C4/C2 support
-CONFIG_ISDN_DRV_AVMB1_C4
-  Enable support for the AVM C4/C2 PCI cards.
-  These cards handle 4/2 BRI ISDN lines (8/4 channels).
-
-Verbose reason code reporting (kernel size +=7K)
-CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
-  If you say Y here, the AVM B1 driver will give verbose reasons for
-  disconnecting. This will increase the size of the kernel by 7 KB. If
-  unsure, say Y.
-
-IBM Active 2000 support
-CONFIG_ISDN_DRV_ACT2000
-  Say Y here if you have an IBM Active 2000 ISDN card. In order to use
-  this card, additional firmware is necessary, which has to be loaded
-  into the card using a utility which is part of the latest
-  isdn4k-utils package. Please read the file
-  <file:Documentation/isdn/README.act2000> for more information.
-
-Auvertech TurboPAM support
-CONFIG_ISDN_DRV_TPAM
-  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/>.
-
-  Please redirect all support questions to support@auvertech.fr.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called tpam.o.
-
-Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)
-CONFIG_HYSDN
-  Say Y here if you have one of Hypercope's active PCI ISDN cards
-  Champ, Ergo and Metro. You will then get a module called hysdn.o.
-  Please read the file <file:Documentation/isdn/README.hysdn> for more
-  information.
-
-HYSDN CAPI 2.0 support
-CONFIG_HYSDN_CAPI
-  Say Y here if you like to use Hypercope's CAPI 2.0 interface.
-
-Support for SUN4 machines (disables SUN4[CDM] support)
-CONFIG_SUN4
-  Say Y here if, and only if, your machine is a Sun4. Note that
-  a kernel compiled with this option will run only on Sun4.
-  (And the current version will probably work only on sun4/330.)
-
-SPARC ESP SCSI support
-CONFIG_SCSI_SUNESP
-  This is the driver for the Sun ESP SCSI host adapter. The ESP
-  chipset is present in most SPARC SBUS-based computers.
-
-  This support is also available as a module called esp.o ( = 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>.
-
-PTI Qlogic, ISP Driver
-CONFIG_SCSI_QLOGICPTI
-  This driver supports SBUS SCSI controllers from PTI or QLogic. These
-  controllers are known under Solaris as qpti and in the openprom as
-  PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are
-  driven by a different driver.
-
-  This support is also available as a module called qlogicpti.o ( =
-  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>.
-
-Sun PROM console
-CONFIG_PROM_CONSOLE
-  Say Y to build a console driver for Sun machines that uses the
-  terminal emulation built into their console PROMS.
-
-/dev/openprom device support
-CONFIG_SUN_OPENPROMIO
-  This driver provides user programs with an interface to the SPARC
-  PROM device tree. The driver implements a SunOS-compatible
-  interface and a NetBSD-compatible interface.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M and read <file:Documentation/modules.txt>. If unsure, say Y.
-
-Openprom tree appears in /proc/openprom
-CONFIG_SUN_OPENPROMFS
-  If you say Y, the OpenPROM device tree will be available as a
-  virtual file system, which you can mount to /proc/openprom by "mount
-  -t openpromfs none /proc/openprom".
-
-  If you want to compile the /proc/openprom 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 openpromfs.o.  If unsure, say M.
-
-Kernel support for Linux/Sparc 32bit binary compatibility
-CONFIG_SPARC32_COMPAT
-  This allows you to run 32-bit binaries on your Ultra.
-  Everybody wants this; say Y.
-
-Kernel support for 32-bit ELF binaries
-CONFIG_BINFMT_ELF32
-  This allows you to run 32-bit Linux/ELF binaries on your Ultra.
-  Everybody wants this; say Y.
-
-Kernel support for 32-bit (ie. SunOS) a.out binaries
-CONFIG_BINFMT_AOUT32
-  This allows you to run 32-bit a.out format binaries on your Ultra.
-  If you want to run SunOS binaries (see SunOS binary emulation below)
-  or other a.out binaries, say Y. If unsure, say N.
-
-SunOS binary emulation
-CONFIG_SUNOS_EMUL
-  This allows you to run most SunOS binaries.  If you want to do this,
-  say Y here and place appropriate files in /usr/gnemul/sunos. See
-  <http://www.ultralinux.org/faq.html> for more information.  If you
-  want to run SunOS binaries on an Ultra you must also say Y to
-  "Kernel support for 32-bit a.out binaries" above.
-
-Mostek real time clock support
-CONFIG_SUN_MOSTEK_RTC
-  The Mostek RTC chip is used on all known Sun computers except
-  some JavaStations. For a JavaStation you need to say Y both here
-  and to "Enhanced Real Time Clock Support".
-
-  Say Y here unless you are building a special purpose kernel.
-
-OBP Flash Device support
-CONFIG_OBP_FLASH
-  The OpenBoot PROM on Ultra systems is flashable. If you want to be
-  able to upgrade the OBP firmware, say Y here.
-
-JavaStation OS Flash SIMM
-CONFIG_SUN_JSFLASH
-  If you say Y here, you will be able to boot from your JavaStation's
-  Flash memory.
-
-Siemens SAB82532 serial support
-CONFIG_SAB82532
-  This driver supports the serial ports on newer (PCI) Ultra systems.
-  Say Y if you want to be able to use your serial ports.
-
-Videopix Frame Grabber
-CONFIG_SUN_VIDEOPIX
-  Say Y here to support the Videopix Frame Grabber from Sun
-  Microsystems, commonly found on SPARCstations.  This card, which is
-  based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and
-  SVIDEO signals.
-
-Sun bidirectional parallel port support
-CONFIG_SUN_BPP
-  Say Y here to support Sun's obsolete variant of IEEE1284
-  bidirectional parallel port protocol as /dev/bppX.  Can be built on
-  x86 machines.
-
-Aurora Multiboard 1600se
-CONFIG_SUN_AURORA
-  The Aurora Multiboard is a multi-port high-speed serial controller.
-  If you have one of these, say Y.
-
-Tadpole TS102 Microcontroller support
-CONFIG_TADPOLE_TS102_UCTRL
-  Say Y here to directly support the TS102 Microcontroller interface
-  on the Tadpole Sparcbook 3.  This device handles power-management
-  events, and can also notice the attachment/detachment of external
-  monitors and mice.
-
-Audio support
-CONFIG_SPARCAUDIO
-  This driver provides support for the build-in sound devices on most
-  Sun machines. If you want to be able to use this, select this option
-  and one or more of the lowlevel drivers below. See
-  <http://www.dementia.org/~shadow/sparcaudio.html> for more
-  information.
-
-AMD7930 Lowlevel Driver
-CONFIG_SPARCAUDIO_AMD7930
-  This driver supports the AMD 7930 chip found on sun4c, 4/6xx, and
-  SparcClassic systems.
-
-CS4231 Lowlevel Driver
-CONFIG_SPARCAUDIO_CS4231
-  This driver supports the Crystal Semiconductor CS4231 chip found on
-  the SS4, SS5, and Ultras.
-
-DBRI Lowlevel Driver
-CONFIG_SPARCAUDIO_DBRI
-  This driver supports the DBRI audio interface found on the SS10,
-  SS20, Sparcbook 3, and Voyager systems.
-
-Dummy Lowlevel Driver
-CONFIG_SPARCAUDIO_DUMMY
-  This is a pseudo-driver used for debugging and testing the
-  sparcaudio subsystem. Say N unless you want to work on this
-  subsystem.
-
-Sparc hardware
-CONFIG_PARPORT_SUNBPP
-  This driver provides support for the bidirectional parallel port
-  found on many Sun machines. Note that many of the newer Ultras
-  actually have pc style hardware instead.
-
-/proc/hardware support
-CONFIG_PROC_HARDWARE
-  Say Y here to support the /proc/hardware file, which gives you
-  access to information about the machine you're running on,
-  including the model, CPU, MMU, clock speed, BogoMIPS rating,
-  and memory size.
-
-Bluetooth subsystem support
-CONFIG_BLUEZ
-  Bluetooth is low-cost, low-power, short-range wireless technology.
-  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/>.
-
-  Linux Bluetooth subsystem consist of several layers:
-               HCI Core (device and connection manager, scheduler)
-               HCI Device drivers (interface to the hardware)
-               L2CAP Module (L2CAP protocol)
-
-  Say Y here to enable Linux Bluetooth support and to build HCI Core
-  layer.
-
-  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.sourceforge.net/>.
-
-  If you want to compile HCI Core as module (hci.o) say M here.
-
-L2CAP protocol support
-CONFIG_BLUEZ_L2CAP
-  L2CAP (Logical Link Control and Adaptation Protocol) provides
-  connection oriented and connection-less data transport.  L2CAP
-  support is required for most Bluetooth applications.
-
-  Say Y here to compile L2CAP support into the kernel or say M to
-  compile it as module (l2cap.o).
-
-HCI UART driver
-CONFIG_BLUEZ_HCIUART
-  Bluetooth HCI UART driver.
-  This driver is required if you want to use Bluetooth devices with
-  serial port interface.
-
-  Say Y here to compile support for Bluetooth UART devices into the
-  kernel or say M to compile it as module (hci_uart.o).
-
-HCI USB driver
-CONFIG_BLUEZ_HCIUSB
-  Bluetooth HCI USB driver.
-  This driver is required if you want to use Bluetooth devices with
-  USB interface.
-
-  Say Y here to compile support for Bluetooth USB devices into the
-  kernel or say M to compile it as module (hci_usb.o).
-
-HCI VHCI virtual HCI device driver
-CONFIG_BLUEZ_HCIVHCI
-  Bluetooth Virtual HCI device driver.
-  This driver is required if you want to use HCI Emulation software.
-
-  Say Y here to compile support for virtual HCI devices into the
-  kernel or say M to compile it as module (hci_vhci.o).
-
-# The following options are for Linux when running on the Hitachi
-# SuperH family of RISC microprocessors.
-
-SuperH RTC support
-CONFIG_SH_RTC
-  Selecting this option will allow the Linux kernel to emulate
-  PC's RTC.
-
-  If unsure, say N.
-
-SuperH DMAC support
-CONFIG_SH_DMA
-  Selecting this option will provide same API as PC's Direct Memory
-  Access Controller(8237A) for SuperH DMAC.
-
-  If unsure, say N.
-
-# Choice: cf_area
-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".
-
-#
-# m68k-specific kernel options
-# Documented by Chris Lawrence <mailto:quango@themall.net> et al.
-#
-Amiga support
-CONFIG_AMIGA
-  This option enables support for the Amiga series of computers. If
-  you plan to use this kernel on an Amiga, say Y here and browse the
-  material available in <file:Documentation/m68k>; otherwise say N.
-
-Commodore A2232 serial support
-CONFIG_A2232
-  This option supports the 2232 7-port serial card shipped with the
-  Amiga 2000 and other Zorro-bus machines, dating from 1989.  At
-  a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip
-  each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The
-  ports were connected with 8 pin DIN connectors on the card bracket,
-  for which 8 pin to DB25 adapters were supplied. The card also had
-  jumpers internally to toggle various pinning configurations.
-
-  This driver can be built as a module; but then "generic_serial.o"
-  will also be built as a module. This has to be loaded before
-  "ser_a2232.o". If you want to do this, answer M here and read
-  "<file:Documentation/modules.txt>".
-
-A4000T SCSI support
-CONFIG_A4000T_SCSI
-  Support for the NCR53C710 SCSI controller on the Amiga 4000T.
-
-A4091 SCSI support
-CONFIG_A4091_SCSI
-  Support for the NCR53C710 chip on the Amiga 4091 Z3 SCSI2 controller
-  (1993).  Very obscure -- the 4091 was part of an Amiga 4000 upgrade
-  plan at the time the Amiga business was sold to DKB.
-
-Atari support
-CONFIG_ATARI
-  This option enables support for the 68000-based Atari series of
-  computers (including the TT, Falcon and Medusa). If you plan to use
-  this kernel on an Atari, say Y here and browse the material
-  available in <file:Documentation/m68k>; otherwise say N.
-
-Hades support
-CONFIG_HADES
-  This option enables support for the Hades Atari clone. If you plan
-  to use this kernel on a Hades, say Y here; otherwise say N.
-
-Macintosh support
-CONFIG_MAC
-  This option enables support for the Apple Macintosh series of
-  computers (yes, there is experimental support now, at least for part
-  of the series).
-
-  Say N unless you're willing to code the remaining necessary support.
-  ;)
-
-HP9000/300 support
-CONFIG_HP300
-  This option enables support for the HP9000/300 series of
-  workstations. Support for these machines is still very experimental.
-  If you plan to try to use the kernel on such a machine say Y here.
-  Everybody else says N.
-
-Q40/Q60 support
-CONFIG_Q40
-  The Q40 is a Motorola 68040-based successor to the Sinclair QL
-  manufactured in Germany.  There is an official Q40 home page at
-  <http://www.q40.de/>.  This option enables support for the Q40 and
-  Q60. Select your CPU below.  For 68LC060 don't forget to enable FPU
-  emulation.
-
-Sun 3 support
-CONFIG_SUN3
-  This option enables support for the Sun 3 series of workstations.
-  Currently, only the Sun 3/80 is supported within the Sun 3x family.
-  You will also want to enable 68030 support.  General Linux
-  information on the Sun 3x series (now discontinued) is at
-  <http://www.angelfire.com/ca2/tech68k/sun3.html>.
-
-  If you don't want to compile a kernel for a Sun 3, say N.
-
-Sun 3X support
-CONFIG_SUN3X
-  This option enables support for the Sun 3x series of workstations.
-  Be warned that this support is very experimental. You will also want
-  to say Y to 68020 support and N to the other processors below.
-  General Linux information on the Sun 3x series (now discontinued)
-  is at <http://www.angelfire.com/ca2/tech68k/sun3.html>.
-
-  If you don't want to compile a kernel for a Sun 3x, say N.
-
-Sun3x builtin serial support
-CONFIG_SUN3X_ZS
-  ZS refers to a type of asynchronous serial port built in to the Sun3
-  and Sun3x workstations; if you have a Sun 3, you probably have
-  these.  Say 'Y' to support ZS ports directly.  This option must be
-  enabled in order to support the
-  keyboard and mouse ports.
-
-Sun keyboard support
-CONFIG_SUN_KEYBOARD
-  Say Y here to support the keyboard found on Sun 3 and 3x
-  workstations.  It can also be used support Sun Type-5 keyboards
-  through an adaptor.  See
-  <http://www.suse.cz/development/input/adapters.html> and
-  <http://sourceforge.net/projects/linuxconsole/> for details on the
-  latter.
-
-68020 support
-CONFIG_M68020
-  If you anticipate running this kernel on a computer with a MC68020
-  processor, say Y. Otherwise, say N. Note that the 68020 requires a
-  68851 MMU (Memory Management Unit) to run Linux/m68k, except on the
-  Sun 3, which provides its own version.
-
-68030 support
-CONFIG_M68030
-  If you anticipate running this kernel on a computer with a MC68030
-  processor, say Y. Otherwise, say N. Note that a MC68EC030 will not
-  work, as it does not include an MMU (Memory Management Unit).
-
-68040 support
-CONFIG_M68040
-  If you anticipate running this kernel on a computer with a MC68LC040
-  or MC68040 processor, say Y. Otherwise, say N. Note that an
-  MC68EC040 will not work, as it does not include an MMU (Memory
-  Management Unit).
-
-68060 support
-CONFIG_M68060
-  If you anticipate running this kernel on a computer with a MC68060
-  processor, say Y. Otherwise, say N.
-
-Math emulation support
-CONFIG_M68KFPU_EMU
-  At some point in the future, this will cause floating-point math
-  instructions to be emulated by the kernel on machines that lack a
-  floating-point math coprocessor.  Thrill-seekers and chronically
-  sleep-deprived psychotic hacker types can say Y now, everyone else
-  should probably wait a while.
-
-Math emulation only kernel
-CONFIG_M68KFPU_EMU_ONLY
-  This option prevents any floating-point instructions from being
-  compiled into the kernel, thereby the kernel doesn't save any
-  floating point context anymore during task switches, so this
-  kernel will only be usable on machines without a floating-point
-  math coprocessor. This makes the kernel a bit faster as no tests
-  needs to be executed whether a floating-point instruction in the
-  kernel should be executed or not.
-
-Math emulation extra precision
-CONFIG_M68KFPU_EMU_EXTRAPREC
-  The fpu uses normally a few bit more during calculations for
-  correct rounding, the emulator can (often) do the same but this
-  extra calculation can cost quite some time, so you can disable
-  it here. The emulator will then "only" calculate with a 64 bit
-  mantissa and round slightly incorrect, what is more then enough
-  for normal usage.
-
-Advanced configuration options
-CONFIG_ADVANCED
-  This gives you access to some advanced options for the CPU. The
-  defaults should be fine for most users, but these options may make
-  it possible for you to improve performance somewhat if you know what
-  you are doing.
-
-  Note that the answer to this question won't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about these options.
-
-  Most users should say N to this question.
-
-Use one physical chunk of memory only
-CONFIG_SINGLE_MEMORY_CHUNK
-  Ignore all but the first contiguous chunk of physical memory for VM
-  purposes.  This will save a few bytes kernel size and may speed up
-  some operations.  Say N if not sure.
-
-Use read-modify-write instructions
-CONFIG_RMW_INSNS
-  This allows to use certain instructions that work with indivisible
-  read-modify-write bus cycles. While this is faster than the
-  workaround of disabling interrupts, it can conflict with DMA
-  ( = direct memory access) on many Amiga systems, and it is also said
-  to destabilize other machines. It is very likely that this will
-  cause serious problems on any Amiga or Atari Medusa if set. The only
-  configuration where it should work are 68030-based Ataris, where it
-  apparently improves performance. But you've been warned! Unless you
-  really know what you are doing, say N. Try Y only if you're quite
-  adventurous.
-
-Amiga Zorro (AutoConfig) bus support
-CONFIG_ZORRO
-  This enables support for the Zorro bus in the Amiga. If you have
-  expansion cards in your Amiga that conform to the Amiga
-  AutoConfig(tm) specification, say Y, otherwise N. Note that even
-  expansion cards that do not fit in the Zorro slots but fit in e.g.
-  the CPU slot may fall in this category, so you have to say Y to let
-  Linux use these.
-
-Zorro device name database
-CONFIG_ZORRO_NAMES
-  By default, the kernel contains a database of all known Zorro device
-  names to make the information in /proc/iomem comprehensible to the
-  user. This database increases the size of the kernel image by about
-  15KB, but it gets freed after the system boots up, so it doesn't
-  take up kernel memory. Anyway, if you are building an installation
-  floppy or kernel for an embedded system where kernel image size
-  really matters, you can disable this feature and you'll get device
-  ID numbers instead of names.
-
-  When in doubt, say Y.
-
-Amiga 1200/600 PCMCIA support
-CONFIG_AMIGA_PCMCIA
-  Include support in the kernel for pcmcia on Amiga 1200 and Amiga
-  600. If you intend to use pcmcia cards say Y; otherwise say N.
-
-Hisoft Whippet PCMCIA serial support
-CONFIG_WHIPPET_SERIAL
-  HiSoft has a web page at <http://www.hisoft.co.uk/>, but there
-  is no listing for the Whippet in their Amiga section.
-
-Amiga Zorro II ramdisk support
-CONFIG_AMIGA_Z2RAM
-  This enables support for using Chip RAM and Zorro II RAM as a
-  ramdisk or as a swap partition. Say Y if you want to include this
-  driver in the kernel. 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 is called z2ram.o. If you want
-  to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-Support for ST-RAM as swap space
-CONFIG_STRAM_SWAP
-  Some Atari 68k macines (including the 520STF and 1020STE) divide
-  their addressible memory into ST and TT sections.  The TT section
-  (up to 512MB) is the main memory; the ST section (up to 4MB) is
-  accessible to the built-in graphics board, runs slower, and is
-  present mainly for backward compatibility with older machines.
-
-  This enables support for using (parts of) ST-RAM as swap space,
-  instead of as normal system memory. This can first enhance system
-  performance if you have lots of alternate RAM (compared to the size
-  of ST-RAM), because executable code always will reside in faster
-  memory. ST-RAM will remain as ultra-fast swap space. On the other
-  hand, it allows much improved dynamic allocations of ST-RAM buffers
-  for device driver modules (e.g. floppy, ACSI, SLM printer, DMA
-  sound). The probability that such allocations at module load time
-  fail is drastically reduced.
-
-ST-RAM statistics in /proc
-CONFIG_STRAM_PROC
-  Say Y here to report ST-RAM usage statistics in /proc/stram.  See
-  the help for CONFIG_STRAM_SWAP for discussion of ST-RAM and its
-  uses.
-
-Atari ACSI support
-CONFIG_ATARI_ACSI
-  This enables support for the Atari ACSI interface. The driver
-  supports hard disks and CD-ROMs, which have 512-byte sectors, or can
-  be switched to that mode. Due to the ACSI command format, only disks
-  up to 1 GB are supported. Special support for certain ACSI to SCSI
-  adapters, which could relax that, isn't included yet. The ACSI
-  driver is also the basis for certain other drivers for devices
-  attached to the ACSI bus: Atari SLM laser printer, BioNet-100
-  Ethernet, and PAMsNet Ethernet. If you want to use one of these
-  devices, you need ACSI support, too.
-
-  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 acsi.o.
-
-Probe all LUNs on each ACSI device
-CONFIG_ACSI_MULTI_LUN
-  If you have a ACSI device that supports more than one LUN (Logical
-  Unit Number), e.g. a CD jukebox, you should say Y here so that all
-  will be found by the ACSI driver. An ACSI device with multiple LUNs
-  acts logically like multiple ACSI devices. The vast majority of ACSI
-  devices have only one LUN, and so most people can say N here and
-  should in fact do so, because it is safer.
-
-Atari SLM laser printer support
-CONFIG_ATARI_SLM
-  If you have an Atari SLM laser printer, say Y to include support for
-  it in the kernel. Otherwise, say N. 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
-  acsi_slm.o. Be warned: the driver needs much ST-RAM and can cause
-  problems due to that fact!
-
-A3000 WD33C93A support
-CONFIG_A3000_SCSI
-  If you have an Amiga 3000 and have SCSI devices connected to the
-  built-in SCSI controller, say Y. Otherwise, say N. 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 is
-  called wd33c93.o. If you want to compile it as a module, say M here
-  and read <file:Documentation/modules.txt>.
-
-A2091 WD33C93A support
-CONFIG_A2091_SCSI
-  If you have a Commodore A2091 SCSI controller, say Y. Otherwise,
-  say N. 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 is called wd33c93.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-GVP Series II WD33C93A support
-CONFIG_GVP11_SCSI
-  If you have a Great Valley Products Series II SCSI controller,
-  answer Y. Also say Y if you have a later model of GVP SCSI
-  controller (such as the GVP A4008 or a Combo board). Otherwise,
-  answer N. This driver does NOT work for the T-Rex series of
-  accelerators from TekMagic and GVP-M.
-
-  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 gvp11.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-CyberStorm SCSI support
-CONFIG_CYBERSTORM_SCSI
-  If you have an Amiga with an original (MkI) Phase5 Cyberstorm
-  accelerator board and the optional Cyberstorm SCSI controller,
-  answer Y. Otherwise, say N.
-
-CyberStorm II SCSI support
-CONFIG_CYBERSTORMII_SCSI
-  If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board
-  and the optional Cyberstorm SCSI controller, say Y. Otherwise,
-  answer N.
-
-Blizzard 2060 SCSI support
-CONFIG_BLZ2060_SCSI
-  If you have an Amiga with a Phase5 Blizzard 2060 accelerator board
-  and want to use the onboard SCSI controller, say Y. Otherwise,
-  answer N.
-
-Blizzard 1230IV/1260 SCSI support
-CONFIG_BLZ1230_SCSI
-  If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard
-  1260 accelerator, and the optional SCSI module, say Y. Otherwise,
-  say N.
-
-Blizzard PowerUP 603e+ SCSI support
-CONFIG_BLZ603EPLUS_SCSI
-  If you have an Amiga 1200 with a Phase5 Blizzard PowerUP 603e+
-  accelerator, say Y. Otherwise, say N.
-
-Fastlane SCSI support
-CONFIG_FASTLANE_SCSI
-  If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use
-  one in the near future, say Y to this question. Otherwise, say N.
-
-BSC Oktagon SCSI support
-CONFIG_OKTAGON_SCSI
-  If you have the BSC Oktagon SCSI disk controller for the Amiga, say
-  Y to this question.  If you're in doubt about whether you have one,
-  see the picture at
-  <http://amiga.multigraph.com/photos/oktagon.html>.
-
-Atari native SCSI support
-CONFIG_ATARI_SCSI
-  If you have an Atari with built-in NCR5380 SCSI controller (TT,
-  Falcon, ...) say Y to get it supported. Of course also, if you have
-  a compatible SCSI controller (e.g. for Medusa).  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 is called
-  atari_scsi.o.  If you want to compile it as a module, say M here and
-  read <file:Documentation/modules.txt>.  This driver supports both
-  styles of NCR integration into the system: the TT style (separate
-  DMA), and the Falcon style (via ST-DMA, replacing ACSI).  It does
-  NOT support other schemes, like in the Hades (without DMA).
-
-Long delays for Toshiba CD-ROMs
-CONFIG_ATARI_SCSI_TOSHIBA_DELAY
-  This option increases the delay after a SCSI arbitration to
-  accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to
-  use a Toshiba CD-ROM drive; otherwise, the option is not needed and
-  would impact performance a bit, so say N.
-
-Reset SCSI-devices at boottime
-CONFIG_ATARI_SCSI_RESET_BOOT
-  Reset the devices on your Atari whenever it boots.  This makes the
-  boot process fractionally longer but may assist recovery from errors
-  that leave the devices with SCSI operations partway completed.
-
-Hades SCSI DMA emulator
-CONFIG_TT_DMA_EMUL
-  This option enables code which emulates the TT SCSI DMA chip on the
-  Hades. This increases the SCSI transfer rates at least ten times
-  compared to PIO transfers.
-
-Ariadne support
-CONFIG_ARIADNE
-  If you have a Village Tronic Ariadne Ethernet adapter, say Y.
-  Otherwise, say N.
-
-  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 is called ariadne.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-Ariadne II and X-Surf support
-CONFIG_ARIADNE2
-  This driver is for the Village Tronic Ariadne II and the Individual
-  Computers X-Surf Ethernet cards. If you have such a card, say Y.
-  Otherwise, say N.
-
-  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 ariadne2.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-A2065 support
-CONFIG_A2065
-  If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise,
-  say N.
-
-  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 is called a2065.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Hydra support
-CONFIG_HYDRA
-  If you have a Hydra Ethernet adapter, say Y. Otherwise, say N.
-
-  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 is called hydra.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Sun3 NCR5380 SCSI
-CONFIG_SUN3_SCSI
-  This option will enable support for the OBIO (onboard io) NCR5380
-  SCSI controller found in the Sun 3/50 and 3/60.  Note that this
-  driver does not provide support for VME SCSI boards.
-  General Linux information on the Sun 3 series (now discontinued)
-  is at <http://www.angelfire.com/ca2/tech68k/sun3.html>.
-
-Sun3x ESP SCSI driver
-CONFIG_SUN3X_ESP
-  The ESP was an on-board SCSI controller used on Sun 3/80
-  machines.  Say Y here to compile in support for it.
-
-PCMCIA NE2000 and compatibles support
-CONFIG_APNE
-  If you have a PCMCIA NE2000 compatible adapter, say Y.  Otherwise,
-  say N.
-
-  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 is called apne.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Atari Lance support
-CONFIG_ATARILANCE
-  Say Y to include support for several Atari Ethernet adapters based
-  on the AMD Lance chipset: RieblCard (with or without battery), or
-  PAMCard VME (also the version by Rhotron, with different addresses).
-
-BioNet-100 support
-CONFIG_ATARI_BIONET
-  Say Y to include support for BioData's BioNet-100 Ethernet adapter
-  for the ACSI port. The driver works (has to work...) with a polled
-  I/O scheme, so it's rather slow :-(
-
-PAMsNet support
-CONFIG_ATARI_PAMSNET
-  Say Y to include support for the PAMsNet Ethernet adapter for the
-  ACSI port ("ACSI node"). The driver works (has to work...) with a
-  polled I/O scheme, so it's rather slow :-(
-
-Amiga mouse support
-CONFIG_AMIGAMOUSE
-  If you want to be able to use an Amiga mouse in Linux, say Y.
-
-  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 is called amigamouse.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Atari mouse support
-CONFIG_ATARIMOUSE
-  If you want to be able to use an Atari mouse in Linux, say Y.
-
-  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 is called atarimouse.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-Atari MFP serial support
-CONFIG_ATARI_MFPSER
-  If you like to use the MFP serial ports ("Modem1", "Serial1") under
-  Linux, say Y. The driver equally supports all kinds of MFP serial
-  ports and automatically detects whether Serial1 is available.
-
-  This driver is also available 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>.
-
-  Note for Falcon users: You also have an MFP port, it's just not
-  wired to the outside... But you could use the port under Linux.
-
-Atari SCC serial support
-CONFIG_ATARI_SCC
-  If you have serial ports based on a Zilog SCC chip (Modem2, Serial2,
-  LAN) and like to use them under Linux, say Y. All built-in SCC's are
-  supported (TT, MegaSTE, Falcon), and also the ST-ESCC. If you have
-  two connectors for channel A (Serial2 and LAN), they are visible as
-  two separate devices.
-
-  This driver is also available 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>.
-
-Atari SCC serial DMA support
-CONFIG_ATARI_SCC_DMA
-  This enables DMA support for receiving data on channel A of the SCC.
-  If you have a TT you may say Y here and read
-  drivers/char/atari_SCC.README. All other users should say N here,
-  because only the TT has SCC-DMA, even if your machine keeps claiming
-  so at boot time.
-
-Atari MIDI serial support
-CONFIG_ATARI_MIDI
-  If you want to use your Atari's MIDI port in Linux, say Y.
-
-  This driver is also available 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>.
-
-Atari DSP56k Digital Signal Processor support
-CONFIG_ATARI_DSP56K
-  If you want to be able to use the DSP56001 in Falcons, say Y. This
-  driver is still experimental, and if you don't know what it is, or
-  if you don't have this processor, just say N.
-
-  This driver is also available 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>.
-
-Support for early boot text console
-CONFIG_BOOTX_TEXT
-  Say Y here to see progress messages from the boot firmware in text
-  mode. Requires either BootX or Open Firmware.
-
-Amiga builtin serial support
-CONFIG_AMIGA_BUILTIN_SERIAL
-  If you want to use your Amiga's built-in serial port in Linux,
-  answer Y.
-
-  This driver is also available 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>.
-
-GVP IO-Extender support
-CONFIG_GVPIOEXT
-  If you want to use a GVP IO-Extender serial card in Linux, say Y.
-  Otherwise, say N.
-
-GVP IO-Extender parallel printer support
-CONFIG_GVPIOEXT_LP
-  Say Y to enable driving a printer from the parallel port on your
-  GVP IO-Extender card, N otherwise.
-
-GVP IO-Extender PLIP support
-CONFIG_GVPIOEXT_PLIP
-  Say Y to enable doing IP over the parallel port on your GVP
-  IO-Extender card, N otherwise.
-
-Multiface Card III serial support
-CONFIG_MULTIFACE_III_TTY
-  If you want to use a Multiface III card's serial port in Linux,
-  answer Y.
-
-  This driver is also available 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>.
-
-Amiga/Atari/PowerMac DMA sound support
-CONFIG_DMASOUND
-  Support built-in audio chips accessible by DMA on various machines
-  that have them.  Note that this symbol does not affect the kernel
-  directly; rather, it controls whether configuration questions
-  enabling DMA sound drivers for various specific machine
-  architectures will be used.
-
-Atari DMA sound support
-CONFIG_DMASOUND_ATARI
-  If you want to use the internal audio of your Atari in Linux, answer
-  Y to this question. This will provide a Sun-like /dev/audio,
-  compatible with the Linux/i386 sound system. Otherwise, say N.
-
-  This driver is also available 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>.
-
-PowerMac DMA sound support
-CONFIG_DMASOUND_AWACS
-  If you want to use the internal audio of your PowerMac in Linux,
-  answer Y to this question. This will provide a Sun-like /dev/audio,
-  compatible with the Linux/i386 sound system. Otherwise, say N.
-
-  This driver is also available 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>.
-
-Amiga DMA sound support
-CONFIG_DMASOUND_PAULA
-  If you want to use the internal audio of your Amiga in Linux, answer
-  Y to this question. This will provide a Sun-like /dev/audio,
-  compatible with the Linux/i386 sound system. Otherwise, say N.
-
-  This driver is also available 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>.
-
-Q40 sound support
-CONFIG_DMASOUND_Q40
-  If you want to use the internal audio of your Q40 in Linux, answer
-  Y to this question. This will provide a Sun-like /dev/audio,
-  compatible with the Linux/i386 sound system. Otherwise, say N.
-
-  This driver is also available 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>.
-
-HP DCA serial support
-CONFIG_HPDCA
-  If you want to use the internal "DCA" serial ports on an HP300
-  machine, say Y here.
-
-HP on-board LANCE support
-CONFIG_HPLANCE
-  If you want to use the builtin "LANCE" Ethernet controller on an
-  HP300 machine, say Y here.
-
-DIO bus support
-CONFIG_DIO
-  Say Y here to enable support for the "DIO" expansion bus used in
-  HP300 machines. If you are using such a system you almost certainly
-  want this.
-
-# Choice: ppctype
-Processor Type
-CONFIG_6xx
-  There are four types of PowerPC chips supported.  The more common
-  types (601, 603, 604, 740, 750, 7400), the Motorola embedded
-  versions (821, 823, 850, 855, 860, 8260), the IBM embedded versions
-  (403 and 405) and the high end 64 bit Power processors (Power 3,
-  Power 4).  Unless you are building a kernel for one of the embedded
-  processor systems, or a 64 bit IBM RS/6000, choose 6xx.  Note that
-  the kernel runs in 32-bit mode even on 64-bit chips.  Also note that
-  because the 82xx family has a 603e core, specific support for that
-  chipset is asked later on.
-
-Motorola MPC8260 CPM support
-CONFIG_8260
-  The MPC8260 CPM (Communications Processor Module) is a typical
-  embedded CPU made by Motorola.  Selecting this option means that
-  you wish to build a kernel for a machine with specifically an 8260
-  for a CPU.
-
-  If in doubt, say N.
-
-# Choice: Machine type
-Oak
-CONFIG_OAK
-  Select Oak if you have an IBM 403GCX "Oak" Evaluation Board.
-
-  Select Walnut if you have an IBM 405GP "Walnut" Evaluation Board.
-
-  More information on these boards is available at:
-  <http://www.chips.ibm.com/products/powerpc/tools/evk_pn.html#GCX>.
-
-Walnut
-CONFIG_WALNUT
-  Select Walnut if you have an IBM 405GP "Walnut" Evaluation Board.
-
-Workarounds for PPC601 bugs
-CONFIG_PPC601_SYNC_FIX
-  Some versions of the PPC601 (the first PowerPC chip) have bugs which
-  mean that extra synchronization instructions are required near
-  certain instructions, typically those that make major changes to the
-  CPU state.  These extra instructions reduce performance slightly.
-  If you say N here, these extra instructions will not be included,
-  resulting in a kernel which will run faster but may not run at all
-  on some systems with the PPC601 chip.
-
-  If in doubt, say Y here.
-
-8xx Cache (Copy-Back or Writethrough)
-CONFIG_8xx_COPYBACK
-  Saying Y here will cause the cache on an MPC8xx processor to be used
-  in Copy-Back mode.  If you say N here, it is used in Writethrough
-  mode.
-
-  If in doubt, say Y here.
-
-MPC860 (Pre Rev. C) CPU6 Silicon Errata
-CONFIG_8xx_CPU6
-  MPC860 CPUs, prior to Rev C have some bugs in the silicon, which
-  require workarounds for Linux (and most other OSes to work).  If you
-  get a BUG() very early in boot, this might fix the problem.  For
-  more details read the document entitled "MPC860 Family Device Errata
-  Reference" on Motorola's website.  This option also incurs a
-  performance hit.
-
-  If in doubt, say N here.
-
-MPC8xx IDE support
-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.
-
-Type of MPC8xx IDE interface
-CONFIG_IDE_8xx_PCCARD
-  Select how the IDE devices are connected to the MPC8xx system:
-
-  8xx_PCCARD uses the 8xx internal PCMCIA interface in combination
-             with a PC Card (e.g. ARGOSY portable Hard Disk Adapter),
-             ATA PC Card HDDs or ATA PC Flash Cards (example: TQM8xxL
-             systems)
-
-  8xx_DIRECT is used for directly connected IDE devices using the 8xx
-             internal PCMCIA interface (example: IVMS8 systems)
-
-  EXT_DIRECT is used for IDE devices directly connected to the 8xx
-             bus using some glue logic, but _not_ the 8xx internal
-             PCMCIA interface (example: IDIF860 systems)
-
-Use SMC2 for UART
-CONFIG_SMC2_UART
-  If you would like to use SMC2 as a serial port, say Y here.
-
-  If in doubt, say Y here.
-
-Use SMC2 for Console
-CONFIG_CONS_SMC2
-  If you are going to have a serial console on your device and are
-  using SMC2 for your serial port, say Y here, else say N.
-
-Use the alternate SMC2 I/O
-CONFIG_ALTSMC2
-  If you have an MPC823 or MPC850 and would like to use the alternate
-  SMC2 for I/O, say Y here.
-
-  If in doubt, say N here.
-
-Enable SCC2 and SCC3 for UART
-CONFIG_USE_SCC_IO
-  If your MPC8xx board has other SCC ports that you would like to use
-  for for a serial port, say Y here.
-
-  If in doubt, say N here.
-
-# Choice: ppc6xxtype
-Machine Type
-CONFIG_ALL_PPC
-  Linux currently supports several different kinds of PowerPC-based
-  machines: Apple Power Macintoshes and clones (such as the Motorola
-  Starmax series), PReP (PowerPC Reference Platform) machines (such
-  as the Motorola PowerStacks, Motorola cPCI/VME embedded systems,
-  and some IBM RS/6000 systems), CHRP (Common Hardware Reference
-  Platform), and several embedded PowerPC systems containing 4xx, 6xx,
-  7xx, 8xx, 74xx, and 82xx processors.  Currently, the default option
-  is to build a kernel which works on the first three.
-
-  Select PowerMac/PReP/MTX/CHRP if configuring for any of the above.
-
-  Select Gemini if configuring for a Synergy Microsystems' Gemini
-  series Single Board Computer.  More information is available at:
-  <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/>.
-
-Synergy-Gemini
-CONFIG_GEMINI
-  Select Gemini if configuring for a Synergy Microsystems' Gemini
-  series Single Board Computer.  More information is available at:
-  <http://www.synergymicro.com/PressRel/97_10_15.html>.
-
-Amiga-Apus
-CONFIG_APUS
-  Select APUS if configuring for a PowerUP Amiga.
-  More information is available at:
-  <http://linux-apus.sourceforge.net/>.
-
-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
-  altivec registers, and turning on the 'altivec enable' bit so user
-  processes can execute altivec instructions.
-
-  This option is only usefully if you have a processor that supports
-  altivec (G4, otherwise known as 74xx series), but does not have
-  any affect on a non-altivec cpu (it does, however add code to the
-  kernel).
-
-  If in doubt, say Y here.
-
-Thermal Management Support
-CONFIG_TAU
-  G3 and G4 processors have an on-chip temperature sensor called the
-  'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die
-  temperature within 2-4 degrees Celsius. This option shows the current
-  on-die temperature in /proc/cpuinfo if the cpu supports it.
-
-  Unfortunately, on some chip revisions, this sensor is very inaccurate
-  and in some cases, does not work at all, so don't assume the cpu
-  temp is actually what /proc/cpuinfo says it is.
-
-Interrupt driven TAU driver
-CONFIG_TAU_INT
-  The TAU supports an interrupt driven mode which causes an interrupt
-  whenever the temperature goes out of range. This is the fastest way
-  to get notified the temp has exceeded a range. With this option off,
-  a timer is used to re-check the temperature periodically.
-
-  However, on some cpus it appears that the TAU interrupt hardware
-  is buggy and can cause a situation which would lead unexplained hard
-  lockups.
-
-  Unless you are extending the TAU driver, or enjoy kernel/hardware
-  debugging, leave this option off.
-
-Average high and low temp
-CONFIG_TAU_AVERAGE
-  The TAU hardware can compare the temperature to an upper and lower bound.
-  The default behavior is to show both the upper and lower bound in
-  /proc/cpuinfo. If the range is large, the temperature is either changing
-  a lot, or the TAU hardware is broken (likely on some G4's). If the range
-  is small (around 4 degrees), the temperature is relatively stable.
-
-Power management support for PowerBooks
-CONFIG_PMAC_PBOOK
-  This provides support for putting a PowerBook to sleep; it also
-  enables media bay support.  Power management works on the
-  PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3. You
-  must get the power management daemon, pmud, to make it work and you
-  must have the /dev/pmu device (see the pmud README).
-
-  Get pmud from <ftp://ftp.samba.org/pub/ppclinux/pmud/>.
-
-  If you have a PowerBook, you should say Y.
-
-  You may also want to compile the dma sound driver as a module and
-  have it autoloaded. The act of removing the module shuts down the
-  sound hardware for more power savings.
-
-Backlight control for LCD screens
-CONFIG_PMAC_BACKLIGHT
-  Say Y here to build in code to manage the LCD backlight on a
-  Macintosh PowerBook.  With this code, the backlight will be turned
-  on and off appropriately on power-management and lid-open/lid-closed
-  events; also, the PowerBook button device will be enabled so you can
-  change the screen brightness.
-
-# Choice: ppc8xxtype
-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:
-    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
-  The RPX-Classic is a single-board computer based on the Motorola
-  MPC860.  It features 16MB of DRAM and a variable amount of flash,
-  I2C EEPROM, thermal monitoring, a PCMCIA slot, a DIP switch and two
-  LEDs.  Variants with Ethernet ports exist.  Say Y here to support it
-  directly.
-
-BSE-IP
-CONFIG_BSEIP
-  Say Y here to support the Bright Star Engineering ipEngine SBC.
-  This is a credit-card-sized device featuring a MPC823 processor,
-  26MB DRAM, 4MB flash, Ethernet, a 16K-gate FPGA, USB, an LCD/video
-  controller, and two RS232 ports.
-
-TQM823L
-CONFIG_TQM823L
-  Say Y here to support the TQM823L, one of an MPC8xx-based family of
-  mini SBCs (half credit-card size) from TQ Components first released
-  in late 1999.  Technical references are at
-  <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
-  <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
-  <http://www.denx.de/embedded-ppc-en.html>.
-
-TQM850L
-CONFIG_TQM850L
-  Say Y here to support the TQM850L, one of an MPC8xx-based family of
-  mini SBCs (half credit-card size) from TQ Components first released
-  in late 1999.  Technical references are at
-  <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
-  <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
-  <http://www.denx.de/embedded-ppc-en.html>.
-
-TQM855L
-CONFIG_TQM855L
-  Say Y here to support the TQM855L, one of an MPC8xx-based family of
-  mini SBCs (half credit-card size) from TQ Components first released
-  in late 1999.  Technical references are at
-  <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
-  <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
-  <http://www.denx.de/embedded-ppc-en.html>.
-
-TQM860L
-CONFIG_TQM860L
-  Say Y here to support the TQM860L, one of an MPC8xx-based family of
-  mini SBCs (half credit-card size) from TQ Components first released
-  in late 1999.  Technical references are at
-  <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
-  <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
-  <http://www.denx.de/embedded-ppc-en.html>.
-
-FPS850
-CONFIG_FPS850
-  Say Y here to support the FingerPrint Sensor from AKENDI IG, based
-  on the TQ Components TQM850L module, released November 1999 and
-  discontinued a year later.
-
-TQM860
-CONFIG_TQM860
-  Say Y here to support the TQM860, one of an MPC8xx-based family of
-  SBCs (credit-card size) from TQ Components first released in 
-  mid-1999 and discontinued mid-2000.
-
-SM850
-CONFIG_SM850
-  Say Y here to support the Service Module 850 from Dependable
-  Computer Systems, an SBC based on the TQM850L module by TQ
-  Components.  This board is no longer in production.  The
-  manufacturer's website is at <http://www.decomsys.com/>.
-
-SPD823TS
-CONFIG_SPD823TS
-  Say Y here to support the Speech Design 823 Tele-Server from Speech
-  Design, released in 2000.  The manufacturer's website is at
-  <http://www.speech-design.de/>.
-
-IVMS8
-CONFIG_IVMS8
-  Say Y here to support the Integrated Voice-Mail Small 8-channel SBC
-  from Speech Design, released March 2001.  The manufacturer's website
-  is at <http://www.speech-design.de/>.
-
-# IVML24 is not yet active
-IVML24
-CONFIG_IVML24
-  Say Y here to support the Integrated Voice-Mail Large 24-channel SBC
-  from Speech Design, released March 2001.  The manufacturer's website
-  is at <http://www.speech-design.de/>.
-
-MBX
-CONFIG_MBX
-  MBX is a line of Motorola single-board computer based around the
-  MPC821 and MPC860 processors, and intended for embedded-controller
-  applications.  Say Y here to support these boards directly.
-
-WinCept
-CONFIG_WINCEPT
-  The Wincept 100/110 is a Motorola single-board computer based on the
-  MPC821 PowerPC, introduced in 1998 and designed to be used in
-  thin-client machines.  Say Y to support it directly.
-
-# More systems that will be supported soon, according to
-# Wolfgang Denk <wd@denx.de>:
-#
-# TQM8260:
-#         MPC8260 based module
-#
-#         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_Rev003.pdf>
-#
-# 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>
-#
-# 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>
-#
-# 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>
-#
-# PCU_E:
-#         PCU = Peripheral Controller Unit; E = extended (?)
-#
-#         Mfr: 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: -
-#         URL: n. a.o
-
-# Choice: ppc82xxtype
-Embedded 82xx Board Type
-CONFIG_EST8260
-  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
-  This provides support for sending raw ADB keycodes to console
-  devices.  This is the default up to 2.4.0, but in future this may be
-  phased out in favor of generic Linux keycodes.  If you say Y here,
-  you can dynamically switch via the
-      /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes
-  sysctl and with the "keyboard_sends_linux_keycodes=" kernel
-  argument.
-
-  If unsure, say Y here.
-
-I2C/SPI Microcode Patch
-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
-  button with keypresses.  If you say Y here, the emulation is still
-  disabled by default.  The emulation is controlled by these sysctl
-  entries:
-      /proc/sys/dev/mac_hid/mouse_button_emulation
-      /proc/sys/dev/mac_hid/mouse_button2_keycode
-      /proc/sys/dev/mac_hid/mouse_button3_keycode
-
-Enhanced Real Time Clock Support (/dev/rtc)
-CONFIG_PPC_RTC
-  If you say Y here and create a character special file /dev/rtc with
-  major number 10 and minor number 135 using mknod ("man mknod"), you
-  will get access to the real time clock (or hardware clock) built
-  into your computer.
-
-  If unsure, say Y here.
-
-Support for Open Firmware device tree in /proc
-CONFIG_PROC_DEVICETREE
-  This option adds a device-tree directory under /proc which contains
-  an image of the device tree that the kernel copies from Open
-  Firmware. If unsure, say Y here.
-
-RTAS (RunTime Abstraction Services) in /proc
-CONFIG_PPC_RTAS
-  When you use this option, you will be able to use RTAS from
-  userspace.
-
-  RTAS stands for RunTime Abstraction Services and should
-  provide a portable way to access and set system information. This is
-  commonly used on RS/6000 (pSeries) computers.
-
-  You can access RTAS via the special proc file system entry rtas.
-  Don't confuse this rtas entry with the one in /proc/device-tree/rtas
-  which is readonly.
-
-  If you don't know if you can use RTAS look into
-  /proc/device-tree/rtas. If there are some entries, it is very likely
-  that you will be able to use RTAS.
-
-  You can do cool things with rtas. To print out information about
-  various sensors in the system, just do a
-
-    $ cat /proc/rtas/sensors
-
-  or if you power off your machine at night but want it running when
-  you enter your office at 7:45 am, do a
-
-    # date -d 'tomorrow 7:30' +%s > /proc/rtas/poweron
-
-  and shutdown.
-
-  If unsure, say Y.
-
-MESH (Power Mac internal SCSI) support
-CONFIG_SCSI_MESH
-  Many Power Macintoshes and clones have a MESH (Macintosh Enhanced
-  SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the
-  other Power Macintoshes do). Say Y to include support for this SCSI
-  adaptor. This driver is also available as a module called mesh.o
-  ( = 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>.
-
-Maximum synchronous transfer rate (MB/s) (0 = async)
-CONFIG_SCSI_MESH_SYNC_RATE
-  On Power Macintoshes (and clones) where the MESH SCSI bus adaptor
-  drives a bus which is entirely internal to the machine (such as the
-  7500, 7600, 8500, etc.), the MESH is capable of synchronous
-  operation at up to 10 MB/s. On machines where the SCSI bus
-  controlled by the MESH can have external devices connected, it is
-  usually rated at 5 MB/s. 5 is a safe value here unless you know the
-  MESH SCSI bus is internal only; in that case you can say 10. Say 0
-  to disable synchronous operation.
-
-53C94 (Power Mac external SCSI) support
-CONFIG_SCSI_MAC53C94
-  On Power Macintoshes (and clones) with two SCSI buses, the external
-  SCSI bus is usually controlled by a 53C94 SCSI bus adaptor. Older
-  machines which only have one SCSI bus, such as the 7200, also use
-  the 53C94. Say Y to include support for the 53C94.
-
-  This driver is also available as a module called mac53c94.o ( = 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>.
-
-MACE (Power Mac Ethernet) support
-CONFIG_MACE
-  Power Macintoshes and clones with Ethernet built-in on the
-  motherboard will usually use a MACE (Medium Access Control for
-  Ethernet) interface. Say Y to include support for the MACE chip.
-
-  This driver is also available as a module called mace.o ( = 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>.
-
-Use AAUI port instead of TP by default
-CONFIG_MACE_AAUI_PORT
-  Some Apple machines (notably the Apple Network Server) which use the
-  MACE ethernet chip have an Apple AUI port (small 15-pin connector),
-  instead of an 8-pin RJ45 connector for twisted-pair ethernet.  Say
-  Y here if you have such a machine.  If unsure, say N.
-  The driver will default to AAUI on ANS anyway, and if you use it as
-  a module, you can provide the port_aaui=0|1 to force the driver.
-
-BMAC (G3 Ethernet) support
-CONFIG_BMAC
-  Say Y for support of BMAC Ethernet interfaces. These are used on G3
-  computers.
-
-  This driver is also available as a module called bmac.o ( = 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>.
-
-GMAC (G4/iBook Ethernet) support
-CONFIG_GMAC
-  Say Y for support of GMAC Ethernet interfaces. These are used on G4
-  and iBook computers.
-
-  This driver is also available as a module called gmac.o ( = 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>.
-
-National DP83902AV (Oak Ethernet) support
-CONFIG_OAKNET
-  Say Y if your machine has this type of Ethernet network card.
-
-  This driver is also available as a module called oaknet.o ( = 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>.
-
-Video For Linux
-CONFIG_VIDEO_DEV
-  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/>.
-
-  If you are interested in writing a driver for such an audio/video
-  device or user software interacting with such a driver, please read
-  the file <file:Documentation/video4linux/API.html>.
-
-  This driver is also available as a module called videodev.o ( = 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>.
-
-Video For Linux /proc file system information
-CONFIG_VIDEO_PROC_FS
-  If you say Y here, you are able to access video device information
-  in /proc/video.
-
-  To use this option, you have to check, that the "/proc file system
-  support" (CONFIG_PROC_FS) is enabled too.
-
-AIMSlab RadioTrack (aka RadioReveal) support
-CONFIG_RADIO_RTRACK
-  Choose Y here if you have one of these FM radio cards, and then fill
-  in the port address below.
-
-  Note that newer AIMSlab RadioTrack cards have a different chipset
-  and are not supported by this driver.  For these cards, use the
-  RadioTrack II driver below.
-
-  If you have a GemTeks combined (PnP) sound- and radio card you must
-  use this driver as a module and setup the card with isapnptools.
-  You must also pass the module a suitable io parameter, 0x248 has
-  been reported to be used by these cards.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video For Linux API.  Information on
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.  More
-  information is contained in the file
-  <file:Documentation/video4linux/radiotrack.txt>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called radio-aimslab.o.
-
-RadioTrack I/O port
-CONFIG_RADIO_RTRACK_PORT
-  Enter either 0x30f or 0x20f here.  The card default is 0x30f, if you
-  haven't changed the jumper setting on the card.
-
-AIMSlab RadioTrack II support
-CONFIG_RADIO_RTRACK2
-  Choose Y here if you have this FM radio card, and then fill in the
-  port address below.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video For Linux API.  Information on
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called radio-rtrack2.o.
-
-RadioTrack II I/O port
-CONFIG_RADIO_RTRACK2_PORT
-  Enter either 0x30c or 0x20c here.  The card default is 0x30c, if you
-  haven't changed the jumper setting on the card.
-
-Aztech/Packard Bell Radio
-CONFIG_RADIO_AZTECH
-  Choose Y here if you have one of these FM radio cards, and then fill
-  in the port address below.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video For Linux API.  Information on
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called radio-aztech.o.
-
-Aztech/Packard Bell radio card I/O port
-CONFIG_RADIO_AZTECH_PORT
-  Enter either 0x350 or 0x358 here.  The card default is 0x350, if you
-  haven't changed the setting of jumper JP3 on the card.  Removing the
-  jumper sets the card to 0x358.
-
-ADS Cadet AM/FM Radio Tuner Card
-CONFIG_RADIO_CADET
-  Choose Y here if you have one of these AM/FM radio cards, and then
-  fill in the port address below.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video For Linux API.  Information on
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  Further documentation on this driver can be found on the WWW at
-  <http://linux.blackhawke.net/cadet.html>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called radio-cadet.o.
-
-SF16FMI Radio
-CONFIG_RADIO_SF16FMI
-  Choose Y here if you have one of these FM radio cards.  If you
-  compile the driver into the kernel and your card is not PnP one, you
-  have to add "sf16fm=<io>" to the kernel command line (I/O address is
-  0x284 or 0x384).
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video For Linux API.  Information on
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called radio-sf16fmi.o.
-
-Typhoon Radio (a.k.a. EcoRadio)
-CONFIG_RADIO_TYPHOON
-  Choose Y here if you have one of these FM radio cards, and then fill
-  in the port address and the frequency used for muting below.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video For Linux API.  Information on
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called radio-typhoon.o.
-
-Support for /proc/radio-typhoon
-CONFIG_RADIO_TYPHOON_PROC_FS
-  Say Y here if you want the typhoon radio card driver to write
-  status information (frequency, volume, muted, mute frequency,
-  base address) to /proc/radio-typhoon. The file can be viewed with
-  your favorite pager (i.e. use "more /proc/radio-typhoon" or "less
-  /proc/radio-typhoon" or simply "cat /proc/radio-typhoon").
-
-Typhoon I/O port (0x316 or 0x336)
-CONFIG_RADIO_TYPHOON_PORT
-  Enter the I/O port of your Typhoon or EcoRadio radio card.
-
-Typhoon frequency set when muting the device (kHz)
-CONFIG_RADIO_TYPHOON_MUTEFREQ
-  Enter the frequency used for muting the radio. The device is never
-  completely silent. If the volume is just turned down, you can still
-  hear silent voices and music. For that reason, the frequency of the
-  radio device is set to the frequency you can enter here whenever
-  the device is muted. There should be no local radio station at that
-  frequency.
-
-Zoltrix Radio
-CONFIG_RADIO_ZOLTRIX
-  Choose Y here if you have one of these FM radio cards, and then fill
-  in the port address below.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video For Linux API.  Information on
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called radio-zoltrix.o.
-
-ZOLTRIX I/O port (0x20c or 0x30c)
-CONFIG_RADIO_ZOLTRIX_PORT
-  Enter the I/O port of your Zoltrix radio card.
-
-I2C on parallel port
-CONFIG_I2C_PARPORT
-  I2C is a simple serial bus system used in many micro controller
-  applications.  Saying Y here will allow you to use your parallel
-  port as an I2C interface.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called i2c-parport.o.
-
-miroSOUND PCM20 radio
-CONFIG_RADIO_MIROPCM20
-  Choose Y here if you have this FM radio card. You also need to say Y
-  to "ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio)" (in "Sound")
-  for this to work.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video For Linux API.  Information on
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called miropcm20.o.
-
-miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL)
-CONFIG_RADIO_MIROPCM20_RDS
-  Choose Y here if you want to see RDS/RBDS information like
-  RadioText, Programme Service name, Clock Time and date, Programme
-  TYpe and Traffic Announcement/Programme identification.  You also
-  need to say Y to "miroSOUND PCM20 radio" and devfs!
-
-  It's not possible to read the raw RDS packets from the device, so
-  the driver cant provide an V4L interface for this.  But the
-  availability of RDS is reported over V4L by the basic driver
-  already.  Here RDS can be read from files in /dev/v4l/rds.
-
-  As module the driver will be called miropcm20-rds.o.
-
-Maestro on board radio
-CONFIG_RADIO_MAESTRO
-  Say Y here to directly support the on-board radio tuner on the
-  Maestro 2 or 2E sound card.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video For Linux API.  Information on
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called radio-maestro.o.
-
-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.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video For Linux API.  Information on
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called radio-maxiradio.o.
-
-GemTek Radio Card support
-CONFIG_RADIO_GEMTEK
-  Choose Y here if you have this FM radio card, and then fill in the
-  port address below.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video For Linux API.  Information on
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called radio-gemtek.o.
-
-GemTek I/O port
-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
-  port is 0x28c.
-
-Gemtek PCI Radio
-CONFIG_RADIO_GEMTEK_PCI
-  Choose Y here if you have this PCI FM radio card.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video for Linux API.  Information on 
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called radio-gemtek-pci.o.
-
-PlanB Video-In for PowerMacs
-CONFIG_VIDEO_PLANB
-  PlanB is the V4L driver for the PowerMac 7x00/8x00 series video
-  input hardware. If you want to experiment with this, say Y.
-  Otherwise, or if you don't understand a word, say N.
-  See <http://www.cpu.lu/~mlan/planb.html> for more info.
-
-  Saying M will compile this driver as a module (planb.o).
-
-TerraTec ActiveRadio
-CONFIG_RADIO_TERRATEC
-  Choose Y here if you have this FM radio card, and then fill in the
-  port address below. (TODO)
-
-  Note: This driver is in its early stages.  Right now volume and
-  frequency control and muting works at least for me, but
-  unfortunately I have not found anybody who wants to use this card
-  with Linux.  So if it is this what YOU are trying to do right now,
-  PLEASE DROP ME A NOTE!!  Rolf Offermanns (rolf@offermanns.de)
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video For Linux API.  Information on
-  this API and pointers to "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called radio-terratec.o.
-
-Terratec I/O port (normally 0x590)
-CONFIG_RADIO_TERRATEC_PORT
-  Fill in the I/O port of your TerraTec FM radio card. If unsure, go
-  with the default.
-
-Trust FM radio card
-CONFIG_RADIO_TRUST
-  This is a driver for the Trust FM radio cards. Say Y if you have
-  such a card and want to use it under Linux.
-
-  This driver is also available as a module called radio-trust.o ( =
-  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>.
-
-Trust I/O port (usually 0x350 or 0x358)
-CONFIG_RADIO_TRUST_PORT
-  Enter the I/O port of your Trust FM radio card. If unsure, try the
-  values "0x350" or "0x358".
-
-BT848 Video For Linux
-CONFIG_VIDEO_BT848
-  Support for BT848 based frame grabber/overlay boards. This includes
-  the Miro, Hauppauge and STB boards. Please read the material in
-  <file:Documentation/video4linux/bttv> for more information.
-
-  If you say Y or M here, you need to say Y or M to "I2C support" and
-  "I2C bit-banging interfaces" in the character device section.
-
-  This driver is available as a module called bttv.o ( = 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>.
-
-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.
-  Function 0 does the video stuff (bt848 compatible), function 1 does
-  the same for audio data.  This is a driver for the audio part of
-  the chip.  If you say 'Y' here you get a oss-compatible dsp device
-  where you can record from.  If you want just watch TV you probably
-  don't need this driver as most TV cards handle sound with a short
-  cable from the TV card to your sound card's line-in.
-
-  This driver is available as a module called btaudio.o ( = 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>.
-
-SGI Vino Video For Linux
-CONFIG_VIDEO_VINO
-  Say Y here to build in support for the Vino video input system found
-  on SGI Indy machines.
-
-Stradis 4:2:2 MPEG-2 video driver
-CONFIG_VIDEO_STRADIS
-  Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
-  driver for PCI.  There is a product page at
-  <http://www.stradis.com/decoder.html>.
-
-Zoran ZR36057/36060 Video For Linux
-CONFIG_VIDEO_ZORAN
-  Say Y here to include support for video cards based on the Zoran
-  ZR36057/36060 encoder/decoder chip (including the Iomega Buz and the
-  Miro DC10 and DC30 video capture cards).
-
-Include support for Iomega 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/>.
-
-Zoran ZR36120/36125 Video For Linux
-CONFIG_VIDEO_ZR36120
-  Support for ZR36120/ZR36125 based frame grabber/overlay boards.
-  This includes the Victor II, WaveWatcher, Video Wonder, Maxi-TV,
-  and Buster boards. Please read the material in
-  <file:Documentation/video4linux/zr36120.txt> for more information.
-
-  This driver is also available as a module called zr36120.o ( = 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>.
-
-SAA5249 Teletext processor
-CONFIG_VIDEO_SAA5249
-  Support for I2C bus based teletext using the SAA5249 chip. At the
-  moment this is only useful on some European WinTV cards.
-
-  This driver is also available as a module called saa5249.o ( = 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>.
-
-QuickCam BW Video For Linux
-CONFIG_VIDEO_BWQCAM
-  Say Y have if you the black and white version of the QuickCam
-  camera. See the next option for the color version.
-
-  This driver is also available as a module called bw-qcam.o ( = 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>.
-
-QuickCam Colour Video For Linux
-CONFIG_VIDEO_CQCAM
-  This is the video4linux driver for the colour version of the
-  Connectix QuickCam.  If you have one of these cameras, say Y here,
-  otherwise say N.  This driver does not work with the original
-  monochrome QuickCam, QuickCam VC or QuickClip.  It is also available
-  as a module (c-qcam.o).
-  Read <file:Documentation/video4linux/CQcam.txt> for more information.
-
-Winbond W9966CF Webcam Video For Linux
-CONFIG_VIDEO_W9966
-  Video4linux driver for Winbond's w9966 based Webcams.
-  Currently tested with the LifeView FlyCam Supra.
-  If you have one of these cameras, say Y here
-  otherwise say N.
-  This driver is also available as a module (w9966.o).
-
-  Check out <file:Documentation/video4linux/w9966.txt> for more
-  information.
-
-CPiA Video For Linux
-CONFIG_VIDEO_CPIA
-  This is the video4linux driver for cameras based on Vision's CPiA
-  (Colour Processor Interface ASIC), such as the Creative Labs Video
-  Blaster Webcam II. If you have one of these cameras, say Y here
-  and select parallel port and/or USB lowlevel support below,
-  otherwise say N. This will not work with the Creative Webcam III.
-
-  Please read <file:Documentation/video4linux/README.cpia> for more
-  information.
-
-  This driver is also available as a module (cpia.o).
-
-CPiA Parallel Port Lowlevel Support
-CONFIG_VIDEO_CPIA_PP
-  This is the lowlevel parallel port support for cameras based on
-  Vision's CPiA (Colour Processor Interface ASIC), such as the
-  Creative Webcam II. If you have the parallel port version of one
-  of these cameras, say Y here, otherwise say N. It is also available
-  as a module (cpia_pp.o).
-
-CPiA USB Lowlevel Support
-CONFIG_VIDEO_CPIA_USB
-  This is the lowlevel USB support for cameras based on Vision's CPiA
-  (Colour Processor Interface ASIC), such as the Creative Webcam II.
-  If you have the USB version of one of these cameras, say Y here,
-  otherwise say N. This will not work with the Creative Webcam III.
-  It is also available as a module (cpia_usb.o).
-
-Mediavision Pro Movie Studio Video For Linux
-CONFIG_VIDEO_PMS
-  Say Y if you have such a thing.  This driver is also available as a
-  module called pms.o ( = 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>.
-
-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
-  <file:Documentation/video4linux/meye.txt> for more information.
-
-  If you say Y or M here, you need to say Y or M to "Sony Programmable
-  I/O Control Device" in the character device section.
-
-  This driver is available as a module called meye.o ( = 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>.
-
-IBM's S/390 architecture
-CONFIG_ARCH_S390
-  Select this option, if you want to run the Kernel on one of IBM's
-  mainframes of the S/390 generation. You should have installed the
-  s390-compiler released by IBM (based on gcc-2.95.1) before.
-
-Merge some code into the kernel to make the image IPLable
-CONFIG_IPL
-  If you want to use the produced kernel to IPL directly from a
-  device, you have to merge a bootsector specific to the device
-  into the first bytes of the kernel. You will have to select the
-  IPL device.
-
-# Choice: s390_ipl
-IPL from a S/390 tape unit
-CONFIG_IPL_TAPE
-  Select this option if you want to IPL the image from a Tape.
-
-IPL from a virtual card reader emulated by VM/ESA
-CONFIG_IPL_RDR_VM
-  Select this option if you are running under VM/ESA and want
-  to IPL the image from the emulated card reader.
-
-IPL from a real card reader
-CONFIG_IPL_RDR
-  Select this option if you want to IPL the image from a real
-  card reader. Maybe you still got one and want to try. We didn't
-  test.
-
-Support for DASD hard disks
-CONFIG_DASD
-  Enable this option if you want to access DASDs directly utilizing
-  S/390s channel subsystem commands. This is necessary for running
-  natively on a single image or an LPAR.
-
-Enable DASD fast write
-CONFIG_DASD_FAST_IO
-  Enable fast I/O for DASDs. That means that the next I/O command
-  is already issued at interrupt time, if an I/O request is pending.
-  This option gives significant speedup of I/O, because we don't
-  schedule the bottom-halves as often as Intel.
-
-Support for IBM-style disk-labels (S/390)
-CONFIG_S390_PARTITION
-  Enable this option to assure standard IBM labels on the DASDs.
-  You must enable it, if you are planning to access DASDs also
-  attached to another IBM mainframe operation system (OS/390, 
-  VM/ESA, VSE/ESA).
-
-ECKD devices
-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.
-
-CKD devices
-CONFIG_DASD_CKD
-  CKD devices are currently unsupported.
-
-FBA devices
-CONFIG_DASD_FBA
-  FBA devices are currently unsupported.
-
-Merge some code into the kernel to make the image IPLable
-CONFIG_IPLABLE
-  If you want to use the produced kernel to IPL directly from a
-  device, you have to merge a bootsector specific to the device
-  into the first bytes of the kernel. You will have to select the
-  IPL device on another question, that pops up, when you select
-  CONFIG_IPLABE.
-
-Support for 3215 line mode terminal
-CONFIG_TN3215
-  Include support for IBM 3215 line-mode terminals.
-
-Support for console on 3215 line mode terminal
-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_TN3270
-  Include support for IBM 3270 line-mode terminals.
-
-Support for console on 3270 line mode terminal
-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
-  Include support for IBM HWC line-mode terminals.
-
-Console on HWC line mode terminal
-CONFIG_HWC_CONSOLE
-  Include support for using an IBM HWC line-mode terminal as the Linux
-  system console.
-
-S/390 tape device support
-CONFIG_S390_TAPE
-  Select this option if you want to access channel-attached tape
-  devices on IBM S/390 or zSeries.
-  If you select this option you will also want to select at
-  least one of the tape interface options and one of the tape
-  hardware options in order to access a tape device.
-  This option is also available as a module. The module will be
-  called tape390.o and include all selected interfaces and
-  hardware drivers.
-
-Support for tape character devices
-CONFIG_S390_TAPE_CHAR
-  Select this option if you want to access your channel-attached
-  tape devices using the character device interface.
-  This interface is similar to other Linux tape devices like
-  SCSI-Tapes (st) and the floppy tape device (ftape).
-  If unsure, say "Y".
-
-Support for tape block devices
-CONFIG_S390_TAPE_BLOCK
-  Select this option if you want to access your channel-attached tape
-  devices using the block device interface.  This interface is similar
-  to CD-ROM devices on other platforms.  The tapes can only be
-  accessed read-only when using this interface.  Have a look at
-  Documentation/s390/TAPE for further information about creating
-  volumes for and using this interface.  It is safe to say "Y" here.
-
-Support for 3490 tape hardware
-CONFIG_S390_TAPE_3490
-  Select this option if you want to access IBM 3480 magnetic
-  tape subsystems and 100% compatibles.
-  It is safe to say "Y" here.
-
-Support for 3480 tape hardware
-CONFIG_S390_TAPE_3480
-  Select this option if you want to access IBM 3490 magnetic
-  tape subsystems and 100% compatibles.
-
-CTC device support
-CONFIG_CTC
-  Select this option if you want to use channel-to-channel networking
-  on IBM S/390 or zSeries. This device driver supports real CTC
-  coupling using ESCON. It also supports virtual CTCs when running
-  under VM. It will use the channel device configuration if this is
-  available.  This option is also available as a module which will be
-  called ctc.o.  If you do not know what it is, it's safe to say "Y".
-
-Support for DIAG access to CMS reserved Disks
-CONFIG_DASD_DIAG
-  Select this option if you want to use CMS reserved Disks under VM
-  with the Diagnose250 command.  If you are not running under VM or
-  unsure what it is, say "N".
-
-XPRAM disk support
-CONFIG_BLK_DEV_XPRAM
-  Select this option if you want to use your expanded storage on S/390
-  or zSeries as a disk.  This is useful as a _fast_ swap device if you
-  want to access more than 2G of memory when running in 31 bit mode.
-  This option is also available as a module which will be called
-  xpram.o.  If unsure, say "N".
-
-Fast IRQ handling
-CONFIG_FAST_IRQ
-  Select this option in order to get the interrupts processed faster
-  on your S/390 or zSeries machine.  If selected, after an interrupt
-  is processed, the channel subsystem will be asked for other pending
-  interrupts which will also be processed before leaving the interrupt
-  context.  This speeds up the I/O a lot. Say "Y".
-
-IUCV device support (VM only)
-CONFIG_IUCV
-  Select this option if you want to use inter-user communication
-  vehicle networking under VM or VIF.  This option is also available
-  as a module which will be called iucv.o. If unsure, say "Y".
-
-Kernel support for 31 bit ELF binaries
-CONFIG_S390_SUPPORT
-  Select this option if you want to enable your system kernel to
-  handle system-calls from ELF binaries for 31 bit ESA.  This option
-  (and some other stuff like libraries and such) is needed for
-  executing 31 bit applications.  It is safe to say "Y".
-
-Channel Device Configuration
-CONFIG_CHANDEV
-  The channel device layer is a layer to provide a consistent
-  interface for configuration & default machine check (devices
-  appearing & disappearing) handling on Linux for s/390 & z/Series
-  channel devices.
-
-  s/390 & z/Series channel devices include among others
-
-  lcs (the most common ethernet/token ring/fddi standard on
-  zSeries)
-  ctc/escon hi speed like serial link standard on zSeries
-  claw used to talk to cisco routers.
-  qeth gigabit ethernet.
-
-  These devices use two channels one read & one write for
-  configuration & communication (& a third channel, the data
-  channel the case of gigabit ethernet). The motivation
-  behind developing this layer was that there was a lot of
-  duplicate code among the channel device drivers for
-  configuration.
-
-  Also the lcs & ctc drivers tended to fight over
-  3088/08's & 3088/1F's which could be either 2216/3172
-  channel attached lcs compatible devices or escon/ctc pipes
-  had to be configured separately as they couldn't autodetect,
-  this is now simplified by doing the configuration in a single
-  place (the channel device layer).
-
-  This layer isn't invasive & it is quite okay to use channel
-  drivers which don't use the channel device layer in
-  conjunction with drivers which do.
-
-  For more info see the chandev manpage usually distributed in
-  <file:Documentation/s390/chandev.8> in the Linux source tree.
-
-SAB3036 tuner support
-CONFIG_TUNER_3036
-  Say Y here to include support for Philips SAB3036 compatible tuners.
-  If in doubt, say N.
-
-Compaq SMART2 support
-CONFIG_BLK_CPQ_DA
-  This is the driver for Compaq Smart Array controllers.  Everyone
-  using these boards should say Y here.  See the file
-  <file:Documentation/cpqarray.txt> for the current list of boards
-  supported by this driver, and for further information on the use of
-  this driver.
-
-Show crashed user process info
-CONFIG_PROCESS_DEBUG
-  Say Y to print all process fault locations to the console.  This is
-  a debugging option; you probably do not want to set it unless you
-  are an S390 port maintainer.
-
-#
-# ARM options
-#
-# CML2 transition note: CML1 asks ARCH_ARCA5K, then has ARCH_A5K and ARCH_ARK
-# as subquestions.  CML2 asks the subquestions in the armtype menu and makes
-# ARCH_ARCA5K a derived symbol.
-ARM System type
-CONFIG_ARCH_ARCA5K
-  This selects what ARM system you wish to build the kernel for. It
-  also selects to some extent the CPU type. If you are unsure what
-  to set this option to, please consult any information supplied with
-  your system.
-
-# Choice: armtype
-A5000
-CONFIG_ARCH_A5K
-  Say Y here to to support the Acorn A5000.  Linux can support the
-  internal IDE disk and CD-ROM interface, serial and parallel port,
-  and the floppy drive.  Note that on some A5000s the floppy is
-  plugged into the wrong socket on the motherboard.
-
-Archimedes
-CONFIG_ARCH_ARC
-  The Acorn Archimedes was an personal computer based on an 8K ARM2
-  processor, released in 1987.  It supported 512K of RAM and 2 800K
-  floppy disks.  Picture and more detailed specifications at
-  <http://www.computingmuseum.com/museum/archi.htm>.
-
-EBSA-110
-CONFIG_ARCH_EBSA110
-  This is an evaluation board for the StrongARM processor available
-  from Digital. It has limited hardware on-board, including an onboard
-  Ethernet interface, two PCMCIA sockets, two serial ports and a
-  parallel port.
-
-RiscPC
-CONFIG_ARCH_RPC
-  On the Acorn Risc-PC, Linux can support the internal IDE disk and
-  CD-ROM interface, serial and parallel port, and the floppy drive.
-
-2MB physical memory
-CONFIG_PAGESIZE_16
-  Say Y here if your Archimedes or A5000 system has only 2MB of
-  memory, otherwise say N.  The resulting kernel will not run on a
-  machine with 4MB of memory.
-
-CATS
-CONFIG_ARCH_CATS
-  Say Y here if you intend to run this kernel on the CATS.
-
-  Saying N will reduce the size of the Footbridge kernel.
-
-EBSA285 (addin mode)
-CONFIG_ARCH_EBSA285_ADDIN
-  Say Y here if you intend to run this kernel on the EBSA285 card
-  in addin mode.
-
-  Saying N will reduce the size of the Footbridge kernel.
-
-EBSA285 (host mode)
-CONFIG_ARCH_EBSA285_HOST
-  Say Y here if you intend to run this kernel on the EBSA285 card
-  in host ("central function") mode.
-
-  Saying N will reduce the size of the Footbridge kernel.
-
-LinkUp Systems L7200 SDB
-CONFIG_ARCH_L7200
-  Say Y here if you intend to run this kernel on a LinkUp Systems
-  L7200 Software Development Board which uses an ARM720T processor.
-  Information on this board can be obtained at:
-
-  <http://www.linkupsys.com/>
-
-  If you have any questions or comments about the Linux kernel port
-  to this board, send e-mail to sjhill@cotw.com.
-
-NetWinder
-CONFIG_ARCH_NETWINDER
-  Say Y here if you intend to run this kernel on the Rebel.COM
-  NetWinder.  Information about this machine can be found at:
-
-  <http://www.netwinder.org/>
-
-  Saying N will reduce the size of the Footbridge kernel.
-
-P720T
-CONFIG_ARCH_P720T
-  Say Y here if you intend to run this kernel on the ARM Prospector
-  720T.
-
-Compaq Personal Server
-CONFIG_ARCH_PERSONAL_SERVER
-  Say Y here if you intend to run this kernel on the Compaq
-  Personal Server.
-
-  Saying N will reduce the size of the Footbridge kernel.
-
-  The Compaq Personal Server is not available for purchase.
-  There are no product plans beyond the current research
-  prototypes at this time.  Information is available at:
-
-  <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.
-
-Assabet
-CONFIG_SA1100_ASSABET
-  Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
-  Microprocessor Development Board (also known as the Assabet).
-
-Neponset
-CONFIG_ASSABET_NEPONSET
-  Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
-  Microprocessor Development Board (Assabet)  with the SA-1111
-  Development Board (Nepon).
-
-Compaq iPAQ H3600
-CONFIG_SA1100_H3600
-  Say Y here if you intend to run this kernel on the Compaq iPAQ
-  H3600 handheld computer.  Information about this machine and the
-  Linux port to this machine can be found at:
-
-  <http://www.handhelds.org/Compaq/index.html#iPAQ_H3600>
-  <http://www.compaq.com/products/handhelds/pocketpc/>
-
-Brutus
-CONFIG_SA1100_BRUTUS
-  Say Y here if you are using the Intel(R) StrongARM(R) SA-1100
-  Microprocessor Development Board (also known as the Brutus).
-
-LART
-CONFIG_SA1100_LART
-  Say Y here if you are using the Linux Advanced Radio Terminal
-  (also known as the LART).  See <http://www.lart.tudelft.nl/> for
-  information on the LART.
-
-GraphicsClient
-CONFIG_SA1100_GRAPHICSCLIENT
-  Say Y here if you are using an Applied Data Systems Intel(R)
-  StrongARM(R) SA-1100 based Graphics Client SBC.  See
-  <http://www.flatpanels.com/> for information on this system.
-
-CerfBoard
-CONFIG_SA1100_CERF
-  The Intrinsyc CerfBoard is based on the StrongARM 1110.
-  More information is available at:
-  <http://www.intrinsyc.com/products/referenceplatforms/cerfboard.html>.
-
-  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
-  from Bright Star Engineering. More information is available at:
-  <http://www.brightstareng.com/arm/nanoeng.htm>.
-
-  Say Y if configuring for a nanoEngine.
-  Say N otherwise.
-
-Pangolin
-CONFIG_SA1100_PANGOLIN
-  Pangolin is a StrongARM 1110-based evaluation platform produced
-  by Dialogue Technology.  It has EISA slots for ease of configuration
-  with SDRAM/Flash memory card, USB/Serial/Audio card, Compact Flash
-  card, and TFT-LCD card.
-
-  Say Y if configuring for a Pangolin.
-  Say N otherwise.
-
-Victor
-CONFIG_SA1100_VICTOR
-  Say Y here if you are using a Visu Aide Intel(R) StrongARM(R)
-  SA-1100 based Victor Digital Talking Book Reader.  See
-  <http://www.visuaide.com/pagevictor.en.html> for information on
-  this system.
-
-Support ARM610 processor
-CONFIG_CPU_ARM610
-  The ARM610 is the successor to the ARM3 processor
-  and was produced by VLSI Technology Inc.
-
-  Say Y if you want support for the ARM610 processor.
-  Otherwise, say N.
-
-Support ARM710 processor
-CONFIG_CPU_ARM710
-  A 32-bit RISC microprocessor based on the ARM7 processor core
-  designed by Advanced RISC Machines Ltd. The ARM710 is the
-  successor to the ARM610 processor. It was released in
-  July 1994 by VLSI Technology Inc.
-
-  Say Y if you want support for the ARM710 processor.
-  Otherwise, say N.
-
-Support ARM720T processor
-CONFIG_CPU_ARM720T
-  A 32-bit RISC processor with 8kByte Cache, Write Buffer and
-  MMU built around an ARM7TDMI core.
-
-  Say Y if you want support for the ARM720T processor.
-  Otherwise, say N.
-
-Support ARM920T processor
-CONFIG_CPU_ARM920T
-  The ARM920T is licensed to be produced by numerous vendors,
-  and is used in the Maverick EP9312.  More information at
-  <http://linuxdevices.com/products/PD2382866068.html>.
-
-  Say Y if you want support for the ARM920T processor.
-  Otherwise, say N.
-
-Support ARM1020 processor
-CONFIG_CPU_ARM1020
-  The ARM1020 is the cached version of the ARM10 processor,
-  with an addition of a floating-point unit.
-
-  Say Y if you want support for the ARM1020 processor.
-  Otherwise, say N.
-
-Support StrongARM SA-110 processor
-CONFIG_CPU_SA110
-  The Intel StrongARM(R) SA-110 is a 32-bit microprocessor and
-  is available at five speeds ranging from 100 MHz to 233 MHz.
-  More information is available at
-  <http://developer.intel.com/design/strong/sa110.htm>.
-
-  Say Y if you want support for the SA-110 processor.
-  Otherwise, say N.
-
-Math emulation
-CONFIG_FPE_NWFPE
-  Say Y to include the NWFPE floating point emulator in the kernel.
-  This is necessary to run most binaries. Linux does not currently
-  support floating point hardware so you need to say Y here even if
-  your machine has an FPA or floating point co-processor podule.
-
-  It is also possible to say M to build the emulator as a module
-  (nwfpe.o) or indeed to leave it out altogether. However, unless you
-  know what you are doing this can easily render your machine
-  unbootable. Saying Y is the safe option.
-
-  You may say N here if you are going to load the Acorn FPEmulator
-  early in the bootup.
-
-FastFPE math emulation
-CONFIG_FPE_FASTFPE
-  Say Y here to include the FAST floating point emulator in the kernel.
-  This is an experimental much faster emulator which has only 32 bit
-  precision for the mantissa.  It does not support any exceptions.
-  This makes it very simple, it is approximately 4-8 times faster than
-  NWFPE.
-
-  It should be sufficient for most programs.  It is definitely not
-  suitable if you do scientific calculations that need double
-  precision for iteration formulas that sum up lots of very small
-  numbers.  If you do not feel you need a faster FP emulation you
-  should better choose NWFPE.
-
-  It is also possible to say M to build the emulator as a module
-  (fastfpe.o).  But keep in mind that you should only load the FP
-  emulator early in the bootup.  You should never change from NWFPE to
-  FASTFPE or vice versa in an active system!
-
-DS1620 thermometer support
-CONFIG_DS1620
-  Say Y here to include support for the thermal management hardware
-  found in the NetWinder. This driver allows the user to control the
-  temperature set points and to read the current temperature.
-
-  It is also possible to say M here to build it as a module (ds1620.o)
-  It is recommended to be used on a NetWinder, but it is not a
-  necessity.
-
-Debug high memory support
-CONFIG_DEBUG_HIGHMEM
-  This options enables addition error checking for high memory systems.
-  Disable for production systems.
-
-Verbose kernel error messages
-CONFIG_DEBUG_ERRORS
-  This option controls verbose debugging information which can be
-  printed when the kernel detects an internal error. This debugging
-  information is useful to kernel hackers when tracking down problems,
-  but mostly meaningless to other people. It's safe to say Y unless
-  you are concerned with the code size or don't want to see these
-  messages.
-
-Compile kernel without frame pointer
-CONFIG_NO_FRAME_POINTER
-  If you say Y here, the resulting kernel will be slightly smaller and
-  faster. However, when a problem occurs with the kernel, the
-  information that is reported is severely limited. Most people
-  should say N here.
-
-Verbose user fault messages
-CONFIG_DEBUG_USER
-  When a user program crashes due to an exception, the kernel can
-  print a brief message explaining what the problem was. This is
-  sometimes helpful for debugging but serves no purpose on a
-  production system. Most people should say N here.
-
-Include gdb debugging information in kernel binary
-CONFIG_DEBUG_INFO
-  Say Y here to include source-level debugging information in the
-  `vmlinux' binary image. This is handy if you want to use gdb or
-  addr2line to debug the kernel. It has no impact on the in-memory
-  footprint of the running kernel but it can increase the amount of
-  time and disk space needed for compilation of the kernel. If in
-  doubt say N.
-
-Kernel low-level debugging functions
-CONFIG_DEBUG_LL
-  Say Y here to include definitions of printascii, printchar, printhex
-  in the kernel.  This is helpful if you are debugging code that
-  executes before the console is initialized.
-
-Kernel low-level debugging messages via footbridge serial port
-CONFIG_DEBUG_DC21285_PORT
-  Say Y here if you want the debug print routines to direct their
-  output to the serial port in the DC21285 (Footbridge). Saying N
-  will cause the debug messages to appear on the first 16550
-  serial port.
-
-Kernel low-level debugging messages via UART2
-CONFIG_DEBUG_CLPS711X_UART2
-  Say Y here if you want the debug print routines to direct their
-  output to the second serial port on these devices.  Saying N will
-  cause the debug messages to appear on the first serial port.
-
-Disable pgtable cache
-CONFIG_NO_PGT_CACHE
-  Normally the kernel maintains a `quicklist' of preallocated
-  pagetable structures in order to increase performance. On machines
-  with very few pages this may however be a loss. Say Y here to
-  disable the pgtable cache.
-
-RISC OS personality
-CONFIG_ARTHUR
-  Say Y here to include the kernel code necessary if you want to run
-  Acorn RISC OS/Arthur binaries under Linux. This code is still very
-  experimental; if this sounds frightening, say N and sleep in peace.
-  You can also say M here to compile this support as a module (which
-  will be called arthur.o).
-
-Initial kernel command line
-CONFIG_CMDLINE
-  On some architectures (EBSA110 and CATS), there is currently no way
-  for the boot loader to pass arguments to the kernel. For these
-  architectures, you should supply some command-line options at build
-  time by entering them here. As a minimum, you should specify the
-  memory size and the root device (e.g., mem=64M root=/dev/nfs).
-
-Kernel-mode alignment trap handler
-CONFIG_ALIGNMENT_TRAP
-  ARM processors can not fetch/store information which is not
-  naturally aligned on the bus, i.e., a 4 byte fetch must start at an
-  address divisible by 4. On 32-bit ARM processors, these non-aligned
-  fetch/store instructions will be emulated in software if you say
-  here, which has a severe performance impact. This is necessary for
-  correct operation of some network protocols. With an IP-only
-  configuration it is safe to say N, otherwise say Y.
-
-DC21285 serial port support
-CONFIG_SERIAL_21285
-  If you have a machine based on a 21285 (Footbridge) StrongARM(R)/
-  PCI bridge you can enable its onboard serial port by enabling this
-  option. The device has major ID 4, minor 64.
-
-Console on DC21285 serial port
-CONFIG_SERIAL_21285_CONSOLE
-  If you have enabled the serial port on the 21285 footbridge you can
-  make it the console by answering Y to this option.
-
-SA1100 serial port support
-CONFIG_SERIAL_SA1100
-  * Orphaned entry retained 20 April 2001 by Russell King       *
-  * If you read this note from the configurator, please contact *
-  * the Configure.help maintainers.                             *
-  If you have a machine based on a SA1100/SA1110 StrongARM CPU you can
-  enable its onboard serial port by enabling this option.
-  Please read <file:Documentation/arm/SA1100/serial_UART> for further
-  info.
-
-Console on SA1100 serial port
-CONFIG_SERIAL_SA1100_CONSOLE
-  * Orphaned entry retained 20 April 2001 by Russell King       *
-  * If you read this note from the configurator, please contact *
-  * the Configure.help maintainers.                             *
-  If you have enabled the serial port on the SA1100/SA1110 StrongARM
-  CPU you can make it the console by answering Y to this option.
-
-L7200 serial port support
-CONFIG_SERIAL_L7200
-  * Orphaned entry retained 20 April 2001 by Russell King       *
-  * If you read this note from the configurator, please contact *
-  * the Configure.help maintainers.                             *
-  If you have a LinkUp Systems L7200 board you can enable its two
-  onboard serial ports by enabling this option. The device numbers
-  are major ID 4 with minor 64 and 65 respectively.
-
-Console on L7200 serial port
-CONFIG_SERIAL_L7200_CONSOLE
-  * Orphaned entry retained 20 April 2001 by Russell King       *
-  * If you read this note from the configurator, please contact *
-  * the Configure.help maintainers.                             *
-  If you have enabled the serial ports on the L7200 development board
-  you can make the first serial port the console by answering Y to
-  this option.
-
-L7200 SDB keyboard support
-CONFIG_KEYBOARD_L7200
-  * Orphaned entry retained 20 April 2001 by Russell King       *
-  * If you read this note from the configurator, please contact *
-  * the Configure.help maintainers.                             *
-  Enable this option if you would like to be able to use a keyboard
-  on a LinkUp Systems L7200 board.
-
-L7200 SDB Fujitsu keyboard support
-CONFIG_KEYBOARD_L7200_NORM
-  * Orphaned entry retained 20 April 2001 by Russell King       *
-  * If you read this note from the configurator, please contact *
-  * the Configure.help maintainers.                             *
-  Select the Fujitsu keyboard if you want a normal QWERTY style
-  keyboard on the LinkUp SDB.
-
-L7200 SDB Prototype keyboard support
-CONFIG_KEYBOARD_L7200_DEMO
-  * Orphaned entry retained 20 April 2001 by Russell King       *
-  * If you read this note from the configurator, please contact *
-  * the Configure.help maintainers.                             *
-  Select the prototype keyboard if you want to play with the
-  LCD/keyboard combination on the LinkUp SDB.
-
-Footbridge Mode
-CONFIG_HOST_FOOTBRIDGE
-  * Orphaned entry retained 20 April 2001 by Russell King       *
-  * If you read this note from the configurator, please contact *
-  * the Configure.help maintainers.                             *
-  The 21285 Footbridge chip can operate in either `host mode' or
-  `add-in' mode.  Say Y if your 21285 is in host mode, and therefore
-  is the configuration master, otherwise say N. This must not be
-  set to Y if the card is used in 'add-in' mode.
-
-MFM hard disk support
-CONFIG_BLK_DEV_MFM
-  Support the MFM hard drives on the Acorn Archimedes both
-  on-board the A4x0 motherboards and via the Acorn MFM podules.
-  Drives up to 64MB are supported. If you haven't got one of these
-  machines or drives just say N.
-
-Old Archimedes floppy (1772) support
-CONFIG_BLK_DEV_FD1772
-  Support the floppy drive on the Acorn Archimedes (A300, A4x0, A540,
-  R140 and R260) series of computers; it supports only 720K floppies
-  at the moment. If you don't have one of these machines just answer
-  N.
-
-Autodetect hard drive geometry
-CONFIG_BLK_DEV_MFM_AUTODETECT
-  If you answer Y, the MFM code will attempt to automatically detect
-  the cylinders/heads/sectors count on your hard drive. WARNING: This
-  sometimes doesn't work and it also does some dodgy stuff which
-  potentially might damage your drive.
-
-NetWinder /dev/flash support
-CONFIG_NWFLASH
-  If you say Y here and create a character device /dev/flash with
-  major 10 and minor 160 you can manipulate the flash ROM containing
-  the NetWinder firmware. Be careful as accidentally overwriting the
-  flash contents can render your computer unbootable. On no account
-  allow random users access to this device. :-)
-
-  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 nwflash.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-  If you're not sure, say N.
-
-SRM environment variables in procfs
-CONFIG_SRM_ENV
-  If you enable this option, a subdirectory called srm_environment
-  will give you access to the most important SRM environment
-  variables. If you've got an Alpha style system supporting
-  SRC, then it is a good idea to say Yes or Module to this driver.
-
-  This driver is also available as a module and will be called
-  srm_env.o if you build it as a module.
-
-Footbridge internal watchdog
-CONFIG_21285_WATCHDOG
-  The Intel Footbridge chip contains a builtin watchdog circuit. Say Y
-  here if you wish to use this. Alternatively say M to compile the
-  driver as a module, which will be called wdt285.o.
-
-  This driver does not work on all machines. In particular, early CATS
-  boards have hardware problems that will cause the machine to simply
-  lock up if the watchdog fires.
-
-  "If in doubt, leave it out" - say N.
-
-NetWinder WB83C977 watchdog
-CONFIG_977_WATCHDOG
-  Say Y here to include support for the WB977 watchdog included in
-  NetWinder machines. Alternatively say M to compile the driver as
-  a module, which will be called wdt977.o.
-
-  Not sure? It's safe to say N.
-
-IrDA subsystem support
-CONFIG_IRDA
-  Say Y here if you want to build support for the IrDA (TM) protocols.
-  The Infrared Data Associations (tm) specifies standards for wireless
-  infrared communication and is supported by most laptops and PDA's.
-
-  To use Linux support for the IrDA (tm) protocols, you will also need
-  some user-space utilities like irattach.  For more information, see
-  the file <file:Documentation/networking/irda.txt>.  You also want to
-  read the IR-HOWTO, available at
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to exchange bits of data (vCal, vCard) with a PDA, you
-  will need to install some OBEX application, such as OpenObex :
-  <http://sourceforge.net/projects/openobex/>
-
-  This support is also available as a module called irda.o.  If you
-  want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.
-
-Ultra (connectionless) protocol
-CONFIG_IRDA_ULTRA
-  Say Y here to support the connectionless Ultra IRDA protocol.
-  Ultra allows to exchange data over IrDA with really simple devices
-  (watch, beacon) without the overhead of the IrDA protocol (no handshaking,
-  no management frames, simple fixed header).
-  Ultra is available as a special socket : socket(AF_IRDA, SOCK_DGRAM, 1);
-
-IrDA cache last LSAP
-CONFIG_IRDA_CACHE_LAST_LSAP
-  Say Y here if you want IrLMP to cache the last LSAP used.  This
-  makes sense since most frames will be sent/received on the same
-  connection.  Enabling this option will save a hash-lookup per frame.
-
-  If unsure, say Y.
-
-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.
-  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 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).
-
-IrLAN protocol
-CONFIG_IRLAN
-  Say Y here if you want to build support for the IrLAN protocol.  If
-  you want to compile it as a module (irlan.o), say M here and read
-  <file:Documentation/modules.txt>.  IrLAN emulates an Ethernet and
-  makes it possible to put up a wireless LAN using infrared beams.
-
-  The IrLAN protocol can be used to talk with infrared access points
-  like the HP NetbeamIR, or the ESI JetEye NET.  You can also connect
-  to another Linux machine running the IrLAN protocol for ad-hoc
-  networking!
-
-IrNET protocol
-CONFIG_IRNET
-  Say Y here if you want to build support for the IrNET protocol.  If
-  you want to compile it as a module (irnet.o), say M here and read
-  <file:Documentation/modules.txt>.  IrNET is a PPP driver, so you
-  will also need a working PPP subsystem (driver, daemon and
-  config)...
-
-  IrNET is an alternate way to tranfer TCP/IP traffic over IrDA.  It
-  uses synchronous PPP over a set of point to point IrDA sockets.  You
-  can use it between Linux machine or with W2k.
-
-IrCOMM protocol
-CONFIG_IRCOMM
-  Say Y here if you want to build support for the IrCOMM protocol.  If
-  you want to compile it as a module (you will get ircomm.o and
-  ircomm-tty.o), say M here and read <file:Documentation/modules.txt>.
-  IrCOMM implements serial port emulation, and makes it possible to
-  use all existing applications that understands TTY's with an
-  infrared link.  Thus you should be able to use application like PPP,
-  minicom and others.  Enabling this option will create two modules
-  called ircomm and ircomm_tty.
-
-IrTTY IrDA Device Driver
-CONFIG_IRTTY_SIR
-  Say Y here if you want to build support for the IrTTY line
-  discipline.  If you want to compile it as a module (irtty.o), say M
-  here and read <file:Documentation/modules.txt>.  IrTTY makes it
-  possible to use Linux's own serial driver for all IrDA ports that
-  are 16550 compatible.  Most IrDA chips are 16550 compatible so you
-  should probably say Y to this option.  Using IrTTY will however
-  limit the speed of the connection to 115200 bps (IrDA SIR mode).
-
-  If unsure, say Y.
-
-IrPORT IrDA serial driver
-CONFIG_IRPORT_SIR
-  Say Y here if you want to build support for the IrPORT IrDA device
-  driver. If you want to compile it as a module (irport.o), say M here
-  and read <file:Documentation/modules.txt>.  IrPORT can be used
-  instead of IrTTY and sometimes this can be better.  One example is
-  if your IrDA port does not have echo-canceling, which will work OK
-  with IrPORT since this driver is working in half-duplex mode only.
-  You don't need to use irattach with IrPORT, but you just insert it
-  the same way as FIR drivers (insmod irport io=0x3e8 irq=11).  Notice
-  that IrPORT is a SIR device driver which means that speed is limited
-  to 115200 bps.
-
-  If unsure, say Y.
-
-USB IrDA FIR dongle Device Driver
-CONFIG_USB_IRDA
-  Say Y here if you want to build support for the USB IrDA FIR Dongle
-  device driver.  If you want to compile it as a module (irda-usb.o),
-  say M here and read <file:Documentation/modules.txt>.  IrDA-USB
-  support the various IrDA USB dongles available and most of their
-  pecularities.  Those dongles plug in the USB port of your computer,
-  are plug and play, and support SIR and FIR (4Mbps) speeds.  On the
-  other hand, those dongles tend to be less efficient than a FIR
-  chipset.
-
-  Please note that the driver is still experimental.  And of course,
-  you will need both USB and IrDA support in your kernel...
-
-Winbond W83977AF IrDA Device Driver
-CONFIG_WINBOND_FIR
-  Say Y here if you want to build IrDA support for the Winbond
-  W83977AF super-io chipset.  This driver should be used for the IrDA
-  chipset in the Corel NetWinder.  The driver supports SIR, MIR and
-  FIR (4Mbps) speeds.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called
-  w83977af_ir.o.
-
-NSC PC87108/PC87338 IrDA Device Driver
-CONFIG_NSC_FIR
-  Say Y here if you want to build support for the NSC PC87108 and
-  PC87338 IrDA chipsets.  This driver supports SIR,
-  MIR and FIR (4Mbps) speeds.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called
-  nsc-ircc.o.
-
-National Semiconductor DP83820 series driver
-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.
-
-Toshiba Type-O IR Port device driver
-CONFIG_TOSHIBA_FIR
-  Say Y here if you want to build support for the Toshiba Type-O IR
-  chipset.  This chipset is used by the Toshiba Libretto 100CT, and
-  many more laptops.  If you want to compile it as a module, say M
-  here and read <file:Documentation/modules.txt>.  The module will be
-  called toshoboe.o.
-
-SMC IrCC
-CONFIG_SMC_IRCC_FIR
-  Say Y here if you want to build support for the SMC Infrared
-  Communications Controller.  It is used in the Fujitsu Lifebook 635t
-  and Sony PCG-505TX.  If you want to compile it as a module, say M
-  here and read <file:Documentation/modules.txt>.  The module will be
-  called smc-ircc.o.
-
-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,
-  M1535, M1535D, M1535+, M1535D Sourth Bridge.  This driver supports
-  SIR, MIR and FIR (4Mbps) speeds.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called
-  ali-ircc.o.
-
-VLSI 82C147 PCI-IrDA 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
-  and 5500 notebooks. The driver provides support for SIR, MIR and
-  FIR (4Mbps) speeds.
-
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>. The module will be called vlsi_ir.o.
-
-Serial dongle support
-CONFIG_DONGLE
-  Say Y here if you have an infrared device that connects to your
-  computer's serial port. These devices are called dongles. Then say Y
-  or M to the driver for your particular dongle below.
-
-  Note that the answer to this question won't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about serial dongles.
-
-ESI JetEye PC dongle
-CONFIG_ESI_DONGLE
-  Say Y here if you want to build support for the Extended Systems
-  JetEye PC dongle.  If you want to compile it as a module, say M here
-  and read <file:Documentation/modules.txt>.  The ESI dongle attaches
-  to the normal 9-pin serial port connector, and can currently only be
-  used by IrTTY.  To activate support for ESI dongles you will have to
-  start irattach like this: "irattach -d esi".
-
-ACTiSYS IR-220L and IR220L+ dongle
-CONFIG_ACTISYS_DONGLE
-  Say Y here if you want to build support for the ACTiSYS IR-220L and
-  IR220L+ dongles.  If you want to compile it as a module, say M here
-  and read <file:Documentation/modules.txt>.  The ACTiSYS dongles
-  attaches to the normal 9-pin serial port connector, and can
-  currently only be used by IrTTY.  To activate support for ACTiSYS
-  dongles you will have to start irattach like this:
-  "irattach -d actisys" or "irattach -d actisys+".
-
-Tekram IrMate 210B dongle
-CONFIG_TEKRAM_DONGLE
-  Say Y here if you want to build support for the Tekram IrMate 210B
-  dongle.  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  The Tekram dongle attaches to the
-  normal 9-pin serial port connector, and can currently only be used
-  by IrTTY.  To activate support for Tekram dongles you will have to
-  start irattach like this: "irattach -d tekram".
-
-Greenwich GIrBIL dongle
-CONFIG_GIRBIL_DONGLE
-  Say Y here if you want to build support for the Greenwich GIrBIL
-  dongle.  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  The Greenwich dongle attaches to
-  the normal 9-pin serial port connector, and can currently only be
-  used by IrTTY.  To activate support for Greenwich dongles you will
-  have to insert "irattach -d girbil" in the /etc/irda/drivers script.
-
-Parallax LiteLink dongle
-CONFIG_LITELINK_DONGLE
-  Say Y here if you want to build support for the Parallax Litelink
-  dongle.  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.  The Parallax dongle attaches to
-  the normal 9-pin serial port connector, and can currently only be
-  used by IrTTY.  To activate support for Parallax dongles you will
-  have to start irattach like this "irattach -d litelink".
-
-Old Belkin dongle
-CONFIG_OLD_BELKIN_DONGLE
-  Say Y here if you want to build support for the Adaptec Airport 1000
-  and 2000 dongles.  If you want to compile it as a module, say M here
-  and read <file:Documentation/modules.txt>.  The module will be
-  called old_belkin.o.  Some information is contained in the comments
-  at the top of <file:drivers/net/irda/old_belkin.c>.
-
-VME (Motorola and BVM) support
-CONFIG_VME
-  Say Y here if you want to build a kernel for a 680x0 based VME
-  board.  Boards currently supported include Motorola boards MVME147,
-  MVME162, MVME166, MVME167, MVME172, and MVME177.  BVME4000 and
-  BVME6000 boards from BVM Ltd are also supported.
-
-MVME147 support
-CONFIG_MVME147
-  Say Y to include support for early Motorola VME boards.  This will
-  build a kernel which can run on MVME147 single-board computers.  If
-  you select this option you will have to select the appropriate
-  drivers for SCSI, Ethernet and serial ports later on.
-
-MVME162, 166 and 167 support
-CONFIG_MVME16x
-  Say Y to include support for Motorola VME boards.  This will build a
-  kernel which can run on MVME162, MVME166, MVME167, MVME172, and
-  MVME177 boards.  If you select this option you will have to select
-  the appropriate drivers for SCSI, Ethernet and serial ports later
-  on.
-
-BVME4000 and BVME6000 support
-CONFIG_BVME6000
-  Say Y to include support for VME boards from BVM Ltd.  This will
-  build a kernel which can run on BVME4000 and BVME6000 boards.  If
-  you select this option you will have to select the appropriate
-  drivers for SCSI, Ethernet and serial ports later on.
-
-Use write-through caching for 68060 supervisor accesses
-CONFIG_060_WRITETHROUGH
-  The 68060 generally uses copyback caching of recently accessed data.
-  Copyback caching means that memory writes will be held in an on-chip
-  cache and only written back to memory some time later.  Saying Y
-  here will force supervisor (kernel) accesses to use writethrough
-  caching.  Writethrough caching means that data is written to memory
-  straight away, so that cache and memory data always agree.
-  Writethrough caching is less efficient, but is needed for some
-  drivers on 68060 based systems where the 68060 bus snooping signal
-  is hardwired on.  The 53c710 SCSI driver is known to suffer from
-  this problem.
-
-WD33C93 SCSI driver for MVME147
-CONFIG_MVME147_SCSI
-  Support for the on-board SCSI controller on the Motorola MVME147
-  single-board computer.
-
-SCC support for MVME147 serial ports
-CONFIG_MVME147_SCC
-  This is the driver for the serial ports on the Motorola MVME147
-  boards.  Everyone using one of these boards should say Y here.
-
-NCR53C710 SCSI driver for MVME16x
-CONFIG_MVME16x_SCSI
-  The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710
-  SCSI controller chip.  Almost everyone using one of these boards
-  will want to say Y to this question.
-
-NCR53C710 SCSI driver for BVME6000
-CONFIG_BVME6000_SCSI
-  The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710
-  SCSI controller chip.  Almost everyone using one of these boards
-  will want to say Y to this question.
-
-MVME147 (Lance) Ethernet support
-CONFIG_MVME147_NET
-  Support for the on-board Ethernet interface on the Motorola MVME147
-  single-board computer.  Say Y here to include the
-  driver for this chip in your kernel.   If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-MVME16x Ethernet support
-CONFIG_MVME16x_NET
-  This is the driver for the Ethernet interface on the Motorola
-  MVME162, 166, 167, 172 and 177 boards.  Say Y here to include the
-  driver for this chip in your kernel.   If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-BVME6000 Ethernet support
-CONFIG_BVME6000_NET
-  This is the driver for the Ethernet interface on BVME4000 and
-  BVME6000 VME boards.  Say Y here to include the driver for this chip
-  in your kernel.   If you want to compile it as a module, say M here
-  and read <file:Documentation/modules.txt>.
-
-CD2401 support for MVME166/7 serial ports
-CONFIG_SERIAL167
-  This is the driver for the serial ports on the Motorola MVME166,
-  167, and 172 boards.  Everyone using one of these boards should say
-  Y here.
-
-SCC support for MVME162 serial ports
-CONFIG_MVME162_SCC
-  This is the driver for the serial ports on the Motorola MVME162 and
-  172 boards.  Everyone using one of these boards should say Y here.
-
-SCC support for BVME6000 serial ports
-CONFIG_BVME6000_SCC
-  This is the driver for the serial ports on the BVME4000 and BVME6000
-  boards from BVM Ltd.  Everyone using one of these boards should say
-  Y here.
-
-7-Segment Display support
-CONFIG_DISPLAY7SEG
-  This is the driver for the 7-segment display and LED present on
-  Sun Microsystems CompactPCI models CP1400 and CP1500.
-
-  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 display7seg.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-  If you do not have a CompactPCI model CP1400 or CP1500, or
-  another UltraSPARC-IIi-cEngine boardset with a 7-segment display,
-  you should say N to this option.
-
-# Choice: cristype
-Etrax-100-LX-v1
-CONFIG_ETRAX100LX
-  Support version 1 of the Etrax 100LX.
-
-Etrax-100-LX-v2
-CONFIG_ETRAX100LX_V2
-  Support version 2 of the Etrax 100LX.
-
-Etrax-100-LX-for-xsim-simulator
-CONFIG_SVINTO_SIM
-  Support the xsim ETRAX Simulator.
-
-DRAM size (dec, in MB)
-CONFIG_ETRAX_DRAM_SIZE
-  Size of DRAM (decimal in MB) typically 2, 8 or 16.
-
-ETRAX Flash Memory configuration
-CONFIG_ETRAX_FLASH_BUSWIDTH
-  Width in bytes of the Flash bus (1, 2 or 4). Is usually 2.
-
-LED configuration on PA
-CONFIG_ETRAX_PA_LEDS
-  The Etrax network driver is responsible for flashing LED's when
-  packets arrive and are sent.  It uses macros defined in
-  <file:include/asm-cris/io.h>, and those macros are defined after what
-  YOU choose in this option.  The actual bits used are configured
-  separately.  Select this if the LEDs are on port PA.  Some products
-  put the leds on PB or a memory-mapped latch (CSP0) instead.
-
-LED configuration on PB
-CONFIG_ETRAX_PB_LEDS
-  The Etrax network driver is responsible for flashing LED's when
-  packets arrive and are sent.  It uses macros defined in
-  <file:include/asm-cris/io.h>, and those macros are defined after what
-  YOU choose in this option.  The actual bits used are configured
-  separately.  Select this if the LEDs are on port PB.  Some products
-  put the leds on PA or a memory-mapped latch (CSP0) instead.
-
-LED configuration on CSP0
-CONFIG_ETRAX_CSP0_LEDS
-  The Etrax network driver is responsible for flashing LED's when
-  packets arrive and are sent. It uses macros defined in
-  <file:include/asm-cris/io.h>, and those macros are defined after what
-  YOU choose in this option.  The actual bits used are configured
-  separately.  Select this if the LEDs are on a memory-mapped latch
-  using chip select CSP0, this is mapped at 0x90000000.
-  Some products put the leds on PA or PB instead.
-
-No LED at all
-CONFIG_ETRAX_NO_LEDS
-  Select this option if you don't have any LED at all.
-
-First green LED bit
-CONFIG_ETRAX_LED1G
-  Bit to use for the first green LED.
-  Most Axis products use bit 2 here.
-
-First red LED bit
-CONFIG_ETRAX_LED1R
-  Bit to use for the first red LED.
-  Most Axis products use bit 3 here.
-  For products with only one controllable LED,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Second green LED bit
-CONFIG_ETRAX_LED2G
-  Bit to use for the second green LED. The "Active" LED.
-  Most Axis products use bit 4 here.
-  For products with only one controllable LED,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Second red LED bit
-CONFIG_ETRAX_LED2R
-  Bit to use for the second red LED.
-  Most Axis products use bit 5 here.
-  For products with only one controllable LED,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Third green LED bit
-CONFIG_ETRAX_LED3G
-  Bit to use for the third green LED. The "Drive" LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Third red LED bit
-CONFIG_ETRAX_LED3R
-  Bit to use for the third red LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Fourth green LED bit
-CONFIG_ETRAX_LED4G
-  Bit to use for the fourth green LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Fourth red LED bit
-CONFIG_ETRAX_LED4R
-  Bit to use for the fourth red LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Fifth green LED bit
-CONFIG_ETRAX_LED5G
-  Bit to use for the fifth green LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Fifth red LED bit
-CONFIG_ETRAX_LED5R
-  Bit to use for the fifth red LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Sixth green LED bit
-CONFIG_ETRAX_LED6G
-  Bit to use for the sixth green LED. The "Drive" LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Sixth red LED bit
-CONFIG_ETRAX_LED6R
-  Bit to use for the sixth red LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Seventh green LED bit
-CONFIG_ETRAX_LED7G
-  Bit to use for the seventh green LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Seventh red LED bit
-CONFIG_ETRAX_LED7R
-  Bit to use for the seventh red LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Eighth yellow LED bit
-CONFIG_ETRAX_LED8Y
-  Bit to use for the eighth yellow LED. The "Drive" LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Ninth yellow LED bit
-CONFIG_ETRAX_LED9Y
-  Bit to use for the ninth yellow LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Tenth yellow LED bit
-CONFIG_ETRAX_LED10Y
-  Bit to use for the tenth yellow LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Eleventh yellow LED bit
-CONFIG_ETRAX_LED11Y
-  Bit to use for the eleventh yellow LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Twelfth red LED bit
-CONFIG_ETRAX_LED12R
-  Bit to use for the twelfth red LED.
-  For products with only one or two controllable LEDs,
-  set this to same as CONFIG_ETRAX_LED1G (normally 2).
-
-Flash LED off during activity
-CONFIG_ETRAX_LED_OFF_DURING_ACTIVITY
-  This option allows you to decide whether the network LED (and
-  Bluetooth LED in case you use Bluetooth) will be on or off when
-  the network is connected, and whether it should flash off or on
-  when there is activity. If you say y to this option the network
-  LED will be lit when there is a connection, and will flash off
-  when there is activity.
-
-PA button configuration
-CONFIG_ETRAX_PA_BUTTON_BITMASK
-  This is a bitmask with information about what bits on PA that
-  are used for buttons.
-  Most products has a so called TEST button on PA1, if that's true
-  use 02 here.
-  Use 00 if there are no buttons on PA.
-  If the bitmask is <> 00 a button driver will be included in the gpio
-  driver. Etrax general I/O support must be enabled.
-
-PA changeable direction bits
-CONFIG_ETRAX_PA_CHANGEABLE_DIR
-  This is a bitmask with information of what bits in PA that a user
-  can change direction on using ioctl's.
-  Bit set = changeable.
-  You probably want 00 here.
-
-PA changeable data bits
-CONFIG_ETRAX_PA_CHANGEABLE_BITS
-  This is a bitmask with information of what bits in PA that a user
-  can change change the value on using ioctl's.
-  Bit set = changeable.
-  You probably want 00 here.
-
-PA changeable direction bits
-CONFIG_ETRAX_PB_CHANGEABLE_DIR
-  This is a bitmask with information of what bits in PB that a user
-  can change direction on using ioctl's.
-  Bit set = changeable.
-  You probably want 00 here.
-
-PB changeable data bits
-CONFIG_ETRAX_PB_CHANGEABLE_BITS
-  This is a bitmask with information of what bits in PB that a user
-  can change the value on using ioctl's.
-  Bit set = changeable.
-  You probably want 00 here.
-
-Kernel debugger (kgdb)
-CONFIG_ETRAX_KGDB
-  The CRIS version of gdb can be used to remotely debug a running
-  Linux kernel via the serial debug port.  Provided you have gdb-cris
-  installed, run gdb-cris vmlinux, then type
-
-  (gdb) set remotebaud 115200           <- kgdb uses 115200 as default
-  (gdb) target remote /dev/ttyS0        <- maybe you use another port
-
-  This should connect you to your booted kernel (or boot it now if you
-  didn't before).  The kernel halts when it boots, waiting for gdb if
-  this option is turned on!
-
-Etrax bus waitstates
-CONFIG_ETRAX_DEF_R_WAITSTATES
-  Waitstates for SRAM, Flash and peripherials (not DRAM).  95f8 is a
-  good choice for most Axis products...
-
-Etrax bus configuration
-CONFIG_ETRAX_DEF_R_BUS_CONFIG
-  Assorted bits controlling write mode, DMA burst length etc.  104 is
-  a good choice for most Axis products...
-
-Etrax SDRAM configuration
-CONFIG_ETRAX_SDRAM
-  Enable this if you use SDRAM chips and configure
-  R_SDRAM_CONFIG and R_SDRAM_TIMING as well.
-
-DRAM size (dec, in MB)
-CONFIG_ETRAX_DEF_R_DRAM_CONFIG
-  The R_DRAM_CONFIG register specifies everything on how the DRAM
-  chips in the system are connected to the Etrax CPU.  This is
-  different depending on the manufacturer, chip type and number of
-  chips.  So this value often needs to be different for each Axis
-  product.
-
-Etrax DRAM timing
-CONFIG_ETRAX_DEF_R_DRAM_TIMING
-  Different DRAM chips have different speeds.  Current Axis products
-  use 50ns DRAM chips which can use the timing: 5611.
-
-Etrax SDRAM configuration
-CONFIG_ETRAX_DEF_R_SDRAM_CONFIG
-  The R_SDRAM_CONFIG register specifies everything on how the SDRAM
-  chips in the system are connected to the Etrax CPU.  This is
-  different depending on the manufacturer, chip type and number of
-  chips.  So this value often needs to be different for each Axis
-  product.
-
-Etrax SDRAM timing
-CONFIG_ETRAX_DEF_R_SDRAM_TIMING
-  Different SDRAM chips have different timing.
-
-Etrax General port A direction
-CONFIG_ETRAX_DEF_R_PORT_PA_DIR
-  Configures the direction of general port A bits.  1 is out, 0 is in.
-  This is often totally different depending on the product used.
-  There are some guidelines though - if you know that only LED's are
-  connected to port PA, then they are usually connected to bits 2-4
-  and you can therefore use 1c.  On other boards which don't have the
-  LED's at the general ports, these bits are used for all kinds of
-  stuff.  If you don't know what to use, it is always safe to put all
-  as inputs, although floating inputs isn't good.
-
-Etrax General port A data
-CONFIG_ETRAX_DEF_R_PORT_PA_DATA
-  Configures the initial data for the general port A bits.  Most
-  products should use 00 here.
-
-Etrax General port B config
-CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG
-  Configures the type of the general port B bits.  1 is chip select,
-  0 is port.  Most products should use 00 here.
-
-Etrax General port B direction
-CONFIG_ETRAX_DEF_R_PORT_PB_DIR
-  Configures the direction of general port B bits. 1 is out, 0 is in.
-  This is often totally different depending on the product used.  Bits
-  0 and 1 on port PB are usually used for I2C communication, but the
-  kernel I2C driver sets the appropriate directions itself so you
-  don't need to take that into consideration when setting this option.
-  If you don't know what to use, it is always safe to put all as
-  inputs.
-
-Etrax General port B data
-CONFIG_ETRAX_DEF_R_PORT_PB_DATA
-  Configures the initial data for the general port A bits.  Most
-  products should use FF here.
-
-Etrax General port device
-CONFIG_ETRAX_GPIO
-  Enables the Etrax general port device (major 120, minors 0 and 1).
-  You can use this driver to access the general port bits. It supports
-  these ioctl's:
-        #include <linux/etraxgpio.h>
-       fd = open("/dev/gpioa", O_RDWR); // or /dev/gpiob
-       ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETBITS), bits_to_set);
-       ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_CLRBITS), bits_to_clear);
-       val = ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_READBITS), NULL);
-  Remember that you need to setup the port directions appropriately in
-  the General configuration.
-
-Etrax parallel data support
-CONFIG_ETRAX_PARDATA
-  Adds support for writing data to the parallel port par0 of the ETRAX
-  100.  If you create a character special file with major number 126,
-  you can write to the data bits of par0.
-  Note: you need to disable Etrax100 parallel port support.
-
-Etrax parallel LCD (HD44780) Driver
-CONFIG_ETRAX_LCD_HD44780
-  Adds support for a HD44780 controlled LCD connected to the parallel
-  port par0 of the Etrax.
-
-Etrax Serial port ser0 support
-CONFIG_ETRAX_SERIAL
-  Enables the ETRAX 100 serial driver for ser0 (ttyS0)
-  You probably want this enabled.
-
-/proc/serial entry
-CONFIG_ETRAX_SERIAL_PROC_ENTRY
-  Enables /proc/serial entry where errors and statistics can be
-  viewed.  CONFIG_PROC_FS must also be set for this to work.
-
-Etrax Serial port fast flush of DMA using fast timer API
-CONFIG_ETRAX_SERIAL_FAST_TIMER
-  Select this to have the serial DMAs flushed at a higher rate than
-  normally, possible by using the fast timer API, the timeout is
-  approx. 4 character times.
-  If unsure, say N.
-
-Etrax Serial port fast flush of DMA
-CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
-  Select this to have the serial DMAs flushed at a higher rate than
-  normally possible through a fast timer interrupt (currently at
-  15360 Hz).
-  If unsure, say N.
-
-Etrax Serial port receive flush timeout
-CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
-  Number of timer ticks between flush of receive fifo (1 tick = 10ms).
-  Try 0-3 for low latency applications.  Approx 5 for high load
-  applications (e.g. PPP).  Maybe this should be more adaptive some
-  day...
-
-Etrax Serial port ser0 DTR, RI, DSR and CD support on PB
-CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB
-  Enables the status and control signals DTR, RI, DSR and CD on PB for
-  ser0.
-
-Serial port 1 enabled
-CONFIG_ETRAX_SERIAL_PORT1
-  Enables the ETRAX 100 serial driver for ser1 (ttyS1).
-
-Etrax Serial port ser1 DTR, RI, DSR and CD support on PB
-CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB
-  Enables the status and control signals DTR, RI, DSR and CD on PB for
-  ser1.
-
-Serial port 2 enabled
-CONFIG_ETRAX_SERIAL_PORT2
-  Enables the ETRAX 100 serial driver for ser2 (ttyS2).
-
-Etrax Serial port ser2 DTR, RI, DSR and CD support on PA
-CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA
-  Enables the status and control signals DTR, RI, DSR and CD on PA for
-  ser2.
-
-Serial port 3 enabled
-CONFIG_ETRAX_SERIAL_PORT3
-  Enables the ETRAX 100 serial driver for ser3 (ttyS3).
-
-Etrax100 RS-485 support
-CONFIG_ETRAX_RS485
-  Enables support for RS-485 serial communication.  For a primer on
-  RS-485, see <http://www.hw.cz/english/docs/rs485/rs485.html>.
-
-Etrax100 RS-485 mode on PA
-CONFIG_ETRAX_RS485_ON_PA
-  Control Driver Output Enable on RS485 tranceiver using a pin on PA
-  port:
-          Axis 2400/2401 uses PA 3.
-
-Etrax100 RS-485 mode on PA bit
-CONFIG_ETRAX_RS485_ON_PA_BIT
-  Control Driver Output Enable on RS485 tranceiver using a this bit
-  on PA port.
-
-Ser0 DTR on PB bit
-CONFIG_ETRAX_SER0_DTR_ON_PB_BIT
-  Specify the pin of the PB port to carry the DTR signal for serial
-  port 0.
-
-Ser0 RI  on PB bit
-CONFIG_ETRAX_SER0_RI_ON_PB_BIT
-  Specify the pin of the PB port to carry the RI signal for serial
-  port 0.
-
-Ser0 DSR on PB bit
-CONFIG_ETRAX_SER0_DSR_ON_PB_BIT
-  Specify the pin of the PB port to carry the DSR signal for serial
-  port 0.
-
-Ser0 CD  on PB bit
-CONFIG_ETRAX_SER0_CD_ON_PB_BIT
-  Specify the pin of the PB port to carry the CD signal for serial
-  port 0.
-
-Ser1 DTR on PB bit
-CONFIG_ETRAX_SER1_DTR_ON_PB_BIT
-  Specify the pin of the PB port to carry the DTR signal for serial
-  port 1.
-
-Ser1 RI  on PB bit
-CONFIG_ETRAX_SER1_RI_ON_PB_BIT
-  Specify the pin of the PB port to carry the RI signal for serial
-  port 1.
-
-Ser1 DSR on PB bit
-CONFIG_ETRAX_SER1_DSR_ON_PB_BIT
-  Specify the pin of the PB port to carry the DSR signal for serial
-  port 1.
-
-Ser1 CD  on PB bit
-CONFIG_ETRAX_SER1_CD_ON_PB_BIT
-  Specify the pin of the PB port to carry the CD signal for serial
-  port 1.
-
-Ser2 DTR on PA bit
-CONFIG_ETRAX_SER2_DTR_ON_PA_BIT
-  Specify the pin of the PA port to carry the DTR signal for serial
-  port 2.
-
-Ser2 RI  on PA bit
-CONFIG_ETRAX_SER2_RI_ON_PA_BIT
-  Specify the pin of the PA port to carry the RI signal for serial
-  port 2.
-
-Ser2 DSR on PA bit
-CONFIG_ETRAX_SER2_DSR_ON_PA_BIT
-  Specify the pin of the PA port to carry the DTR signal for serial
-  port 2.
-
-Ser2 CD  on PA bit
-CONFIG_ETRAX_SER2_CD_ON_PA_BIT
-  Specify the pin of the PA port to carry the CD signal for serial
-  port 2.
-
-Etrax100 RS-485 disable receiver
-CONFIG_ETRAX_RS485_DISABLE_RECEIVER
-  It's necessary to disable the serial receiver to avoid serial
-  loopback.  Not all products are able to do this in software only.
-  Axis 2400/2401 must disable receiver.
-
-Etrax100 I2C Support
-CONFIG_ETRAX_I2C
-  Enables an I2C driver on PB0 and PB1 on ETRAX100.
-  EXAMPLE usage:
-        i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val);
-       ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg);
-       i2c_arg = I2C_READARG(STA013_READ_ADDR, reg);
-       val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg);
-
-Etrax100 I2C configuration
-CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
-  Select whether to use the special I2C mode in the PB I/O register or
-  not.  This option needs to be selected in order to use some drivers
-  that access the I2C I/O pins directly instead of going through the
-  I2C driver, like the DS1302 realtime-clock driver.  If you are
-  uncertain, choose Y here.
-
-Etrax100 I2C EEPROM (NVRAM) support
-CONFIG_ETRAX_I2C_EEPROM
-  Enables I2C EEPROM (non-volatile RAM) on PB0 and PB1 using the I2C
-  driver.  Select size option: Probed, 2k, 8k, 16k.
-  (Probing works for 2k and 8k but not that well for 16k)
-
-Etrax100 I2C EEPROM (NVRAM) size/16kB
-CONFIG_ETRAX_I2C_EEPROM_16KB
-  Use a 16kB EEPROM.
-
-Etrax100 I2C EEPROM (NVRAM) size/2kB
-CONFIG_ETRAX_I2C_EEPROM_2KB
-  Use a 2kB EEPROM.
-
-Etrax100 I2C EEPROM (NVRAM) size/8kB
-CONFIG_ETRAX_I2C_EEPROM_8KB
-  Use a 8kB EEPROM.
-
-Etrax100 I2C EEPROM (NVRAM) size/probe
-CONFIG_ETRAX_I2C_EEPROM_PROBE
-  Specifies size or auto probe of the EEPROM size.
-  Options: Probed, 2k, 8k, 16k.
-  (Probing works for 2k and 8k but not that well for 16k)
-
-Etrax DS1302 Real-Time Clock driver
-CONFIG_ETRAX_DS1302
-  Enables the driver for the DS1302 Real-Time Clock battery-backed
-  chip on some products.  The kernel reads the time when booting, and
-  the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a
-  rtc_time struct (see <file:include/asm-cris/rtc.h>) on the /dev/rtc
-  device, major 121.  You can check the time with cat /proc/rtc, but
-  normal time reading should be done using libc function time and
-  friends.
-
-Etrax DS1302 RST on the Generic Port
-CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
-  If your product has the RST signal line for the DS1302 RTC on the
-  Generic Port then say Y here, otherwise leave it as N in which
-  case the RST signal line is assumed to be connected to Port PB
-  (just like the SCL and SDA lines).
-
-Etrax DS1302 RST bit number
-CONFIG_ETRAX_DS1302_RSTBIT
-  This is the bit number for the RST signal line of the DS1302 RTC on
-  the selected port. If you have selected the generic port then it
-  should be bit 27, otherwise your best bet is bit 5.
-
-Etrax DS1302 SCL bit number
-CONFIG_ETRAX_DS1302_SCLBIT
-  This is the bit number for the SCL signal line of the DS1302 RTC on
-  Port PB. This is probably best left at 3.
-
-Etrax DS1302 SDA bit number
-CONFIG_ETRAX_DS1302_SDABIT
-  This is the bit number for the SDA signal line of the DS1302 RTC on
-  Port PB. This is probably best left at 2.
-
-Etrax 100 IDE Reset
-CONFIG_ETRAX_IDE_CSP0_8_RESET
-  Configures the pin used to reset the IDE bus.
-
-Etrax 100 IDE Reset
-CONFIG_ETRAX_IDE_CSPE1_16_RESET
-  Configures the pin used to reset the IDE bus.
-
-Etrax 100 ATA/IDE support
-CONFIG_ETRAX_IDE_DELAY
-  Sets the time to wait for disks to regain consciousness after reset.
-
-Etrax 100 IDE Reset
-CONFIG_ETRAX_IDE_G27_RESET
-  Configures the pin used to reset the IDE bus.
-
-IDE reset on PB Bit 7
-CONFIG_ETRAX_IDE_PB7_RESET
-  Configures the pin used to reset the IDE bus.
-
-USB 1.1 host
-CONFIG_ETRAX_USB_HOST
-  This option enables the host functionality of the ETRAX 100LX
-  built-in USB controller. In host mode the controller is designed
-  for CTRL and BULK traffic only, INTR traffic may work as well
-  however (depending on the requirements of timeliness).
-
-USB 1.1 host port 1 enabled
-CONFIG_ETRAX_USB_HOST_PORT1
-  This option enables port 1 of the ETRAX 100LX USB root hub (RH).
-
-USB 1.1 host port 2 enabled
-CONFIG_ETRAX_USB_HOST_PORT2
-  This option enables port 2 of the ETRAX 100LX USB root hub (RH).
-
-ETRAX 100LX 10/100Mbit Ethernet controller
-CONFIG_ETRAX_ETHERNET
-  This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet
-  controller.
-
-ETRAX 100LX Synchronous serial ports
-CONFIG_ETRAX_SYNCHRONOUS_SERIAL
-  This option enables support for the ETRAX 100LX built-in
-  synchronous serial ports. These ports are used for continuous
-  streamed data like audio. The default setting is compatible
-  with the STA 013 MP3 decoder, but can easily be tuned to fit
-  any other audio encoder/decoder and SPI.
-
-ETRAX 100LX Synchronous serial port 0 enabled
-CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0
-  Enables the ETRAX 100LX synchronous serial port 0 (syncser0).
-
-ETRAX 100LX Synchronous serial port 0 uses DMA
-CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA
-  Makes synchronous serial port 0 use DMA.
-
-ETRAX 100LX Synchronous serial port 1 enabled
-CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1
-  Enables the ETRAX 100LX synchronous serial port 1 (syncser1).
-
-ETRAX 100LX Synchronous serial port 1 uses DMA
-CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA
-  Makes synchronous serial port 1 use DMA.
-
-Delay for drives to regain consciousness
-CONFIG_IDE_DELAY
-  Number of seconds to wait for IDE drives to spin up after an IDE
-  reset.
-
-ARTPEC-1 support
-CONFIG_JULIETTE
-  The ARTPEC-1 is a video-compression chip used in the AXIS 2100
-  network camera, which is built around an ETRAX-100 board.  With this
-  option selected, the ETRAX kernel configures a DMA channel at boot
-  time to talk to the chip.
-
-Axis flash-map support
-CONFIG_ETRAX_AXISFLASHMAP
-  This option enables MTD mapping of flash devices.  Needed to use
-  flash memories.  If unsure, say Y.
-
-Byte-offset of partition table sector
-CONFIG_ETRAX_PTABLE_SECTOR
-  Byte-offset of the partition table in the first flash chip.
-  The default value is 64kB and should not be changed unless
-  you know exactly what you are doing. The only valid reason
-  for changing this is when the flash block size is bigger
-  than 64kB (e.g. when using two parallel 16 bit flashes).
-
-Enable Etrax100 watchdog
-CONFIG_ETRAX_WATCHDOG
-  Enable the built-in watchdog timer support on Etrax100 embedded
-  network computers.
-
-# Choice: crisdebug
-Serial-0
-CONFIG_ETRAX_DEBUG_PORT0
-  Choose a serial port for the ETRAX debug console.  Default to
-  port 0.
-
-Etrax debug port on ser1
-CONFIG_ETRAX_DEBUG_PORT1
-  Use serial port 1 for the console.
-
-Etrax debug port on ser2
-CONFIG_ETRAX_DEBUG_PORT2
-  Use serial port 2 for the console.
-
-Etrax debug port on ser3
-CONFIG_ETRAX_DEBUG_PORT3
-  Use serial port 3 for the console.
-
-No Etrax debug port
-CONFIG_ETRAX_DEBUG_PORT_NULL
-  Disable serial-port debugging.
-
-Parallel port support
-CONFIG_ETRAX_PARPORT
-  Say Y here to enable the ETRAX on-board parallel ports.
-
-Parallel port 0 enabled
-CONFIG_ETRAX_PARALLEL_PORT0
-  Say Y here to enable parallel port 0.
-
-Parallel port 1 enabled
-CONFIG_ETRAX_PARALLEL_PORT1
-  Say Y here to enable parallel port 1.
-
-# Choice: crisrescue
-Select a product rescue port
-CONFIG_ETRAX_RESCUE_SER0
-  Select one of the four serial ports as a rescue port.  The default
-  is port 0.
-
-Serial-1
-CONFIG_ETRAX_RESCUE_SER1
-  Use serial port 1 as the rescue port.
-
-Serial-2
-CONFIG_ETRAX_RESCUE_SER2
-  Use serial port 2 as the rescue port.
-
-Serial-3
-CONFIG_ETRAX_RESCUE_SER3
-  Use serial port 3 as the rescue port.
-
-RIO Hardware Watchdog support
-CONFIG_WATCHDOG_RIO
-  Say Y here to support the hardware watchdog capability on Sun RIO
-  machines.  The watchdog timeout period is normally one minute but
-  can be changed with a boot-time parameter.
-
-CP1XXX Hardware Watchdog support
-CONFIG_WATCHDOG_CP1XXX
-  This is the driver for the hardware watchdog timers present on
-  Sun Microsystems CompactPCI models CP1400 and CP1500.
-
-  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 cpwatchdog.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-  If you do not have a CompactPCI model CP1400 or CP1500, or
-  another UltraSPARC-IIi-cEngine boardset with hardware watchdog,
-  you should say N to this option.
-
-# Choice: ia64type
-Itanium
-CONFIG_ITANIUM
-  Select your IA64 processor type.  The default is Intel Itanium.
-
-McKinley
-CONFIG_MCKINLEY
-  Select this to configure for a McKinley processor.
-
-# Choice: ia64system
-IA-64 system type
-CONFIG_IA64_GENERIC
-  This selects the system type of your hardware.  A "generic" kernel
-  will run on any supported IA-64 system.  However, if you configure
-  a kernel for your specific system, it will be faster and smaller.
-
-  To find out what type of IA-64 system you have, you may want to
-  check the IA-64 Linux web site at <http://www.linux-ia64.org/>.
-  As of the time of this writing, most hardware is DIG compliant,
-  so the "DIG-compliant" option is usually the right choice.
-
-  HP-simulator   For the HP simulator
-                 (<http://software.hp.com/ia64linux/>).
-  SN1-simulator  For the SGI SN1 simulator.
-  DIG-compliant  For DIG ("Developer's Interface Guide") compliant
-                 system.
-
-  If you don't know what to do, choose "generic".
-
-# Choice: pagesize
-Kernel page size
-CONFIG_IA64_PAGE_SIZE_4KB
-  This lets you select the page size of the kernel.  For best IA-64
-  performance, a page size of 8KB or 16KB is recommended.  For best
-  IA-32 compatibility, a page size of 4KB should be selected (the vast
-  majority of IA-32 binaries work perfectly fine with a larger page
-  size).  For Itanium systems, do NOT chose a page size larger than
-  16KB.
-
-  4KB                For best IA-32 compatibility
-  8KB                For best IA-64 performance
-  16KB               For best IA-64 performance
-  64KB               Not for Itanium.
-
-  If you don't know what to do, choose 8KB.
-
-Enable Itanium A-step specific code
-CONFIG_ITANIUM_ASTEP_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with an A-step CPU.  You have an A-step CPU if the "revision" field
-  in /proc/cpuinfo is 0.
-
-Enable Itanium B-step specific code
-CONFIG_ITANIUM_BSTEP_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with a B-step CPU.  You have a B-step CPU if the "revision" field in
-  /proc/cpuinfo has a value in the range from 1 to 4.
-
-Enable Itanium B0-step specific code
-CONFIG_ITANIUM_B0_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with a B0-step CPU.  You have a B0-step CPU if the "revision" field
-  in /proc/cpuinfo is 1.
-
-Enable Itanium C-step specific code
-CONFIG_ITANIUM_CSTEP_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with a C-step CPU.  You have a C-step CPU if the "revision" field in
-  /proc/cpuinfo is in the range of 5 to 8.
-
-Enable Itanium B1-step specific code
-CONFIG_ITANIUM_B1_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with a B1-step CPU.  You have a B1-step CPU if the "revision" field
-  in /proc/cpuinfo is 2.
-
-Enable Itanium B2-step specific code
-CONFIG_ITANIUM_B2_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with a B2-step CPU.  You have a B2-step CPU if the "revision" field
-  in /proc/cpuinfo is 3.
-
-Enable Itanium C0-step specific code
-CONFIG_ITANIUM_C0_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with a C0-step CPU.  You have a C0-step CPU if the "revision" field
-  in /proc/cpuinfo is 5.
-
-Force interrupt redirection
-CONFIG_IA64_HAVE_IRQREDIR
-  Select this option if you know that your system has the ability to
-  redirect interrupts to different CPUs.  Select N here if you're
-  unsure.
-
-Enable IA-64 Machine Check Abort
-CONFIG_IA64_MCA
-  Say Y here to enable machine check support for IA-64.  If you're
-  unsure, answer Y.
-
-Disable IA-64 Virtual Hash Page Table
-CONFIG_DISABLE_VHPT
-  The Virtual Hash Page Table (VHPT) enhances virtual address
-  translation performance.  Normally you want the VHPT active but you
-  can select this option to disable the VHPT for debugging.  If you're
-  unsure, answer N.
-
-Enable McKinley A-step specific code
-CONFIG_MCKINLEY_ASTEP_SPECIFIC
-  Select this option to build a kernel for an IA64 McKinley system
-  with any A-stepping CPU.
-
-Enable McKinley A0/A1-step specific code
-CONFIG_MCKINLEY_A0_SPECIFIC
-  Select this option to build a kernel for an IA64 McKinley system
-  with an A0 or A1 stepping CPU.
-
-Turn on compare-and-exchange bug checking (slow!)
-CONFIG_IA64_DEBUG_CMPXCHG
-  Selecting this option turns on bug checking for the IA64
-  compare-and-exchange instructions.  This is slow!  Itaniums
-  from step B3 or later don't have this problem. If you're unsure,
-  select N.
-
-IA64 IRQ bug checking
-CONFIG_IA64_DEBUG_IRQ
-  Selecting this option turns on bug checking for the IA64 irq_save
-  and restore instructions.  It's useful for tracking down spinlock
-  problems, but slow!  If you're unsure, select N.
-
-Early printk support (requires VGA!)
-CONFIG_IA64_EARLY_PRINTK
-  Selecting this option uses the VGA screen for printk() output before
-  the consoles are initialised.  It is useful for debugging problems
-  early in the boot process, but only if you have a VGA screen
-  attached.  If you're unsure, select N.
-
-Print possible IA64 hazards to console
-CONFIG_IA64_PRINT_HAZARDS
-  Selecting this option prints more information for Illegal Dependency
-  Faults, that is, for Read after Write, Write after Write or Write
-  after Read violations.  This option is ignored if you are compiling
-  for an Itanium A step processor (CONFIG_ITANIUM_ASTEP_SPECIFIC).  If
-  you're unsure, select Y.
-
-Performance monitor support
-CONFIG_PERFMON
-  Selects whether support for the IA-64 performance monitor hardware
-  is included in the kernel.  This makes some kernel data-structures a
-  little bigger and slows down execution a bit, but it is still
-  usually a good idea to turn this on.  If you're unsure, say N.
-
-/proc/pal support
-CONFIG_IA64_PALINFO
-  If you say Y here, you are able to get PAL (Processor Abstraction
-  Layer) information in /proc/pal.  This contains useful information
-  about the processors in your systems, such as cache and TLB sizes
-  and the PAL firmware version in use.
-
-  To use this option, you have to check that the "/proc file system
-  support" (CONFIG_PROC_FS) is enabled, too.
-
-Kernel support for IA-32 emulation
-CONFIG_IA32_SUPPORT
-  IA64 processors can run IA32 (that is, x86) binaries by emulating
-  the IA32 instruction set.  Say Y here to build in kernel support for
-  this.  If in doubt, say Y.
-
-/proc/efi/vars support
-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.
-
-  To use this option, you have to check that the "/proc file system
-  support" (CONFIG_PROC_FS) is enabled, too.
-
-Directly Connected Compact Flash support
-CONFIG_CF_ENABLER
-  Compact Flash is a small, removable mass storage device introduced
-  in 1994 originally as a PCMCIA device.  If you say `Y' here, you
-  compile in support for Compact Flash devices directly connected to
-  a SuperH processor.  A Compact Flash FAQ is available at
-  <http://www.compactflash.org/faqs/faq.htm>.
-
-  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, select 'N'.
-
-Kernel debugging
-CONFIG_DEBUG_KERNEL
-  Say Y here if you are developing drivers or trying to debug and
-  identify kernel problems.
-
-Debug memory allocations
-CONFIG_DEBUG_SLAB
-  Say Y here to have the kernel do limited verification on memory
-  allocation as well as poisoning memory on free to catch use of freed
-  memory.
-
-Memory mapped I/O debug support
-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()
-  calls are forgotten.  Memory mapped I/O will go through an extra
-  check to catch access to unmapped ISA addresses, an access method
-  that can still be used by old drivers that are being ported from
-  2.0/2.2.
-
-Spinlock debugging
-CONFIG_DEBUG_SPINLOCK
-  Say Y here and build SMP to catch missing spinlock initialization
-  and certain other kinds of spinlock errors commonly made.  This is
-  best used in conjunction with the NMI watchdog so that spinlock
-  deadlocks are also debuggable.
-
-Verbose BUG() reporting (adds 70K)
-CONFIG_DEBUG_BUGVERBOSE
-  Say Y here to make BUG() panics output the file name and line number
-  of the BUG call as well as the EIP and oops trace.  This aids
-  debugging but costs about 70-100K of memory.
-
-Include kgdb kernel debugger
-CONFIG_KGDB
-  Include in-kernel hooks for kgdb, the Linux kernel source level
-  debugger.  This project has a web page at
-  <http://kgdb.sourceforge.net/>.
-
-Include xmon kernel debugger
-CONFIG_XMON
-  Include in-kernel hooks for the xmon kernel monitor/debugger
-  supported by the PPC port.
-
-Include kgdb kernel debugger
-CONFIG_KWDB
-  Include in-kernel hooks for kdb, the source level debugger for the
-  PA-RISC port.
-
-IODC console
-CONFIG_IODC_CONSOLE
-  IODC is HP's pre-PCI standard for device identification (a la PCI
-  vendor, device IDs), detection, configuration, initialization and so
-  on.  It also can provide firmware function to do the actual IO,
-  which are slow, not really defined for runtime usage and generally
-  not desirable.
-
-  See <http://www.linuxhq.com/kernel/v2.4/doc/parisc/IODC.txt.html>
-  for the gory details.
-
-  Say Y here to enable use of the IODC firmware functions for console
-  I/O.  This is only useful on older PA-RISC workstations.  If in
-  doubt, say Y.
-
-U2/Uturn I/O MMU
-CONFIG_IOMMU_CCIO
-  Say Y here to enable DMA management routines for the first
-  generation of PA-RISC cache-coherent machines.  Programs the
-  U2/Uturn chip in "Virtual Mode" and use the I/O MMU.
-
-LBA/Elroy PCI support
-CONFIG_PCI_LBA
-  Say Y here to give the PA-RISC kernel access to PCI configuration
-  and IO-port space on PA-RISC workstations equipped with a Lower Bus
-  Adapter (LBA).  This includes A, B, C, J, L, and N-class machines
-  with 4-digit model numbers, also the A300.
-
-LASI I/O support
-CONFIG_GSC_LASI
-  Say Y here to directly support the LASI controller chip found on
-  PA-RISC workstations.  Linux-oriented documentation for this chip
-  can be found at <http://www.parisc-linux.org/documentation/>.
-
-LASI/ASP builtin parallel-port
-CONFIG_PARPORT_GSC
-  Say Y here to build in low-level parallel-support for PC-style
-  hardware integrated in the LASI-Controller (on the GSC Bus) for
-  HP-PARISC workstations.
-
-Fujitsu Vendor Specific
-CONFIG_BLK_DEV_IDEDISK_FUJITSU
-  Enable vendor-specific code for Fujitsu IDE disks.  Unless you are
-  the IDE maintainer, you probably do not want to mess with this.
-
-IBM Vendor Specific
-CONFIG_BLK_DEV_IDEDISK_IBM
-  Enable vendor-specific code for IBM IDE disks.  Unless you are the
-  IDE maintainer, you probably do not want to mess with this.
-
-Maxtor Vendor Specific
-CONFIG_BLK_DEV_IDEDISK_MAXTOR
-  Enable vendor-specific code for Maxtor IDE disks.  Unless you are
-  the IDE maintainer, you probably do not want to mess with this.
-
-Quantum Vendor Specific
-CONFIG_BLK_DEV_IDEDISK_QUANTUM
-  Enable vendor-specific code for Quantum IDE disks.  Unless you are
-  the IDE maintainer, you probably do not want to mess with this.
-
-Seagate Vendor Specific
-CONFIG_BLK_DEV_IDEDISK_SEAGATE
-  Enable vendor-specific code for Seagate IDE disks.  Unless you are
-  the IDE maintainer, you probably do not want to mess with this.
-
-Western Digital Vendor Specific
-CONFIG_BLK_DEV_IDEDISK_WD
-  Enable vendor-specific code for Western Digital IDE disks.  Unless
-  you are the IDE maintainer, you probably do not want to mess with
-  this.
-
-TiVo Commerial Application Specific
-CONFIG_BLK_DEV_TIVO
-  Enable vendor-specific code for TiVo IDE disks.  Unless you are the
-  IDE maintainer, you probably do not want to mess with this.
-
-# Choice: superhsys
-Generic
-CONFIG_SH_GENERIC
-  Select Generic if configuring for a generic SuperH system.
-  The "generic" option compiles in *all* the possible hardware
-  support and relies on the sh_mv= kernel commandline option to choose
-  at runtime which routines to use.  "MV" stands for "machine vector";
-  each of the machines below is described by a machine vector.
-
-  Select SolutionEngine if configuring for a Hitachi SH7709
-  or SH7750/7750S evalutation board.
-
-  Select Overdrive if configuring for a ST407750 Overdrive board.
-  More information at
-  <http://linuxsh.sourceforge.net/docs/7750overdrive.php3>.
-
-  Select HP620 if configuring for a HP Jornada HP620.
-  More information (hardware only) at
-  <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/>.
-
-  Select HP690 if configuring for a HP Jornada HP690.
-  More information (hardware only) at
-  <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/>.
-
-  Select EC3104 if configuring for a system with an Eclipse
-  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
-  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
-  or SH7750 evalutation board.
-
-7751 SolutionEngine
-CONFIG_SH_7751_SOLUTION_ENGINE
-  Select 7751 SolutionEngine if configuring for a Hitachi SH7751
-  evalutation board.
-
-Overdrive
-CONFIG_SH_OVERDRIVE
-  Select Overdrive if configuring for a ST407750 Overdrive board.
-  More information at
-  <http://linuxsh.sourceforge.net/docs/7750overdrive.php3>.
-
-HP620
-CONFIG_SH_HP620
-  Select HP620 if configuring for a HP jornada HP620.
-  More information (hardware only) at
-  <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/>.
-
-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/>.
-
-CqREEK
-CONFIG_SH_CQREEK
-  Select CqREEK if configuring for a CqREEK SH7708 or SH7750.
-  More information at
-  <http://sources.redhat.com/ecos/hardware.html#SuperH>.
-
-DMIDA
-CONFIG_SH_DMIDA
-  Select DMIDA if configuring for a DataMyte 4000 Industrial
-  Digital Assistant. More information at <http://www.dmida.com/>.
-
-EC3104
-CONFIG_SH_EC3104
-  Select EC3104 if configuring for a system with an Eclipse
-  International EC3104 chip, e.g. the Harris AD2000.
-
-Dreamcast
-CONFIG_SH_DREAMCAST
-  Select Dreamcast if configuring for a SEGA Dreamcast.
-  More information at
-  <http://www.m17n.org/linux-sh/dreamcast/>.  There is a
-  Dreamcast project is at <http://linuxdc.sourceforge.net/>.
-
-BareCPU
-CONFIG_SH_UNKNOWN
-  "Bare CPU" aka "unknown" means an SH-based system which is not one
-  of the specific ones mentioned above, which means you need to enter
-  all sorts of stuff like CONFIG_MEMORY_START because the config
-  system doesn't already know what it is.  You get a machine vector
-  without any platform-specific code in it, so things like the RTC may
-  not work.
-
-  This option is for the early stages of porting to a new machine.
-
-# Choice: superhtype
-SH7707
-CONFIG_CPU_SUBTYPE_SH7707
-  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.
-
-  Select SH7708 if you have a  60 Mhz SH-3 HD6417708S or
-                if you have a 100 Mhz SH-3 HD6417708R CPU.
-
-  Select SH7709 if you have a  80 Mhz SH-3 HD6417709 CPU.
-
-  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
-                if you have a 100 Mhz SH-3 HD6417708R CPU.
-
-SH7709
-CONFIG_CPU_SUBTYPE_SH7709
-  Select SH7709 if you have a  80 Mhz SH-3 HD6417709 CPU.
-
-SH7750
-CONFIG_CPU_SUBTYPE_SH7750
-  Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
-
-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.  
-
-  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.
-
-  Tweak this only when porting to a new machine which is not already
-  known by the config system.  Changing it from the known correct
-  value on any of the known systems will only lead to disaster.
-
-Hitachi HD64461 companion chip support
-CONFIG_HD64461
-  The Hitachi HD64461 provides an interface for
-  the SH7709 CPU, supporting a LCD controller,
-  CRT color controller, IrDA up to 4 Mbps, and a
-  PCMCIA controller supporting 2 slots.
-
-  More information is available at
-  <http://semiconductor.hitachi.com/windowsce/superh/sld013.htm>.
-
-  Say Y if you want support for the HD64461.
-  Otherwise, say N.
-
-HD64461 PCMCIA enabler
-CONFIG_HD64461_ENABLER
-  Say Y here if you want to enable PCMCIA support
-  via the HD64461 companion chip.
-  Otherwise, say N.
-
-HD64461 virtualized IRQ number
-CONFIG_HD64461_IRQ
-  The default setting of the HD64461 IRQ is 36.
-
-  Do not change this unless you know what you are doing.
-
-Hitachi HD64465 companion chip support
-CONFIG_HD64465
-  The Hitachi HD64465 provides an interface for
-  the SH7750 CPU, supporting a LCD controller,
-  CRT color controller, IrDA, USB, PCMCIA,
-  keyboard controller, and a printer interface.
-
-  More information is available at
-  <http://global.hitachi.com/New/cnews/E/1998/981019B.html>.
-
-  Say Y if you want support for the HD64465.
-  Otherwise, say N.
-
-HD64465 virtualized IRQ number
-CONFIG_HD64465_IRQ
-  The default setting of the HD64465 IRQ is 5.
-
-  Do not change this unless you know what you are doing.
-
-HD64465 start address
-CONFIG_HD64465_IOBASE
-  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 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. 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 (Serial
-  Communication Interface with FIFO) which are built into the Hitachi
-  SuperH processor.  The option provides 1 to 3 (depending
-  on the CPU model) standard Linux tty devices, /dev/ttySC[012]; one
-  of these is normally used as the system console.
-
-  If in doubt, press "y".
-
-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 (including calls to read and
-  write characters to a system console, get a MAC address from an
-  on-board Ethernet interface, and shut down the hardware).  Note this
-  does not work with machines with an existing operating system in
-  mask ROM and no flash (WindowsCE machines fall in this category).
-  If unsure, say N.
-
-GDB Stub kernel debug
-CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
-  If you say Y here, it will be possible to remotely debug the SuperH
-  kernel using gdb, if you have the gdb-sh-stub package from
-  www.m17n.org (or any conforming standard LinuxSH BIOS) in FLASH or
-  EPROM.  This enlarges your kernel image disk size by several
-  megabytes but allows you to load, run and debug the kernel image
-  remotely using gdb.  This is only useful for kernel hackers.  If
-  unsure, say N.
-
-Console output to GDB
-CONFIG_GDB_CONSOLE
-  If you are using GDB for remote debugging over a serial port and
-  would like kernel messages to be formatted into GDB $O packets so
-  that GDB prints them as program output, say 'Y'.
-
-CRC32 functions
-CONFIG_CRC32
-  This option is provided for the case where no in-kernel-tree
-  modules require CRC32 functions, but a module built outside the
-  kernel tree does. Such modules that use library CRC32 functions
-  require M here.
-
-#
-# A couple of things I keep forgetting:
-#   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet,
-#               Intel, IRQ, ISDN, Linux, MSDOS, NetWare, NetWinder,
-#               NFS, PCI, SCSI, SPARC
-#   two words:  file system, hard drive, hard disk, home page,
-#               user space, web site
-#   other:      it's safe to save; daemon; use --, not - or ---;
-#               use KB for 1024 bytes, not kB or K.
-#
-#
-# This is used by Emacs' spell checker ispell.el:
-#
-# 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
-# LocalWords:  ISA EISA Microchannel VESA BIOSes IPC SYSVIPC ipc Ctrl dmesg hlt
-# LocalWords:  BINFMT Linkable http ac uk jo html GCC SPARC AVANTI CABRIOLET EB
-# LocalWords:  netscape gcc LD CC toplevel MODVERSIONS insmod rmmod modprobe IP
-# LocalWords:  genksyms INET loopback gatewaying Ethernet PPP ARP Arp MEMSIZE
-# LocalWords:  howto multicasting MULTICAST MBONE firewalling ipfw ACCT resp ip
-# LocalWords:  proc acct IPIP encapsulator decapsulator klogd RARP EXT PS
-# LocalWords:  telnetting subnetted NAGLE rlogin NOSR ttyS TGA techinfo mbone nl
-# LocalWords:  Mb SKB IPX Novell dosemu DDP ATALK vmalloc visar ehome
-# LocalWords:  SD CHR scsi thingy SG CD LUNs LUN jukebox Adaptec BusLogic EATA
-# LocalWords:  buslogic DMA DPT ATT eata dma PIO UltraStor fdomain umsdos ext
-# LocalWords:  QLOGIC qlogic TMC seagate Trantor ultrastor FASST wd NETDEVICES
-# LocalWords:  unix BBS linux CSLIP PLIP Kirch's LDP CSlip SL SCC IRQ csustan
-# LocalWords:  Turbo Laplink plip NCSA port's ReQuest IRQs EQL SMC AMD PCnet NE
-# LocalWords:  COM ELPLUS Com EtherLinkIII VLB Arcnet Cabletron DEPCA DE carlos
-# LocalWords:  depca EtherWorks EWRK ewrk SEEQ EtherExpress EEXPRESS NI xxx dia
-# LocalWords:  EtherExpress WaveLAN wavelan PCLAN HPLAN VG SK Ansel Xen de ZNET
-# LocalWords:  PCMCIA cb stanford LAN TEC RealTek ATP atp DLINK NetTools VISWS
-# LocalWords:  TR Sony CDU caddyless cdu Mitsumi MCD cd mcd XA MultiSession CDA
-# LocalWords:  Matsushita Panasonic SBPCD Soundblaster Longshine sbpcd Aztech
-# LocalWords:  Okano Wearnes AZTCD CDD SE aztcd sonycd Goldstar GSCD Philips fs
-# LocalWords:  LMS OPTCD Sanyo SJCD minix faqs xiafs XIA msdos mtools Cichocki
-# LocalWords:  std softlinks umssync NetworkFileSharing nfsd mountd CDs HPFS TI
-# LocalWords:  hpfs SYSV SCO iBCS Wyse WordPerfect tsx mit unixes sysv NR irisa
-# LocalWords:  SMB WfW Cyclades async mux Logitech busmouse MouseSystem aka AST
-# LocalWords:  PSMOUSE Compaq trackballs Travelmate Inport ATIXL ATI busmice ld
-# LocalWords:  gpm config QIC DYNCONF FTAPE Stor Ftape ftape pcsndrv manpage NT
-# LocalWords:  readprofile diskdrives org com masq EtherTalk tcp netrom sunacm
-# LocalWords:  misc AIC aic pio scc Portmaster eql GIS PhotoCDs MCDX Perell PG
-# LocalWords:  mcdx gscd optcd sjcd ISP hdparm Workgroups Lan samba PARIDE PCD
-# LocalWords:  filesystems smbfs ATA ppp PCTech RZ www powerquest txt CMD ESDI
-# LocalWords:  chipset FB multicast MROUTE appletalk ifconfig IBMTR multiport
-# LocalWords:  Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard
-# LocalWords:  Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem
-# LocalWords:  carleton DECstation SUNFD JENSEN Noname XXXM SLiRP LILO's amifb
-# LocalWords:  pppd Zilog ZS SRM bootloader ez mainmenu rarp ipfwadm paride pcd
-# LocalWords:  RTNETLINK mknod xos MTU lwared Macs netatalk macs cs Wolff
-# LocalWords:  dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress
-# LocalWords:  ICL EtherTeam ETH IDESCSI TXC SmartRAID SmartCache httpd sjc dlp
-# LocalWords:  thesphere TwoServers BOOTP DHCP ncpfs BPQETHER BPQ MG HIPPI cern
-# 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 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
-# LocalWords:  QD qd UMC umc ALI ali lena fnet fr azstarnet cdr fb MDA ps esdi
-# LocalWords:  Avanti XL AlphaStations Jensen DECpc AXPpci UDB Cabriolet MCA RC
-# LocalWords:  AlphaPC mca AOUT OUTput PPro sipx gwdg lo nwe FourPort Boca unm
-# LocalWords:  Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT
-# LocalWords:  OPTi isp irq noisp VFAT vfat NTFS losetup dmsdosfs dosfs ISDN MP
-# LocalWords:  NOWAYOUT behaviour dialin isdn callback BTX Teles  XXXX LVM lvm
-# LocalWords:  ICN EDSS Cisco
-# LocalWords:  ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr
-# LocalWords:  ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD
-# LocalWords:  initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS
-# LocalWords:  FC DC dc PPA IOMEGA's ppa RNFS FMV Fujitsu ARPD arpd loran layes
-# LocalWords:  FRAD indiana framerelay DLCI DCLIs Sangoma SDLA mrouted sync sec
-# LocalWords:  Starmode Metricom MosquitoNet mosquitonet kbit nfsroot Digiboard
-# LocalWords:  DIGI Xe Xeve digiboard UMISC touchscreens mtu Ethernets HBAs MEX
-# LocalWords:  Shifflett netcom js jshiffle WIC DECchip ELCP EtherPower dst RTC
-# LocalWords:  rtc SMP lp Digi Intl RightSwitch DGRS dgrs AFFS Amiga UFS SDL AP
-# LocalWords:  Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au artoo MFB
-# LocalWords:  hitchcock Crynwr cnam pktdrvr NCSA's CyDROM CyCD-ROM FreeBSD NeXT
-# LocalWords:  NeXTstep disklabel disklabels SMD FFS tm AmigaOS diskfiles Un IQ
-# LocalWords:  Bernd informatik rwth aachen uae affs multihosting bytecode java
-# LocalWords:  applets applet JDK ncsa cabi SNI Alphatronix readme LANs scarab
-# LocalWords:  winsock RNIS caltech OSPF honour Honouring Mbit LocalTalk DEFRAG
-# LocalWords:  localtalk download Packetwin Baycom baycom interwork ASCII JNT
-# LocalWords:  Camtec proxying indyramp defragment defragmented UDP FAS FASXX
-# LocalWords:  FastSCSI SIO FDC qlogicfas QLogic qlogicisp setbaycom ife ee LJ
-# LocalWords:  ethz ch Travelmates ProAudioSpectrum ProAudio SoundMan SB SBPro
-# LocalWords:  Thunderboard SM OPL FM ADLIB TSR Gravis MPU PSS ADI SW DSP codec
-# LocalWords:  ADSP ESC ASIC daughtercard GUSMAX MSS NX AdLib Excell Ensoniq YM
-# LocalWords:  SoundScape Spea MediaTriX AudioTriX WSS OTI ThunderBoard VoxWare
-# LocalWords:  Soundscape SSCAPE TRIX MediaTrix PnP Maui dsp midixx EIA getty
-# LocalWords:  mgetty sendfax gert greenie muc lowlevel Lasermate LanManager io
-# LocalWords:  OOPSes trackball binghamton mobileip ncr IOMAPPED settags ns ser
-# LocalWords:  setsync NEGO MPARITY autotuning prefetch PIIX cdwrite utils rc
-# LocalWords:  PCWATCHDOG berkprod bitgate boldt ucsb jf kyoto jp euc Tetsuyasu
-# LocalWords:  YAMADA tetsu cauchy nslab ntt nevod perm su doc kaf kheops wsc
-# LocalWords:  traduc Bourgin dbourgin menuconfig kfill READMEs HOWTOs Virge WA
-# LocalWords:  IDEDISK IDEFLOPPY EIDE firewalls QMAGIC ZMAGIC LocalWords opti
-# LocalWords:  SVGATextMode vga svga Xkernel syr jmwobus comfaqs dhcp flakey GD
-# LocalWords:  IPv IPng interoperability ipng ipv radio's tapr pkthome PLP nano
-# LocalWords:  Ses Mhz sethdlc SOUNDMODEM WindowsSoundSystem smdiag pcf inka ES
-# LocalWords:  smmixer ptt circ soundmodem MKISS FDDI DEFEA DEFPA DEFXX redhat
-# LocalWords:  HyperNews khg mconv sed lina wuftpd MicroChannel netlink irc cum
-# LocalWords:  raudio RealAudio PPROP NETBIOS GUI IBMMCA ELMC Racal Interlan fi
-# LocalWords:  eth shapecfg src esp PCWD PREVSTAT bootparam sig bitwizard SBC
-# LocalWords:  downloads AFSK TCM FP Karn KA FSK RUH LinkSys cron mouseman LLC
-# LocalWords:  SyQuest SyQuest's CCITT MicroSolutions BPCD bpcd ESPSERIAL PROM
-# LocalWords:  SUNESP openprom OPENPROMIO quango themall al TT MC MMU LC RMW AA
-# LocalWords:  INSNS Ataris AutoConfig ZORRO OCS AMIFB Agnus Denise ECS CDTV GB
-# LocalWords:  AGA Cybervision CYBER GSP TMS DMI Zorro ACSI ROMs SLM BioNet GVP
-# LocalWords:  PAMsNet TekMagic Cyberstorm MkI CYBERSTORMII MkII BLZ onboard cx
-# LocalWords:  Village Tronic ATARILANCE RieblCard PAMCard VME MFP sangoma LAPB
-# LocalWords:  Rhotron BioData's Multiface AMIGAMOUSE COPCON Amiga's bitplanes
-# LocalWords:  ATARIMOUSE MFPSER SCC's MegaSTE ESCC Atari's GVPIOEXT DMASOUND
-# LocalWords:  fdutils cisco univercd rpcg htm iface lapb LAPBETHER tpqic qic
-# LocalWords:  SYNTH xd en binfmt aout ipip terra ipx sd sr sg wic framebuffer
-# LocalWords:  ibmmca lapbether mkiss dlci sdla fmv eepro eexpress ni hp ne es
-# LocalWords:  ibmtr isofs ROMFS romfs pcxx cyclades istallion psaux msbusmouse
-# LocalWords:  atixlmouse sbin softdog pcwd USS Lite ACI miroSOUND PCM miroPCM
-# LocalWords:  microcontroller miro Voxware downloading teles acsi slm gvp ltpc
-# LocalWords:  atari ariadne amigamouse atarimouse builtin IPDDP maths bradford
-# LocalWords:  AppleTalk Farallon PhoneNet Zubkoff lnz SCCB HAPN WANs vesafb nt
-# LocalWords:  wanrouter WANPIPE multiprotocol Mbps wanpipe EtherWORKS nodma SC
-# LocalWords:  smp HiSax SiemensChipSet Siemens AVM Elsa ITK hisax PCC MICROR
-# LocalWords:  Mircolink EURO DSS Spellcaster BRI sc spellcast Digiboards GPIO
-# LocalWords:  SYMBIOS COMPAT SDMS rev ASUS Tekram HX VX API ibmmcascsi ASY asy
-# LocalWords:  loader's PCnetPCI automounter AUTOFS amd autofs VT Gallant's Pnp
-# LocalWords:  AEDSP aedsp enskip tik Sysctl sysctl PARPORT parport pnp IDs EPP
-# LocalWords:  Autoprobe bart patrickr HDLS READBACK AB usr DAMA DS SparQ aten
-# LocalWords:  Symbios PCscsi tmscsim RoamAbout GHz Hinds contrib mathematik ok
-# LocalWords:  darmstadt okir DIGIEPCA International's Xem digiepca epca bootup
-# LocalWords:  zorro CAPI AVMB capi avmb VP SYN syncookies EM em pc Ethertalk
-# LocalWords:  Dayna DL Daynatalk LT PhoneNET ATB Daystar queueing CMDS SCBs ls
-# LocalWords:  SCB STATS Thinnet ThunderLAN TLAN Netelligent NetFlex tlan james
-# LocalWords:  caldera Preload Preloading slowdowns schoebel uni NBD nbd prog
-# LocalWords:  stuttgart rdist TRANS hostnames mango jukeboxes ESS userland PD
-# LocalWords:  hardlinked NAMETRANS env mtab fstab umount nologin runlevel gid
-# LocalWords:  adm Nodename hostname uname Kernelname bootp nmi DI OV StegFS
-# LocalWords:  KERNNAME kname ktype kernelname Kerneltype KERNTYPE Alt RX mdafb
-# LocalWords:  dataless kerneltype SYSNAME Comtrol Rocketport palmtop fbset EGS
-# LocalWords:  nvram SYSRQ SysRq PrintScreen sysrq NVRAMs NvRAM Shortwave RTTY
-# LocalWords:  Sitor Amtor Pactor GTOR hayes TX TMOUT JFdocs BIGMEM DAC IRQ's
-# LocalWords:  IDEPCI IDEDMA PDC pdc TRM trm raidtools luthien nuclecu BAGET VR
-# LocalWords:  unam mx miguel koobera uic EMUL solaris pp ieee lpsg co DMAs TOS
-# LocalWords:  BLDCONFIG preloading jumperless BOOTINIT modutils multipath GRE
-# LocalWords:  misconfigured autoconfiguration IPGRE ICMP tracert ipautofw PIM
-# LocalWords:  netis rlynch autofw ipportfw monmouth ipsubs portforwarding pimd
-# LocalWords:  portfw PIMSM netweb usc pim pf EUI aggregatable PB decapsulate
-# LocalWords:  ipddp Decapsulation DECAP bool HAMRADIO tcpdump af CDs tx FBCON
-# LocalWords:  ethertap multisession PPC MMIO GDT GDTH ICP gdth hamradio  bpp
-# LocalWords:  lmh weejock AIMSlab RadioTrack RTRACK HZP OptoSCC TRX rx TRXECHO
-# LocalWords:  DMASCC paccomm dmascc addr cfg oevsv oe kib picpar FDX baudrate
-# LocalWords:  baudrates fdx HDX hdx PSK kanren frforum QoS SCHED CBQ SCH sched
-# LocalWords:  sch cbq CSZ Shenker Zhang csz SFQ sfq TBF tbf PFIFO fifo PRIO RW
-# LocalWords:  prio Micom xIO dwmw rimi OMIRR omirr omirrd unicode ntfs cmu NIC
-# LocalWords:  Braam braam Schmidt's freiburg nls codepages codepage Romanian
-# LocalWords:  Slovak Slovenian Sorbian Nordic iso Catalan Faeroese Galician SZ
-# LocalWords:  Valencian Slovene Esperanto Estonian Latvian Belarusian KOI mt
-# LocalWords:  charset Inuit Greenlandic Sami Lappish koi Alexey Kuznetsov's sa
-# LocalWords:  Specialix specialix DTR RTS RTSCTS cycladesZ Exabyte ftape's inr
-# LocalWords:  Iomega's LBFM claus ZFTAPE VFS zftape zft William's lzrw DFLT kb
-# LocalWords:  MTSETBLK MTIOCTOP qft setblk zftape's tar's afio's setdrvbuffer
-# LocalWords:  Procfs Exabyte's THR FCD sysvinit init PSC pscwdt VMIDI Euro SAB
-# LocalWords:  Mostek Fastlane PowerMac PReP PMAC PowerPC Macintoshes Starmax
-# LocalWords:  PowerStack Starmaxes MCOMMON DEVICETREE ATY IMS IMSTT videodev
-# LocalWords:  BT Hauppauge STB bttv Quickcam BW BWQCAM bw qcam Mediavision PMS
-# LocalWords:  pms Avatar Freecom Imation Superdisk BPCK bpck COMM comm DSTR ru
-# LocalWords:  dstr EPAT EPEZ epat EPIA epia FreeCom FRPW frpw KingByte KBIC HW
-# LocalWords:  KingByte's kbic OnSpec ValuStore FASTROUTE fastroute FLOWCONTROL
-# LocalWords:  struct APIC realtime OSs LynxOS CNC tmp cvf HFS hfs ADFS Risc os
-# LocalWords:  adfs ncpmount namespace SUBDIR reexport NDS kcore FT SPX spx DAT
-# LocalWords:  interserver BLKSZ NUMBUFFERS apmd Tadpole ANA roestock QuickCam
-# LocalWords:  isapnptools Colour CQCAM colour Connectix QuickClip prive mentre
-# LocalWords:  KMOD kmod conformant utexas kharker UnixWare Mwave cgi cl ts ibm
-# LocalWords:  eXchange threepio oakland simtel pre ULTRAMCA EtherLink isa luik
-# LocalWords:  EtherLink OpenBSD pts DEVPTS devpts ptmx ttyp glibc readback SA
-# LocalWords:  mwave OLDCARD isdnloop linklevel loopctrl Eicon Diehl DIEHLDIVA
-# LocalWords:  ASUSCOM AsusCom TELEINT semiactiv Sedlbauer Sportster TA MIC ITH
-# LocalWords:  NETjet NetJet Niccy Neuhaus sparcs AOC AOCD AOCE Microlink SAA
-# LocalWords:  teletext WinTV saa iproute tc Quadra Performa PowerBook tor AUN
-# LocalWords:  setserial compsoc steve Econet econet AUNUDP psched TEQL TLE CLS
-# LocalWords:  teql FW Ingres TwistedPair MTRR MTRRs mtrr cfs crypto TD ktti KT
-# LocalWords:  PHd ICS ipchains adelaide rustcorp syslog Cumana steganography
-# LocalWords:  AcornSCSI EcoSCSI EESOX EESOXSCSI Powertec POWERTECSCSI dec SF
-# LocalWords:  RadioReveal gatekeeper aimslab aztech FMI sf fmi RTL rtl cesdis
-# LocalWords:  Yellowfin gsfc nasa gov yellowfin pcnet Mylex LNE lne EtherH hs
-# LocalWords:  EBSA chattr RiscOS Winmodem AGP Atomwide DUALSP pcsp robinson CT
-# LocalWords:  SGALAXY Waverider DSPxxx TRXPRO AudioTrix OSWF MOT CFB DSY kbps
-# LocalWords:  tuwien kkudielk LVD mega lun MAXTAGS Gbps arcnet Olicom SNA PAE
-# LocalWords:  SysKonnect tms sna etherboot ufs NetBEUI MultiSound MSNDCLAS GX
-# LocalWords:  MSNDINIT MSNDPERM MSNDPIN PNDSPINI PNDSPERM Ensoniq's RetinaZ SS
-# LocalWords:  AudioPCI lspci SonicVibes sonicvibes SPARCs roadrunner CLgen UPA
-# LocalWords:  swansea shtml Zoltrix zoltrix BINUTILS EGCS binutils VIDC DACs
-# LocalWords:  CyberVision Cirrus PowerBooks Topcat SBUS CGsix TurboGX BWtwo SS
-# LocalWords:  CGthree TCX unswappable vfb fbcon hicolor truecolor AFB ILBM SOC
-# LocalWords:  IPLAN gracilis Fibre SBus SparcSTORAGE SV jnewbigin swin QNX qnx
-# LocalWords:  PTY PTYS ptyxx ttyxx PTYs ssh sb Avance ALS pss pvv kerneli hd
-# LocalWords:  synth WaveFront MSND NONPNP AudioExcelDSP STRAM APUS CHRP MBX Nx
-# LocalWords:  PowerMac's BMAC radiotrack rtrack miropcm OFFBOARD HPT UDMA DVD
-# LocalWords:  hpt fokus gmd Cyrix DXL SLC DLC NexGen MediaGX GXm IDT WinChip
-# LocalWords:  MMX MII valkyrie mdacon vdolive VDOLive cuseeme CU hippi rrunner
-# LocalWords:  SeeMe ipmasqadm juanjox ipmarkfw markfw TNCs Microdyne rhine lib
-# LocalWords:  libc jsX gamepad gameport CHF FCS FPGaming MadCatz ASSASIN GrIP
-# LocalWords:  Assasin gamepads GamePad PDPI gamecards gamecard WingMan BSP WCS
-# LocalWords:  ThunderPad CyberMan SideWinder ThrustMaster DirectConnect NES XF
-# LocalWords:  Millenium SNES PSX Multisystem Nintendo PlayStation Amstrad CPC
-# LocalWords:  Sega TurboGraFX Steffen Schwenke Multiststem PDIF FIFOSIZE EPLUS
-# LocalWords:  PowerUP RoadRunner tahallah dos functionkey setterm imladris Woz
-# LocalWords:  PowerMacs Winbond Algorithmics ALGOR algor ECOFF IRIX SGI SGI's
-# LocalWords:  gfx virtualized Xpmac mklinux XFree FBDev Woodhouse mvhi Seeq fp
-# LocalWords:  SGISEEQ HIgh ADB ADBMOUSE crosscompiler CROSSCOMPILE FPE GDB gdb
-# LocalWords:  JOYPORT rp spoofing DawiControl NOGENSUPP EEPROM HSSI Alessandro
-# LocalWords:  singleprocessor tex MATHEMU FRIQ Maxell friq Alcor XLT AlphaBook
-# LocalWords:  AlphaPCI DP LX Miata Mikasa Noritake RPX UX BX Takara EV PRIMO
-# LocalWords:  TSC Matrox Productiva matroxfb matrox multihead ia linuxhq MFW
-# LocalWords:  mfw AAA MCS Initio XXU initio imm AutoDetect IZIP CTR usec HDLC
-# LocalWords:  COSA SRP muni cz kas cosa Alteon AceNIC acenic VTOC OSes GMT SAx
-# LocalWords:  Inspiron localtime INTS Thinkpads Ralf Brown's Flightstick NNN
-# LocalWords:  Xterminator Blackhawk NN mpu ioports DCA HPDCA HPLANCE DIO Corel
-# LocalWords:  GemTek gemtek CMDLINE IrDA PDA's irmanager irattach RR AVA DN rg
-# LocalWords:  uit dagb irda LSAP IrLMP RR's IrLAP IR alloc skb's kfree skb's
-# LocalWords:  GZIP IrLAN NetbeamIR ESI JetEye IrOBEX IrCOMM TTY's minicom dti
-# LocalWords:  ircomm ircomm pluto thiguchi IrTTY Linux's bps NetWinder MIR NSC
-# LocalWords:  ACTiSYS dongle dongles esi actisys IrMate tekram BVM MVME
-# LocalWords:  BVME BVME WRITETHROUGH copyback writethrough fwmark syncookie tu
-# LocalWords:  alphalinux GOBIOS csn chemnitz nat ACARD AMI MegaRAID megaraid
-# LocalWords:  QNXFS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia
-# LocalWords:  IrLPT UIRCC Tecra Strebel jstrebel suse Eichwalder ke INI INIA
-# LocalWords:  FCP qlogicfc sym isapnp DTLK DoubleTalk rcsys dtlk DMAP SGIVW ar
-# LocalWords:  dmabuf EcoRadio MUTEFREQ GIrBIL girbil tepkom vol mha diplom PQS
-# LocalWords:  bmac Microgate SyncLink synclink hdlc excl ioaddr Tane tanep TCQ
-# LocalWords:  PDS SMALLDOS charsets bigfoot kernelfr mcs cls fw rsvp SKnet sk
-# LocalWords:  SKMC USB UHCI OHCI intel compaq usb ohci HCD Virt Compaq's hcd
-# LocalWords:  VROOTHUB KBD ARRs MCRs NWBUTTON nwbutton NUM WaveArtist APNE cpu
-# LocalWords:  apne blackhawke PlanB lu mlan planb NWFPE FPA nwfpe unbootable
-# LocalWords:  FPEmulator ds vmlinux initialization discardable pgtable PGT mdw
-# LocalWords:  quicklist pagetable arthur StrongARM podule podules Autodetect
-# LocalWords:  dodgy IrPORT irport Litelink litelink SuSE rtfm internet hda CY
-# LocalWords:  multmode DriveReady SeekComplete DriveStatusError miscompile AEC
-# LocalWords:  mainboard's Digital's alim FastTrak aec PIIXn piix Gayle Eyetech
-# LocalWords:  Catweasel IDEDOUBLER Powerbook Centris ICSIDE RapIDE OSM HDM IOP
-# LocalWords:  HDM's OSM's lan FibreChannel ECP autoprobe itg lbl ipmasq cjb IC
-# LocalWords:  bieringer Caulfield's dreamtime decnet SIOCFIGCONF SIOCGIFCONF
-# LocalWords:  rtnetlink Endnode Aironet Arlan Telxon ylenurme arlan ACB aeschi
-# LocalWords:  Sealevel sealevel Cyclom br wanconfig tarball conectiva cycsyn
-# LocalWords:  devel bazar cyclomx NetGear GA IBMOL Lanstreamer uhci eu efs CYZ
-# LocalWords:  olympic linuxtr usbcore acm EZUSB downloader EFS XFS INTR op IIC
-# LocalWords:  heine soundcore JavaStations JavaStation GemTeks TerraTec TODO
-# LocalWords:  ActiveRadio Standalone terratec Rolf Offermanns rolf offermanns
-# LocalWords:  Zoran ZR Buz LML CPQ DA cpqarray PPDEV deviceid vlp ppdev atyfb
-# LocalWords:  AcceleRAID eXtremeRAID NETFILTER Netfilter masqueraded netfilter
-# LocalWords:  kernelnotes Cardbus PCMCIA's CardBus clgenfb Permedia YAM MMAP
-# LocalWords:  mmapped ATM atm PVCs SVCs InARP ATMARP neighbour neighbours MPOA
-# LocalWords:  VCs ENI FPGA Tonga MMF MF UTP printks ZeitNet ZN ZATM uPD SAR PN
-# LocalWords:  approx NICStAR NICs ForeRunnerLE Madge Collage ATMizer Dxxxx VCI
-# LocalWords:  ServeRAID IPS ips ipslinux gzip BSDCOMP LZW RAYCS Interphase app
-# LocalWords:  Tachyon IPHASE Surfboard NextLevel SURFboard jacksonville Tigon
-# LocalWords:  fventuri adelphia siglercm linuxpower AceNICs Starfire starfire
-# LocalWords:  ISOC CPiA cpia uss ACPI UDF DirectCD udf CDRW's OSF Manx acpi DM
-# LocalWords:  Unixware cymru Computone IntelliPort Intelliport computone SI sx
-# LocalWords:  adbmouse DRI DRM dlabs GMX PLCs Applicom fieldbus applicom int
-# LocalWords:  VWSND eg ESSSOLO CFU CFNR scribed eiconctrl eicon hylafax KFPU
-# LocalWords:  EXTRAPREC fpu mainboards KHTTPD kHTTPd khttpd Xcelerator SBNI tw
-# LocalWords:  LOGIBUSMOUSE Granch granch sbni Raylink NOHIGHMEM Athlon SIM sim
-# LocalWords:  hpl Tourrilhes DuraLAN starfire Davicom davicom dmfe auk tms tr
-# LocalWords:  TokenExpress Belkin Peracom eTek DVDs infradead Cxxx Adlib AV ZX
-# LocalWords:  NeoMagic CPi CPt Celeron decapsulation Undeletion BFS bfs nVidia
-# LocalWords:  OnStream Irongate Riva phonedev QuickNet LineJack PhoneJack IXJ
-# LocalWords:  Quicknet PhoneJACK LineJACK ixj pnpdump Quicknet's Joandi SSID
-# LocalWords:  aironet quickconfig adhoc btw bap NONCS cardservices Xircom lin
-# LocalWords:  Netwave AirSurfer netwave HomePNA failover MVP iMacs ALi aktual
-# LocalWords:  Aladin HIDBP usbkbd KEYBDEV MOUSEDEV JOYDEV EVDEV UAB WhiteHEAT
-# LocalWords:  Handspring ov DABUSB URB URB's dabusb CRAMFS NFSv ELV IOAPIC WIP
-# LocalWords:  NLMv SMBus ALGOBIT algo PHILIPSPAR philips elv Velleman velleman
-# LocalWords:  ALGOPCF Elektor elektor CHARDEV dfx TDFX tdfx Extensa dof gravis
-# LocalWords:  assasin logitech Overdrive thrustmaster DWave Aureal magellan db
-# LocalWords:  SpaceTec SpaceOrb SpaceBall spaceorb FLX spaceball turbografx zr
-# LocalWords:  amiga ESS's WaveWatcher Maxi belkin RW's ata glx GART MPV Baget
-# LocalWords:  OpenGL Xserver agpgart HOTPLUG CyberPro Integraphics Netwinder
-# LocalWords:  aty FONTWIDTH eni zatm nicstar ForeRunner OC DECstations DEC's
-# LocalWords:  PHYsical SUNI reinsertion ChipSAR KVC PHY ClassID iphase iadbg
-# LocalWords:  DEVS FireWire PCILynx pcilynx LOCALRAM miro's DV RAWIO GRED Mk
-# LocalWords:  Diffserv DSMARK Ingress Qdisc TCINDEX TMSPCI tmspci Ringode JE
-# LocalWords:  MADGEMC madgemc TokenRing SMCTR TokenCard smctr Wacom Graphire
-# LocalWords:  mousedev ConnectTech HandSpring Xirlink IBMCAM ibmcam SN
-# LocalWords:  DEVICEFS yyy Cymraeg Dwave SIMM JSFLASH JavaStation's multilink
-# LocalWords:  nsc ircc DDB Vrc CMN TB PROMs Vino rivafb DDC Matroxes MGA TVO
-# LocalWords:  MAVEN fbdev crtc maven matroxset NTSC PCA SBA AAL SKFP DAS SAS
-# LocalWords:  skfp Intuos ADMtek's pegasus PLUSB plusb pointopoint mp rio Xeon
-# LocalWords:  DEVFS devfs dd bs EDSS german TELESPCI FRITZPCI HFC HFCS BDS HST
-# LocalWords:  ISURF ISAR Saphir HSTSAPHIR Telekom BKM Scitel Quadro SCT Gazel
-# LocalWords:  SP PRI Hypercope HYSDN Hypercope's hysdn IbssJoinNetTimeout FTDI
-# LocalWords:  ARCNet Keyspan PDA ADMtek sgalaxy sgbase opl mpuio mpuirq sbio
-# LocalWords:  sbirq sbdma gus uart mssio mssirq mssdma sscape maui mouirq iph
-# LocalWords:  CHDLC UPS's usbmouse wacom wmforce keybdev joydev fibre Trunking
-# LocalWords:  Etherchannel IOC Moxa Intellio moxa SmartIO mxser Mixcom EFI ir
-# LocalWords:  MIXCOMWD mixcomwd SENDCOMPLETE GMAC iBook gmac OAKNET oaknet PCG
-# LocalWords:  diffserv irlan irtty toshoboe IrCC Lifebook idex AUTODMA FIP Cxx
-# LocalWords:  Yenta Databook TCIC FMVJ fmvj NMCLAN LiveWire nmclan XIRC xirc
-# LocalWords:  loadkeys setfont shm SuperIO soc SOCAL socal FCAL fc fcal COMX
-# LocalWords:  MultiGate ITConsult comx CMX HiCOMX downloadable hw LoCOMX PROTO
-# LocalWords:  locomx MixCOM mixcom proto MyriCOM MYRI Sbus myri sbus IBMLS hme
-# LocalWords:  lanstreamer baseT HAPPYMEAL qfe sunhme SUNLANCE sunlance BigMAC
-# LocalWords:  SUNBMAC sunbmac QuadEthernet SUNQE qe FastEthernet sunqe DSB PTI
-# LocalWords:  DSBR dsbr procinfo QLOGICPTI qpti ptisp QLGC qlogicpti se LBA NF
-# LocalWords:  OPENPROMFS OpenPROM openpromfs OBP OpenBoot flashable Multiboard
-# LocalWords:  SPARCAUDIO SparcClassic Ultras DBRI Sparcbook sparcaudio SUNBPP
-# LocalWords:  UltraDMA WDC CRC CONNTRACK IPTABLES iptables nfmark interface's
-# LocalWords:  tdfxfb TNTx HGA hgafb VERBOSEDEBUG SunTrunking SunSoft XIRTULIP
-# LocalWords:  ethercards PNIC Macronix MXIC ASIX xircom Mustek MDC gphoto mdc
-# LocalWords:  CramFs Cramfs uid cramfs AVM's kernelcapi PCIV cdrdao Cdparanoia
-# LocalWords:  DMX Domex dmx wellington ftdi sio Accton Billington Corega FEter
-# LocalWords:  MELCO LUA PNA Linksys SNC chkdsk AWACS Webcam RAMFS Ramfs ramfs
-# LocalWords:  ramfiles MAKEDEV pty WDTPCI APA apa
-#
-# The following sets edit modes for GNU EMACS
-# Local Variables:
-# case-fold-search:nil
-# fill-prefix:"  "
-# adaptive-fill:nil
-# fill-column:70
-# End:
diff -u --recursive --new-file v2.5.2/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt
--- v2.5.2/linux/Documentation/DMA-mapping.txt	Fri Oct 12 15:35:53 2001
+++ linux/Documentation/DMA-mapping.txt	Tue Jan 15 11:48:13 2002
@@ -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.
@@ -685,6 +688,97 @@
 
 This is possible with the DAC interfaces purely because they are
 not translated in any way.
+
+		Optimizing Unmap State Space Consumption
+
+On many platforms, pci_unmap_{single,page}() is simply a nop.
+Therefore, keeping track of the mapping address and length is a waste
+of space.  Instead of filling your drivers up with ifdefs and the like
+to "work around" this (which would defeat the whole purpose of a
+portable API) the following facilities are provided.
+
+Actually, instead of describing the macros one by one, we'll
+transform some example code.
+
+1) Use DECLARE_PCI_UNMAP_{ADDR,LEN} in state saving structures.
+   Example, before:
+
+	struct ring_state {
+		struct sk_buff *skb;
+		dma_addr_t mapping;
+		__u32 len;
+	};
+
+   after:
+
+	struct ring_state {
+		struct sk_buff *skb;
+		DECLARE_PCI_UNMAP_ADDR(mapping)
+		DECLARE_PCI_UNMAP_LEN(len)
+	};
+
+   NOTE: DO NOT put a semicolon at the end of the DECLARE_*()
+         macro.
+
+2) Use pci_unmap_{addr,len}_set to set these values.
+   Example, before:
+
+	ringp->mapping = FOO;
+	ringp->len = BAR;
+
+   after:
+
+	pci_unmap_addr_set(ringp, mapping, FOO);
+	pci_unmap_len_set(ringp, len, BAR);
+
+3) Use pci_unmap_{addr,len} to access these values.
+   Example, before:
+
+	pci_unmap_single(pdev, ringp->mapping, ringp->len,
+			 PCI_DMA_FROMDEVICE);
+
+   after:
+
+	pci_unmap_single(pdev,
+			 pci_unmap_addr(ringp, mapping),
+			 pci_unmap_len(ringp, len),
+			 PCI_DMA_FROMDEVICE);
+
+It really should be self-explanatory.  We treat the ADDR and LEN
+seperately, because it is possible for an implementation to only
+need the address in order to perform the unmap operation.
+
+			Platform Issues
+
+If you are just writing drivers for Linux and do not maintain
+an architecture port for the kernel, you can safely skip down
+to "Closing".
+
+1) Struct scatterlist requirements.
+
+   Struct scatterlist must contain, at a minimum, the following
+   members:
+
+	char *address;
+	struct page *page;
+	unsigned int offset;
+	unsigned int length;
+
+   The "address" member will disappear in 2.5.x
+
+   This means that your pci_{map,unmap}_sg() and all other
+   interfaces dealing with scatterlists must be able to cope
+   properly with page being non NULL.
+
+   A scatterlist is in one of two states.  The base address is
+   either specified by "address" or by a "page+offset" pair.
+   If "address" is NULL, then "page+offset" is being used.
+   If "page" is NULL, then "address" is being used.
+
+   In 2.5.x, all scatterlists will use "page+offset".  But during
+   2.4.x we still have to support the old method.
+
+2) More to come...
 
 			   Closing
 
diff -u --recursive --new-file v2.5.2/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile
--- v2.5.2/linux/Documentation/DocBook/Makefile	Mon Jan 14 18:25:07 2002
+++ linux/Documentation/DocBook/Makefile	Fri Jan 25 16:17:51 2002
@@ -1,7 +1,8 @@
 BOOKS	:= wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
 	   kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
 	   kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
-	   deviceiobook.sgml procfs-guide.sgml tulip-user.sgml
+	   deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
+	   writing_usb_driver.sgml
 
 PS	:=	$(patsubst %.sgml, %.ps, $(BOOKS))
 PDF	:=	$(patsubst %.sgml, %.pdf, $(BOOKS))
@@ -65,6 +66,9 @@
 tulip-user.sgml: tulip-user.tmpl
 	$(TOPDIR)/scripts/docgen <$< >$@
 
+writing_usb_driver.sgml: writing_usb_driver.tmpl
+	$(TOPDIR)/scripts/docgen <$< >$@
+
 sis900.sgml: sis900.tmpl $(TOPDIR)/drivers/net/sis900.c
 	$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/sis900.c \
 		<sis900.tmpl >sis900.sgml
@@ -93,6 +97,8 @@
 		$(TOPDIR)/drivers/net/8390.c \
 		$(TOPDIR)/drivers/char/serial.c \
 		$(TOPDIR)/drivers/pci/pci.c \
+		$(TOPDIR)/drivers/hotplug/pci_hotplug_core.c \
+		$(TOPDIR)/drivers/hotplug/pci_hotplug_util.c \
 		$(TOPDIR)/drivers/block/ll_rw_blk.c \
 		$(TOPDIR)/drivers/sound/sound_core.c \
 		$(TOPDIR)/drivers/sound/sound_firmware.c \
diff -u --recursive --new-file v2.5.2/linux/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl
--- v2.5.2/linux/Documentation/DocBook/kernel-api.tmpl	Mon Jan 14 18:25:07 2002
+++ linux/Documentation/DocBook/kernel-api.tmpl	Mon Jan 21 15:44:21 2002
@@ -162,6 +162,10 @@
      <sect1><title>PCI Support Library</title>
 !Edrivers/pci/pci.c
      </sect1>
+     <sect1><title>PCI Hotplug Support Library</title>
+!Edrivers/hotplug/pci_hotplug_core.c
+!Edrivers/hotplug/pci_hotplug_util.c
+     </sect1>
      <sect1><title>MCA Architecture</title>
 	<sect2><title>MCA Device Functions</title>
 !Earch/i386/kernel/mca.c
diff -u --recursive --new-file v2.5.2/linux/Documentation/DocBook/kernel-hacking.tmpl linux/Documentation/DocBook/kernel-hacking.tmpl
--- v2.5.2/linux/Documentation/DocBook/kernel-hacking.tmpl	Mon Jan 14 18:25:07 2002
+++ linux/Documentation/DocBook/kernel-hacking.tmpl	Tue Jan 15 13:53:50 2002
@@ -371,8 +371,7 @@
   </para>
 
   <programlisting>
-if (current-&gt;need_resched)
-        schedule(); /* Will sleep */ 
+cond_resched(); /* Will sleep */ 
   </programlisting>
 
   <para>
diff -u --recursive --new-file v2.5.2/linux/Documentation/DocBook/writing_usb_driver.tmpl linux/Documentation/DocBook/writing_usb_driver.tmpl
--- v2.5.2/linux/Documentation/DocBook/writing_usb_driver.tmpl	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/DocBook/writing_usb_driver.tmpl	Fri Jan 25 16:17:51 2002
@@ -0,0 +1,469 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+
+<book id="USBDeviceDriver">
+ <bookinfo>
+  <title>Writing USB Device Drivers</title>
+  
+  <authorgroup>
+   <author>
+    <firstname>Greg</firstname>
+    <surname>Kroah-Hartman</surname>
+    <affiliation>
+     <address>
+      <email>greg@kroah.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2001-2002</year>
+   <holder>Greg Kroah-Hartman</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+     This documentation is free software; you can redistribute
+     it and/or modify it under the terms of the GNU General Public
+     License as published by the Free Software Foundation; either
+     version 2 of the License, or (at your option) any later
+     version.
+   </para>
+      
+   <para>
+     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.
+   </para>
+      
+   <para>
+     You should have received a copy of the GNU General Public
+     License along with this program; if not, write to the Free
+     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+     MA 02111-1307 USA
+   </para>
+      
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+
+   <para>
+     This documentation is based on an article published in 
+     Linux Journal Magazine, October 2001, Issue 90.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="intro">
+      <title>Introduction</title>
+  <para>
+      The Linux USB subsystem has grown from supporting only two different
+      types of devices in the 2.2.7 kernel (mice and keyboards), to over 20
+      different types of devices in the 2.4 kernel. Linux currently supports
+      almost all USB class devices (standard types of devices like keyboards,
+      mice, modems, printers and speakers) and an ever-growing number of
+      vendor-specific devices (such as USB to serial converters, digital
+      cameras, Ethernet devices and MP3 players). For a full list of the
+      different USB devices currently supported, see Resources.
+  </para>
+  <para>
+      The remaining kinds of USB devices that do not have support on Linux are
+      almost all vendor-specific devices. Each vendor decides to implement a
+      custom protocol to talk to their device, so a custom driver usually needs
+      to be created. Some vendors are open with their USB protocols and help
+      with the creation of Linux drivers, while others do not publish them, and
+      developers are forced to reverse-engineer. See Resources for some links
+      to handy reverse-engineering tools.
+  </para>
+  <para>
+      Because each different protocol causes a new driver to be created, I have
+      written a generic USB driver skeleton, modeled after the pci-skeleton.c
+      file in the kernel source tree upon which many PCI network drivers have
+      been based. This USB skeleton can be found at drivers/usb/usb-skeleton.c
+      in the kernel source tree. In this article I will walk through the basics
+      of the skeleton driver, explaining the different pieces and what needs to
+      be done to customize it to your specific device.
+  </para>
+  </chapter>
+
+  <chapter id="basics">
+      <title>Linux USB Basics</title>
+  <para>
+      If you are going to write a Linux USB driver, please become familiar with
+      the USB protocol specification. It can be found, along with many other
+      useful documents, at the USB home page (see Resources). An excellent
+      introduction to the Linux USB subsystem can be found at the USB Working
+      Devices List (see Resources). It explains how the Linux USB subsystem is
+      structured and introduces the reader to the concept of USB urbs, which
+      are essential to USB drivers.
+  </para>
+  <para>
+      The first thing a Linux USB driver needs to do is register itself with
+      the Linux USB subsystem, giving it some information about which devices
+      the driver supports and which functions to call when a device supported
+      by the driver is inserted or removed from the system. All of this
+      information is passed to the USB subsystem in the usb_driver structure.
+      The skeleton driver declares a usb_driver as:
+  </para>
+  <programlisting>
+static struct usb_driver skel_driver = {
+        name:        "skeleton",
+        probe:       skel_probe,
+        disconnect:  skel_disconnect,
+        fops:        &amp;skel_fops,
+        minor:       USB_SKEL_MINOR_BASE,
+        id_table:    skel_table,
+};
+  </programlisting>
+  <para>
+      The variable name is a string that describes the driver. It is used in
+      informational messages printed to the system log. The probe and
+      disconnect function pointers are called when a device that matches the
+      information provided in the id_table variable is either seen or removed.
+  </para>
+  <para>
+      The fops and minor variables are optional. Most USB drivers hook into
+      another kernel subsystem, such as the SCSI, network or TTY subsystem.
+      These types of drivers register themselves with the other kernel
+      subsystem, and any user-space interactions are provided through that
+      interface. But for drivers that do not have a matching kernel subsystem,
+      such as MP3 players or scanners, a method of interacting with user space
+      is needed. The USB subsystem provides a way to register a minor device
+      number and a set of file_operations function pointers that enable this
+      user-space interaction. The skeleton driver needs this kind of interface,
+      so it provides a minor starting number and a pointer to its
+      file_operations functions.
+  </para>
+  <para>
+      The USB driver is then registered with a call to usb_register, usually in
+      the driver's init function, as shown here:
+  </para>
+  <programlisting>
+static int __init usb_skel_init(void)
+{
+        int result;
+
+        /* register this driver with the USB subsystem */
+        result = usb_register(&amp;skel_driver);
+        if (result &lt; 0) {
+                err(&quot;usb_register failed for the &quot;__FILE__ &quot;driver.&quot;
+                    &quot;Error number %d&quot;, result);
+                return -1;
+        }
+
+        return 0;
+}
+module_init(usb_skel_init);
+  </programlisting>
+  <para>
+      When the driver is unloaded from the system, it needs to unregister
+      itself with the USB subsystem. This is done with the usb_unregister
+      function:
+  </para>
+  <programlisting>
+static void __exit usb_skel_exit(void)
+{
+        /* deregister this driver with the USB subsystem */
+        usb_deregister(&amp;skel_driver);
+}
+module_exit(usb_skel_exit);
+  </programlisting>
+  <para>
+     To enable the linux-hotplug system to load the driver automatically when
+     the device is plugged in, you need to create a MODULE_DEVICE_TABLE. The
+     following code tells the hotplug scripts that this module supports a
+     single device with a specific vendor and product ID:
+  </para>
+  <programlisting>
+/* table of devices that work with this driver */
+static struct usb_device_id skel_table [] = {
+        { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
+        { }                      /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, skel_table);
+  </programlisting>
+  <para>
+     There are other macros that can be used in describing a usb_device_id for
+     drivers that support a whole class of USB drivers. See usb.h for more
+     information on this.
+  </para>
+  </chapter>
+
+  <chapter id="device">
+      <title>Device operation</title>
+  <para>
+     When a device is plugged into the USB bus that matches the device ID
+     pattern that your driver registered with the USB core, the probe function
+     is called. The usb_device structure, interface number and the interface ID
+     are passed to the function:
+  </para>
+  <programlisting>
+static void * skel_probe(struct usb_device *dev,
+unsigned int ifnum, const struct usb_device_id *id)
+  </programlisting>
+  <para>
+     The driver now needs to verify that this device is actually one that it
+     can accept. If not, or if any error occurs during initialization, a NULL
+     value is returned from the probe function. Otherwise a pointer to a
+     private data structure containing the driver's state for this device is
+     returned. That pointer is stored in the usb_device structure, and all
+     callbacks to the driver pass that pointer.
+  </para>
+  <para>
+     In the skeleton driver, we determine what end points are marked as bulk-in
+     and bulk-out. We create buffers to hold the data that will be sent and
+     received from the device, and a USB urb to write data to the device is
+     initialized. Also, we register the device with the devfs subsystem,
+     allowing users of devfs to access our device. That registration looks like
+     the following:
+  </para>
+  <programlisting>
+/* initialize the devfs node for this device and register it */
+sprintf(name, &quot;skel%d&quot;, skel->minor);
+skel->devfs = devfs_register (usb_devfs_handle,
+                              name,
+                              DEVFS_FL_DEFAULT,
+                              USB_MAJOR,
+                              USB_SKEL_MINOR_BASE + skel->minor,
+                              S_IFCHR | S_IRUSR | S_IWUSR |
+                              S_IRGRP | S_IWGRP | S_IROTH,
+                              &amp;skel_fops,
+                              NULL);
+  </programlisting>
+  <para>
+     If the devfs_register function fails, we do not care, as the devfs
+     subsystem will report this to the user.
+  </para>
+  <para>
+     Conversely, when the device is removed from the USB bus, the disconnect
+     function is called with the device pointer. The driver needs to clean any
+     private data that has been allocated at this time and to shut down any
+     pending urbs that are in the USB system. The driver also unregisters
+     itself from the devfs subsystem with the call:
+  </para>
+  <programlisting>
+/* remove our devfs node */
+devfs_unregister(skel->devfs);
+  </programlisting>
+  <para>
+     Now that the device is plugged into the system and the driver is bound to
+     the device, any of the functions in the file_operations structure that
+     were passed to the USB subsystem will be called from a user program trying
+     to talk to the device. The first function called will be open, as the
+     program tries to open the device for I/O. Within the skeleton driver's
+     open function we increment the driver's usage count if it is a module with
+     a call to MODULE_INC_USE_COUNT. With this macro call, if the driver is
+     compiled as a module, the driver cannot be unloaded until a corresponding
+     MODULE_DEC_USE_COUNT macro is called.  We also increment our private usage
+     count and save off a pointer to our internal structure in the file
+     structure. This is done so that future calls to file operations will
+     enable the driver to determine which device the user is addressing. All of
+     this is done with the following code:
+  </para>
+  <programlisting>
+/* increment our usage count for the module */
+MOD_INC_USE_COUNT;
+++skel->open_count;
+
+/* save our object in the file's private structure */
+file->private_data = skel;
+  </programlisting>
+  <para>
+     After the open function is called, the read and write functions are called
+     to receive and send data to the device. In the skel_write function, we
+     receive a pointer to some data that the user wants to send to the device
+     and the size of the data. The function determines how much data it can
+     send to the device based on the size of the write urb it has created (this
+     size depends on the size of the bulk out end point that the device has).
+     Then it copies the data from user space to kernel space, points the urb to
+     the data and submits the urb to the USB subsystem.  This can be shown in
+     he following code:
+  </para>
+  <programlisting>
+/* we can only write as much as 1 urb will hold */
+bytes_written = (count > skel->bulk_out_size) ? skel->bulk_out_size : count;
+
+/* copy the data from user space into our urb */
+copy_from_user(skel->write_urb->transfer_buffer, buffer, bytes_written);
+
+/* set up our urb */
+usb_fill_bulk_urb(skel->write_urb,
+                  skel->dev,
+                  usb_sndbulkpipe(skel->dev, skel->bulk_out_endpointAddr),
+                  skel->write_urb->transfer_buffer,
+                  bytes_written,
+                  skel_write_bulk_callback,
+                  skel);
+
+/* send the data out the bulk port */
+result = usb_submit_urb(skel->write_urb);
+if (result) {
+        err(&quot;Failed submitting write urb, error %d&quot;, result);
+}
+  </programlisting>
+  <para>
+     When the write urb is filled up with the proper information using the
+     FILL_BULK_URB function, we point the urb's completion callback to call our
+     own skel_write_bulk_callback function. This function is called when the
+     urb is finished by the USB subsystem. The callback function is called in
+     interrupt context, so caution must be taken not to do very much processing
+     at that time. Our implementation of skel_write_bulk_callback merely
+     reports if the urb was completed successfully or not and then returns.
+  </para>
+  <para>
+     The read function works a bit differently from the write function in that
+     we do not use an urb to transfer data from the device to the driver.
+     Instead we call the usb_bulk_msg function, which can be used to send or
+     receive data from a device without having to create urbs and handle
+     urb completion callback functions. We call the usb_bulk_msg function,
+     giving it a buffer into which to place any data received from the device
+     and a timeout value. If the timeout period expires without receiving any
+     data from the device, the function will fail and return an error message.
+     This can be shown with the following code:
+  </para>
+  <programlisting>
+/* do an immediate bulk read to get data from the device */
+retval = usb_bulk_msg (skel->dev,
+                       usb_rcvbulkpipe (skel->dev,
+                       skel->bulk_in_endpointAddr),
+                       skel->bulk_in_buffer,
+                       skel->bulk_in_size,
+                       &amp;count, HZ*10);
+/* if the read was successful, copy the data to user space */
+if (!retval) {
+        if (copy_to_user (buffer, skel->bulk_in_buffer, count))
+                retval = -EFAULT;
+        else
+                retval = count;
+}
+  </programlisting>
+  <para>
+     The usb_bulk_msg function can be very useful for doing single reads or
+     writes to a device; however, if you need to read or write constantly to a
+     device, it is recommended to set up your own urbs and submit them to the
+     USB subsystem.
+  </para>
+  <para>
+     When the user program releases the file handle that it has been using to
+     talk to the device, the release function in the driver is called.  In this
+     function we decrement the module usage count with a call to
+     MOD_DEC_USE_COUNT (to match our previous call to MOD_INC_USE_COUNT).  We
+     also determine if there are any other programs that are currently talking
+     to the device (a device may be opened by more than one program at one
+     time). If this is the last user of the device, then we shut down any
+     possible pending writes that might be currently occurring.  This is all
+     done with:
+  </para>
+  <programlisting>
+/* decrement our usage count for the device */
+--skel->open_count;
+if (skel->open_count &lt;= 0) {
+        /* shutdown any bulk writes that might be going on */
+        usb_unlink_urb (skel->write_urb);
+        skel->open_count = 0;
+}
+/* decrement our usage count for the module */
+MOD_DEC_USE_COUNT;
+  </programlisting>
+  <para>
+     One of the more difficult problems that USB drivers must be able to handle
+     smoothly is the fact that the USB device may be removed from the system at
+     any point in time, even if a program is currently talking to it. It needs
+     to be able to shut down any current reads and writes and notify the
+     user-space programs that the device is no longer there.  The following
+     code is an example of how to do this: </para>
+  <programlisting>
+/* if the device is not opened, then we clean right now */
+if (skel->open_count) {
+        minor_table[skel->minor] = NULL;
+        if (skel->bulk_in_buffer != NULL)
+                kfree (skel->bulk_in_buffer);
+        if (skel->bulk_out_buffer != NULL)
+                kfree (skel->bulk_out_buffer);
+        if (skel->write_urb != NULL)
+                usb_free_urb (skel->write_urb);
+        kfree (skel);
+} else {
+        skel->dev = NULL;
+        up (&amp;skel->sem);
+}
+  </programlisting>
+  <para>
+     If a program currently has an open handle to the device, we only null the
+     usb_device structure in our local structure, as it has now gone away. For
+     every read, write, release and other functions that expect a device to be
+     present, the driver first checks to see if this usb_device structure is
+     still present. If not, it releases that the device has disappeared, and a
+     -ENODEV error is returned to the user-space program.  When the release
+     function is eventually called, it determines if there is no usb_device
+     structure and if not, it does the cleanup that the skel_disconnect
+     function normally does if there are no open files on the device (see
+     Listing 5).
+  </para>
+  <programlisting>
+if (skel->dev == NULL) {
+        /* the device was unplugged before the file was released */
+        minor_table[skel->minor] = NULL;
+        if (skel->bulk_in_buffer != NULL)
+                kfree (skel->bulk_in_buffer);
+        if (skel->bulk_out_buffer != NULL)
+                kfree (skel->bulk_out_buffer);
+        if (skel->write_urb != NULL)
+                usb_free_urb (skel->write_urb);
+        kfree (skel);
+        goto exit;
+}
+  </programlisting>
+  </chapter>
+
+  <chapter id="iso">
+      <title>Isochronous Data</title>
+  <para>
+     This usb-skeleton driver does not have any examples of interrupt or
+     isochronous data being sent to or from the device. Interrupt data is sent
+     almost exactly as bulk data is, with a few minor exceptions.  Isochronous
+     data works differently with continuous streams of data being sent to or
+     from the device. The audio and video camera drivers are very good examples
+     of drivers that handle isochronous data and will be useful if you also
+     need to do this.
+  </para>
+  </chapter>
+  
+  <chapter id="Conclusion">
+      <title>Conclusion</title>
+  <para>
+     Writing Linux USB device drivers is not a difficult task as the
+     usb-skeleton driver shows. This driver, combined with the other current
+     USB drivers, should provide enough examples to help a beginning author
+     create a working driver in a minimal amount of time. The linux-usb-devel
+     mailing list archives also contain a lot of helpful information.
+  </para>
+  </chapter>
+
+  <chapter id="resources">
+      <title>Resources</title>
+  <para>
+     The Linux USB Project: <ulink url="http://www.linux-usb.org">http://www.linux-usb.org/</ulink>
+  </para>
+  <para>
+     Linux Hotplug Project: <ulink url="http://linux-hotplug.sourceforge.net">http://linux-hotplug.sourceforge.net/</ulink>
+  </para>
+  <para>
+     Linux USB Working Devices List: <ulink url="http://www.qbik.ch/usb/devices">http://www.qbik.ch/usb/devices/</ulink>
+  </para>
+  <para>
+     linux-usb-devel Mailing List Archives: <ulink url="http://marc.theaimsgroup.com/?l=linux-usb-devel">http://marc.theaimsgroup.com/?l=linux-usb-devel</ulink>
+  </para>
+  <para>
+     Programming Guide for Linux USB Device Drivers: <ulink url="http://usb.cs.tum.edu/usbdoc">http://usb.cs.tum.edu/usbdoc</ulink>
+  </para>
+  <para>
+     USB Home Page: <ulink url="http://www.usb.org">http://www.usb.org</ulink>
+  </para>
+  </chapter>
+
+</book>
diff -u --recursive --new-file v2.5.2/linux/Documentation/IRQ-affinity.txt linux/Documentation/IRQ-affinity.txt
--- v2.5.2/linux/Documentation/IRQ-affinity.txt	Thu Feb 24 22:41:16 2000
+++ linux/Documentation/IRQ-affinity.txt	Mon Jan 21 15:55:46 2002
@@ -8,7 +8,7 @@
 affinity then the value will not change from the default 0xffffffff.
 
 Here is an example of restricting IRQ44 (eth1) to CPU0-3 then restricting
-the IRQ to CPU4-8 (this is an 8-CPU SMP box):
+the IRQ to CPU4-7 (this is an 8-CPU SMP box):
 
 [root@moon 44]# cat smp_affinity
 ffffffff
diff -u --recursive --new-file v2.5.2/linux/Documentation/cachetlb.txt linux/Documentation/cachetlb.txt
--- v2.5.2/linux/Documentation/cachetlb.txt	Sun Oct 21 10:40:36 2001
+++ linux/Documentation/cachetlb.txt	Tue Jan 15 10:56:35 2002
@@ -49,17 +49,18 @@
 	page table operations such as what happens during
 	fork, and exec.
 
-3) void flush_tlb_range(struct mm_struct *mm,
+3) void flush_tlb_range(struct vm_area_struct *vma,
 			unsigned long start, unsigned long end)
 
 	Here we are flushing a specific range of (user) virtual
 	address translations from the TLB.  After running, this
 	interface must make sure that any previous page table
-	modifications for the address space 'mm' in the range 'start'
-	to 'end' will be visible to the cpu.  That is, after running,
-	there will be no entries in the TLB for 'mm' for virtual
-	addresses in the range 'start' to 'end'.
+	modifications for the address space 'vma->vm_mm' in the range
+	'start' to 'end' will be visible to the cpu.  That is, after
+	running, here will be no entries in the TLB for 'mm' for
+	virtual addresses in the range 'start' to 'end'.
 
+	The "vma" is the backing store being used for the region.
 	Primarily, this is used for munmap() type operations.
 
 	The interface is provided in hopes that the port can find
@@ -130,9 +131,9 @@
 	   change_all_page_tables_of(mm);
 	   flush_tlb_mm(mm);
 
-	2) flush_cache_range(mm, start, end);
+	2) flush_cache_range(vma, start, end);
 	   change_range_of_page_tables(mm, start, end);
-	   flush_tlb_range(mm, start, end);
+	   flush_tlb_range(vma, start, end);
 
 	3) flush_cache_page(vma, page);
 	   set_pte(pte_pointer, new_pte_val);
@@ -173,14 +174,15 @@
 	page table operations such as what happens during
 	fork, exit, and exec.
 
-3) void flush_cache_range(struct mm_struct *mm,
+3) void flush_cache_range(struct vm_area_struct *vma,
 			  unsigned long start, unsigned long end)
 
 	Here we are flushing a specific range of (user) virtual
 	addresses from the cache.  After running, there will be no
-	entries in the cache for 'mm' for virtual addresses in the
-	range 'start' to 'end'.
+	entries in the cache for 'vma->vm_mm' for virtual addresses in
+	the range 'start' to 'end'.
 
+	The "vma" is the backing store being used for the region.
 	Primarily, this is used for munmap() type operations.
 
 	The interface is provided in hopes that the port can find
@@ -275,7 +277,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 -u --recursive --new-file v2.5.2/linux/Documentation/filesystems/Locking linux/Documentation/filesystems/Locking
--- v2.5.2/linux/Documentation/filesystems/Locking	Fri Feb 16 15:53:08 2001
+++ linux/Documentation/filesystems/Locking	Tue Jan 29 21:15:47 2002
@@ -219,7 +219,7 @@
 locking rules:
 	All except ->poll() may block.
 		BKL
-llseek:		yes
+llseek:		yes	(see below)
 read:		no
 write:		no
 readdir:	yes	(see below)
@@ -234,6 +234,10 @@
 lock:		yes
 readv:		no
 writev:		no
+
+->llseek() locking has moved from llseek to the individual llseek
+implementations.  If your fs is not using generic_file_llseek, you
+need to acquire and release the BKL in your ->llseek().
 
 ->open() locking is in-transit: big lock partially moved into the methods.
 The only exception is ->open() in the instances of file_operations that never
diff -u --recursive --new-file v2.5.2/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- v2.5.2/linux/Documentation/filesystems/devfs/ChangeLog	Mon Jan 14 18:25:07 2002
+++ linux/Documentation/filesystems/devfs/ChangeLog	Tue Jan 29 10:59:46 2002
@@ -1869,3 +1869,19 @@
 - Added support for multiple Compaq cpqarray controllers
 
 - Fixed (rare, old) race in <devfs_lookup>
+===============================================================================
+Changes for patch v207
+
+- Fixed deadlock bug in <devfs_d_revalidate_wait>
+
+- Tag VFS deletable in <devfs_mk_symlink> if handle ignored
+
+- Updated README from master HTML file
+===============================================================================
+Changes for patch v208
+
+- Added KERN_* to remaining messages
+
+- Cleaned up declaration of <stat_read>
+
+- Updated README from master HTML file
diff -u --recursive --new-file v2.5.2/linux/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README
--- v2.5.2/linux/Documentation/filesystems/devfs/README	Mon Jan 14 18:25:07 2002
+++ linux/Documentation/filesystems/devfs/README	Tue Jan 29 10:59:46 2002
@@ -3,7 +3,16 @@
 
 Linux Devfs (Device File System) FAQ
 Richard Gooch
-21-DEC-2001
+24-JAN-2002
+
+
+Document languages:
+
+
+
+
+
+
 
 -----------------------------------------------------------------------------
 
@@ -69,6 +78,7 @@
 What I don't like about devfs
 How to report bugs
 Strange kernel messages
+Compilation problems with devfsd
 
 
 Other resources
@@ -837,8 +847,8 @@
 will now work as before.
 
 Hopefully for most people devfs will have enough support so that they
-can mount devfs directly over /dev without loosing most functionality
-(i.e. loosing access to various devices). As of 22-JAN-1998 (devfs
+can mount devfs directly over /dev without losing most functionality
+(i.e. losing access to various devices). As of 22-JAN-1998 (devfs
 patch version 10) I am now running this way. All the devices I have
 are available in devfs, so I don't lose anything.
 
@@ -1477,6 +1487,7 @@
 What I don't like about devfs
 How to report bugs
 Strange kernel messages
+Compilation problems with devfsd
 
 
 
@@ -1677,7 +1688,7 @@
 minor limitation
 
 
-simplying increasing the device number size is insufficient. Apart
+simply increasing the device number size is insufficient. Apart
 from causing a lot of pain, it doesn't solve the management issues
 of a /dev with thousands or more device nodes
 
@@ -1828,6 +1839,29 @@
 
 
 
+
+Compilation problems with devfsd
+
+Usually, you can compile devfsd just by typing in
+make in the source directory, followed by a make
+install (as root). Sometimes, you may have problems, particularly
+on broken configurations.
+
+
+
+error messages relating to DEVFSD_NOTIFY_DELETE
+
+This happened because you have an ancient set of kernel headers
+installed in /usr/include/linux or /usr/src/linux.
+Install kernel 2.4.10 or later. You may need to pass the
+KERNEL_DIR variable to make (if you did not install
+the new kernel sources as /usr/src/linux), or you may copy
+the devfs_fs.h file in the kernel source tree into
+/usr/include/linux.
+
+
+
+
 -----------------------------------------------------------------------------
 
 
@@ -1882,9 +1916,21 @@
 
 
 
+The document master (in English) by rgooch@atnf.csiro.au is
+available at
+
+http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html
+
+
+
 A Korean translation by viatoris@nownuri.net is available at
 
-http://home.nownuri.net/~viatoris/devfs/devfs.html 
+http://viatoris.new21.org/devfs/devfs.html
+
 
 
 
+-----------------------------------------------------------------------------
+Most flags courtesy of ITA's 
+Flags of All Countries
+used with permission. 
diff -u --recursive --new-file v2.5.2/linux/Documentation/i386/boot.txt linux/Documentation/i386/boot.txt
--- v2.5.2/linux/Documentation/i386/boot.txt	Wed Nov  7 14:46:01 2001
+++ linux/Documentation/i386/boot.txt	Thu Jan 24 11:06:16 2002
@@ -2,7 +2,7 @@
 		     ----------------------------
 
 		    H. Peter Anvin <hpa@zytor.com>
-			Last update 2000-10-29
+			Last update 2002-01-01
 
 On the i386 platform, the Linux kernel uses a rather complicated boot
 convention.  This has evolved partially due to historical aspects, as
@@ -25,12 +25,15 @@
 Protocol 2.01:	(Kernel 1.3.76) Added a heap overrun warning.
 
 Protocol 2.02:	(Kernel 2.4.0-test3-pre3) New command line protocol.
-		Lower the conventional memory ceiling.  No overwrite
+		Lower the conventional memory ceiling.	No overwrite
 		of the traditional setup area, thus making booting
 		safe for systems which use the EBDA from SMM or 32-bit
 		BIOS entry points.  zImage deprecated but still
 		supported.
 
+Protocol 2.03:	(Kernel 2.4.18-pre1) Explicitly makes the highest possible
+		initrd address available to the bootloader.
+
 
 **** MEMORY LAYOUT
 
@@ -45,7 +48,7 @@
 098000	+------------------------+	
 	|  Kernel setup		 |	The kernel real-mode code.
 090200	+------------------------+
-	|  Kernel boot sector    |	The kernel legacy boot sector.
+	|  Kernel boot sector	 |	The kernel legacy boot sector.
 090000	+------------------------+
 	|  Protected-mode kernel |	The bulk of the kernel image.
 010000	+------------------------+
@@ -62,16 +65,16 @@
 When using bzImage, the protected-mode kernel was relocated to
 0x100000 ("high memory"), and the kernel real-mode block (boot sector,
 setup, and stack/heap) was made relocatable to any address between
-0x10000 and end of low memory.  Unfortunately, in protocols 2.00 and
+0x10000 and end of low memory.	Unfortunately, in protocols 2.00 and
 2.01 the command line is still required to live in the 0x9XXXX memory
 range, and that memory range is still overwritten by the early kernel.
-The 2.02 protocol fixes that.
+The 2.02 protocol resolves that problem.
 
 It is desirable to keep the "memory ceiling" -- the highest point in
 low memory touched by the boot loader -- as low as possible, since
 some newer BIOSes have begun to allocate some rather large amounts of
 memory, called the Extended BIOS Data Area, near the top of low
-memory.  The boot loader should use the "INT 12h" BIOS call to verify
+memory.	 The boot loader should use the "INT 12h" BIOS call to verify
 how much low memory is available.
 
 Unfortunately, if INT 12h reports that the amount of memory is too
@@ -112,7 +115,8 @@
 0202/4	2.00+	header		Magic signature "HdrS"
 0206/2	2.00+	version		Boot protocol version supported
 0208/4	2.00+	realmode_swtch	Boot loader hook (see below)
-020C/4	2.00+	start_sys	Points to kernel version string
+020C/2	2.00+	start_sys	The load-low segment (0x1000) (obsolete)
+020E/2	2.00+	kernel_version	Pointer to kernel version string
 0210/1	2.00+	type_of_loader	Boot loader identifier
 0211/1	2.00+	loadflags	Boot protocol option flags
 0212/2	2.00+	setup_move_size	Move to high memory size (used with hooks)
@@ -123,6 +127,7 @@
 0224/2	2.01+	heap_end_ptr	Free memory after setup end
 0226/2	N/A	pad1		Unused
 0228/4	2.02+	cmd_line_ptr	32-bit pointer to the kernel command line
+022C/4	2.03+	initrd_addr_max	Highest legal initrd address
 
 For backwards compatibility, if the setup_sects field contains 0, the
 real value is 4.
@@ -140,6 +145,15 @@
 setting fields in the header, you must make sure only to set fields
 supported by the protocol version in use.
 
+The "kernel_version" field, if set to a nonzero value, contains a
+pointer to a null-terminated human-readable kernel version number
+string, less 0x200.  This can be used to display the kernel version to
+the user.  This value should be less than (0x200*setup_sects).  For
+example, if this value is set to 0x1c00, the kernel version number
+string can be found at offset 0x1e00 in the kernel file.  This is a
+valid value if and only if the "setup_sects" field contains the value
+14 or higher.
+
 Most boot loaders will simply load the kernel at its target address
 directly.  Such boot loaders do not need to worry about filling in
 most of the fields in the header.  The following fields should be
@@ -160,6 +174,9 @@
 	3  SYSLINUX
 	4  EtherBoot
 
+	Please contact <hpa@zytor.com> if you need a bootloader ID
+	value assigned.
+
   loadflags, heap_end_ptr:
 	If the protocol version is 2.01 or higher, enter the
 	offset limit of the setup heap into heap_end_ptr and set the
@@ -180,9 +197,9 @@
 
 	The initrd should typically be located as high in memory as
 	possible, as it may otherwise get overwritten by the early
-	kernel initialization sequence.  However, it must never be
-	located above address 0x3C000000 if you want all kernels to
-	read it.
+	kernel initialization sequence.	 However, it must never be
+	located above the address specified in the initrd_addr_max
+	field.	The initrd should be at least 4K page aligned.
 
   cmd_line_ptr:
 	If the protocol version is 2.02 or higher, this is a 32-bit
@@ -192,7 +209,15 @@
 	command line, in which case you can point this to an empty
 	string (or better yet, to the string "auto".)  If this field
 	is left at zero, the kernel will assume that your boot loader
-	does not support the 2.02 protocol.
+	does not support the 2.02+ protocol.
+
+  ramdisk_max:
+	The maximum address that may be occupied by the initrd
+	contents.  For boot protocols 2.02 or earlier, this field is
+	not present, and the maximum address is 0x37FFFFFF.  (This
+	address is defined as the address of the highest safe byte, so
+	if your ramdisk is exactly 131072 bytes long and this field is
+	0x37FFFFFF, you can start your ramdisk at 0x37FE0000.)
 
 
 **** THE KERNEL COMMAND LINE
@@ -254,14 +279,14 @@
 		if ( protocol >= 0x0202 ) {
 			cmd_line_ptr = base_ptr + 0x9000;
 		} else {
-			cmd_line_magic  = 0xA33F;
+			cmd_line_magic	= 0xA33F;
 			cmd_line_offset = 0x9000;
 			setup_move_size = 0x9100;
 		}
 	} else {
 		/* Very old kernel */
 
-		cmd_line_magic  = 0xA33F;
+		cmd_line_magic	= 0xA33F;
 		cmd_line_offset = 0x9000;
 
 		/* A very old kernel MUST have its real-mode code
@@ -411,4 +436,3 @@
 
 	After completing your hook, you should jump to the address
 	that was in this field before your boot loader overwrote it.
-
diff -u --recursive --new-file v2.5.2/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.5.2/linux/Documentation/ioctl-number.txt	Wed Jul 11 16:35:37 2001
+++ linux/Documentation/ioctl-number.txt	Thu Jan 17 14:06:53 2002
@@ -101,7 +101,8 @@
 'S'	82-FF	scsi/scsi.h		conflict!
 'T'	all	linux/soundcard.h	conflict!
 'T'	all	asm-i386/ioctls.h	conflict!
-'U'	all	linux/drivers/usb/usb.h
+'U'	00-EF	linux/drivers/usb/usb.h
+'U'	F0-FF	drivers/usb/auerswald.c
 'V'	all	linux/vt.h
 'W'	00-1F	linux/watchdog.h	conflict!
 'W'	00-1F	linux/wanrouter.h	conflict!
diff -u --recursive --new-file v2.5.2/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt
--- v2.5.2/linux/Documentation/kernel-parameters.txt	Wed Jun 20 11:21:33 2001
+++ linux/Documentation/kernel-parameters.txt	Mon Jan 21 15:55:46 2002
@@ -125,6 +125,13 @@
 
 	BusLogic=	[HW,SCSI]
 
+	cachesize=	[BUGS=ix86] Override level 2 CPU cache size detection.
+			Sometimes CPU hardware bugs make them report the cache
+			size incorrectly. The kernel will attempt work arounds
+			to fix known problems, but for some CPUs it is not
+			possible to determine what the correct size should be.
+			This option provides an override for these situations.
+
 	cdu31a=		[HW,CD]
 
 	chandev=	[HW,NET] 
diff -u --recursive --new-file v2.5.2/linux/Documentation/networking/decnet.txt linux/Documentation/networking/decnet.txt
--- v2.5.2/linux/Documentation/networking/decnet.txt	Fri Feb 16 15:53:08 2001
+++ linux/Documentation/networking/decnet.txt	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/Documentation/pci.txt linux/Documentation/pci.txt
--- v2.5.2/linux/Documentation/pci.txt	Sun Nov  4 09:31:57 2001
+++ linux/Documentation/pci.txt	Mon Jan 21 15:55:46 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/Documentation/scsi-generic.txt linux/Documentation/scsi-generic.txt
--- v2.5.2/linux/Documentation/scsi-generic.txt	Tue May  1 16:04:56 2001
+++ linux/Documentation/scsi-generic.txt	Sun Jan 27 11:35:23 2002
@@ -1,793 +1,101 @@
-            Notes on Linux's SG driver version 2.1.39
-            -----------------------------------------
-                                                        20010329
-
+            Notes on Linux SCSI Generic (sg) driver
+            ---------------------------------------
+                                                        20020126
 Introduction
 ============
 The SCSI Generic driver (sg) is one of the four "high level" SCSI device
 drivers along with sd, st and sr (disk, tape and CDROM respectively). Sg
 is more generalized (but lower level) than its siblings and tends to be
 used on SCSI devices that don't fit into the already serviced categories.
-Thus sg is used for scanners, cd writers and reading audio cds digitally
+Thus sg is used for scanners, CD writers and reading audio CDs digitally
 amongst other things.
 
-These are notes on the Linux SCSI generic packet device driver (sg)
-describing version 2.1.39 . The original driver was written by Lawrence
-Foard and remained in place with minimal changes since circa 1992.
-Version 2 of this driver remains backward compatible (binary and
-source **) with the original. It adds scatter gather, command queuing,
-per file descriptor sequencing, asynchronous notification and better
-error reporting.
-
-This is an abridged version of the sg documentation that is targeted
-at the linux/Documentation directory. The full document can be found
-at http://www.torque.net/sg/p/scsi-generic_long.txt .
-
-The Linux 2.4 series kernels have now been released. Lk 2.4 contains
-an upgraded "version 3" sg driver which is described in a supplementary
-document at http://www.torque.net/sg/p/scsi-generic_v3.txt .
-
-The interface and usage of the original sg driver have been documented
-by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy
-of the document is version 1.5 dated 7th May 1996. It can found at
-ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO-SCSI-Programming-HOWTO .
-A copy of this document can be found at:
-http://www.torque.net/sg/p/original/HOWTO-SCSI-Programming-HOWTO.txt .
-
-** It is possible to write applications that perform differently
-depending on whether they are using the original or this version of
-the sg device driver. The author is not aware of any useful
-pre-existing applications that have problems with version 2.
-
-
-Architecture
-============
-The SCSI generic packet device driver (sg) is a character based device.
-It is one of the four high level device driver in the SCSI sub-system;
-the others are sd (for direct-access devices - disks), st (for tapes)
-and sr (for data cdroms). Sd and sr are block devices while st (like sg)
-is a character device.
-
-The unifying layer of the SCSI sub-system is the so-called mid-level.
-Below that are the "low level" drivers which are the drivers for the
-various adapters supported by Linux. Also at this level are pseudo
-adapter drivers such as ide-scsi which converts the SCSI protocol to
-ATAPI (which are similar to one another) for use by IDE devices.
-
-Since sg is a character device it supports the traditional Unix
-system calls of open(), close(), read(), write() and ioctl(). Two other
-related system calls: poll() and fcntl() are added to this list and
-how they interact with the sg device driver is documented later.
-
-An SG device is accessed by write()ing SCSI commands plus any associated
-outgoing data to it; the resulting status codes and any incoming data are
-then obtained by a read() call. The device can be opened O_NONBLOCK
-(non-blocking) and poll() used to monitor its progress. The device may be
-opened O_EXCL which excludes other "sg" users from this device (but not
-"sd", "st" or "sr" users). The buffer given to the write() call is made
-up as follows:
-        - struct sg_header image (see below)
-        - scsi command (6, 10 or 12 bytes long)
-        - data to be written to the device (if any)
-
-The buffer received from the corresponding read() call contains:
-        - struct sg_header image (check status/errors + sense_buffer)
-        - data read back from device (if any)
-
-The given SCSI command has its LUN field overwritten by the LUN value of
-the associated sg device that has been open()ed.
-
-SCSI commands are only attempted once (i.e. there are no internal
-retries). If appropriate (e.g. a SCSI READ) the data buffer is copied back
-to user space irrespective of the values of the various SCSI related
-error/status codes. [Some adapters that use an old error interface in
-the SCSI mid level ignore the retry count and retry certain errors.]
-
-
-sg_header
-=========
-This is the name of the control structure that conveys information
-about the length of data to be read/written by the associated SCSI
-command. It also conveys error and status information from the
-read() call. An instance of this structure is the first thing that
-is placed in the data buffers of both write() and read().
-
-In its original form it looked like this:
-struct sg_header {
-    int pack_len;
-    int reply_len;
-    int pack_id;
-    int result;
-    unsigned int twelve_byte:1;
-    unsigned int other_flags:31;
-    unsigned char sense_buffer[16];
-}; /* this structure is 36 bytes long */
-
-The 'pack_len' is bizarre and ends up having the 'reply_len' put in it
-(perhaps it had a use at some stage). Even though it looks like an
-input variable, it is not read by sg internally (only written).
-
-The 'reply_len' is the length of the data the corresponding read()
-will/should request (including the sg_header).
-
-The 'pack_id' is not acted upon by the sg device driver but is conveyed
-back to the corresponding read() so it can be used for sequencing by an
-application.
-
-The 'result' is also bizarre, turning certain types of host codes to 0 (no
-error), EBUSY or EIO. With better error reporting now available, the
-'result' is best ignored.
-
-The 'twelve_byte' field overrides the internal SCSI command length detection
-algorithm for group 6 and 7 commands (ie when 1st byte >= 0xc0) and forces
-a command length of 12 bytes.
-The command length detection algorithm is as follows:
-Group:  0    1    2    3    4    5    6    7
-Length: 6   10   10   12   12   12   10   10
-
-'other_flags' was originally documented as "not used" but some current
-applications assume it has 0 placed in it.
-
-The 'sense_buffer' is the first 16 bytes of SCSI sense buffer that is
-returned when the target returns a SCSI status code of CHECK_CONDITION
-or COMMAND_TERMINATED [or (driver_status & DRIVER_SENSE) is true]. This
-buffer should be at least 18 bytes long and arguably 32 bytes; unfortunately
-this is unlikely to happen in the 2.2.x series of kernels.
-
-
-The new sg_header offered in this driver is:
-#define SG_MAX_SENSE 16
-struct sg_header
-{
-    int pack_len;    /* [o] reply_len (ie useless) ignored as input */
-    int reply_len;   /* [i] max length of expected reply (inc. sg_header) */
-    int pack_id;     /* [io] id number of packet (use ints >= 0) */
-    int result;      /* [o] 0==ok, else (+ve) Unix errno (best ignored) */
-    unsigned int twelve_byte:1;
-        /* [i] Force 12 byte command length for group 6 & 7 commands  */
-    unsigned int target_status:5;   /* [o] scsi status from target */
-    unsigned int host_status:8;     /* [o] host status (see "DID" codes) */
-    unsigned int driver_status:8;   /* [o] driver status+suggestion */
-    unsigned int other_flags:10;    /* unused */
-    unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] Output in 3 cases:
-           when target_status is CHECK_CONDITION or
-           when target_status is COMMAND_TERMINATED or
-           when (driver_status & DRIVER_SENSE) is true. */
-};      /* This structure is 36 bytes long on i386 */
-
-Firstly the new header is binary compatible with the original. This is
-important for keeping existing apps working without recompilation.
-
-Only those elements (or fields) that are new or in some way different
-from the original are documented below.
-
-'pack_id' becomes input to a read() when ioctl(sg_fd, SG_SET_FORCE_PACK_ID,
-&one) is active. A 'pack_id' of -1 is interpreted as fetch the oldest
-waiting packet; any other value will cause the read() to wait (or yield
-EAGAIN) until a packet with that 'pack_id' becomes available. In all cases
-the value of 'pack_id' available after a read() is the value given to that
-variable in the prior, corresponding write().
-
-The SCSI command length can now be given directly using the SG_NEXT_CMD_LEN
-ioctl().
-
-The 'target_status' field is always output and is the (masked and shifted
-1 bit right) SCSI status code from the target device. The allowable
-values are (found in <scsi/scsi.h>):
-/* N.B. 1 bit offset from usual SCSI status values */
-#define GOOD                 0x00
-#define CHECK_CONDITION      0x01
-#define CONDITION_GOOD       0x02
-#define BUSY                 0x04
-#define INTERMEDIATE_GOOD    0x08
-#define INTERMEDIATE_C_GOOD  0x0a
-#define RESERVATION_CONFLICT 0x0c
-#define COMMAND_TERMINATED   0x11
-#define QUEUE_FULL           0x14
-When the 'target_status' is CHECK_CONDITION or COMMAND_TERMINATED the
-'sense_buffer' is output. Note that when (driver_status & DRIVER_SENSE)
-is true then the 'sense_buffer' is also output (this seems to occur when
-the ide-scsi emulation is used). When the 'sense_buffer' is output the
-SCSI Sense Key can be found at (sense_buffer[2] & 0x0f) .
-
-The 'host_status' field is always output and has the following values
-whose "defines" are not visible outside the kernel. A copy of these
-defines can be found in sg_err.h (see the utilities section):
-#define DID_OK          0x00 /* NO error                                */
-#define DID_NO_CONNECT  0x01 /* Couldn't connect before timeout period  */
-#define DID_BUS_BUSY    0x02 /* BUS stayed busy through time out period */
-#define DID_TIME_OUT    0x03 /* TIMED OUT for other reason              */
-#define DID_BAD_TARGET  0x04 /* BAD target, device not responding?      */
-#define DID_ABORT       0x05 /* Told to abort for some other reason     */
-#define DID_PARITY      0x06 /* Parity error                            */
-#define DID_ERROR       0x07 /* Internal error [DMA underrun on aic7xxx]*/
-#define DID_RESET       0x08 /* Reset by somebody.                      */
-#define DID_BAD_INTR    0x09 /* Got an interrupt we weren't expecting.  */
-#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer            */
-#define DID_SOFT_ERROR  0x0b /* The low level driver wants a retry      */
-
-The 'driver_status' field is always output. When ('driver_status' &
-DRIVER_SENSE) is true the 'sense_buffer' is also output. A copy of these
-defines can be found in sg_err.h (see the utilities section):
-#define DRIVER_OK           0x00 /* Typically no suggestion */
-#define DRIVER_BUSY         0x01
-#define DRIVER_SOFT         0x02
-#define DRIVER_MEDIA        0x03
-#define DRIVER_ERROR        0x04
-#define DRIVER_INVALID      0x05
-#define DRIVER_TIMEOUT      0x06
-#define DRIVER_HARD         0x07
-#define DRIVER_SENSE        0x08 /* Implies sense_buffer output */
-/* above status 'or'ed with one of the following suggestions */
-#define SUGGEST_RETRY       0x10
-#define SUGGEST_ABORT       0x20
-#define SUGGEST_REMAP       0x30
-#define SUGGEST_DIE         0x40
-#define SUGGEST_SENSE       0x80
-
-'other_flags' still remains as a 10 bit field (reduced from 31 bits), so
-code that places 0 in it will still be happy. It is not used.
-
-
-System Calls
-============
-What follows are descriptions of the characteristics of the standard
-Unix operating system calls when applied to a SCSI generic device
-using this version of the device driver.
-
-open(const char * filename, int flags)
---------------------------------------
-The filename should be an 'sg' device such as
-/dev/sg[0,1,2,...]
-/dev/sg[a-z]             <<< now deprecated >>>
-or a symbolic link to one of these. [Devfs has its own sub-directory for
-sg devices with entries like: /dev/scsi/host1/bus2/target3/lun4/generic .]
-It seems as though SCSI devices are allocated to sg minor numbers in the
-same order as they appear in 'cat /proc/scsi/scsi'. Sg is a "character"
-based Linux device driver.  This means it has an open/close/read/write/ioctl
-type interface.
-
-Flags can be either O_RDONLY or O_RDWR or-ed with either
-O_EXCL          waits for other opens on sg device to be closed before
-                proceeding. If O_NONBLOCK is set then yields EBUSY when
-                someone else has the sg device open. The combination of
-                O_RDONLY and O_EXCL is disallowed.
-O_NONBLOCK      Sets non-blocking mode. Calls that would otherwise block
-                yield EAGAIN (eg read() ) or EBUSY (eg open() ).
-
-The original version of sg did not allow the O_RDONLY (yielding a EACCES
-error). This version allows it for accessing ioctls (e.g. doing an sg
-device scan with the SG_GET_SCSI_ID ioctl) but write()s will not be
-allowed. These flags are found in <fcntl.h> .
-
-By default, sequencing is per file descriptor in this version of sg. This
-means, for example that 2 processes can independently manipulate the same
-sg device at the same time. This may or may not make sense depending on
-the application: 2 processes (logically) reading from the same direct access
-device (ie a disk) is ok while running 2 instances of cd writing software
-on the same device at the same time probably wouldn't be a good idea. The
-previous version of sg supported only per device sequencing and this can
-still be selected with the SG_SET_MERGE_FD,1 ioctl().
-
-The driver will attempt to reserve SG_DEF_RESERVED_SIZE bytes (32KBytes in
-the current sg.h) on open(). The size of this reserved buffer can
-subsequently be modified with the SG_SET_RESERVED_SIZE ioctl(). In both
-cases these are requests subject to various dynamic constraints. The actual
-amount of memory obtained can be found by the SG_GET_RESERVED_SIZE ioctl().
-The reserved buffer will be used if:
-    -  it is not already in use (eg when command queuing is in use)
-    -  a write() does not call for a buffer size larger than the
-       reserved size.
-
-Returns a file descriptor if >= 0 , otherwise -1 implies an error.
-
-Error codes (value in 'errno' after -1 returned):
-EACCES          Either the user doesn't have appropriate permissions on
-                'filename' or attempted to use both O_RDONLY and O_EXCL
-EBUSY           O_NONBLOCK set and some user of this sg device has O_EXCL
-                set while someone is already using this device
-EINTR           while waiting for an "exclusive" lock to clear, a signal
-                is received, just try again ...
-ENODEV          sg not compiled into kernel or the kernel cannot find the
-                sg module (or it can't initialize itself (low memory??))
-ENOENT          given filename not found
-ENOMEM          An attempt to get memory to store this open's context
-                failed (this was _not_ a request to reserve DMA memory)
-ENXIO           either there is no attached device corresponding to given
-                filename or scsi sub-system is currently processing some
-                error (eg doing a device reset) or the sg driver/module
-                removed or corrupted
-
-
-write(int sg_fd, const void * buffer, size_t count)
----------------------------------------------------
-Even though sg is a character-based device driver it sends and receives
-packets to/from the associated scsi device. Write() is used to send a
-packet containing 2 mandatory parts and 1 optional part. The mandatory
-parts are:
-  - a control block (an instance of struct sg_header)
-  - a SCSI command (6, 10 or 12 bytes long)
-The optional part is:
-  - outgoing data (eg if a SCSI write command is being sent)
-These should appear as one contiguous string in the buffer given to
-write() in the above order with no pad characters.
-
-If a write() accepts this packet then at some later time the user should
-call a read() to get the result of the SCSI command. The previous sg
-driver enforced a strict write()/read()/write()/read() regime so that a
-second write() would block until first read() was finished. This sg
-driver relaxes that condition and thereby allows command queuing
-(limit is SG_MAX_QUEUE (16) outstanding packets per file descriptor).
-However, for backward compatibility, command queuing is turned off
-by default (#define SG_DEF_COMMAND_Q 0 in sg.h). This can be changed
-via the SG_SET_COMMAND_Q ioctl() [or by recompiling after changing
-the above define to 1].
-
-In this sg driver a write() should return more or less immediately.
-
-Returns number of bytes written if > 0 , otherwise -1 implies an error.
-
-Error codes (value in 'errno' after -1 returned):
-EACCES          opened with RD_ONLY flag
-EAGAIN          SCSI mid-level out of command blocks (rare), try again.
-                This is more likely to happen when queuing commands,
-                so wait a bit (eg usleep(10000) ) before trying again
-EDOM            a) command queuing off: a packet is already queued
-                b) command queuing on: too many packets queued
-                   (SG_MAX_QUEUE exceeded)
-EFAULT          'buffer' for 'count' bytes is an invalid memory range
-EIO             a) incoming buffer too short. It should be at least
-                   (6 + sizeof(struct sg_header))==42 bytes long
-                b) SCSI command length given in SG_NEXT_CMD_LEN too long
-                c) reply_len negative
-ENOMEM          can't get memory for DMA. Take evasive action ...
-ENXIO           either scsi sub-system is currently processing some error
-                (eg doing a device reset) or the sg driver/module removed
-                or corrupted
-
-
-read(int sg_fd, void * buffer, size_t count)
---------------------------------------------
-Read() is used to receive a packet containing 1 mandatory part and 1
-optional part. The mandatory part is:
-  - a control block (an instance of struct sg_header)
-The optional part is:
-  - incoming data (eg if a SCSI read command was sent by earlier write() )
-The buffer given to a read() and its corresponding count should be
-sufficient to accommodate this packet to avoid truncation. Truncation occurs
-if count < sg_header::replylen .
-
-By default, read() will return the oldest packet queued up. If the
-SG_SET_FORCE_PACK_ID,1 ioctl() is active then read() will attempt to
-fetch the packet whose pack_id (given earlier to write()) matches the
-sg_header::pack_id given to this read(). If not available it will either
-wait or yield EAGAIN. As a special case, -1 in sg_header::pack_id given
-to read() will match the oldest packet.
-
-Returns number of bytes read if > 0 , otherwise -1 implies an error.
-Unfortunately the return value in the non-error case is simply the
-same as the count argument. It is not the actual number of bytes
-DMA-ed by the SCSI device. This driver is currently unable to provide
-such an underrun indication.
-
-If the SCSI device reports an error then a REQUEST SENSE is automatically
-done and the output is placed in the sense_buffer array which is in the
-control block. This action is sometimes called "auto-sense".
-
-Error codes (value in 'errno' after -1 returned):
-EAGAIN          either no waiting packet or requested packet is not
-                available while O_NONBLOCK flag was set
-EFAULT          'buffer' for 'count' bytes is an invalid memory range
-EINTR           while waiting for a packet, a signal is received, just
-                try again ...
-EIO             if the 'count' given to read() is < sizeof(struct sg_header)
-                and the 'result' element in sg_header is non-zero. Not a
-                recommended error reporting technique
-ENXIO           either scsi sub-system is currently processing some error
-                (eg doing a device reset) or the sg driver/module removed
-                or corrupted
-
-
-close(int sg_fd)
-----------------
-Preferably a close() should be done after all issued write()s have had
-their corresponding read() calls completed. Unfortunately this is not
-always possible. The semantics of close() in Unix are to return more
-or less immediately (ie not wait on any event) so the driver needs to
-arrange for an orderly cleanup of those packets that are still "in
-flight".
-
-A process that has an open file descriptor to an sg device may be aborted
-(eg by a kill signal). In this case, the kernel automatically calls close
-(which is called 'sg_release()' in the version 2 driver) to facilitate
-the cleanup mentioned above.
-
-A problem persists in version 2.1.39 if the sg driver is a module and is
-removed while packets are still "in flight".
-
-Returns 0 if successful, otherwise -1 implies an error.
-
-Error codes (value in 'errno' after -1 returned):
-ENXIO           sg driver/module removed or corrupted
-
-ioctl(int sg_fd, int command, ...)  [sg specific]
--------------------------------------------------
-Ken Thompson (or perhaps some other Unix luminary) described ioctl() as
-the "garbage bin of Unix". This driver compounds the situation by adding
-more ...
-If a ioctl command is not recognized by sg (and the various lower levels
-that it may pass the command on to) then the error EINVAL occurs. If an
-invalid address is given (in the 3rd argument) then the error EFAULT occurs.
-
-Those commands with an appended "+" are new in version 2.
-
-Those commands with an appended "W" are only accessible from file
-descriptors opened with O_RDWR. They will yield EACCES otherwise.
-
-SG_GET_TIMEOUT:
-Ignores its 3rd argument and _returns_ the timeout value (which will be
->= 0 ). The unit of this timeout is "jiffies" which are currently 10
-millisecond intervals on i386 (less on an alpha). Linux supplies
-a manifest constant HZ which is the number of "jiffies" in 1 second.
-
-SG_SET_TIMEOUT:
-Assumes 3rd argument points to an int containing the new timeout value
-for this file descriptor. The unit is a "jiffy". Packets that are
-already "in flight" will not be affected. The default value is set
-on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h). This default is
-currently 1 minute and may not be long enough for formats. Negative
-values will yield an EIO error.
-
-SG_EMULATED_HOST:
-Assumes 3rd argument points to an int and outputs a flag indicating
-whether the host (adapter) is connected to a real SCSI bus or is an
-emulated one (eg ide-scsi device driver). A value of 1 means emulated
-while 0 is not.
-
-SG_SET_TRANSFORM  W:
-Only is meaningful when SG_EMULATED host has yielded 1 (i.e. the low-level
-is the ide-scsi device driver); otherwise an EINVAL error occurs. The
-default state is to _not_ transform SCSI commands to the corresponding
-ATAPI commands but pass them straight through as is. [Only certain classes
-of SCSI commands need to be transformed to their ATAPI equivalents.]
-The third argument is interpreted as an integer. When it is non-zero then
-a flag is set inside the ide-scsi driver that transforms subsequent
-commands sent to this driver. When zero is passed as the 3rd argument to
-this ioctl then the flag within the ide-scsi driver is cleared and
-subsequent commands are not transformed. Beware, this state will affect
-all devices (and hence all related sg file descriptors) associated with
-this ide-scsi "bus".
-
-SG_GET_TRANSFORM:
-Third argument is ignored. Only is meaningful when SG_EMULATED host has
-yielded 1 (ie the low-level is the ide-scsi device driver); otherwise
-an EINVAL error occurs. Returns 0 to indicate _not_ transforming SCSI
-to ATAPI commands (default). Returns 1 when it is transforming them.
-
-SG_SET_FORCE_LOW_DMA +:
-Assumes 3rd argument points to an int containing 0 or 1. 0 (default)
-means sg decides whether to use memory above 16 Mbyte level (on i386)
-based on the host adapter being used by this SCSI device. Typically
-PCI SCSI adapters will indicate they can DMA to the whole 32 bit address
-space.
-If 1 is given then the host adapter is overridden and only memory below
-the 16MB level is used for DMA. A requirement for this should be
-extremely rare. If the "reserved" buffer allocated on open() is not in
-use then it will be de-allocated and re-allocated under the 16MB level
-(and the latter operation could fail yielding ENOMEM).
-Only the current file descriptor is affected.
-
-SG_GET_LOW_DMA +:
-Assumes 3rd argument points to an int and places 0 or 1 in it. 0
-indicates the whole 32 bit address space is being used for DMA transfers
-on this file descriptor. 1 indicates the memory below the 16MB level
-(on i386) is being used (and this may be the case because the host
-adapters setting has been overridden by SG_SET_FORCE_LOW_DMA,1 .
-
-SG_GET_SCSI_ID +:
-Assumes 3rd argument is pointing to an object of type Sg_scsi_id (see
-sg.h) and populates it. That structure contains ints for host_no,
-channel, scsi_id, lun, scsi_type, allowable commands per lun and
-queue_depth. Most of this information is available from other sources
-(eg SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER) but tends to be
-awkward to collect.
-Allowable commands per lun and queue_depth give an insight to the
-command queuing capabilities of the adapters and the device. The latter
-overrides the former (logically) and the former is only of interest
-if it is equal to queue_depth which probably indicates the device
-does not support queueing commands (e.g. most scanners).
-
-SG_SET_FORCE_PACK_ID +:
-Assumes 3rd argument is pointing to an int. 0 (default) instructs read()
-to return the oldest (written) packet if multiple packets are
-waiting to be read (when command queuing is being used).
-1 instructs read() to view the sg_header::pack_id as input and return the
-oldest packet matching that pack_id or wait until it arrives (or yield
-EAGAIN if O_NONBLOCK is in force). As a special case the pack_id of -1
-given to read() in the mode will match the oldest packet.
-Only the current file descriptor is affected by this command.
-
-SG_GET_PACK_ID +:
-Assumes 3rd argument points to an int and places the pack_id of the
-oldest (written) packet in it. If no packet is waiting to be read then
-yields -1.
-
-SG_GET_NUM_WAITING +:
-Assumes 3rd argument points to an int and places the number of packets
-waiting to be read in it.
-
-SG_GET_SG_TABLESIZE +:
-Assumes 3rd argument points to an int and places the maximum number of
-scatter gather elements supported by the host adapter. 0 indicates that
-the adapter does support scatter gather.
-
-SG_SET_RESERVED_SIZE +W:
-Assumes 3rd argument is pointing to an int. That value will be used to
-request a new reserved buffer of that size. The previous reserved buffer
-is freed (if it is not in use; if it was in use -EBUSY is returned).
-A new reserved buffer is then allocated and its actual size can be found by
-calling the SG_GET_RESERVED_SIZE ioctl(). The reserved buffer is then used
-for DMA purposes by subsequent write() commands if it is not already in
-use and if the write() is not calling for a buffer size larger than that
-reserved. The reserved buffer may well be a series of kernel buffers if the
-adapter supports scatter-gather. Large buffers can be requested (eg 1 MB).
-
-SG_GET_RESERVED_SIZE +:
-Assumes 3rd argument points to an int and places the size in bytes of
-the reserved buffer from open() or the most recent SG_SET_RESERVED_SIZE
-ioctl() call on this fd.  The result can be 0 if memory is very tight. In
-this case it may not be wise to attempt something like burning a CD on
-this file descriptor.
-
-SG_SET_MERGE_FD +W:
-Assumes 3rd argument is pointing to an int. 0 (the default) causes all
-subsequent sequencing to be per file descriptor. 1 causes all subsequent
-sequencing to be per device. If this command tries to change the current
-state and there is one or more _other_ file descriptors using this sg
-device then an EBUSY error occurs. Per device sequencing was the original
-semantics and allowed, for example different processes to "share" the
-device, one perhaps write()ing with the other one read()ing. This command
-is supplied if anyone needs those semantics. Per file descriptor
-sequencing, perhaps with the use of the O_EXCL flag, seems more sensible.
-
-SG_GET_MERGE_FD +:
-Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
-sequencing is per file descriptor. 1 implies sequencing is per device
-(original sg driver's semantics).
-
-SG_SET_COMMAND_Q +:
-Assumes 3rd argument is pointing to an int. 0 (current default, set by
-SG_DEF_COMMAND_Q in sg.h) disables command queuing. Attempts to write()
-a packet while one is already queued will result in a EDOM error.
-1 turns command queuing on.
-Changing the queuing state only affects write()s done after the change.
-Only the current file descriptor is affected by this command.
-
-SG_GET_COMMAND_Q +:
-Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
-that command queuing is off on this file descriptor. 1 implies command
-queuing is on.
-
-SG_SET_UNDERRUN_FLAG +:
-Assumes 3rd argument is pointing to an int. 0 (current default, set by
-SG_DEF_UNDERRUN_FLAG in sg.h) requests underruns be ignored. 1 requests
-that underruns be flagged. [The only low level driver that acts on this
-at the moment is the aic7xxx which yields a DID_ERROR error on underrun.]
-Only the current file descriptor is affected by this command (unless
-"per device" sequencing has been selected).
-
-SG_GET_UNDERRUN_FLAG +:
-Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
-that underruns are not being reported. 1 implies that underruns are being
-reported (see SG_SET_UNDERRUN_FLAG for more details).
-
-SG_NEXT_CMD_LEN +:
-Assumes 3rd argument is pointing to an int. The value of the int (if > 0)
-will be used as the SCSI command length of the next SCSI command sent to
-a write() on this fd. After that write() the SCSI command length logic is
-reset to use automatic length detection (ie depending on SCSI command group
-and the 'twelve_byte' field). If the current SCSI command length maximum of
-12 is exceeded then the affected write() will yield an EDOM error.
-Giving this ioctl() a value of 0 will set automatic length detection for
-the next write(). N.B. Only the following write() on this fd is affected by
-this ioctl().
-
-SG_GET_VERSION_NUM +:
-Assumes 3rd argument points to an int. The version number is then placed
-in that int. A sg version such as 2.1.36 will yield "20136" from this ioctl.
-
-SG_SCSI_RESET +:
-Assumes 3rd argument points to an int. Unfortunately doesn't currently
-do much (may in the future after other issues are resolved). Yields an
-EBUSY error if the SCSI bus or the associated device is being reset
-when this ioctl() is called, otherwise returns 0.
-N.B. In some recent distributions there is a patch to the SCSI mid level
-code that activates this ioctl. Check your distribution.
-
-SG_SET_DEBUG +:
-Assumes 3rd argument is pointing to an int. 0 (default) turns debugging
-off. Values > 0 cause the SCSI sense buffer to be decoded and output
-to the console/log when a SCSI device error occurs. Values > 8 cause
-the current sg device driver's state to be output to the console/log
-(this is a "one off" effect).
-If you need a _lot_ of the SCSI sub-system debug information (mainly from
-the mid-level) then try 'echo "scsi dump 0" > /proc/scsi/scsi' and lots of
-debug will appear in your console/log.
-
-
-poll(struct pollfd * udfds, unsigned int nfds, int timeout_ms)
---------------------------------------------------------------
-This is a native call in Linux 2.2 but most of its capabilities are available
-through the older select() call. Given a choice poll() should probably be
-used. Typically poll() is used when a sg scsi device is open()ed O_NONBLOCK
-for polling; and optionally with asynchronous notification as well using
-the fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal.
-Only if something drastically is wrong (eg file handle gone stale) will
-POLLERR ever be set. POLLPRI, POLLHUP and POLLNVAL are never set.
-POLLIN is set when there is one or more packets waiting to be read.
-When POLLIN is set it implies that a read() will not block (nor yield
-EAGAIN in non-blocking mode) but return a packet immediately.
-POLLOUT (aka POLLWRNORM) is set when write() is able to accept a packet
-(ie will _not_ yield an EDOM error). The setting of POLLOUT is affected
-by the SG_SET_COMMAND_Q state: if the state is on then POLLOUT will remain
-set until the number of queued packets reaches SG_MAX_QUEUE, if the
-state is off then POLLOUT is only set when no packets are queued.
-Note that a packet can be queued after write()ing but not available to be
-read(); this typically happens when a SCSI read command is issued while
-the data is being retrieved.
-Poll() is per file descriptor unless SG_SET_MERGE_FD is set in which case
-it is per device.
-
-
-fcntl(int sg_fd, int cmd) or fcntl(int sg_fd, int cmd, long arg)
-----------------------------------------------------------------
-There are several uses for this system call in association with a sg
-file descriptor. The following pseudo code shows code that is useful for
-scanning the sg devices, taking care not to be caught in a wait for
-an O_EXCL lock by another process, and when the appropriate device is
-found, switching to normal blocked io. A working example of this logic
-is in the sg_scan utility program.
-
-open("/dev/sg0", O_RDONLY | O_NONBLOCK)
-/* check device, EBUSY means some other process has O_EXCL lock on it */
-/* when the device you want is found then ... */
-flags = fcntl(sg_fd, F_GETFL)
-fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK))
-/* since, for simple apps, it is easier to use normal blocked io */
-
-
-Some work has to be done in Linux to set up for asynchronous notification.
-This is a non-blocking mode of operation in which, when the driver receives
-data back from a device so that a read() can be done, it sends a SIGPOLL
-(aka SIGIO) signal to the owning process. A working example of this logic
-is in the sg_poll test program.
-
-sigemptyset(&sig_set)
-sigaddset(&sig_set, SIGPOLL)
-sigaction(SIGPOLL, &s_action, 0)
-fcntl(sg_fd, F_SETOWN, getpid())
-flags = fcntl(sg_fd, F_GETFL);
-fcntl(sg_fd, F_SETFL, flags | O_ASYNC)
-
-
-Utility and Test Programs
-=========================
-See the README file in the sg_utils<date>.tgz tarball. Look on the
-http://www.torque.net/sg website for the latest version.
-
-Briefly, that tarball contains the following utilities:
-sg_dd512        'dd' like program that assumes 512 byte blocks size
-sg_dd2048       'dd' like program that assumes 2048 byte blocks size
-sg_dd2352       'dd' like program that assumes 2352 byte blocks size
-sgq_dd512       like 'sg_dd512' but does command queuing on "if"
-sgp_dd          probably the most flexible 'dd' variant. It uses POSIX
-                threads, block size set by "bs=..." plus other options.
-sg_scan         outputs information (optionally Inquiry) on SCSI devices
-sg_rbuf         tests SCSI bus transfer speed (without physical IO)
-sg_whoami       outputs info (optionally capacity) of given SCSI device
-sginfo          outputs "mode" information about SCSI devices (it is a
-                  re-port of the scsiinfo program onto the sg interface)
-
-It also contains the following test programs:
-sg_debug        outputs sg driver state to console/log file
-sg_poll         tests asynchronous notification
-sg_runt_ex      example run time selection program for application authors
-sg_simple1      example program first time users
-sg_simple2      like sg_simple1 but with more primitive error processing
-sg_inquiry      does a SCSI Inquiry command (from original HOWTO)
-sg_tst_med      checks presence of media (from original HOWTO)
-
-There are also 2 source files (sg_err.[hc]) for outputting and categorizing
-SCSI 2 errors and warnings. This code is used by most of the above
-utility and test programs.
-
-The following programs: sg_dd512, sg_dd2048, sg_dd2352, sg_scan, sg_runt_ex,
-sg_rbuf, sg_tst_med, sg_inquiry and sginfo, can be compiled either for this
-new sg driver _or_ the original sg driver (in 2.0 or 2.2 series kernels).
-sg_runt_ex can be run on 2.0, 2.2 or 2.3 series kernels even if it is
-compiled on a different series (eg compiled on 2.0, run on 2.2).
-
-
-Header files
-============
-User applications need to find the correct "sg.h" header file matching
-their kernel in order to write code using the sg device driver. This is
-sometimes more difficult than it should be. The correct "sg.h" will usually
-be found at /usr/src/linux/include/scsi/sg.h . Another important header
-file is "scsi.h" which will be in the same directory.
-
-When "#include <scsi/sg.h>" is written in an application then this refers
-to the file /usr/include/scsi/sg.h . A problem sometimes arises because
-the files in the /usr/include/scsi directory are controlled by the GNU
-library people who maintain glibc. Unfortunately these 2 versions of
-the sg.h header file are not always in sync. [This was the case in Redhat
-6.0 and 6.1 .] Glibc 2.1.3 and later versions should get this right.
-
-If this is a problem, the user may need to copy sg.h (and scsi.h) from
-the kernel source includes to /usr/include scsi. If the user can change
-the effected source code then another approach is to rely on the fact that
-/usr/src/linux is a symbolic link to /usr/src/linux/include/linux and
-change the sg.h include to look like:
-    #include <linux/../scsi/sg.h>
-This solution is used by the author of cdparanoia (Monty) in his application.
-
-[Former scsi generic documents suggested adding a symbolic link to
-bypass this problem but that is not popular with the glibc maintainers.
-I would like to thank Andreas Jaeger <aj@suse.de> for his contributions
-on this subject.]
-
-
-Extra information in scsi-generic_long.txt
-==========================================
-This document is an abridged form of a more comprehensive document called
-scsi-generic_long.txt (see www.torque.net/sg/p/scsi-generic_long.txt).
-
-The longer document contains additional sections on:
-   - memory issues
-   - ioctl()s in common with sd, st + sr
-   - distinguishing the original from the new driver
-   - SG_BIG_BUFF and friends
-   - shortcomings
-   - future directions
-   - an appendix with some SCSI 2 information in it
-
-
-References
-==========
-http://www.t10.org      Very important site for SCSI related information.
-                        Contains SCSI 2 and 3 draft standards.
-http://www.andante.org/scsi.html
-                        This is Eric Youngdale's site. Eric is primarily
-                        responsible for the Linux SCSI architecture and
-                        its mid-level implementation.
-http://www.kernel.dk    Jens Axboe's site for Linux cdrom matters including
-                        the SCSI "sr" driver.
-http://www.torque.net/sg
-                        My site with sg related information.
-newsgroup:linux-scsi@vger.kernel.org
-                        Newsgroup for Linux related SCSI matters
-/usr/src/linux/MAINTAINERS
-                        This is a file in the Linux kernel source that
-                        contains up to date information about who maintains
-                        what and where information can be found. Links to
-                        SCSI adapter information are also here.
-
-
-Conclusion
-==========
-The SCSI generic packet device driver attempts to make as few assumptions
-as possible about the device it is connected to while giving applications
-using it as much flexibility as possible on the SCSI command level. Sg
-needs to hide the "messy" kernel related details while protecting
-the integrity of the kernel against sg "abuse". Some of these aims are
-contradictory and some compromises need to be made. For example: should
-a sg based application be able to reset a SCSI bus when that could cause
-collateral damage to a disk holding the root file system? There is no
-easy answer to this and many other related questions.
-
-If you have any suggestion about sg (or improving (the accuracy of) this
-document) please contact me.
+Rather than document the driver's interface here, version information
+is provided plus pointers (i.e. URLs) where to find documentation
+and examples.
+
+
+Major versions of the sg driver
+===============================
+There are three major versions of sg found in the linux kernel (lk):
+      - sg version 1 (original) from 1992 to early 1999 (lk 2.2.5) . 
+	It is based in the sg_header interface structure.
+      - sg version 2 from lk 2.2.6 in the 2.2 series. It is based on
+	an extended version of the sg_header interface structure.
+      - sg version 3 found in the lk 2.4 series (and the lk 2.5 series).
+	It adds the sg_io_hdr interface structure.
+
+
+Sg driver documentation
+=======================
+The most recent documentation of the sg driver is kept at the Linux
+Documentation Project's (LDP) site: 
+http://www.linuxdoc.org/HOWTO/SCSI-Generic-HOWTO
+This describes the sg version 3 driver found in the lk 2.4 series.
+The LDP renders documents in single and multiple page HTML, postscript
+and pdf. This document can also be found at:
+http://www.torque.net/sg/p/sg_v3_ho.html
+
+Documentation for the version 2 sg driver found in the lk 2.2 series can
+be found at http://www.torque.net/sg/p/scsi-generic.txt . A larger version
+is at:  http://www.torque.net/sg/p/scsi-generic_long.txt .
+
+The original documentation for the sg driver (prior to lk 2.2.6) can be
+found at http://www.torque.net/sg/p/original/SCSI-Programming-HOWTO.txt
+and in the LDP archives.
+
+A changelog with brief notes can be found in the
+/usr/src/linux/include/scsi/sg.h file. Note that the glibc maintainers copy 
+and edit this file (removing its changelog for example) before placing it 
+in /usr/include/scsi/sg.h . Driver debugging information and other notes 
+can be found at the top of the /usr/src/linux/drivers/scsi/sg.c file.
+
+A more general description of the Linux SCSI subsystem of which sg is a 
+part can be found at http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO .
+
+
+Example code and utilities
+==========================
+There are two packages of sg utilities:
+  - sg3_utils   for the sg version 3 driver found in lk 2.4
+  - sg_utils    for the sg version 2 (and original) driver found in lk 2.2
+                and earlier
+Both packages will work in the lk 2.4 series however sg3_utils offers more
+capabilities. They can be found at: http://www.torque.net/sg and 
+freshmeat.net
+
+Another approach is to look at the applications that use the sg driver.
+These include cdrecord, cdparanoia, SANE and cdrdao.
+
+
+Mapping of Linux kernel versions to sg driver versions
+======================================================
+Here is a list of linux kernels in the 2.4 series that had new version
+of the sg driver:
+      lk 2.4.0 : sg version 3.1.17
+      lk 2.4.7 : sg version 3.1.19 
+      lk 2.4.10 : sg version 3.1.20  **
+      lk 2.4.17 : sg version 3.1.22 
+
+** There were 3 changes to sg version 3.1.20 by third parties in the
+   next six linux kernel versions.
+
+For reference here is a list of linux kernels in the 2.2 series that had 
+new version of the sg driver:
+      lk 2.2.0 : original sg version [with no version number]
+      lk 2.2.6 : sg version 2.1.31
+      lk 2.2.8 : sg version 2.1.32
+      lk 2.2.10 : sg version 2.1.34 [SG_GET_VERSION_NUM ioctl first appeared]
+      lk 2.2.14 : sg version 2.1.36
+      lk 2.2.16 : sg version 2.1.38
+      lk 2.2.17 : sg version 2.1.39
+      lk 2.2.20 : sg version 2.1.40
+
+The lk 2.5 development series has recently commenced and it currently
+contains sg version 3.5.23 which is functionally equivalent to sg
+version 3.1.22 found in lk 2.4.17 .
 
 
 Douglas Gilbert
+26th January 2002
 dgilbert@interlog.com
diff -u --recursive --new-file v2.5.2/linux/Documentation/scsi.txt linux/Documentation/scsi.txt
--- v2.5.2/linux/Documentation/scsi.txt	Tue Apr 28 14:22:04 1998
+++ linux/Documentation/scsi.txt	Sun Jan 27 11:35:47 2002
@@ -1,30 +1,44 @@
+SCSI subsystem documentation
+============================
+The Linux Documentation Project (LDP) maintains a document describing
+the SCSI subsystem in the Linux kernel (lk) 2.4 series. See:
+http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO . The LDP has single
+and multiple page HTML renderings as well as postscript and pdf.
+It can also be found at http://www.torque.net/scsi/SCSI-2.4-HOWTO .
 
-	The scsi support in the linux kernel can be modularized in a
-number of different ways depending upon the needs of the end user.  To
-understand  your options, we should first define a few terms.
-
-	The scsi-core contains the core of scsi support.  Without it
-you can do nothing with any of the other scsi drivers.  The scsi core
-support can be a module (scsi_mod.o), or it can be built into the kernel.
-If the core is a module, it must be the first scsi module loaded, and
-if you unload the modules, it will have to be the last one unloaded.
-
-	The individual upper and lower level drivers can be loaded in any
-order once the scsi core is present in the kernel (either compiled in
-or loaded as a module).  The disk driver (sd_mod.o), cdrom driver (sr_mod.o),
-tape driver (st.o) and scsi generics driver (sg.o) represent the upper level
-drivers to support the various assorted devices which can be controlled.
-You can for example load the tape driver to use the tape drive, and then
-unload it once you have no further need for the driver (and release the
-associated memory).
-
-	The lower level drivers are the ones that support the
-individual cards that are supported for the hardware platform that you
-are running under.  Examples are aha1542.o to drive Adaptec 1542
-cards.  Rather than list the drivers which *can* be modularized, it is
-easier to list the ones which cannot, since the list only contains a
-few entries.  The drivers which have NOT been modularized are:
 
-	NCR5380 boards of one kind or another including PAS16,
-		Trantor T128/128F/228, 
+Notes on using modules in the SCSI subsystem
+============================================
+The scsi support in the linux kernel can be modularized in a number of 
+different ways depending upon the needs of the end user.  To understand
+your options, we should first define a few terms.
+
+The scsi-core (also known as the "mid level") contains the core of scsi 
+support.  Without it you can do nothing with any of the other scsi drivers.
+The scsi core support can be a module (scsi_mod.o), or it can be built into
+the kernel. If the core is a module, it must be the first scsi module 
+loaded, and if you unload the modules, it will have to be the last one 
+unloaded.  In practice the modprobe and rmmod commands (and "autoclean")
+will enforce the correct ordering of loading and unloading modules in
+the SCSI subsystem.
+
+The individual upper and lower level drivers can be loaded in any order 
+once the scsi core is present in the kernel (either compiled in or loaded
+as a module).  The disk driver (sd_mod.o), cdrom driver (sr_mod.o),
+tape driver ** (st.o) and scsi generics driver (sg.o) represent the upper 
+level drivers to support the various assorted devices which can be 
+controlled.  You can for example load the tape driver to use the tape drive, 
+and then unload it once you have no further need for the driver (and release
+the associated memory).
+
+The lower level drivers are the ones that support the individual cards that
+are supported for the hardware platform that you are running under. Those
+individual cards are often called Host Bus Adapters (HBAs). For example the
+aic7xxx.o driver is used to control all recent SCSI controller cards from 
+Adaptec. Almost all lower level drivers can be built either as modules or 
+built into the kernel.
+
+
+** There is a variant of the st driver for controlling OnStream tape
+   devices. Its module name is osst.o .
 
diff -u --recursive --new-file v2.5.2/linux/MAINTAINERS linux/MAINTAINERS
--- v2.5.2/linux/MAINTAINERS	Mon Jan 14 18:25:07 2002
+++ linux/MAINTAINERS	Tue Jan 29 10:37:00 2002
@@ -154,8 +154,6 @@
 
 AD1816 SOUND DRIVER
 P:	Thorsten Knabe
-M:	Thorsten Knabe <tek@rbg.informatik.tu-darmstadt.de>
-M:	Thorsten Knabe <tek01@hrzpub.tu-darmstadt.de>
 W:	http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html
 W:	http://www.tu-darmstadt.de/~tek01/projects/linux.html
 S:	Maintained
@@ -216,7 +214,6 @@
 
 ARPD SUPPORT
 P:	Jonathan Layes
-M:	layes@loran.com
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
@@ -235,7 +232,6 @@
 
 BERKSHIRE PRODUCTS PC WATCHDOG DRIVER
 P:	Kenji Hollis
-M:	kenji@bitgate.com
 W:	http://ftp.bitgate.com/pcwd/
 S:	Maintained
 
@@ -412,6 +408,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
@@ -427,13 +429,11 @@
 DIGI INTL. EPCA DRIVER
 P:	Chad Schwartz
 M:      support@dgii.com
-M:      chads@dgii.com
 L:      digilnux@dgii.com
 S:      Maintained
 
 DIGI RIGHTSWITCH NETWORK DRIVER
 P:	Rick Richardson
-M:	rick@remotepoint.com
 L:	linux-net@vger.kernel.org
 W:	http://www.dgii.com/linux/
 S:	Maintained
@@ -479,7 +479,7 @@
 
 DRM DRIVERS
 P:	Rik Faith
-M:	faith@valinux.com
+M:	faith@redhat.com
 L:	dri-devel@lists.sourceforge.net
 S:	Supported
 
@@ -491,7 +491,6 @@
 
 EATA-DMA SCSI DRIVER
 P:	Michael Neuffer
-M:	mike@i-Connect.Net
 L:	linux-eata@i-connect.net, linux-scsi@vger.kernel.org
 S:	Maintained
 
@@ -700,12 +699,12 @@
 IDE DRIVER [GENERAL]
 P:	Andre Hedrick
 M:	andre@linux-ide.org
-M:	andre@aslab.com
-M:	andre@suse.com
+M:	andre@linuxdiskcert.org
 L:	linux-kernel@vger.kernel.org
 W:	http://www.kernel.org/pub/linux/kernel/people/hedrick/
 W:	http://www.linux-ide.org/
-S:	Supported
+W:	http://www.linuxdiskcert.org/
+S:	Maintained
 
 IDE/ATAPI CDROM DRIVER
 P:	Jens Axboe
@@ -921,11 +920,16 @@
 
 LOGICAL VOLUME MANAGER
 P:     Heinz Mauelshagen
-M:     mge@sistina.de
 L:     linux-LVM@sistina.com
 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
@@ -1010,6 +1014,11 @@
 M:	andrewtv@usa.net
 S:	Maintained
 
+NATSEMI ETHERNET DRIVER (DP8381x)
+P: Tim Hockin
+M:	thockin@hockin.org
+S:	Maintained
+
 NCP FILESYSTEM
 P:	Petr Vandrovec
 M:	vandrove@vc.cvut.cz
@@ -1117,7 +1126,7 @@
 
 OLYMPIC NETWORK DRIVER
 P:	Peter De Shrijver
-M:	p2@ace.ulyssis.sutdent.kuleuven.ac.be	
+M:	p2@ace.ulyssis.student.ac.be
 P:	Mike Phillips
 M:	mikep@linuxtr.net 
 L:	linux-net@vger.kernel.org
@@ -1133,8 +1142,8 @@
 S:	Maintained
 
 OPL3-SA2, SA3, and SAx DRIVER
-P:	Scott Murray
-M:	scott@spiteful.org
+P:	Zwane Mwaikambo
+M:	zwane@commfireservices.com
 L:	linux-sound@vger.kernel.org
 S:	Maintained
 
@@ -1276,7 +1285,6 @@
 
 RISCOM8 DRIVER
 P:	Dmitry Gorodchanin
-M:	pgmdsg@ibi.com
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
@@ -1643,13 +1651,11 @@
 USB SERIAL BELKIN F5U103 DRIVER
 P:	William Greathouse
 M:	wgreathouse@smva.com
-M:	wgreathouse@myfavoritei.com
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
 
 USB SERIAL CYBERJACK PINPAD/E-COM DRIVER
-M:	linux-usb@sii.li
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Supported
@@ -1775,7 +1781,6 @@
 
 ZF MACHZ WATCHDOG
 P:	Fernando Fuganti
-M:	fuganti@conectiva.com.br
 M:	fuganti@netbank.com.br
 W:	http://cvs.conectiva.com.br/drivers/ZFL-watchdog/
 S:	Maintained
diff -u --recursive --new-file v2.5.2/linux/Makefile linux/Makefile
--- v2.5.2/linux/Makefile	Mon Jan 14 18:25:07 2002
+++ linux/Makefile	Tue Jan 29 18:24:01 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 2
+SUBLEVEL = 3
 EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -131,7 +131,8 @@
 
 DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
 DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o
-DRIVERS-y += drivers/char/char.o \
+DRIVERS-y += drivers/base/base.o \
+	drivers/char/char.o \
 	drivers/block/block.o \
 	drivers/misc/misc.o \
 	drivers/net/net.o \
@@ -169,7 +170,7 @@
 DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a
 DRIVERS-$(CONFIG_ALL_PPC) += drivers/macintosh/macintosh.o
 DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o
-DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o
+DRIVERS-$(CONFIG_PNP) += drivers/pnp/pnp.o
 DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a
 DRIVERS-$(CONFIG_VT) += drivers/video/video.o
 DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/paride.a
diff -u --recursive --new-file v2.5.2/linux/arch/alpha/Config.help linux/arch/alpha/Config.help
--- v2.5.2/linux/arch/alpha/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/Config.help	Fri Jan 25 16:04:31 2002
@@ -0,0 +1,648 @@
+CONFIG_SMP
+  This enables support for systems with more than one CPU. If you have
+  a system with only one CPU, like most personal computers, say N. If
+  you have a system with more than one CPU, say Y.
+
+  If you say N here, the kernel will run on single and multiprocessor
+  machines, but will use only one CPU of a multiprocessor machine. If
+  you say Y here, the kernel will run on many, but not all,
+  singleprocessor machines. On a singleprocessor machine, the kernel
+  will run faster if you say N here.
+
+  Note that if you say Y here and choose architecture "586" or
+  "Pentium" under "Processor family", the kernel will not work on 486
+  architectures. Similarly, multiprocessor kernels for the "PPro"
+  architecture may not work on all Pentium based boards.
+
+  People using multiprocessor machines who say Y here should also say
+  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+  Management" code will be disabled if you say Y here.
+
+  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-HOWTO available at
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you don't know what to do here, say N.
+
+CONFIG_ALPHA
+  The Alpha is a 64-bit general-purpose processor designed and
+  marketed by the Digital Equipment Corporation of blessed memory, now
+  Compaq.  Alpha Linux dates from 1995-1996 and was the first non-x86
+  port. The Alpha Linux project has a home page at
+  <http://www.alphalinux.org/>.
+
+CONFIG_MATHEMU
+  This option is required for IEEE compliant floating point arithmetic
+  on the Alpha. The only time you would ever not say Y is to say M in
+  order to debug the code. Say Y unless you know what you are doing.
+
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+CONFIG_DISCONTIGMEM
+  Say Y to upport efficient handling of discontiguous physical memory,
+  for architectures which are either NUMA (Non-Uniform Memory Access)
+  or have huge holes in the physical address space for other reasons.
+  See <file:Documentation/vm/numa> for more.
+
+CONFIG_NUMA
+  Say Y to compile the kernel to support NUMA (Non-Uniform Memory
+  Access).  This option is for configuring high-end multiprocessor
+  server machines.  If in doubt, say N.
+
+CONFIG_ALPHA_GENERIC
+  This is the system type of your hardware.  A "generic" kernel will
+  run on any supported Alpha system. However, if you configure a
+  kernel for your specific system, it will be faster and smaller.
+
+  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:
+
+  Alcor/Alpha-XLT     AS 600
+  Alpha-XL            XL-233, XL-266
+  AlphaBook1          Alpha laptop
+  Avanti              AS 200, AS 205, AS 250, AS 255, AS 300, AS 400
+  Cabriolet           AlphaPC64, AlphaPCI64
+  DP264               DP264
+  EB164               EB164 21164 evaluation board
+  EB64+               EB64+ 21064 evaluation board
+  EB66                EB66 21066 evaluation board
+  EB66+               EB66+ 21066 evaluation board
+  Jensen              DECpc 150, DEC 2000 model 300,
+                      DEC 2000 model 500
+  LX164               AlphaPC164-LX
+  Miata               Personal Workstation 433a, 433au, 500a,
+                      500au, 600a, or 600au
+  Mikasa              AS 1000
+  Noname              AXPpci33, UDB (Multia)
+  Noritake            AS 1000A, AS 600A, AS 800
+  PC164               AlphaPC164
+  Rawhide             AS 1200, AS 4000, AS 4100
+  Ruffian             RPX164-2, AlphaPC164-UX, AlphaPC164-BX
+  SX164               AlphaPC164-SX
+  Sable               AS 2000, AS 2100
+  Shark		      DS 20L
+  Takara              Takara
+  Titan               Privateer
+  Wildfire            AlphaServer GS 40/80/160/320
+
+  If you don't know what to do, choose "generic".
+
+CONFIG_ALPHA_ALCOR
+  For systems using the Digital ALCOR chipset: 5 chips (4, 64-bit data
+  slices (Data Switch, DSW) - 208-pin PQFP and 1 control (Control, I/O
+  Address, CIA) - a 383 pin plastic PGA).  It provides a DRAM
+  controller (256-bit memory bus) and a PCI interface.  It also does
+  all the work required to support an external Bcache and to maintain
+  memory coherence when a PCI device DMAs into (or out of) memory.
+
+CONFIG_ALPHA_XL
+  XL-233 and XL-266-based Alpha systems.
+
+CONFIG_ALPHA_BOOK1
+  Dec AlphaBook1/Burns Alpha-based laptops.
+
+CONFIG_ALPHA_AVANTI
+  Avanti AS 200, AS 205, AS 250, AS 255, AS 300, and AS 400-based
+  Alphas. Info at
+  <http://www.unix-ag.org/Linux-Alpha/Architectures/Avanti.html>.
+
+CONFIG_ALPHA_CABRIOLET
+  Cabriolet AlphaPC64, AlphaPCI64 systems.  Derived from EB64+ but now
+  baby-AT with Flash boot ROM, no on-board SCSI or Ethernet. 3 ISA
+  slots, 4 PCI slots (one pair are on a shared slot), uses plug-in
+  Bcache SIMMs.  Requires power supply with 3.3V output.
+
+CONFIG_ALPHA_DP264
+  Various 21264 systems with the tsunami core logic chipset.
+  API Networks: 264DP, UP2000(+), CS20;
+  Compaq: DS10(E,L), XP900, XP1000, DS20(E), ES40.
+
+CONFIG_ALPHA_EB164
+  EB164 21164 evaluation board from DEC.  Uses 21164 and ALCOR.  Has
+  ISA and PCI expansion (3 ISA slots, 2 64-bit PCI slots (one is
+  shared with an ISA slot) and 2 32-bit PCI slots.  Uses plus-in
+  Bcache SIMMs. I/O sub-system provides SuperI/O (2S, 1P, FD), KBD,
+  MOUSE (PS2 style), RTC/NVRAM.  Boot ROM is Flash.  PC-AT-sized
+  motherboard.  Requires power supply with 3.3V output.
+
+CONFIG_ALPHA_EB64P
+  Uses 21064 or 21064A and APECs.  Has ISA and PCI expansion (3 ISA,
+  2 PCI, one pair are on a shared slot). Supports 36-bit DRAM SIMs.
+  ISA bus generated by Intel SaturnI/O PCI-ISA bridge. On-board SCSI
+  (NCR 810 on PCI) Ethernet (Digital 21040), KBD, MOUSE (PS2 style),
+  SuperI/O (2S, 1P, FD), RTC/NVRAM. Boot ROM is EPROM.  PC-AT size.
+  Runs from standard PC power supply.
+
+CONFIG_ALPHA_EB66
+  A Digital DS group board.  Uses 21066 or 21066A.  I/O sub-system is
+  identical to EB64+.  Baby PC-AT size.  Runs from standard PC power
+  supply.  The EB66 schematic was published as a marketing poster
+  advertising the 21066 as "the first microprocessor in the world with
+  embedded PCI".
+
+CONFIG_ALPHA_EB66P
+  Later variant of the EB66 board.
+
+CONFIG_ALPHA_EIGER
+  Apparently an obscure OEM single-board computer based on the
+  Typhoon/Tsunami chipset family. Information on it is scanty.
+
+CONFIG_ALPHA_JENSEN
+  DEC PC 150 AXP (aka Jensen): This is a very old Digital system - one
+  of the first-generation Alpha systems. A number of these systems
+  seem to be available on the second- hand market. The Jensen is a
+  floor-standing tower system which originally used a 150MHz 21064 It
+  used programmable logic to interface a 486 EISA I/O bridge to the
+  CPU.
+
+CONFIG_ALPHA_LX164
+  A technical overview of this board is available at
+  <http://www.unix-ag.org/Linux-Alpha/Architectures/LX164.html>.
+
+CONFIG_ALPHA_MIATA
+  The Digital PersonalWorkStation (PWS 433a, 433au, 500a, 500au, 600a,
+  or 600au).  There is an Installation HOWTO for this hardware at
+  <http://members.brabant.chello.nl/~s.vandereijk/miata.html>.
+
+CONFIG_ALPHA_MIKASA
+  AlphaServer 1000-based Alpha systems.
+
+CONFIG_ALPHA_NAUTILUS
+  Alpha systems based on the AMD 751 & ALI 1543C chipsets.
+
+CONFIG_ALPHA_NONAME
+  The AXPpci33 (aka NoName), is based on the EB66 (includes the Multia
+  UDB).  This design was produced by Digital's Technical OEM (TOEM)
+  group. It uses the 21066 processor running at 166MHz or 233MHz. It
+  is a baby-AT size, and runs from a standard PC power supply. It has
+  5 ISA slots and 3 PCI slots (one pair are a shared slot). There are
+  2 versions, with either PS/2 or large DIN connectors for the
+  keyboard.
+
+CONFIG_ALPHA_NORITAKE
+  AlphaServer 1000A, AlphaServer 600A, and AlphaServer 800-based
+  systems.
+
+CONFIG_ALPHA_RAWHIDE
+  AlphaServer 1200, AlphaServer 4000 and AlphaServer 4100 machines.
+  See HOWTO at
+  <http://www.alphalinux.org/docs/rawhide/4100_install.shtml>.
+
+CONFIG_ALPHA_RUFFIAN
+  Samsung APC164UX.  There is a page on known problems and workarounds
+  at <http://www.alphalinux.org/faq/FAQ-11.html>.
+
+CONFIG_ALPHA_SABLE
+  Digital AlphaServer 2000 and 2100-based systems.
+
+CONFIG_ALPHA_TAKARA
+  Alpha 11164-based OEM single-board computer.
+
+CONFIG_ALPHA_WILDFIRE
+  AlphaServer GS 40/80/160/320 SMP based on the EV67 core.
+
+CONFIG_ALPHA_PRIMO
+  Say Y if you have an AS 1000 5/xxx or an AS 1000A 5/xxx.
+
+CONFIG_ALPHA_GAMMA
+  Say Y if you have an AS 2000 5/xxx or an AS 2100 5/xxx.
+
+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/>.
+
+  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
+  kernel just like lilo does for the x86 architecture) which can be
+  loaded either from ARC or can be installed directly as a permanent
+  firmware replacement from floppy (which requires changing a certain
+  jumper on the motherboard). If you want to do either of these, say N
+  here. If MILO doesn't work on your system (true for Jensen
+  motherboards), you can bypass it altogether and boot Linux directly
+  from an SRM console; say Y here in order to do that. Note that you
+  won't be able to boot from an IDE disk using SRM.
+
+  If unsure, say N.
+
+CONFIG_ALPHA_LEGACY_START_ADDRESS
+  The 2.4 kernel changed the kernel start address from 0x310000
+  to 0x810000 to make room for the Wildfire's larger SRM console.
+
+  If you're using aboot 0.7 or later, the bootloader will examine the
+  ELF headers to determine where to transfer control. Unfortunately,
+  most older bootloaders -- APB or MILO -- hardcoded the kernel start
+  address rather than examining the ELF headers, and the result is a
+  hard lockup.
+
+  Say Y if you have a broken bootloader.  Say N if you do not, or if
+  you wish to run on Wildfire.
+
+CONFIG_ALPHA_LARGE_VMALLOC
+  Process creation and other aspects of virtual memory management can
+  be streamlined if we restrict the kernel to one PGD for all vmalloc
+  allocations.  This equates to about 8GB.
+
+  Under normal circumstances, this is so far and above what is needed
+  as to be laughable.  However, there are certain applications (such
+  as benchmark-grade in-kernel web serving) that can make use of as
+  much vmalloc space as is available.
+
+  Say N unless you know you need gobs and gobs of vmalloc space.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_PCI
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_HOTPLUG
+  Say Y here if you want to plug devices into your computer while
+  the system is running, and be able to use them quickly.  In many
+  cases, the devices can likewise be unplugged at any time too.
+
+  One well known example of this is PCMCIA- or PC-cards, credit-card
+  size devices such as network cards, modems or hard drives which are
+  plugged into slots found on all modern laptop computers.  Another
+  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.
+  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.
+
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+  computer.  These are credit-card size devices such as network cards,
+  modems or hard drives often used with laptops computers.  There are
+  actually two varieties of these cards: the older 16 bit PCMCIA cards
+  and the newer 32 bit CardBus cards.  If you want to use CardBus
+  cards, you need to say Y here and also to "CardBus support" below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  Please also read the PCMCIA-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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_KCORE_AOUT
+  Not necessary unless you're using a very out-of-date binutils
+  version.  You probably want KCORE_ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_AOUT
+  A.out (Assembler.OUTput) is a set of formats for libraries and
+  executables used in the earliest versions of UNIX. Linux used the
+  a.out formats QMAGIC and ZMAGIC until they were replaced with the
+  ELF format.
+
+  As more and more programs are converted to ELF, the use for a.out
+  will gradually diminish. If you disable this option it will reduce
+  your kernel by one page. This is not much and by itself does not
+  warrant removing support. However its removal is a good idea if you
+  wish to ensure that absolutely none of your programs will use this
+  older executable format. If you don't know what to answer at this
+  point then answer Y. If someone told you "You need a kernel with
+  QMAGIC support" then you'll have to say Y here. You may answer M to
+  compile a.out support as a module and later load the module when you
+  want to use a program or library in a.out format. The module will be
+  called binfmt_aout.o. Saying M or N here is dangerous though,
+  because some crucial programs on your system might still be in A.OUT
+  format.
+
+CONFIG_BINFMT_EM86
+  Say Y here if you want to be able to execute Linux/Intel ELF
+  binaries just like native Alpha binaries on your Alpha machine. For
+  this to work, you need to have the emulator /usr/bin/em86 in place.
+
+  You can get the same functionality by saying N here and saying Y to
+  "Kernel support for MISC binaries".
+
+  You may answer M to compile the emulation support as a module and
+  later load the module when you want to use a Linux/Intel binary. The
+  module will be called binfmt_em86.o. If unsure, say Y.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_VGA_CONSOLE
+  Saying Y here will allow you to use Linux in text mode through a
+  display that complies with the generic VGA standard. Virtually
+  everyone wants that.
+
+  The program SVGATextMode can be used to utilize SVGA video cards to
+  their full potential in text mode. Download it from
+  <ftp://ibiblio.org/pub/Linux/utils/console/>.
+
+  Say Y.
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_CD_NO_IDESCSI
+  If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y
+  here, otherwise N. Read the CD-ROM-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about these CD-ROM drives. If you are unsure what you
+  have, say Y and find out whether you have one of the following
+  drives.
+
+  For each of these drivers, a file Documentation/cdrom/{driver_name}
+  exists. Especially in cases where you do not know exactly which kind
+  of drive you have you should read there. Most of these drivers use a
+  file drivers/cdrom/{driver_name}.h where you can define your
+  interface parameters and switch some internal goodies.
+
+  All these CD-ROM drivers are also usable as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want). If you want to compile them as module, say M instead of Y and
+  read <file:Documentation/modules.txt>.
+
+  If you want to use any of these CD-ROM drivers, you also have to
+  answer Y or M to "ISO 9660 CD-ROM file system support" below (this
+  answer will get "defaulted" for you if you enable any of the Linux
+  CD-ROM drivers).
+
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y.  Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. General information about
+  the modular sound system is contained in the files
+  <file:Documentation/sound/Introduction>.  The file
+  <file:Documentation/sound/README.OSS> contains some slightly
+  outdated but still useful information as well.
+
+  If you have a PnP sound card and you want to configure it at boot
+  time using the ISA PnP tools (read
+  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished.  To do
+  this, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/sound/README.modules>; the module will be
+  called soundcore.o.
+
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and supporting utilities to do that are in the pcsp
+  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_ISDN
+  ISDN ("Integrated Services Digital Networks", called RNIS in France)
+  is a special type of fully digital telephone service; it's mostly
+  used to connect to your Internet service provider (with SLIP or
+  PPP).  The main advantage is that the speed is higher than ordinary
+  modem/telephone connections, and that you can have voice
+  conversations while downloading stuff.  It only works if your
+  computer is equipped with an ISDN card and both you and your service
+  provider purchased an ISDN line from the phone company.  For
+  details, read <http://alumni.caltech.edu/~dank/isdn/> on the WWW.
+
+  This driver allows you to use an ISDN-card for networking
+  connections and as dialin/out device.  The isdn-tty's have a built
+  in AT-compatible modem emulator.  Network devices support autodial,
+  channel-bundling, callback and caller-authentication without having
+  a daemon running.  A reduced T.70 protocol is supported with tty's
+  suitable for German BTX.  On D-Channel, the protocols EDSS1
+  (Euro-ISDN) and 1TR6 (German style) are supported.  See
+  <file:Documentation/isdn/README> for more information.
+
+  If you want to compile the ISDN code 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 isdn.o. If unsure, say N.
+
+CONFIG_SRM_ENV
+  If you enable this option, a subdirectory called srm_environment
+  will give you access to the most important SRM environment
+  variables. If you've got an Alpha style system supporting
+  SRC, then it is a good idea to say Yes or Module to this driver.
+
+  This driver is also available as a module and will be called
+  srm_env.o if you build it as a module.
+
+CONFIG_DEBUG_KERNEL
+  Say Y here if you are developing drivers or trying to debug and
+  identify kernel problems.
+
+CONFIG_DEBUG_SLAB
+  Say Y here to have the kernel do limited verification on memory
+  allocation as well as poisoning memory on free to catch use of freed
+  memory.
+
+CONFIG_DEBUG_SPINLOCK
+  Say Y here and build SMP to catch missing spinlock initialization
+  and certain other kinds of spinlock errors commonly made.  This is
+  best used in conjunction with the NMI watchdog so that spinlock
+  deadlocks are also debuggable.
+
diff -u --recursive --new-file v2.5.2/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.5.2/linux/arch/alpha/config.in	Mon Jan 14 18:25:07 2002
+++ linux/arch/alpha/config.in	Thu Jan 24 11:29:38 2002
@@ -8,21 +8,7 @@
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 
-mainmenu_name "Kernel configuration of Linux for Alpha machines"
-
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
-  bool 'Kernel module loader' CONFIG_KMOD
-fi
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'General setup'
@@ -241,10 +227,6 @@
    define_bool CONFIG_PCMCIA n
 fi
 
-bool 'Networking support' CONFIG_NET
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
 if [ "$CONFIG_PROC_FS" = "y" ]; then
    choice 'Kernel core (/proc/kcore) format' \
 	"ELF		CONFIG_KCORE_ELF	\
diff -u --recursive --new-file v2.5.2/linux/arch/alpha/kernel/check_asm.c linux/arch/alpha/kernel/check_asm.c
--- v2.5.2/linux/arch/alpha/kernel/check_asm.c	Sat Nov 27 15:42:54 1999
+++ linux/arch/alpha/kernel/check_asm.c	Mon Jan 28 15:14:22 2002
@@ -12,13 +12,13 @@
 	printf("#define TASK_FLAGS %ld\n",
 	       (long)offsetof(struct task_struct, flags));
 	printf("#define TASK_SIGPENDING %ld\n",
-	       (long)offsetof(struct task_struct, sigpending));
+#error	       (long)offsetof(struct task_struct, sigpending));
 	printf("#define TASK_ADDR_LIMIT %ld\n",
 	       (long)offsetof(struct task_struct, addr_limit));
 	printf("#define TASK_EXEC_DOMAIN %ld\n",
 	       (long)offsetof(struct task_struct, exec_domain));
 	printf("#define TASK_NEED_RESCHED %ld\n",
-	       (long)offsetof(struct task_struct, need_resched));
+#error	       (long)offsetof(struct task_struct, work.need_resched));
 	printf("#define TASK_SIZE %ld\n", sizeof(struct task_struct));
 	printf("#define STACK_SIZE %ld\n", sizeof(union task_union));
 
diff -u --recursive --new-file v2.5.2/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.5.2/linux/arch/alpha/kernel/entry.S	Fri Nov  9 13:45:35 2001
+++ linux/arch/alpha/kernel/entry.S	Mon Jan 28 15:14:22 2002
@@ -30,11 +30,11 @@
  */
 #define TASK_STATE		0
 #define TASK_FLAGS		8
-#define TASK_SIGPENDING		16
+#error #define TASK_SIGPENDING		16
 #define TASK_ADDR_LIMIT		24
 #define TASK_EXEC_DOMAIN	32
-#define TASK_NEED_RESCHED	40
-#define TASK_PTRACE		48
+#error #define TASK_NEED_RESCHED	40
+#error #define TASK_PTRACE		48
 #define TASK_PROCESSOR		100
 
 /*
@@ -580,11 +580,11 @@
 	and	$0,8,$0
 	beq	$0,restore_all
 ret_from_reschedule:
-	ldq	$2,TASK_NEED_RESCHED($8)
+#error	ldq	$2,TASK_NEED_RESCHED($8)
 	lda	$4,init_task_union
 	bne	$2,reschedule
 	xor	$4,$8,$4
-	ldl	$5,TASK_SIGPENDING($8)
+#error	ldl	$5,TASK_SIGPENDING($8)
 	beq	$4,restore_all
 	bne	$5,signal_return
 restore_all:
diff -u --recursive --new-file v2.5.2/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.5.2/linux/arch/alpha/kernel/process.c	Mon Jan 14 18:25:07 2002
+++ linux/arch/alpha/kernel/process.c	Mon Jan 28 15:14:22 2002
@@ -82,9 +82,9 @@
 
 		/* Although we are an idle CPU, we do not want to 
 		   get into the scheduler unnecessarily.  */
-		long oldval = xchg(&current->need_resched, -1UL);
+		long oldval = xchg(&current->work.need_resched, -1UL);
 		if (!oldval)
-			while (current->need_resched < 0);
+			while (current->work.need_resched < 0);
 		schedule();
 		check_pgt_cache();
 	}
diff -u --recursive --new-file v2.5.2/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.5.2/linux/arch/alpha/kernel/smp.c	Mon Jan 14 18:25:07 2002
+++ linux/arch/alpha/kernel/smp.c	Tue Jan 15 10:56:35 2002
@@ -1048,10 +1048,10 @@
 }
 
 void
-flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
 	/* On the Alpha we always flush the whole user tlb.  */
-	flush_tlb_mm(mm);
+	flush_tlb_mm(vma->vm_mm);
 }
 
 static void
diff -u --recursive --new-file v2.5.2/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- v2.5.2/linux/arch/alpha/kernel/time.c	Sat Nov 17 11:47:44 2001
+++ linux/arch/alpha/kernel/time.c	Wed Jan 23 15:28:39 2002
@@ -379,8 +379,6 @@
 	/* Startup the timer source. */
 	alpha_mv.init_rtc();
 
-	do_get_fast_time = do_gettimeofday;
-
 	/*
 	 * If we had wanted SRM console printk echoing early, undo it now.
 	 *
diff -u --recursive --new-file v2.5.2/linux/arch/alpha/vmlinux.lds.in linux/arch/alpha/vmlinux.lds.in
--- v2.5.2/linux/arch/alpha/vmlinux.lds.in	Thu Nov 22 10:54:10 2001
+++ linux/arch/alpha/vmlinux.lds.in	Wed Jan 23 10:54:42 2002
@@ -41,7 +41,15 @@
 
   . = ALIGN(8);
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
 
   . = ALIGN(2*8192);	/* Align double page for init_task_union */
diff -u --recursive --new-file v2.5.2/linux/arch/arm/Config.help linux/arch/arm/Config.help
--- v2.5.2/linux/arch/arm/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/Config.help	Fri Jan 25 16:04:31 2002
@@ -0,0 +1,824 @@
+CONFIG_ARM
+  The ARM series is a line of low-power-consumption RISC chip designs
+  licensed by ARM ltd and targeted at embedded applications and
+  handhelds such as the Compaq IPAQ.  ARM-based PCs are no longer
+  manufactured, but  legacy ARM-based PC hardware remains popular in
+  Europe.  There is an ARM Linux project with a web page at
+  <http://www.arm.linux.org.uk/>.
+
+CONFIG_LEDS
+  If you say Y here, the LEDs on your machine will be used
+  to provide useful information about your current system status.
+
+  If you are compiling a kernel for a NetWinder or EBSA-285, you will
+  be able to select which LEDs are active using the options below. If
+  you are compiling a kernel for the EBSA-110 or the LART however, the
+  red LED will simply flash regularly to indicate that the system is
+  still functional. It is safe to say Y here if you have a CATS
+  system, but the driver will do nothing.
+
+CONFIG_LEDS_TIMER
+  If you say Y here, one of the system LEDs (the green one on the
+  NetWinder, the amber one on the EBSA285, or the red one on the LART)
+  will flash regularly to indicate that the system is still
+  operational. This is mainly useful to kernel hackers who are
+  debugging unstable kernels.
+
+  The LART uses the same LED for both Timer LED and CPU usage LED
+  functions. You may choose to use both, but the Timer LED function
+  will overrule the CPU usage LED.
+
+CONFIG_LEDS_CPU
+  If you say Y here, the red LED will be used to give a good real
+  time indication of CPU usage, by lighting whenever the idle task
+  is not currently executing.
+
+  The LART uses the same LED for both Timer LED and CPU usage LED
+  functions. You may choose to use both, but the Timer LED function
+  will overrule the CPU usage LED.
+
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+CONFIG_DISCONTIGMEM
+  Say Y to upport efficient handling of discontiguous physical memory,
+  for architectures which are either NUMA (Non-Uniform Memory Access)
+  or have huge holes in the physical address space for other reasons.
+  See <file:Documentation/vm/numa> for more.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_PCI
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_PCI_INTEGRATOR
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_HOTPLUG
+  Say Y here if you want to plug devices into your computer while
+  the system is running, and be able to use them quickly.  In many
+  cases, the devices can likewise be unplugged at any time too.
+
+  One well known example of this is PCMCIA- or PC-cards, credit-card
+  size devices such as network cards, modems or hard drives which are
+  plugged into slots found on all modern laptop computers.  Another
+  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.
+  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.
+
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+  computer.  These are credit-card size devices such as network cards,
+  modems or hard drives often used with laptops computers.  There are
+  actually two varieties of these cards: the older 16 bit PCMCIA cards
+  and the newer 32 bit CardBus cards.  If you want to use CardBus
+  cards, you need to say Y here and also to "CardBus support" below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  Please also read the PCMCIA-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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_KCORE_AOUT
+  Not necessary unless you're using a very out-of-date binutils
+  version.  You probably want KCORE_ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_AOUT
+  A.out (Assembler.OUTput) is a set of formats for libraries and
+  executables used in the earliest versions of UNIX. Linux used the
+  a.out formats QMAGIC and ZMAGIC until they were replaced with the
+  ELF format.
+
+  As more and more programs are converted to ELF, the use for a.out
+  will gradually diminish. If you disable this option it will reduce
+  your kernel by one page. This is not much and by itself does not
+  warrant removing support. However its removal is a good idea if you
+  wish to ensure that absolutely none of your programs will use this
+  older executable format. If you don't know what to answer at this
+  point then answer Y. If someone told you "You need a kernel with
+  QMAGIC support" then you'll have to say Y here. You may answer M to
+  compile a.out support as a module and later load the module when you
+  want to use a program or library in a.out format. The module will be
+  called binfmt_aout.o. Saying M or N here is dangerous though,
+  because some crucial programs on your system might still be in A.OUT
+  format.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_VGA_CONSOLE
+  Saying Y here will allow you to use Linux in text mode through a
+  display that complies with the generic VGA standard. Virtually
+  everyone wants that.
+
+  The program SVGATextMode can be used to utilize SVGA video cards to
+  their full potential in text mode. Download it from
+  <ftp://ibiblio.org/pub/Linux/utils/console/>.
+
+  Say Y.
+
+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)
+
+CONFIG_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'
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_ARM_THUMB
+  Say Y if you want to have kernel support for ARM Thumb instructions,
+  fault handlers, and system calls.
+
+  The Thumb instruction set is a compressed form of the standard ARM
+  instruction set resulting in smaller binaries at the expense of
+  slightly less efficient code.
+
+  If you don't know what this all is, saying Y is a safe choice.
+
+CONFIG_PM
+  "Power Management" means that parts of your computer are shut
+  off or put into a power conserving "sleep" mode if they are not
+  being used.  There are two competing standards for doing this: APM
+  and ACPI.  If you want to use either one, say Y here and then also
+  to the requisite support below.
+
+  Power Management is most important for battery powered laptop
+  computers; if you have a laptop, check out the Linux Laptop home
+  page on the WWW at
+  <http://www.cs.utexas.edu/users/kharker/linux-laptop/> and the
+  Battery Powered Linux mini-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that, even if you say N here, Linux on the x86 architecture
+  will issue the hlt instruction if nothing is to be done, thereby
+  sending the processor to sleep and saving power.
+
+CONFIG_APM
+  APM is a BIOS specification for saving power using several different
+  techniques. This is mostly useful for battery powered laptops with
+  APM compliant BIOSes. If you say Y here, the system time will be
+  reset after a RESUME operation, the /proc/apm device will provide
+  battery status information, and user-space programs will receive
+  notification of APM "events" (e.g. battery status change).
+
+  If you select "Y" here, you can disable actual use of the APM
+  BIOS by passing the "apm=off" option to the kernel at boot time.
+
+  Note that the APM support is almost completely disabled for
+  machines with more than one CPU.
+
+  In order to use APM, you will need supporting software. For location
+  and more information, read <file:Documentation/pm.txt> and the
+  Battery Powered Linux mini-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver does not spin down disk drives (see the hdparm(8)
+  manpage ("man 8 hdparm") for that), and it doesn't turn off
+  VESA-compliant "green" monitors.
+
+  This driver does not support the TI 4000M TravelMate and the ACER
+  486/DX4/75 because they don't have compliant BIOSes. Many "green"
+  desktop machines also don't have compliant BIOSes, and this driver
+  may cause those machines to panic during the boot phase.
+
+  Generally, if you don't have a battery in your machine, there isn't
+  much point in using this driver and you should say N. If you get
+  random kernel OOPSes or reboots that don't seem to be related to
+  anything, try disabling/enabling this option (or disabling/enabling
+  APM in your BIOS).
+
+  Some other things you should try when experiencing seemingly random,
+  "weird" problems:
+
+   1) make sure that you have enough swap space and that it is
+      enabled.
+   2) pass the "no-hlt" option to the kernel
+   3) switch on floating point emulation in the kernel and pass
+      the "no387" option to the kernel
+   4) pass the "floppy=nodma" option to the kernel
+   5) pass the "mem=4M" option to the kernel (thereby disabling
+      all but the first 4 MB of RAM)
+   6) make sure that the CPU is not over clocked.
+   7) read the sig11 FAQ at <http://www.bitwizard.nl/sig11/>
+   8) disable the cache from your BIOS settings
+   9) install a fan for the video card or exchange video RAM
+   10) install a better fan for the CPU
+   11) exchange RAM chips
+   12) exchange the motherboard.
+
+  To compile this driver as a module ( = code which can be inserted in
+  and removed from the running kernel whenever you want), say M here
+  and read <file:Documentation/modules.txt>. The module will be called
+  apm.o.
+
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y.  Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. General information about
+  the modular sound system is contained in the files
+  <file:Documentation/sound/Introduction>.  The file
+  <file:Documentation/sound/README.OSS> contains some slightly
+  outdated but still useful information as well.
+
+  If you have a PnP sound card and you want to configure it at boot
+  time using the ISA PnP tools (read
+  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished.  To do
+  this, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/sound/README.modules>; the module will be
+  called soundcore.o.
+
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and supporting utilities to do that are in the pcsp
+  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_ISDN
+  ISDN ("Integrated Services Digital Networks", called RNIS in France)
+  is a special type of fully digital telephone service; it's mostly
+  used to connect to your Internet service provider (with SLIP or
+  PPP).  The main advantage is that the speed is higher than ordinary
+  modem/telephone connections, and that you can have voice
+  conversations while downloading stuff.  It only works if your
+  computer is equipped with an ISDN card and both you and your service
+  provider purchased an ISDN line from the phone company.  For
+  details, read <http://alumni.caltech.edu/~dank/isdn/> on the WWW.
+
+  This driver allows you to use an ISDN-card for networking
+  connections and as dialin/out device.  The isdn-tty's have a built
+  in AT-compatible modem emulator.  Network devices support autodial,
+  channel-bundling, callback and caller-authentication without having
+  a daemon running.  A reduced T.70 protocol is supported with tty's
+  suitable for German BTX.  On D-Channel, the protocols EDSS1
+  (Euro-ISDN) and 1TR6 (German style) are supported.  See
+  <file:Documentation/isdn/README> for more information.
+
+  If you want to compile the ISDN code 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 isdn.o. If unsure, say N.
+
+CONFIG_ARCH_ARCA5K
+  This selects what ARM system you wish to build the kernel for. It
+  also selects to some extent the CPU type. If you are unsure what
+  to set this option to, please consult any information supplied with
+  your system.
+
+CONFIG_ARCH_A5K
+  Say Y here to to support the Acorn A5000.  Linux can support the
+  internal IDE disk and CD-ROM interface, serial and parallel port,
+  and the floppy drive.  Note that on some A5000s the floppy is
+  plugged into the wrong socket on the motherboard.
+
+CONFIG_ARCH_ARC
+  The Acorn Archimedes was an personal computer based on an 8K ARM2
+  processor, released in 1987.  It supported 512K of RAM and 2 800K
+  floppy disks.  Picture and more detailed specifications at
+  <http://www.computingmuseum.com/museum/archi.htm>.
+
+CONFIG_ARCH_EBSA110
+  This is an evaluation board for the StrongARM processor available
+  from Digital. It has limited hardware on-board, including an onboard
+  Ethernet interface, two PCMCIA sockets, two serial ports and a
+  parallel port.
+
+CONFIG_ARCH_RPC
+  On the Acorn Risc-PC, Linux can support the internal IDE disk and
+  CD-ROM interface, serial and parallel port, and the floppy drive.
+
+CONFIG_PAGESIZE_16
+  Say Y here if your Archimedes or A5000 system has only 2MB of
+  memory, otherwise say N.  The resulting kernel will not run on a
+  machine with 4MB of memory.
+
+CONFIG_ARCH_CATS
+  Say Y here if you intend to run this kernel on the CATS.
+
+  Saying N will reduce the size of the Footbridge kernel.
+
+CONFIG_ARCH_EBSA285_ADDIN
+  Say Y here if you intend to run this kernel on the EBSA285 card
+  in addin mode.
+
+  Saying N will reduce the size of the Footbridge kernel.
+
+CONFIG_ARCH_EBSA285_HOST
+  Say Y here if you intend to run this kernel on the EBSA285 card
+  in host ("central function") mode.
+
+  Saying N will reduce the size of the Footbridge kernel.
+
+CONFIG_ARCH_L7200
+  Say Y here if you intend to run this kernel on a LinkUp Systems
+  L7200 Software Development Board which uses an ARM720T processor.
+  Information on this board can be obtained at:
+
+  <http://www.linkupsys.com/>
+
+  If you have any questions or comments about the Linux kernel port
+  to this board, send e-mail to sjhill@cotw.com.
+
+CONFIG_ARCH_NETWINDER
+  Say Y here if you intend to run this kernel on the Rebel.COM
+  NetWinder.  Information about this machine can be found at:
+
+  <http://www.netwinder.org/>
+
+  Saying N will reduce the size of the Footbridge kernel.
+
+CONFIG_ARCH_P720T
+  Say Y here if you intend to run this kernel on the ARM Prospector
+  720T.
+
+CONFIG_ARCH_PERSONAL_SERVER
+  Say Y here if you intend to run this kernel on the Compaq
+  Personal Server.
+
+  Saying N will reduce the size of the Footbridge kernel.
+
+  The Compaq Personal Server is not available for purchase.
+  There are no product plans beyond the current research
+  prototypes at this time.  Information is available at:
+
+  <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.
+
+CONFIG_SA1100_ASSABET
+  Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
+  Microprocessor Development Board (also known as the Assabet).
+
+CONFIG_ASSABET_NEPONSET
+  Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
+  Microprocessor Development Board (Assabet)  with the SA-1111
+  Development Board (Nepon).
+
+CONFIG_SA1100_H3600
+  Say Y here if you intend to run this kernel on the Compaq iPAQ
+  H3600 handheld computer.  Information about this machine and the
+  Linux port to this machine can be found at:
+
+  <http://www.handhelds.org/Compaq/index.html#iPAQ_H3600>
+  <http://www.compaq.com/products/handhelds/pocketpc/>
+
+CONFIG_SA1100_BRUTUS
+  Say Y here if you are using the Intel(R) StrongARM(R) SA-1100
+  Microprocessor Development Board (also known as the Brutus).
+
+CONFIG_SA1100_LART
+  Say Y here if you are using the Linux Advanced Radio Terminal
+  (also known as the LART).  See <http://www.lart.tudelft.nl/> for
+  information on the LART.
+
+CONFIG_SA1100_GRAPHICSCLIENT
+  Say Y here if you are using an Applied Data Systems Intel(R)
+  StrongARM(R) SA-1100 based Graphics Client SBC.  See
+  <http://www.flatpanels.com/> for information on this system.
+
+CONFIG_SA1100_CERF
+  The Intrinsyc CerfBoard is based on the StrongARM 1110.
+  More information is available at:
+  <http://www.intrinsyc.com/products/referenceplatforms/cerfboard.html>.
+
+  Say Y if configuring for an Intrinsyc CerfBoard.
+  Say N otherwise.
+
+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/>.
+
+CONFIG_SA1100_NANOENGINE
+  The nanoEngine is a StrongARM 1110-based single board computer
+  from Bright Star Engineering. More information is available at:
+  <http://www.brightstareng.com/arm/nanoeng.htm>.
+
+  Say Y if configuring for a nanoEngine.
+  Say N otherwise.
+
+CONFIG_SA1100_PANGOLIN
+  Pangolin is a StrongARM 1110-based evaluation platform produced
+  by Dialogue Technology.  It has EISA slots for ease of configuration
+  with SDRAM/Flash memory card, USB/Serial/Audio card, Compact Flash
+  card, and TFT-LCD card.
+
+  Say Y if configuring for a Pangolin.
+  Say N otherwise.
+
+CONFIG_SA1100_VICTOR
+  Say Y here if you are using a Visu Aide Intel(R) StrongARM(R)
+  SA-1100 based Victor Digital Talking Book Reader.  See
+  <http://www.visuaide.com/pagevictor.en.html> for information on
+  this system.
+
+CONFIG_CPU_ARM610
+  The ARM610 is the successor to the ARM3 processor
+  and was produced by VLSI Technology Inc.
+
+  Say Y if you want support for the ARM610 processor.
+  Otherwise, say N.
+
+CONFIG_CPU_ARM710
+  A 32-bit RISC microprocessor based on the ARM7 processor core
+  designed by Advanced RISC Machines Ltd. The ARM710 is the
+  successor to the ARM610 processor. It was released in
+  July 1994 by VLSI Technology Inc.
+
+  Say Y if you want support for the ARM710 processor.
+  Otherwise, say N.
+
+CONFIG_CPU_ARM720T
+  A 32-bit RISC processor with 8kByte Cache, Write Buffer and
+  MMU built around an ARM7TDMI core.
+
+  Say Y if you want support for the ARM720T processor.
+  Otherwise, say N.
+
+CONFIG_CPU_ARM920T
+  The ARM920T is licensed to be produced by numerous vendors,
+  and is used in the Maverick EP9312.  More information at
+  <http://linuxdevices.com/products/PD2382866068.html>.
+
+  Say Y if you want support for the ARM920T processor.
+  Otherwise, say N.
+
+CONFIG_CPU_ARM1020
+  The ARM1020 is the cached version of the ARM10 processor,
+  with an addition of a floating-point unit.
+
+  Say Y if you want support for the ARM1020 processor.
+  Otherwise, say N.
+
+CONFIG_CPU_SA110
+  The Intel StrongARM(R) SA-110 is a 32-bit microprocessor and
+  is available at five speeds ranging from 100 MHz to 233 MHz.
+  More information is available at
+  <http://developer.intel.com/design/strong/sa110.htm>.
+
+  Say Y if you want support for the SA-110 processor.
+  Otherwise, say N.
+
+CONFIG_FPE_NWFPE
+  Say Y to include the NWFPE floating point emulator in the kernel.
+  This is necessary to run most binaries. Linux does not currently
+  support floating point hardware so you need to say Y here even if
+  your machine has an FPA or floating point co-processor podule.
+
+  It is also possible to say M to build the emulator as a module
+  (nwfpe.o) or indeed to leave it out altogether. However, unless you
+  know what you are doing this can easily render your machine
+  unbootable. Saying Y is the safe option.
+
+  You may say N here if you are going to load the Acorn FPEmulator
+  early in the bootup.
+
+CONFIG_FPE_FASTFPE
+  Say Y here to include the FAST floating point emulator in the kernel.
+  This is an experimental much faster emulator which has only 32 bit
+  precision for the mantissa.  It does not support any exceptions.
+  This makes it very simple, it is approximately 4-8 times faster than
+  NWFPE.
+
+  It should be sufficient for most programs.  It is definitely not
+  suitable if you do scientific calculations that need double
+  precision for iteration formulas that sum up lots of very small
+  numbers.  If you do not feel you need a faster FP emulation you
+  should better choose NWFPE.
+
+  It is also possible to say M to build the emulator as a module
+  (fastfpe.o).  But keep in mind that you should only load the FP
+  emulator early in the bootup.  You should never change from NWFPE to
+  FASTFPE or vice versa in an active system!
+
+CONFIG_DEBUG_ERRORS
+  This option controls verbose debugging information which can be
+  printed when the kernel detects an internal error. This debugging
+  information is useful to kernel hackers when tracking down problems,
+  but mostly meaningless to other people. It's safe to say Y unless
+  you are concerned with the code size or don't want to see these
+  messages.
+
+CONFIG_NO_FRAME_POINTER
+  If you say Y here, the resulting kernel will be slightly smaller and
+  faster. However, when a problem occurs with the kernel, the
+  information that is reported is severely limited. Most people
+  should say N here.
+
+CONFIG_DEBUG_USER
+  When a user program crashes due to an exception, the kernel can
+  print a brief message explaining what the problem was. This is
+  sometimes helpful for debugging but serves no purpose on a
+  production system. Most people should say N here.
+
+CONFIG_DEBUG_INFO
+  Say Y here to include source-level debugging information in the
+  `vmlinux' binary image. This is handy if you want to use gdb or
+  addr2line to debug the kernel. It has no impact on the in-memory
+  footprint of the running kernel but it can increase the amount of
+  time and disk space needed for compilation of the kernel. If in
+  doubt say N.
+
+CONFIG_DEBUG_LL
+  Say Y here to include definitions of printascii, printchar, printhex
+  in the kernel.  This is helpful if you are debugging code that
+  executes before the console is initialized.
+
+CONFIG_DEBUG_DC21285_PORT
+  Say Y here if you want the debug print routines to direct their
+  output to the serial port in the DC21285 (Footbridge). Saying N
+  will cause the debug messages to appear on the first 16550
+  serial port.
+
+CONFIG_DEBUG_CLPS711X_UART2
+  Say Y here if you want the debug print routines to direct their
+  output to the second serial port on these devices.  Saying N will
+  cause the debug messages to appear on the first serial port.
+
+CONFIG_NO_PGT_CACHE
+  Normally the kernel maintains a `quicklist' of preallocated
+  pagetable structures in order to increase performance. On machines
+  with very few pages this may however be a loss. Say Y here to
+  disable the pgtable cache.
+
+CONFIG_ARTHUR
+  Say Y here to include the kernel code necessary if you want to run
+  Acorn RISC OS/Arthur binaries under Linux. This code is still very
+  experimental; if this sounds frightening, say N and sleep in peace.
+  You can also say M here to compile this support as a module (which
+  will be called arthur.o).
+
+CONFIG_CMDLINE
+  On some architectures (EBSA110 and CATS), there is currently no way
+  for the boot loader to pass arguments to the kernel. For these
+  architectures, you should supply some command-line options at build
+  time by entering them here. As a minimum, you should specify the
+  memory size and the root device (e.g., mem=64M root=/dev/nfs).
+
+CONFIG_ALIGNMENT_TRAP
+  ARM processors can not fetch/store information which is not
+  naturally aligned on the bus, i.e., a 4 byte fetch must start at an
+  address divisible by 4. On 32-bit ARM processors, these non-aligned
+  fetch/store instructions will be emulated in software if you say
+  here, which has a severe performance impact. This is necessary for
+  correct operation of some network protocols. With an IP-only
+  configuration it is safe to say N, otherwise say Y.
+
+CONFIG_DEBUG_KERNEL
+  Say Y here if you are developing drivers or trying to debug and
+  identify kernel problems.
+
+CONFIG_DEBUG_SLAB
+  Say Y here to have the kernel do limited verification on memory
+  allocation as well as poisoning memory on free to catch use of freed
+  memory.
+
+CONFIG_DEBUG_SPINLOCK
+  Say Y here and build SMP to catch missing spinlock initialization
+  and certain other kinds of spinlock errors commonly made.  This is
+  best used in conjunction with the NMI watchdog so that spinlock
+  deadlocks are also debuggable.
+
+CONFIG_DEBUG_BUGVERBOSE
+  Say Y here to make BUG() panics output the file name and line number
+  of the BUG call as well as the EIP and oops trace.  This aids
+  debugging but costs about 70-100K of memory.
+
diff -u --recursive --new-file v2.5.2/linux/arch/arm/config.in linux/arch/arm/config.in
--- v2.5.2/linux/arch/arm/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/arm/config.in	Thu Jan 24 11:29:38 2002
@@ -14,20 +14,7 @@
 define_bool CONFIG_GENERIC_BUST_SPINLOCK n
 define_bool CONFIG_GENERIC_ISA_DMA n
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-bool 'Prompt for obsolete code/drivers' CONFIG_OBSOLETE
-endmenu
-
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-dep_bool '  Set version information on all module symbols' CONFIG_MODVERSIONS $CONFIG_MODULES
-dep_bool '  Kernel module loader' CONFIG_KMOD $CONFIG_MODULES
-endmenu
-
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'System Type'
@@ -467,10 +454,6 @@
 else
    define_bool CONFIG_PCMCIA n
 fi
-bool 'Networking support' CONFIG_NET
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
 comment 'At least one math emulation must be selected'
 tristate 'NWFPE math emulation' CONFIG_FPE_NWFPE
 dep_tristate 'FastFPE math emulation (experimental)' CONFIG_FPE_FASTFPE $CONFIG_EXPERIMENTAL
diff -u --recursive --new-file v2.5.2/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c
--- v2.5.2/linux/arch/arm/kernel/ecard.c	Sun Aug 12 11:13:59 2001
+++ linux/arch/arm/kernel/ecard.c	Wed Jan 23 10:54:42 2002
@@ -243,6 +243,8 @@
  */
 static void ecard_init_pgtables(struct mm_struct *mm)
 {
+	struct vm_area_struct vma;
+
 	/* We want to set up the page tables for the following mapping:
 	 *  Virtual	Physical
 	 *  0x03000000	0x03000000
@@ -274,8 +276,10 @@
 		dst_addr += PGDIR_SIZE;
 	}
 
-	flush_tlb_range(mm, IO_START, IO_START + IO_SIZE);
-	flush_tlb_range(mm, EASI_START, EASI_START + EASI_SIZE);
+	vma.vm_mm = mm;
+
+	flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE);
+	flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE);
 }
 
 static int ecard_init_mm(void)
@@ -1092,6 +1096,8 @@
 
 	ecard_proc_init();
 }
+
+subsys_initcall(ecard_init);
 
 EXPORT_SYMBOL(ecard_startfind);
 EXPORT_SYMBOL(ecard_find);
diff -u --recursive --new-file v2.5.2/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S
--- v2.5.2/linux/arch/arm/kernel/entry-common.S	Mon Jan 14 18:25:08 2002
+++ linux/arch/arm/kernel/entry-common.S	Mon Jan 28 15:14:22 2002
@@ -34,8 +34,8 @@
  * stack.
  */
 ret_fast_syscall:
-	ldr	r1, [tsk, #TSK_NEED_RESCHED]
-	ldr	r2, [tsk, #TSK_SIGPENDING]
+#error	ldr	r1, [tsk, #TSK_NEED_RESCHED]
+#error	ldr	r2, [tsk, #TSK_SIGPENDING]
 	teq	r1, #0				@ need_resched || sigpending
 	teqeq	r2, #0
 	bne	slow
@@ -54,8 +54,8 @@
 	bl	SYMBOL_NAME(schedule)
 ENTRY(ret_to_user)
 ret_slow_syscall:
-	ldr	r1, [tsk, #TSK_NEED_RESCHED]
-	ldr	r2, [tsk, #TSK_SIGPENDING]
+#error	ldr	r1, [tsk, #TSK_NEED_RESCHED]
+#error	ldr	r2, [tsk, #TSK_SIGPENDING]
 1:	teq	r1, #0				@ need_resched => schedule()
 	bne	reschedule
 	teq	r2, #0				@ sigpending => do_signal()
@@ -66,7 +66,7 @@
 	mov	r0, #0				@ NULL 'oldset'
 	mov	r1, sp				@ 'regs'
 	mov	r2, why				@ 'syscall'
-	b	SYMBOL_NAME(do_signal)		@ note the bl above sets lr
+#error	b	SYMBOL_NAME(do_signal)		@ note the bl above sets lr
 
 /*
  * This is how we return from a fork.  __switch_to will be calling us
@@ -82,7 +82,7 @@
 	beq	ret_slow_syscall
 	mov	r1, sp
 	mov	r0, #1				@ trace exit [IP = 1]
-	bl	SYMBOL_NAME(syscall_trace)
+#error	bl	SYMBOL_NAME(syscall_trace)
 	b	ret_slow_syscall
 	
 
@@ -160,7 +160,7 @@
 __sys_trace:
 	add	r1, sp, #S_OFF
 	mov	r0, #0				@ trace entry [IP = 0]
-	bl	SYMBOL_NAME(syscall_trace)
+#error	bl	SYMBOL_NAME(syscall_trace)
 
 	adrsvc	al, lr, __sys_trace_return	@ return address
 	add	r1, sp, #S_R0 + S_OFF		@ pointer to regs
@@ -173,7 +173,7 @@
 	str	r0, [sp, #S_R0 + S_OFF]!	@ save returned r0
 	mov	r1, sp
 	mov	r0, #1				@ trace exit [IP = 1]
-	bl	SYMBOL_NAME(syscall_trace)
+#error	bl	SYMBOL_NAME(syscall_trace)
 	b	ret_slow_syscall
 
 	.align	5
diff -u --recursive --new-file v2.5.2/linux/arch/arm/kernel/init_task.c linux/arch/arm/kernel/init_task.c
--- v2.5.2/linux/arch/arm/kernel/init_task.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/arm/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -5,6 +5,7 @@
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- v2.5.2/linux/arch/arm/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/arm/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -91,7 +91,7 @@
 		if (!idle)
 			idle = arch_idle;
 		leds_event(led_idle_start);
-		while (!current->need_resched)
+		while (!need_resched())
 			idle();
 		leds_event(led_idle_end);
 		schedule();
diff -u --recursive --new-file v2.5.2/linux/arch/arm/tools/getconstants.c linux/arch/arm/tools/getconstants.c
--- v2.5.2/linux/arch/arm/tools/getconstants.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/arm/tools/getconstants.c	Mon Jan 28 15:14:22 2002
@@ -37,10 +37,10 @@
 
 void func(void)
 {
-DEFN("TSK_SIGPENDING",		OFF_TSK(sigpending));
+#error DEFN("TSK_SIGPENDING",		OFF_TSK(sigpending));
 DEFN("TSK_ADDR_LIMIT",		OFF_TSK(addr_limit));
-DEFN("TSK_NEED_RESCHED",	OFF_TSK(need_resched));
-DEFN("TSK_PTRACE",		OFF_TSK(ptrace));
+#error DEFN("TSK_NEED_RESCHED",	OFF_TSK(need_resched));
+#error DEFN("TSK_PTRACE",		OFF_TSK(ptrace));
 DEFN("TSK_USED_MATH",		OFF_TSK(used_math));
 
 DEFN("TSS_SAVE",		OFF_TSK(thread.save));
diff -u --recursive --new-file v2.5.2/linux/arch/arm/vmlinux-armo.lds.in linux/arch/arm/vmlinux-armo.lds.in
--- v2.5.2/linux/arch/arm/vmlinux-armo.lds.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/arm/vmlinux-armo.lds.in	Wed Jan 23 10:54:42 2002
@@ -27,7 +27,13 @@
 			*(.setup.init)
 		__setup_end = .;
 		__initcall_start = .;
-			*(.initcall.init)
+			*(.initcall1.init)
+			*(.initcall2.init)
+			*(.initcall3.init)
+			*(.initcall4.init)
+			*(.initcall5.init)
+			*(.initcall6.init)
+			*(.initcall7.init)
 		__initcall_end = .;
 		. = ALIGN(32768);
 		__init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/arm/vmlinux-armv.lds.in linux/arch/arm/vmlinux-armv.lds.in
--- v2.5.2/linux/arch/arm/vmlinux-armv.lds.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/arm/vmlinux-armv.lds.in	Wed Jan 23 10:54:42 2002
@@ -26,7 +26,13 @@
 			*(.setup.init)
 		__setup_end = .;
 		__initcall_start = .;
-			*(.initcall.init)
+			*(.initcall1.init)
+			*(.initcall2.init)
+			*(.initcall3.init)
+			*(.initcall4.init)
+			*(.initcall5.init)
+			*(.initcall6.init)
+			*(.initcall7.init)
 		__initcall_end = .;
 		. = ALIGN(4096);
 		__init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/cris/Config.help linux/arch/cris/Config.help
--- v2.5.2/linux/arch/cris/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/Config.help	Fri Jan 25 16:04:29 2002
@@ -0,0 +1,447 @@
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_CD_NO_IDESCSI
+  If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y
+  here, otherwise N. Read the CD-ROM-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about these CD-ROM drives. If you are unsure what you
+  have, say Y and find out whether you have one of the following
+  drives.
+
+  For each of these drivers, a file Documentation/cdrom/{driver_name}
+  exists. Especially in cases where you do not know exactly which kind
+  of drive you have you should read there. Most of these drivers use a
+  file drivers/cdrom/{driver_name}.h where you can define your
+  interface parameters and switch some internal goodies.
+
+  All these CD-ROM drivers are also usable as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want). If you want to compile them as module, say M instead of Y and
+  read <file:Documentation/modules.txt>.
+
+  If you want to use any of these CD-ROM drivers, you also have to
+  answer Y or M to "ISO 9660 CD-ROM file system support" below (this
+  answer will get "defaulted" for you if you enable any of the Linux
+  CD-ROM drivers).
+
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y.  Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. General information about
+  the modular sound system is contained in the files
+  <file:Documentation/sound/Introduction>.  The file
+  <file:Documentation/sound/README.OSS> contains some slightly
+  outdated but still useful information as well.
+
+  If you have a PnP sound card and you want to configure it at boot
+  time using the ISA PnP tools (read
+  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished.  To do
+  this, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/sound/README.modules>; the module will be
+  called soundcore.o.
+
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and supporting utilities to do that are in the pcsp
+  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+CONFIG_ISDN
+  ISDN ("Integrated Services Digital Networks", called RNIS in France)
+  is a special type of fully digital telephone service; it's mostly
+  used to connect to your Internet service provider (with SLIP or
+  PPP).  The main advantage is that the speed is higher than ordinary
+  modem/telephone connections, and that you can have voice
+  conversations while downloading stuff.  It only works if your
+  computer is equipped with an ISDN card and both you and your service
+  provider purchased an ISDN line from the phone company.  For
+  details, read <http://alumni.caltech.edu/~dank/isdn/> on the WWW.
+
+  This driver allows you to use an ISDN-card for networking
+  connections and as dialin/out device.  The isdn-tty's have a built
+  in AT-compatible modem emulator.  Network devices support autodial,
+  channel-bundling, callback and caller-authentication without having
+  a daemon running.  A reduced T.70 protocol is supported with tty's
+  suitable for German BTX.  On D-Channel, the protocols EDSS1
+  (Euro-ISDN) and 1TR6 (German style) are supported.  See
+  <file:Documentation/isdn/README> for more information.
+
+  If you want to compile the ISDN code 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 isdn.o. If unsure, say N.
+
+CONFIG_ETRAX100LX
+  Support version 1 of the Etrax 100LX.
+
+CONFIG_ETRAX100LX_V2
+  Support version 2 of the Etrax 100LX.
+
+CONFIG_SVINTO_SIM
+  Support the xsim ETRAX Simulator.
+
+CONFIG_ETRAX_DRAM_SIZE
+  Size of DRAM (decimal in MB) typically 2, 8 or 16.
+
+CONFIG_ETRAX_FLASH_BUSWIDTH
+  Width in bytes of the Flash bus (1, 2 or 4). Is usually 2.
+
+CONFIG_ETRAX_PA_LEDS
+  The Etrax network driver is responsible for flashing LED's when
+  packets arrive and are sent.  It uses macros defined in
+  <file:include/asm-cris/io.h>, and those macros are defined after what
+  YOU choose in this option.  The actual bits used are configured
+  separately.  Select this if the LEDs are on port PA.  Some products
+  put the leds on PB or a memory-mapped latch (CSP0) instead.
+
+CONFIG_ETRAX_PB_LEDS
+  The Etrax network driver is responsible for flashing LED's when
+  packets arrive and are sent.  It uses macros defined in
+  <file:include/asm-cris/io.h>, and those macros are defined after what
+  YOU choose in this option.  The actual bits used are configured
+  separately.  Select this if the LEDs are on port PB.  Some products
+  put the leds on PA or a memory-mapped latch (CSP0) instead.
+
+CONFIG_ETRAX_CSP0_LEDS
+  The Etrax network driver is responsible for flashing LED's when
+  packets arrive and are sent. It uses macros defined in
+  <file:include/asm-cris/io.h>, and those macros are defined after what
+  YOU choose in this option.  The actual bits used are configured
+  separately.  Select this if the LEDs are on a memory-mapped latch
+  using chip select CSP0, this is mapped at 0x90000000.
+  Some products put the leds on PA or PB instead.
+
+CONFIG_ETRAX_NO_LEDS
+  Select this option if you don't have any LED at all.
+
+CONFIG_ETRAX_LED1G
+  Bit to use for the first green LED.
+  Most Axis products use bit 2 here.
+
+CONFIG_ETRAX_LED1R
+  Bit to use for the first red LED.
+  Most Axis products use bit 3 here.
+  For products with only one controllable LED,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED2G
+  Bit to use for the second green LED. The "Active" LED.
+  Most Axis products use bit 4 here.
+  For products with only one controllable LED,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED2R
+  Bit to use for the second red LED.
+  Most Axis products use bit 5 here.
+  For products with only one controllable LED,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED3G
+  Bit to use for the third green LED. The "Drive" LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED3R
+  Bit to use for the third red LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED4G
+  Bit to use for the fourth green LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED4R
+  Bit to use for the fourth red LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED5G
+  Bit to use for the fifth green LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED5R
+  Bit to use for the fifth red LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED6G
+  Bit to use for the sixth green LED. The "Drive" LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED6R
+  Bit to use for the sixth red LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED7G
+  Bit to use for the seventh green LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED7R
+  Bit to use for the seventh red LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED8Y
+  Bit to use for the eighth yellow LED. The "Drive" LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED9Y
+  Bit to use for the ninth yellow LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED10Y
+  Bit to use for the tenth yellow LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED11Y
+  Bit to use for the eleventh yellow LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_LED12R
+  Bit to use for the twelfth red LED.
+  For products with only one or two controllable LEDs,
+  set this to same as CONFIG_ETRAX_LED1G (normally 2).
+
+CONFIG_ETRAX_KGDB
+  The CRIS version of gdb can be used to remotely debug a running
+  Linux kernel via the serial debug port.  Provided you have gdb-cris
+  installed, run gdb-cris vmlinux, then type
+
+  (gdb) set remotebaud 115200           <- kgdb uses 115200 as default
+  (gdb) target remote /dev/ttyS0        <- maybe you use another port
+
+  This should connect you to your booted kernel (or boot it now if you
+  didn't before).  The kernel halts when it boots, waiting for gdb if
+  this option is turned on!
+
+CONFIG_ETRAX_DEF_R_WAITSTATES
+  Waitstates for SRAM, Flash and peripherials (not DRAM).  95f8 is a
+  good choice for most Axis products...
+
+CONFIG_ETRAX_DEF_R_BUS_CONFIG
+  Assorted bits controlling write mode, DMA burst length etc.  104 is
+  a good choice for most Axis products...
+
+CONFIG_ETRAX_SDRAM
+  Enable this if you use SDRAM chips and configure
+  R_SDRAM_CONFIG and R_SDRAM_TIMING as well.
+
+CONFIG_ETRAX_DEF_R_DRAM_CONFIG
+  The R_DRAM_CONFIG register specifies everything on how the DRAM
+  chips in the system are connected to the Etrax CPU.  This is
+  different depending on the manufacturer, chip type and number of
+  chips.  So this value often needs to be different for each Axis
+  product.
+
+CONFIG_ETRAX_DEF_R_DRAM_TIMING
+  Different DRAM chips have different speeds.  Current Axis products
+  use 50ns DRAM chips which can use the timing: 5611.
+
+CONFIG_ETRAX_DEF_R_SDRAM_CONFIG
+  The R_SDRAM_CONFIG register specifies everything on how the SDRAM
+  chips in the system are connected to the Etrax CPU.  This is
+  different depending on the manufacturer, chip type and number of
+  chips.  So this value often needs to be different for each Axis
+  product.
+
+CONFIG_ETRAX_DEF_R_SDRAM_TIMING
+  Different SDRAM chips have different timing.
+
+CONFIG_ETRAX_DEF_R_PORT_PA_DIR
+  Configures the direction of general port A bits.  1 is out, 0 is in.
+  This is often totally different depending on the product used.
+  There are some guidelines though - if you know that only LED's are
+  connected to port PA, then they are usually connected to bits 2-4
+  and you can therefore use 1c.  On other boards which don't have the
+  LED's at the general ports, these bits are used for all kinds of
+  stuff.  If you don't know what to use, it is always safe to put all
+  as inputs, although floating inputs isn't good.
+
+CONFIG_ETRAX_DEF_R_PORT_PA_DATA
+  Configures the initial data for the general port A bits.  Most
+  products should use 00 here.
+
+CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG
+  Configures the type of the general port B bits.  1 is chip select,
+  0 is port.  Most products should use 00 here.
+
+CONFIG_ETRAX_DEF_R_PORT_PB_DIR
+  Configures the direction of general port B bits. 1 is out, 0 is in.
+  This is often totally different depending on the product used.  Bits
+  0 and 1 on port PB are usually used for I2C communication, but the
+  kernel I2C driver sets the appropriate directions itself so you
+  don't need to take that into consideration when setting this option.
+  If you don't know what to use, it is always safe to put all as
+  inputs.
+
+CONFIG_ETRAX_DEF_R_PORT_PB_DATA
+  Configures the initial data for the general port A bits.  Most
+  products should use FF here.
+
+CONFIG_ETRAX_WATCHDOG
+  Enable the built-in watchdog timer support on Etrax100 embedded
+  network computers.
+
+CONFIG_ETRAX_DEBUG_PORT0
+  Choose a serial port for the ETRAX debug console.  Default to
+  port 0.
+
+CONFIG_ETRAX_DEBUG_PORT1
+  Use serial port 1 for the console.
+
+CONFIG_ETRAX_DEBUG_PORT2
+  Use serial port 2 for the console.
+
+CONFIG_ETRAX_DEBUG_PORT3
+  Use serial port 3 for the console.
+
+CONFIG_ETRAX_DEBUG_PORT_NULL
+  Disable serial-port debugging.
+
+CONFIG_ETRAX_RESCUE_SER0
+  Select one of the four serial ports as a rescue port.  The default
+  is port 0.
+
+CONFIG_ETRAX_RESCUE_SER1
+  Use serial port 1 as the rescue port.
+
+CONFIG_ETRAX_RESCUE_SER2
+  Use serial port 2 as the rescue port.
+
+CONFIG_ETRAX_RESCUE_SER3
+  Use serial port 3 as the rescue port.
+
diff -u --recursive --new-file v2.5.2/linux/arch/cris/Makefile linux/arch/cris/Makefile
--- v2.5.2/linux/arch/cris/Makefile	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/Makefile	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.22 2001/10/01 14:42:38 bjornw Exp $
+# $Id: Makefile,v 1.3 2002/01/21 15:21:23 bjornw Exp $
 # cris/Makefile
 #
 # This file is included by the global makefile so that you can add your own
@@ -29,18 +29,17 @@
               -e s/@CONFIG_ETRAX_DRAM_SIZE_M@/$(CONFIG_ETRAX_DRAM_SIZE)/ \
               < $(LD_SCRIPT) > $(LD_SCRIPT).tmp; \
      else true; \
-     fi && $(CROSS_COMPILE)gcc -mlinux -nostdlib
+     fi && $(CROSS_COMPILE)ld -mcrislinux
 
-LINKFLAGS = -mlinux -T $(LD_SCRIPT).tmp
+LINKFLAGS = -T $(LD_SCRIPT).tmp
 
 # objcopy is used to make binary images from the resulting linked file
 
 OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
 
-# normally, gcc on a linux box adds __linux__ but we do it "manually"
-# -mlinux enables -march=v10, -fno-underscores among others
+# -mlinux enables -march=v10, -fno-underscores, -D__linux__ among others
 
-CFLAGS := $(CFLAGS) -mlinux -fno-strict-aliasing -pipe -D__linux__
+CFLAGS := $(CFLAGS) -mlinux -pipe
 
 ifdef CONFIG_ETRAX_KGDB
 CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g
@@ -57,7 +56,7 @@
 # each others config options
 SUBDIRS += arch/cris/boot/rescue
 endif
-CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o
+CORE_FILES := arch/cris/kernel/kernel.o arch/cris/mm/mm.o $(CORE_FILES)
 DRIVERS += arch/cris/drivers/drivers.o
 LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a)
 LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC)
diff -u --recursive --new-file v2.5.2/linux/arch/cris/README.mm linux/arch/cris/README.mm
--- v2.5.2/linux/arch/cris/README.mm	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/README.mm	Mon Jan 21 16:00:39 2002
@@ -3,6 +3,9 @@
 HISTORY:
 
 $Log: README.mm,v $
+Revision 1.1.1.1  2001/12/17 13:59:27  bjornw
+Import of Linux 2.5.1
+
 Revision 1.1  2000/07/10 16:25:21  bjornw
 Initial revision
 
diff -u --recursive --new-file v2.5.2/linux/arch/cris/boot/compressed/README linux/arch/cris/boot/compressed/README
--- v2.5.2/linux/arch/cris/boot/compressed/README	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/boot/compressed/README	Mon Jan 21 16:00:39 2002
@@ -1,6 +1,6 @@
 Creation of the self-extracting compressed kernel image (vmlinuz)
 -----------------------------------------------------------------
-$Id: README,v 1.1 2000/11/22 17:20:46 bjornw Exp $
+$Id: README,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
 
 This can be slightly confusing because it's a process with many steps.
 
diff -u --recursive --new-file v2.5.2/linux/arch/cris/boot/compressed/misc.c linux/arch/cris/boot/compressed/misc.c
--- v2.5.2/linux/arch/cris/boot/compressed/misc.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/boot/compressed/misc.c	Mon Jan 21 16:00:39 2002
@@ -1,7 +1,7 @@
 /*
  * misc.c
  *
- * $Id: misc.c,v 1.6 2001/04/09 10:00:21 starvik Exp $
+ * $Id: misc.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  * 
  * This is a collection of several routines from gzip-1.0.3 
  * adapted for Linux.
diff -u --recursive --new-file v2.5.2/linux/arch/cris/boot/rescue/head.S linux/arch/cris/boot/rescue/head.S
--- v2.5.2/linux/arch/cris/boot/rescue/head.S	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/boot/rescue/head.S	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.8 2001/10/03 17:15:15 bjornw Exp $
+/* $Id: head.S,v 1.2 2001/12/18 13:35:12 bjornw Exp $
  * 
  * Rescue code, made to reside at the beginning of the
  * flash-memory. when it starts, it checks a partition
@@ -114,7 +114,7 @@
 
 #define NOP_DI 0xf025050f
 #define RAM_INIT_MAGIC 0x56902387
-		
+
 	.text
 	
 	;; This is the entry point of the rescue code
@@ -144,7 +144,13 @@
 jumptarget:	
 	.dword	0xffffffff	; can be overwritten later to insert new code
 	
-no_newjump:	
+no_newjump:
+#ifdef CONFIG_ETRAX_ETHERNET		
+	;; Start MII clock to make sure it is running when tranceiver is reset
+	move.d 0x3, $r0    ; enable = on, phy = mii_clk
+	move.d $r0, [R_NETWORK_GEN_CONFIG]
+#endif
+	
 	;; We need to setup the bus registers before we start using the DRAM
 #include "../../lib/dram_init.S"
 
diff -u --recursive --new-file v2.5.2/linux/arch/cris/boot/rescue/kimagerescue.S linux/arch/cris/boot/rescue/kimagerescue.S
--- v2.5.2/linux/arch/cris/boot/rescue/kimagerescue.S	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/boot/rescue/kimagerescue.S	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: kimagerescue.S,v 1.5 2001/10/03 17:15:15 bjornw Exp $
+/* $Id: kimagerescue.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  * 
  * Rescue code to be prepended on a kimage and copied to the
  * rescue serial port.
diff -u --recursive --new-file v2.5.2/linux/arch/cris/boot/rescue/testrescue.S linux/arch/cris/boot/rescue/testrescue.S
--- v2.5.2/linux/arch/cris/boot/rescue/testrescue.S	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/boot/rescue/testrescue.S	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: testrescue.S,v 1.3 2001/10/03 17:15:15 bjornw Exp $
+/* $Id: testrescue.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  *
  * Simple testcode to download by the rescue block.
  * Just lits some LEDs to show it was downloaded correctly.
diff -u --recursive --new-file v2.5.2/linux/arch/cris/config.in linux/arch/cris/config.in
--- v2.5.2/linux/arch/cris/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/cris/config.in	Thu Jan 24 11:29:38 2002
@@ -8,33 +8,19 @@
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'General setup'
 
-bool 'Networking support' CONFIG_NET
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
-
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 
 bool 'Use kernel gdb debugger' CONFIG_ETRAX_KGDB
 
 bool 'Enable Etrax100 watchdog' CONFIG_ETRAX_WATCHDOG
+if [ "$CONFIG_ETRAX_WATCHDOG" = "y" ]; then
+	bool 'Disable watchdog during Oops printouts' CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+fi
 
 endmenu
 
@@ -250,6 +236,6 @@
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
-endmenu
 
 source lib/Config.in
+endmenu
diff -u --recursive --new-file v2.5.2/linux/arch/cris/cris.ld linux/arch/cris/cris.ld
--- v2.5.2/linux/arch/cris/cris.ld	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/cris.ld	Wed Jan 23 10:54:42 2002
@@ -63,7 +63,13 @@
   	__setup_end = .;
   	.initcall.init : {
 		__initcall_start = .;
-		*(.initcall.init);
+		*(.initcall1.init);
+		*(.initcall2.init);
+		*(.initcall3.init);
+		*(.initcall4.init);
+		*(.initcall5.init);
+		*(.initcall6.init);
+		*(.initcall7.init);
 		__initcall_end = .;
 
 		/* We fill to the next page, so we can discard all init
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/Config.help linux/arch/cris/drivers/Config.help
--- v2.5.2/linux/arch/cris/drivers/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/Config.help	Fri Jan 25 16:04:29 2002
@@ -0,0 +1,574 @@
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+CONFIG_BLK_DEV_IDE
+  If you say Y here, you will use the full-featured IDE driver to
+  control up to ten ATA/IDE interfaces, each being able to serve a
+  "master" and a "slave" device, for a total of up to twenty ATA/IDE
+  disk/cdrom/tape/floppy drives.
+
+  Useful information about large (>540 MB) IDE disks, multiple
+  interfaces, what to do if ATA/IDE devices are not automatically
+  detected, sound card ATA/IDE ports, module support, and other
+  topics, is contained in <file:Documentation/ide.txt>. For detailed
+  information about hard drives, consult the Disk-HOWTO and the
+  Multi-Disk-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  To fine-tune ATA/IDE drive/interface parameters for improved
+  performance, look for the hdparm package at
+  <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),
+  say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/ide.txt>. The module will be called ide-mod.o.
+  Do not compile this driver as a module if your root file system (the
+  one containing the directory /) is located on an IDE device.
+
+  If you have one or more IDE drives, say Y or M here. If your system
+  has no IDE drives, or if memory requirements are really tight, you
+  could say N here, and select the "Old hard disk driver" below
+  instead to save about 13 KB of memory in the kernel.
+
+CONFIG_BLK_DEV_IDEDISK
+  This will include enhanced support for MFM/RLL/IDE hard disks.  If
+  you have a MFM/RLL/IDE disk, and there is no special reason to use
+  the old hard disk driver instead, say Y.  If you have an SCSI-only
+  system, you can say N here.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ide-disk.o.  Do not compile this driver as a module
+  if your root file system (the one containing the directory /) is
+  located on the IDE disk. If unsure, say Y.
+
+CONFIG_BLK_DEV_IDECD
+  If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is
+  a newer protocol used by IDE CD-ROM and TAPE drives, similar to the
+  SCSI protocol. Most new CD-ROM drives use ATAPI, including the
+  NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI
+  double(2X) or better speed drives.
+
+  If you say Y here, the CD-ROM drive will be identified at boot time
+  along with other IDE devices, as "hdb" or "hdc", or something
+  similar (check the boot messages with dmesg). If this is your only
+  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".
+
+  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),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ide-cd.o.
+
+CONFIG_PARPORT
+  If you want to use devices connected to your machine's parallel port
+  (the connector at the computer with 25 holes), e.g. printer, ZIP
+  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
+  <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
+  the WWW.
+
+  It is possible to share a single parallel port among several devices
+  and it is safe to compile all the corresponding drivers into the
+  kernel.  If you want to compile parallel port 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
+  parport.o.  If you have more than one parallel port and want to
+  specify which port and IRQ to be used by this driver at module load
+  time, take a look at <file:Documentation/parport.txt>.
+
+  If unsure, say Y.
+
+CONFIG_PARPORT_1284
+  If you have a printer that supports status readback or device ID, or
+  want to use a device that uses enhanced parallel port transfer modes
+  such as EPP and ECP, say Y here to enable advanced IEEE 1284
+  transfer modes. Also say Y if you want device ID information to
+  appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N.
+
+CONFIG_NET_ETHERNET
+  Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
+  type of Local Area Network (LAN) in universities and companies.
+
+  Common varieties of Ethernet are: 10BASE-2 or Thinnet (10 Mbps over
+  coaxial cable, linking computers in a chain), 10BASE-T or twisted
+  pair (10 Mbps over twisted pair cable, linking computers to central
+  hubs), 10BASE-F (10 Mbps over optical fiber links, using hubs),
+  100BASE-TX (100 Mbps over two twisted pair cables, using hubs),
+  100BASE-T4 (100 Mbps over 4 standard voice-grade twisted pair
+  cables, using hubs), 100BASE-FX (100 Mbps over optical fiber links)
+  [the 100BASE varieties are also known as Fast Ethernet], and Gigabit
+  Ethernet (1 Gbps over optical fiber or short copper links).
+
+  If your Linux machine will be connected to an Ethernet and you have
+  an Ethernet network interface card (NIC) installed in your computer,
+  say Y here and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. You will then also have
+  to say Y to the driver for your particular NIC.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about Ethernet network cards. If unsure, say N.
+
+CONFIG_MTD
+  Memory Technology Devices are flash, RAM and similar chips, often
+  used for solid state file systems on embedded devices. This option
+  will provide the generic support for MTD drivers to register
+  themselves with the kernel and for potential users of MTD devices
+  to enumerate the devices which are present and obtain a handle on
+  them. It will also allow you to select individual drivers for 
+  particular hardware and users of MTD devices. If unsure, say N.
+
+CONFIG_MTD_PARTITIONS
+  If you have a device which needs to divide its flash chip(s) up
+  into multiple 'partitions', each of which appears to the user as
+  a separate MTD device, you require this option to be enabled. If
+  unsure, say 'Y'.
+
+  Note, however, that you don't need this option for the DiskOnChip
+  devices. Partitioning on NFTL 'devices' is a different - that's the
+  'normal' form of partitioning used on a block device.
+
+CONFIG_MTD_CHAR
+  This provides a character device for each MTD device present in
+  the system, allowing the user to read and write directly to the
+  memory chips, and also use ioctl() to obtain information about
+  the device, or to erase parts of it.
+
+CONFIG_MTD_BLOCK
+  Although most flash chips have an erase size too large to be useful
+  as block devices, it is possible to use MTD devices which are based
+  on RAM chips in this manner. This block device is a user of MTD
+  devices performing that function.
+
+  At the moment, it is also required for the Journalling Flash File
+  System(s) to obtain a handle on the MTD device when it's mounted
+  (although JFFS and JFFS2 don't actually use any of the functionality
+  of the mtdblock device).
+
+  Later, it may be extended to perform read/erase/modify/write cycles
+  on flash chips to emulate a smaller block size. Needless to say,
+  this is very unsafe, but could be useful for file systems which are
+  almost never written to.
+
+  You do not need this option for use with the DiskOnChip devices. For
+  those, enable NFTL support (CONFIG_NFTL) instead.
+
+CONFIG_MTD_CFI
+  The Common Flash Interface specification was developed by Intel,
+  AMD and other flash manufactures that provides a universal method
+  for probing the capabilities of flash devices. If you wish to
+  support any device that is CFI-compliant, you need to enable this
+  option. Visit <http://www.amd.com/products/nvd/overview/cfi.html>
+  for more information on CFI.
+
+CONFIG_MTD_CFI_INTELEXT
+  The Common Flash Interface defines a number of different command
+  sets which a CFI-compliant chip may claim to implement. This code
+  provides support for one of those command sets, used on Intel
+  StrataFlash and other parts.
+
+CONFIG_MTD_CFI_AMDSTD
+  The Common Flash Interface defines a number of different command
+  sets which a CFI-compliant chip may claim to implement. This code
+  provides support for one of those command sets, used on chips 
+  chips including the AMD Am29LV320.
+
+CONFIG_MTD_AMDSTD
+  This option enables support for flash chips using AMD-compatible
+  commands, including some which are not CFI-compatible and hence 
+  cannot be used with the CONFIG_MTD_CFI_AMDSTD option.
+
+  It also works on AMD compatible chips that do conform to CFI.
+
+CONFIG_USB
+  Universal Serial Bus (USB) is a specification for a serial bus
+  subsystem which offers higher speeds and more features than the
+  traditional PC serial port.  The bus supplies power to peripherals
+  and allows for hot swapping.  Up to 127 USB peripherals can be
+  connected to a single USB port in a tree structure.  The USB port is
+  the root of the tree, the peripherals are the leaves and the inner
+  nodes are special USB devices called hubs.  Many newer PC's have USB
+  ports and newer peripherals such as scanners, keyboards, mice,
+  modems, and printers support the USB protocol and can be connected
+  to the PC via those ports.
+
+  Say Y here if your computer has a USB port and you want to use USB
+  devices.  You then need to say Y to at least one of "UHCI support"
+  or "OHCI support" below (the type of interface that the USB hardware
+  in your computer provides to the operating system) and then choose
+  from among the drivers for USB peripherals.  You may want to check
+  out the information provided in <file:Documentation/usb/> and
+  especially the links given in <file:Documentation/usb/usb-help.txt>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usbcore.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_PRINTER
+  If you intend to attach a printer to the parallel port of your Linux
+  box (as opposed to using a serial printer; if the connector at the
+  printer has 9 or 25 holes ["female"], then it's serial), say Y.
+  Also read the Printing-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  It is possible to share one parallel port among several devices
+  (e.g. printer and ZIP drive) and it is safe to compile the
+  corresponding drivers into the kernel.  If you want to compile this
+  driver as a module however ( = code which can be inserted in and
+  removed from the running kernel whenever you want), say M here and
+  read <file:Documentation/modules.txt> and
+  <file:Documentation/parport.txt>.  The module will be called lp.o.
+
+  If you have several parallel ports, you can specify which ports to
+  use with the "lp" kernel command line option.  (Try "man bootparam"
+  or see the documentation of your boot loader (lilo or loadlin) about
+  how to pass options to the kernel at boot time.)  The syntax of the
+  "lp" command line option can be found in <file:drivers/char/lp.c>.
+
+  If you have more than 8 printers, you need to increase the LP_NO
+  macro in lp.c and the PARPORT_MAX macro in parport.h.
+
+CONFIG_ETRAX_PA_BUTTON_BITMASK
+  This is a bitmask with information about what bits on PA that
+  are used for buttons.
+  Most products has a so called TEST button on PA1, if that's true
+  use 02 here.
+  Use 00 if there are no buttons on PA.
+  If the bitmask is <> 00 a button driver will be included in the gpio
+  driver. Etrax general I/O support must be enabled.
+
+CONFIG_ETRAX_PA_CHANGEABLE_DIR
+  This is a bitmask with information of what bits in PA that a user
+  can change direction on using ioctl's.
+  Bit set = changeable.
+  You probably want 00 here.
+
+CONFIG_ETRAX_PA_CHANGEABLE_BITS
+  This is a bitmask with information of what bits in PA that a user
+  can change change the value on using ioctl's.
+  Bit set = changeable.
+  You probably want 00 here.
+
+CONFIG_ETRAX_PB_CHANGEABLE_DIR
+  This is a bitmask with information of what bits in PB that a user
+  can change direction on using ioctl's.
+  Bit set = changeable.
+  You probably want 00 here.
+
+CONFIG_ETRAX_PB_CHANGEABLE_BITS
+  This is a bitmask with information of what bits in PB that a user
+  can change the value on using ioctl's.
+  Bit set = changeable.
+  You probably want 00 here.
+
+CONFIG_ETRAX_GPIO
+  Enables the Etrax general port device (major 120, minors 0 and 1).
+  You can use this driver to access the general port bits. It supports
+  these ioctl's:
+        #include <linux/etraxgpio.h>
+       fd = open("/dev/gpioa", O_RDWR); // or /dev/gpiob
+       ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETBITS), bits_to_set);
+       ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_CLRBITS), bits_to_clear);
+       val = ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_READBITS), NULL);
+  Remember that you need to setup the port directions appropriately in
+  the General configuration.
+
+CONFIG_ETRAX_SERIAL
+  Enables the ETRAX 100 serial driver for ser0 (ttyS0)
+  You probably want this enabled.
+
+CONFIG_ETRAX_SERIAL_FAST_TIMER
+  Select this to have the serial DMAs flushed at a higher rate than
+  normally, possible by using the fast timer API, the timeout is
+  approx. 4 character times.
+  If unsure, say N.
+
+CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
+  Select this to have the serial DMAs flushed at a higher rate than
+  normally possible through a fast timer interrupt (currently at
+  15360 Hz).
+  If unsure, say N.
+
+CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
+  Number of timer ticks between flush of receive fifo (1 tick = 10ms).
+  Try 0-3 for low latency applications.  Approx 5 for high load
+  applications (e.g. PPP).  Maybe this should be more adaptive some
+  day...
+
+CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB
+  Enables the status and control signals DTR, RI, DSR and CD on PB for
+  ser0.
+
+CONFIG_ETRAX_SERIAL_PORT1
+  Enables the ETRAX 100 serial driver for ser1 (ttyS1).
+
+CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB
+  Enables the status and control signals DTR, RI, DSR and CD on PB for
+  ser1.
+
+CONFIG_ETRAX_SERIAL_PORT2
+  Enables the ETRAX 100 serial driver for ser2 (ttyS2).
+
+CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA
+  Enables the status and control signals DTR, RI, DSR and CD on PA for
+  ser2.
+
+CONFIG_ETRAX_SERIAL_PORT3
+  Enables the ETRAX 100 serial driver for ser3 (ttyS3).
+
+CONFIG_ETRAX_RS485
+  Enables support for RS-485 serial communication.  For a primer on
+  RS-485, see <http://www.hw.cz/english/docs/rs485/rs485.html>.
+
+CONFIG_ETRAX_RS485_ON_PA
+  Control Driver Output Enable on RS485 tranceiver using a pin on PA
+  port:
+          Axis 2400/2401 uses PA 3.
+
+CONFIG_ETRAX_RS485_ON_PA_BIT
+  Control Driver Output Enable on RS485 tranceiver using a this bit
+  on PA port.
+
+CONFIG_ETRAX_SER0_DTR_ON_PB_BIT
+  Specify the pin of the PB port to carry the DTR signal for serial
+  port 0.
+
+CONFIG_ETRAX_SER0_RI_ON_PB_BIT
+  Specify the pin of the PB port to carry the RI signal for serial
+  port 0.
+
+CONFIG_ETRAX_SER0_DSR_ON_PB_BIT
+  Specify the pin of the PB port to carry the DSR signal for serial
+  port 0.
+
+CONFIG_ETRAX_SER0_CD_ON_PB_BIT
+  Specify the pin of the PB port to carry the CD signal for serial
+  port 0.
+
+CONFIG_ETRAX_SER1_DTR_ON_PB_BIT
+  Specify the pin of the PB port to carry the DTR signal for serial
+  port 1.
+
+CONFIG_ETRAX_SER1_RI_ON_PB_BIT
+  Specify the pin of the PB port to carry the RI signal for serial
+  port 1.
+
+CONFIG_ETRAX_SER1_DSR_ON_PB_BIT
+  Specify the pin of the PB port to carry the DSR signal for serial
+  port 1.
+
+CONFIG_ETRAX_SER1_CD_ON_PB_BIT
+  Specify the pin of the PB port to carry the CD signal for serial
+  port 1.
+
+CONFIG_ETRAX_SER2_DTR_ON_PA_BIT
+  Specify the pin of the PA port to carry the DTR signal for serial
+  port 2.
+
+CONFIG_ETRAX_SER2_RI_ON_PA_BIT
+  Specify the pin of the PA port to carry the RI signal for serial
+  port 2.
+
+CONFIG_ETRAX_SER2_DSR_ON_PA_BIT
+  Specify the pin of the PA port to carry the DTR signal for serial
+  port 2.
+
+CONFIG_ETRAX_SER2_CD_ON_PA_BIT
+  Specify the pin of the PA port to carry the CD signal for serial
+  port 2.
+
+CONFIG_ETRAX_RS485_DISABLE_RECEIVER
+  It's necessary to disable the serial receiver to avoid serial
+  loopback.  Not all products are able to do this in software only.
+  Axis 2400/2401 must disable receiver.
+
+CONFIG_ETRAX_I2C
+  Enables an I2C driver on PB0 and PB1 on ETRAX100.
+  EXAMPLE usage:
+        i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val);
+       ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg);
+       i2c_arg = I2C_READARG(STA013_READ_ADDR, reg);
+       val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg);
+
+CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+  Select whether to use the special I2C mode in the PB I/O register or
+  not.  This option needs to be selected in order to use some drivers
+  that access the I2C I/O pins directly instead of going through the
+  I2C driver, like the DS1302 realtime-clock driver.  If you are
+  uncertain, choose Y here.
+
+CONFIG_ETRAX_I2C_EEPROM
+  Enables I2C EEPROM (non-volatile RAM) on PB0 and PB1 using the I2C
+  driver.  Select size option: Probed, 2k, 8k, 16k.
+  (Probing works for 2k and 8k but not that well for 16k)
+
+CONFIG_ETRAX_I2C_EEPROM_16KB
+  Use a 16kB EEPROM.
+
+CONFIG_ETRAX_I2C_EEPROM_2KB
+  Use a 2kB EEPROM.
+
+CONFIG_ETRAX_I2C_EEPROM_8KB
+  Use a 8kB EEPROM.
+
+CONFIG_ETRAX_I2C_EEPROM_PROBE
+  Specifies size or auto probe of the EEPROM size.
+  Options: Probed, 2k, 8k, 16k.
+  (Probing works for 2k and 8k but not that well for 16k)
+
+CONFIG_ETRAX_DS1302
+  Enables the driver for the DS1302 Real-Time Clock battery-backed
+  chip on some products.  The kernel reads the time when booting, and
+  the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a
+  rtc_time struct (see <file:include/asm-cris/rtc.h>) on the /dev/rtc
+  device, major 121.  You can check the time with cat /proc/rtc, but
+  normal time reading should be done using libc function time and
+  friends.
+
+CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
+  If your product has the RST signal line for the DS1302 RTC on the
+  Generic Port then say Y here, otherwise leave it as N in which
+  case the RST signal line is assumed to be connected to Port PB
+  (just like the SCL and SDA lines).
+
+CONFIG_ETRAX_DS1302_RSTBIT
+  This is the bit number for the RST signal line of the DS1302 RTC on
+  the selected port. If you have selected the generic port then it
+  should be bit 27, otherwise your best bet is bit 5.
+
+CONFIG_ETRAX_DS1302_SCLBIT
+  This is the bit number for the SCL signal line of the DS1302 RTC on
+  Port PB. This is probably best left at 3.
+
+CONFIG_ETRAX_DS1302_SDABIT
+  This is the bit number for the SDA signal line of the DS1302 RTC on
+  Port PB. This is probably best left at 2.
+
+CONFIG_ETRAX_IDE_CSP0_8_RESET
+  Configures the pin used to reset the IDE bus.
+
+CONFIG_ETRAX_IDE_DELAY
+  Sets the time to wait for disks to regain consciousness after reset.
+
+CONFIG_ETRAX_IDE_G27_RESET
+  Configures the pin used to reset the IDE bus.
+
+CONFIG_ETRAX_IDE_PB7_RESET
+  Configures the pin used to reset the IDE bus.
+
+CONFIG_ETRAX_USB_HOST
+  This option enables the host functionality of the ETRAX 100LX
+  built-in USB controller. In host mode the controller is designed
+  for CTRL and BULK traffic only, INTR traffic may work as well
+  however (depending on the requirements of timeliness).
+
+CONFIG_ETRAX_USB_HOST_PORT1
+  This option enables port 1 of the ETRAX 100LX USB root hub (RH).
+
+CONFIG_ETRAX_USB_HOST_PORT2
+  This option enables port 2 of the ETRAX 100LX USB root hub (RH).
+
+CONFIG_ETRAX_ETHERNET
+  This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet
+  controller.
+
+CONFIG_ETRAX_SYNCHRONOUS_SERIAL
+  This option enables support for the ETRAX 100LX built-in
+  synchronous serial ports. These ports are used for continuous
+  streamed data like audio. The default setting is compatible
+  with the STA 013 MP3 decoder, but can easily be tuned to fit
+  any other audio encoder/decoder and SPI.
+
+CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0
+  Enables the ETRAX 100LX synchronous serial port 0 (syncser0).
+
+CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA
+  Makes synchronous serial port 0 use DMA.
+
+CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1
+  Enables the ETRAX 100LX synchronous serial port 1 (syncser1).
+
+CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA
+  Makes synchronous serial port 1 use DMA.
+
+CONFIG_JULIETTE
+  The ARTPEC-1 is a video-compression chip used in the AXIS 2100
+  network camera, which is built around an ETRAX-100 board.  With this
+  option selected, the ETRAX kernel configures a DMA channel at boot
+  time to talk to the chip.
+
+CONFIG_ETRAX_AXISFLASHMAP
+  This option enables MTD mapping of flash devices.  Needed to use
+  flash memories.  If unsure, say Y.
+
+CONFIG_ETRAX_PTABLE_SECTOR
+  Byte-offset of the partition table in the first flash chip.
+  The default value is 64kB and should not be changed unless
+  you know exactly what you are doing. The only valid reason
+  for changing this is when the flash block size is bigger
+  than 64kB (e.g. when using two parallel 16 bit flashes).
+
+CONFIG_ETRAX_PARPORT
+  Say Y here to enable the ETRAX on-board parallel ports.
+
+CONFIG_ETRAX_PARALLEL_PORT0
+  Say Y here to enable parallel port 0.
+
+CONFIG_ETRAX_PARALLEL_PORT1
+  Say Y here to enable parallel port 1.
+
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/Config.in linux/arch/cris/drivers/Config.in
--- v2.5.2/linux/arch/cris/drivers/Config.in	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/drivers/Config.in	Mon Jan 21 16:00:39 2002
@@ -175,11 +175,11 @@
   hex  '  PB user changeable bits mask' CONFIG_ETRAX_PB_CHANGEABLE_BITS FF
 fi
 
-bool 'ARTPEC-1 support' CONFIG_JULIETTE
-
-if [ "$CONFIG_JULIETTE" = "y" ]; then
-   source arch/cris/drivers/juliette/Config.in
-fi
+#bool 'ARTPEC-1 support' CONFIG_JULIETTE
+#
+#if [ "$CONFIG_JULIETTE" = "y" ]; then
+#   source arch/cris/drivers/juliette/Config.in
+#fi
 
 bool 'USB host' CONFIG_ETRAX_USB_HOST
 if [ "$CONFIG_ETRAX_USB_HOST" = "y" ]; then
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/axisflashmap.c linux/arch/cris/drivers/axisflashmap.c
--- v2.5.2/linux/arch/cris/drivers/axisflashmap.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/drivers/axisflashmap.c	Mon Jan 21 16:00:39 2002
@@ -11,6 +11,17 @@
  * partition split defined below.
  *
  * $Log: axisflashmap.c,v $
+ * Revision 1.2  2001/12/18 13:35:15  bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.17  2001/11/12 19:42:38  pkj
+ * Fixed compiler warnings.
+ *
+ * Revision 1.16  2001/11/08 11:18:58  jonashg
+ * Always read from uncached address to avoid problems with flushing
+ * cachelines after write and MTD-erase. No performance loss have been
+ * seen yet.
+ *
  * Revision 1.15  2001/10/19 12:41:04  jonashg
  * Name of probe has changed in MTD.
  *
@@ -121,7 +132,7 @@
 static void flash_copy_from(struct map_info *map, void *to,
 			    unsigned long from, ssize_t len)
 {
-	memcpy(to, (void *)(FLASH_CACHED_ADDR + from), len);
+	memcpy(to, (void *)(FLASH_UNCACHED_ADDR + from), len);
 }
 
 static void flash_write8(struct map_info *map, __u8 d, unsigned long adr)
@@ -237,7 +248,7 @@
 	int use_default_ptable = 1; /* Until proven otherwise */
 	const char *pmsg = "  /dev/flash%d at 0x%x, size 0x%x\n";
 
-	printk(KERN_NOTICE "Axis flash mapping: %x at %x\n",
+	printk(KERN_NOTICE "Axis flash mapping: %x at %lx\n",
 	       WINDOW_SIZE, FLASH_CACHED_ADDR);
 
 #ifdef CONFIG_MTD_CFI
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/bluetooth/Makefile linux/arch/cris/drivers/bluetooth/Makefile
--- v2.5.2/linux/arch/cris/drivers/bluetooth/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/bluetooth/Makefile	Mon Jan 21 16:00:39 2002
@@ -0,0 +1,25 @@
+include $(APPS)/Rules.elinux
+
+all:
+
+install:	src/bluetooth.c include/btcommon.h
+	ln -sfn ../../arch/cris/drivers/bluetooth/include ../../../../include/linux/bluetooth
+	if ! grep arch/cris/drivers/bluetooth/src/Config.in ../Config.in; then \
+	  echo '' >> ../Config.in; \
+	  echo 'if [ "$$CONFIG_ETRAX_SERIAL" = "y" ]; then' >> ../Config.in; \
+	  echo '  source arch/cris/drivers/bluetooth/src/Config.in' >> ../Config.in; \
+	  echo 'fi' >> ../Config.in; \
+	fi
+	if ! grep bluetooth/src/bt.o ../Makefile; then \
+	  perl -pi -e "s:include:obj-\\\$$(CONFIG_BLUETOOTH)                 += bluetooth/src/bt.o\nsubdir-\\\$$(CONFIG_BLUETOOTH)              += bluetooth/src\n\ninclude:" ../Makefile; \
+	fi
+
+clean:
+
+src/bluetooth.c:
+	@echo "You must install the OpenBT src directory before install can be done here!"
+	@exit 1
+
+include/btcommon.h:
+	@echo "You must install the OpenBT include directory before install can be done here!"
+	@exit 1
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/ds1302.c linux/arch/cris/drivers/ds1302.c
--- v2.5.2/linux/arch/cris/drivers/ds1302.c	Wed Jul  4 11:50:38 2001
+++ linux/arch/cris/drivers/ds1302.c	Mon Jan 21 16:00:39 2002
@@ -7,6 +7,9 @@
 *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
 *!
 *! $Log: ds1302.c,v $
+*! Revision 1.1.1.1  2001/12/17 13:59:27  bjornw
+*! Import of Linux 2.5.1
+*!
 *! Revision 1.11  2001/06/14 12:35:52  jonashg
 *! The ATA hack is back. It is unfortunately the only way to set g27 to output.
 *!
@@ -82,7 +85,7 @@
 *!
 *! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
 *!
-*! $Id: ds1302.c,v 1.11 2001/06/14 12:35:52 jonashg Exp $
+*! $Id: ds1302.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
 *!
 *!***************************************************************************/
 
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/eeprom.c linux/arch/cris/drivers/eeprom.c
--- v2.5.2/linux/arch/cris/drivers/eeprom.c	Thu Jul 26 15:10:06 2001
+++ linux/arch/cris/drivers/eeprom.c	Mon Jan 21 16:00:39 2002
@@ -20,6 +20,9 @@
 *!                                  in the spin-lock.
 *!
 *!  $Log: eeprom.c,v $
+*!  Revision 1.1.1.1  2001/12/17 13:59:27  bjornw
+*!  Import of Linux 2.5.1
+*!
 *!  Revision 1.8  2001/06/15 13:24:29  jonashg
 *!  * Added verification of pointers from userspace in read and write.
 *!  * Made busy counter volatile.
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/ethernet.c linux/arch/cris/drivers/ethernet.c
--- v2.5.2/linux/arch/cris/drivers/ethernet.c	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/drivers/ethernet.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: ethernet.c,v 1.18 2001/10/03 14:40:43 jonashg Exp $
+/* $Id: ethernet.c,v 1.2 2001/12/18 13:35:15 bjornw Exp $
  *
  * e100net.c: A network driver for the ETRAX 100LX network controller.
  *
@@ -7,6 +7,24 @@
  * The outline of this driver comes from skeleton.c.
  *
  * $Log: ethernet.c,v $
+ * Revision 1.2  2001/12/18 13:35:15  bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.21  2001/11/23 11:54:49  starvik
+ * Added IFF_PROMISC and IFF_ALLMULTI handling in set_multicast_list
+ * Removed compiler warnings
+ *
+ * Revision 1.20  2001/11/12 19:26:00  pkj
+ * * Corrected e100_negotiate() to not assign half to current_duplex when
+ *   it was supposed to compare them...
+ * * Cleaned up failure handling in e100_open().
+ * * Fixed compiler warnings.
+ *
+ * Revision 1.19  2001/11/09 07:43:09  starvik
+ * Added full duplex support
+ * Added ioctl to set speed and duplex
+ * Clear LED timer only runs when LED is lit
+ *
  * Revision 1.18  2001/10/03 14:40:43  jonashg
  * Update rx_bytes counter.
  *
@@ -104,6 +122,7 @@
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
+#include <asm/ethernet.h>
 
 //#define ETHDEBUG
 #define D(x)
@@ -120,7 +139,7 @@
 
 static struct sockaddr default_mac = {
 	0,
-        { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 }
+	{ 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 }
 };
 
 /* Information that need to be kept for each board. */
@@ -136,6 +155,14 @@
 };
 
 
+/* Duplex settings */
+enum duplex
+{
+	half,
+	full,
+	autoneg
+};
+
 /* Dma descriptors etc. */
 
 #define RX_BUF_SIZE 32768
@@ -148,9 +175,18 @@
 /* 
 ** MDIO constants.
 */
-#define MDIO_BASE_STATUS_REG   0x1
-#define MDIO_BASE_CONTROL_REG  0x0
-#define MDIO_LINK_UP_MASK      0x4
+#define MDIO_BASE_STATUS_REG                0x1
+#define MDIO_BASE_CONTROL_REG               0x0
+#define MDIO_BC_NEGOTIATE                0x0200
+#define MDIO_BC_FULL_DUPLEX_MASK         0x0100
+#define MDIO_BC_AUTO_NEG_MASK            0x1000
+#define MDIO_BC_SPEED_SELECT_MASK        0x2000
+#define MDIO_ADVERTISMENT_REG               0x4
+#define MDIO_ADVERT_100_FD                0x100
+#define MDIO_ADVERT_100_HD                0x080
+#define MDIO_ADVERT_10_FD                 0x040
+#define MDIO_ADVERT_10_HD                 0x020
+#define MDIO_LINK_UP_MASK                   0x4
 #define MDIO_START                          0x1
 #define MDIO_READ                           0x2
 #define MDIO_WRITE                          0x1
@@ -158,6 +194,7 @@
 
 /* Broadcom specific */
 #define MDIO_AUX_CTRL_STATUS_REG           0x18
+#define MDIO_FULL_DUPLEX_IND                0x1
 #define MDIO_SPEED                          0x2
 #define MDIO_PHYS_ADDR                      0x0
 
@@ -165,18 +202,25 @@
 #define NET_FLASH_TIME                  (HZ/50) /* 20 ms */
 #define NET_FLASH_PAUSE                (HZ/100) /* 10 ms */
 #define NET_LINK_UP_CHECK_INTERVAL       (2*HZ) /* 2 s   */
+#define NET_DUPLEX_CHECK_INTERVAL        (2*HZ) /* 2 s   */
 
 #define NO_NETWORK_ACTIVITY 0
 #define NETWORK_ACTIVITY    1
 
 #define RX_DESC_BUF_SIZE   256
 #define NBR_OF_RX_DESC     (RX_BUF_SIZE / \
-			    RX_DESC_BUF_SIZE)
+                            RX_DESC_BUF_SIZE)
 
 #define GET_BIT(bit,val)   (((val) >> (bit)) & 0x01)
 
+/* Define some macros to access ETRAX 100 registers */
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
+					  IO_FIELD(##reg##, field, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
+					  IO_STATE(##reg##, field, val)
+
 static etrax_dma_descr *myNextRxDesc;  /* Points to the next descriptor to
-					  to be processed */
+                                          to be processed */
 static etrax_dma_descr *myLastRxDesc;  /* The last processed descriptor */
 static etrax_dma_descr *myPrevRxDesc;  /* The descriptor right before myNextRxDesc */
 
@@ -187,13 +231,21 @@
 
 static struct sk_buff *tx_skb;
 
+static unsigned int network_rec_config_shadow = 0;
+
 /* Network speed indication. */
 static struct timer_list speed_timer;
 static struct timer_list clear_led_timer;
-static int current_speed;
+static int current_speed; /* Speed read from tranceiver */
+static int current_speed_selection; /* Speed selected by user */
 static int led_next_time;
 static int led_active;
 
+/* Duplex */
+static struct timer_list duplex_timer;
+static int full_duplex;
+static enum duplex current_duplex;
+
 /* Index to functions, as function prototypes. */
 
 static int etrax_ethernet_init(struct net_device *dev);
@@ -206,6 +258,8 @@
 static void e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void e100_rx(struct net_device *dev);
 static int e100_close(struct net_device *dev);
+static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static void e100_tx_timeout(struct net_device *dev);
 static struct net_device_stats *e100_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 static void e100_hardware_send_packet(char *buf, int length);
@@ -213,6 +267,11 @@
 static void update_tx_stats(struct net_device_stats *);
 
 static void e100_check_speed(unsigned long dummy);
+static void e100_set_speed(unsigned long speed);
+static void e100_check_duplex(unsigned long dummy);
+static void e100_set_duplex(enum duplex);
+static void e100_negotiate(void);
+
 static unsigned short e100_get_mdio_reg(unsigned char reg_num);
 static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd);
 static void e100_send_mdio_bit(unsigned char bit);
@@ -278,6 +337,8 @@
 	dev->get_stats          = e100_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 	dev->set_mac_address    = e100_set_mac_address;
+	dev->do_ioctl           = e100_ioctl;
+	dev->tx_timeout         = e100_tx_timeout;
 
 	/* set the default MAC address */
 
@@ -287,7 +348,7 @@
 
 	/* Initialise receive descriptors */
 
-	for(i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
+	for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
 		RxDescList[i].ctrl   = 0;
 		RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
 		RxDescList[i].next   = virt_to_phys(&RxDescList[i + 1]);
@@ -313,12 +374,18 @@
 	/* Initialize speed indicator stuff. */
 
 	current_speed = 10;
+	current_speed_selection = 0; /* Auto */
 	speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
 	speed_timer.function = e100_check_speed;
 	add_timer(&speed_timer);
+        
 	clear_led_timer.function = e100_clear_network_leds;
-	clear_led_timer.expires = jiffies + HZ/10;
-	add_timer(&clear_led_timer);
+        
+	full_duplex = 0;
+	current_duplex = autoneg;
+	duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;		
+	duplex_timer.function = e100_check_duplex;
+	add_timer(&duplex_timer);
 
 	return 0;
 }
@@ -335,7 +402,7 @@
 
 	/* remember it */
 
-        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
 	/* Write it to the hardware.
 	 * Note the way the address is wrapped:
@@ -409,21 +476,21 @@
 
 	if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rx_interrupt, 0,
 			cardname, (void *)dev)) {
-		goto grace_exit;
+		goto grace_exit0;
 	}
 
 	/* allocate the irq corresponding to the transmitting DMA */
 
 	if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100tx_interrupt, 0,
 			cardname, (void *)dev)) {
-		goto grace_exit;
+		goto grace_exit1;
 	}
 
 	/* allocate the irq corresponding to the network errors etc */
 
 	if (request_irq(NETWORK_STATUS_IRQ_NBR, e100nw_interrupt, 0,
 			cardname, (void *)dev)) {
-		goto grace_exit;
+		goto grace_exit2;
 	}
 
 	/*
@@ -431,18 +498,12 @@
 	 * and clean up on failure.
 	 */
 
-	if(request_dma(NETWORK_TX_DMA_NBR, cardname)) {
-		goto grace_exit;
+	if (request_dma(NETWORK_TX_DMA_NBR, cardname)) {
+		goto grace_exit3;
 	}
 
-	if(request_dma(NETWORK_RX_DMA_NBR, cardname)) {
-	grace_exit:
-		/* this will cause some 'trying to free free irq' but what the heck... */
-		free_dma(NETWORK_TX_DMA_NBR);
-		free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);
-		free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
-		free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
-		return -EAGAIN;
+	if (request_dma(NETWORK_RX_DMA_NBR, cardname)) {
+		goto grace_exit4;
 	}
 
 	/* give the HW an idea of what MAC address we want */
@@ -459,9 +520,10 @@
 
 	*R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */
 #else
-	*R_NETWORK_REC_CONFIG =
-		IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) |
-		IO_STATE(R_NETWORK_REC_CONFIG, ma0,       enable);
+	SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, broadcast, receive);
+	SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, ma0, enable);
+	SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
+	*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
 #endif
 
 	*R_NETWORK_GEN_CONFIG =
@@ -507,6 +569,17 @@
 	netif_start_queue(dev);
 
 	return 0;
+
+grace_exit4:
+	free_dma(NETWORK_TX_DMA_NBR);
+grace_exit3:
+	free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
+grace_exit2:
+	free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
+grace_exit1:
+	free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);
+grace_exit0:
+	return -EAGAIN;
 }
 
 
@@ -532,10 +605,119 @@
 	add_timer(&speed_timer);
 }
 
+static void
+e100_negotiate(void)
+{
+	unsigned short cmd;
+	unsigned short data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG);
+	int bitCounter;
+
+	/* Discard old speed and duplex settings */
+	data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | 
+	          MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD);
+  
+	switch (current_speed_selection) {
+		case 10 :
+			if (current_duplex == full)
+				data |= MDIO_ADVERT_10_FD;
+			else if (current_duplex == half)
+				data |= MDIO_ADVERT_10_HD;
+			else
+				data |= MDIO_ADVERT_10_HD |  MDIO_ADVERT_10_FD;
+			break;
+
+		case 100 :
+			 if (current_duplex == full)
+				data |= MDIO_ADVERT_100_FD;
+			else if (current_duplex == half)
+				data |= MDIO_ADVERT_100_HD;
+			else
+				data |= MDIO_ADVERT_100_HD |  MDIO_ADVERT_100_FD;
+			break;
+
+		case 0 : /* Auto */
+			 if (current_duplex == full)
+				data |= MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD;
+			else if (current_duplex == half)
+				data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_10_HD;
+			else
+				data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD;
+			break;
+
+		default : /* assume autoneg speed and duplex */
+			data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | 
+			        MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD;
+	}
+
+	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
+	      (MDIO_ADVERTISMENT_REG<< 2);
+
+	e100_send_mdio_cmd(cmd, 1);
+
+	/* Data... */
+	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
+		e100_send_mdio_bit(GET_BIT(bitCounter, data));
+	}
+
+	/* Renegotiate with link partner */
+	data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG);
+	data |= MDIO_BC_NEGOTIATE;
+
+	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
+	      (MDIO_BASE_CONTROL_REG<< 2);
+
+	e100_send_mdio_cmd(cmd, 1);
+
+	/* Data... */
+	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
+		e100_send_mdio_bit(GET_BIT(bitCounter, data));
+	}  
+}
+
+static void
+e100_set_speed(unsigned long speed)
+{
+	current_speed_selection = speed;
+	e100_negotiate();
+}
+
+static void
+e100_check_duplex(unsigned long dummy)
+{
+	unsigned long data;
+
+	data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG);
+        
+	if (data & MDIO_FULL_DUPLEX_IND) {
+		if (!full_duplex) { /* Duplex changed to full? */
+			full_duplex = 1;
+			SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
+			*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+		}
+	} else { /* half */
+		if (full_duplex) { /* Duplex changed to half? */
+			full_duplex = 0;
+			SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
+			*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+		}
+	}
+
+	/* Reinitialize the timer. */
+	duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
+	add_timer(&duplex_timer);
+}
+
+static void 
+e100_set_duplex(enum duplex new_duplex)
+{
+	current_duplex = new_duplex;
+	e100_negotiate();
+}
+
+
 static unsigned short
 e100_get_mdio_reg(unsigned char reg_num)
 {
-	unsigned long flags;
 	unsigned short cmd;    /* Data to be sent on MDIO port */
 	unsigned short data;   /* Data read from MDIO */
 	int bitCounter;
@@ -549,7 +731,7 @@
 	data = 0;
 	
 	/* Data... */
-	for(bitCounter=15; bitCounter>=0 ; bitCounter--) {
+	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
 		data |= (e100_receive_mdio_bit() << bitCounter);
 	}
 
@@ -563,14 +745,14 @@
 	unsigned char data = 0x2;
 	
 	/* Preamble */
-	for(bitCounter = 31; bitCounter>= 0; bitCounter--)
+	for (bitCounter = 31; bitCounter>= 0; bitCounter--)
 		e100_send_mdio_bit(GET_BIT(bitCounter, MDIO_PREAMBLE));
 
-	for(bitCounter = 15; bitCounter >= 2; bitCounter--)
+	for (bitCounter = 15; bitCounter >= 2; bitCounter--)
 		e100_send_mdio_bit(GET_BIT(bitCounter, cmd));
 
 	/* Turnaround */
-	for(bitCounter = 1; bitCounter >= 0 ; bitCounter--)
+	for (bitCounter = 1; bitCounter >= 0 ; bitCounter--)
 		if (write_cmd)
 			e100_send_mdio_bit(GET_BIT(bitCounter, data));
 		else
@@ -606,7 +788,6 @@
 static void 
 e100_reset_tranceiver(void)
 {
-	unsigned long flags;
 	unsigned short cmd;
 	unsigned short data;
 	int bitCounter;
@@ -619,7 +800,7 @@
 	
 	data |= 0x8000;
 	
-	for(bitCounter = 15; bitCounter >= 0 ; bitCounter--) {
+	for (bitCounter = 15; bitCounter >= 0 ; bitCounter--) {
 		e100_send_mdio_bit(GET_BIT(bitCounter, data));
 	}
 }
@@ -706,15 +887,14 @@
 	struct net_device *dev = (struct net_device *)dev_id;
 	unsigned long irqbits = *R_IRQ_MASK2_RD;
  
-	if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
-
+	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
 		/* acknowledge the eop interrupt */
 
 		*R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do);
 
 		/* check if one or more complete packets were indeed received */
 
-		while(*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) {
+		while (*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) {
 			/* Take out the buffer and give it to the OS, then
 			 * allocate a new buffer to put a packet in.
 			 */
@@ -747,8 +927,7 @@
 	struct net_local *np = (struct net_local *)dev->priv;
 
 	/* check for a dma0_eop interrupt */
-	if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { 
-		
+	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { 
 		/* This protects us from concurrent execution of
 		 * our dev->hard_start_xmit function above.
 		 */
@@ -759,7 +938,7 @@
 
 		*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
 
-		if(*R_DMA_CH0_FIRST == 0 && tx_skb) {
+		if (*R_DMA_CH0_FIRST == 0 && tx_skb) {
 			np->stats.tx_bytes += tx_skb->len;
 			np->stats.tx_packets++;
 			/* dma is ready with the transmission of the data in tx_skb, so now
@@ -784,19 +963,19 @@
 	unsigned long irqbits = *R_IRQ_MASK0_RD;
 
 	/* check for underrun irq */
-	if(irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) { 
+	if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) { 
 		*R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);
 		np->stats.tx_errors++;
 		D(printk("ethernet receiver underrun!\n"));
 	}
 
 	/* check for overrun irq */
-	if(irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { 
+	if (irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { 
 		update_rx_stats(&np->stats); /* this will ack the irq */
 		D(printk("ethernet receiver overrun!\n"));
 	}
 	/* check for excessive collision irq */
-	if(irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { 
+	if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { 
 		*R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);
 		np->stats.tx_errors++;
 		D(printk("ethernet excessive collisions!\n"));
@@ -809,11 +988,13 @@
 e100_rx(struct net_device *dev)
 {
 	struct sk_buff *skb;
-	int length=0;
-	int i;
+	int length = 0;
 	struct net_local *np = (struct net_local *)dev->priv;
 	struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc;
 	unsigned char *skb_data_ptr;
+#ifdef ETHDEBUG
+	int i;
+#endif
 
 	if (!led_active && jiffies > led_next_time) {
 		/* light the network leds depending on the current speed. */
@@ -822,6 +1003,7 @@
 		/* Set the earliest time we may clear the LED */
 		led_next_time = jiffies + NET_FLASH_TIME;
 		led_active = 1;
+		mod_timer(&clear_led_timer, jiffies + HZ/10);
 	}
 
 	/* If the packet is broken down in many small packages then merge
@@ -842,7 +1024,7 @@
 	printk("Got a packet of length %d:\n", length);
 	/* dump the first bytes in the packet */
 	skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf);
-	for(i = 0; i < 8; i++) {
+	for (i = 0; i < 8; i++) {
 		printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8,
 		       skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3],
 		       skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]);
@@ -869,7 +1051,7 @@
 
 	/* this loop can be made using max two memcpy's if optimized */
 
-	while(mySaveRxDesc != myNextRxDesc) {
+	while (mySaveRxDesc != myNextRxDesc) {
 		memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf),
 		       mySaveRxDesc->sw_len);
 		skb_data_ptr += mySaveRxDesc->sw_len;
@@ -946,6 +1128,37 @@
 	return 0;
 }
 
+static int
+e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	/* Maybe default should return -EINVAL instead? */
+	switch (cmd) {
+		case SET_ETH_SPEED_10:                  /* 10 Mbps */
+			e100_set_speed(10);
+			break;
+		case SET_ETH_SPEED_100:                /* 100 Mbps */
+			e100_set_speed(100);
+			break;
+		case SET_ETH_SPEED_AUTO:              /* Auto negotiate speed */
+			e100_set_speed(0);
+			break;
+		case SET_ETH_DUPLEX_HALF:              /* Hhalf duplex. */
+			e100_set_duplex(half);
+			break;
+		case SET_ETH_DUPLEX_FULL:              /* Full duplex. */
+			e100_set_duplex(full);
+			break;
+		case SET_ETH_DUPLEX_AUTO:             /* Autonegotiate duplex*/
+			e100_set_duplex(autoneg);
+			break;
+		default: /* Auto neg */
+			e100_set_speed(0);
+			e100_set_duplex(autoneg);
+			break;
+	}
+	return 0;
+}
+
 static void
 update_rx_stats(struct net_device_stats *es)
 {
@@ -996,26 +1209,31 @@
 	int num_addr = dev->mc_count;
 	unsigned long int lo_bits;
 	unsigned long int hi_bits;
-	if (num_addr == -1)
+	if (dev->flags & IFF_PROMISC)
 	{
 		/* promiscuous mode */
 		lo_bits = 0xfffffffful;
 		hi_bits = 0xfffffffful;
 
-                /* Enable individual receive */
-		*R_NETWORK_REC_CONFIG =
-		  IO_STATE(R_NETWORK_REC_CONFIG, broadcast,  receive) |
-		  IO_STATE(R_NETWORK_REC_CONFIG, ma0,        enable) |
-		  IO_STATE(R_NETWORK_REC_CONFIG, individual, receive);
+		/* Enable individual receive */
+		SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, receive);
+		*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+	} else if (dev->flags & IFF_ALLMULTI) {
+		/* enable all multicasts */
+		lo_bits = 0xfffffffful;
+		hi_bits = 0xfffffffful;
+
+		/* Disable individual receive */
+		SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
+		*R_NETWORK_REC_CONFIG =  network_rec_config_shadow;
 	} else if (num_addr == 0) {
 		/* Normal, clear the mc list */
 		lo_bits = 0x00000000ul;
 		hi_bits = 0x00000000ul;
 
-                /* Disable individual receive */
-		*R_NETWORK_REC_CONFIG =
-		  IO_STATE(R_NETWORK_REC_CONFIG, broadcast,  receive) |
-		  IO_STATE(R_NETWORK_REC_CONFIG, ma0,        enable);
+		/* Disable individual receive */
+		SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
+		*R_NETWORK_REC_CONFIG =  network_rec_config_shadow;
 	} else {
 		/* MC mode, receive normal and MC packets */
 		char hash_ix;
@@ -1057,10 +1275,9 @@
 			}
 			dmi = dmi->next;
 		}
-                /* Disable individual receive */
-		*R_NETWORK_REC_CONFIG =
-		  IO_STATE(R_NETWORK_REC_CONFIG, broadcast,  receive) |
-		  IO_STATE(R_NETWORK_REC_CONFIG, ma0,        enable);
+		/* Disable individual receive */
+		SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
+		*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
 	}
 	*R_NETWORK_GA_0 = lo_bits;
 	*R_NETWORK_GA_1 = hi_bits;
@@ -1078,6 +1295,7 @@
 		/* Set the earliest time we may clear the LED */
 		led_next_time = jiffies + NET_FLASH_TIME;
 		led_active = 1;
+		mod_timer(&clear_led_timer, jiffies + HZ/10);
 	}
 
 	/* configure the tx dma descriptor */
@@ -1095,16 +1313,13 @@
 static void
 e100_clear_network_leds(unsigned long dummy)
 {
-        if (led_active && jiffies > led_next_time) {
+	if (led_active && jiffies > led_next_time) {
 		e100_set_network_leds(NO_NETWORK_ACTIVITY);
 
 		/* Set the earliest time we may set the LED */
 		led_next_time = jiffies + NET_FLASH_PAUSE;
 		led_active = 0;
 	}
-
-        clear_led_timer.expires = jiffies + HZ/10;
-	add_timer(&clear_led_timer);
 }
 
 static void
@@ -1143,7 +1358,7 @@
 
 	d->init = etrax_ethernet_init;
 
-	if(register_netdev(d) == 0)
+	if (register_netdev(d) == 0)
 		return 0;
 	else
 		return -ENODEV;
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/examples/kiobuftest.c linux/arch/cris/drivers/examples/kiobuftest.c
--- v2.5.2/linux/arch/cris/drivers/examples/kiobuftest.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/examples/kiobuftest.c	Mon Jan 21 16:00:39 2002
@@ -10,6 +10,9 @@
  * Author:  Bjorn Wesen
  *
  * $Log: kiobuftest.c,v $
+ * Revision 1.1.1.1  2001/12/17 13:59:27  bjornw
+ * Import of Linux 2.5.1
+ *
  * Revision 1.2  2001/02/27 13:52:50  bjornw
  * malloc.h -> slab.h
  *
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/gpio.c linux/arch/cris/drivers/gpio.c
--- v2.5.2/linux/arch/cris/drivers/gpio.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/drivers/gpio.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: gpio.c,v 1.11 2001/10/30 14:39:12 johana Exp $
+/* $Id: gpio.c,v 1.2 2001/12/18 13:35:15 bjornw Exp $
  *
  * Etrax general port I/O device
  *
@@ -9,6 +9,13 @@
  *             Johan Adolfsson  (read/set directions, write)
  *
  * $Log: gpio.c,v $
+ * Revision 1.2  2001/12/18 13:35:15  bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.12  2001/11/12 19:42:15  pkj
+ * * Corrected return values from gpio_leds_ioctl().
+ * * Fixed compiler warnings.
+ *
  * Revision 1.11  2001/10/30 14:39:12  johana
  * Added D() around gpio_write printk.
  *
@@ -74,7 +81,9 @@
 
 static char gpio_name[] = "etrax gpio";
 
+#if 0
 static wait_queue_head_t *gpio_wq;
+#endif
 
 static int gpio_ioctl(struct inode *inode, struct file *file,
 		      unsigned int cmd, unsigned long arg);
@@ -143,7 +152,7 @@
 {
 	/* TODO poll on alarms! */
 #if 0
-        if(!ANYTHING_WANTED) {
+        if (!ANYTHING_WANTED) {
 		D(printk("gpio_select sleeping task\n"));
 	        select_wait(&gpio_wq, table);
 	        return 0;
@@ -160,16 +169,14 @@
 	unsigned char data, clk_mask, data_mask, write_msb;
 	unsigned long flags;
 	ssize_t retval = count;
-	if (verify_area(VERIFY_READ, buf, count))
-	{
+	if (verify_area(VERIFY_READ, buf, count)) {
 		return -EFAULT;
 	}
 	clk_mask = priv->clk_mask;
 	data_mask = priv->data_mask;
 	/* It must have been configured using the IO_CFG_WRITE_MODE */
 	/* Perhaps a better error code? */
-	if (clk_mask == 0 || data_mask == 0) 
-	{
+	if (clk_mask == 0 || data_mask == 0) {
 		return -EPERM;
 	}
 	write_msb = priv->write_msb;
@@ -178,7 +185,7 @@
 		int i;
 		data = *buf++;
 		if (priv->write_msb) {
-			for (i = 7; i>=0;i--) {
+			for (i = 7; i >= 0;i--) {
 				save_flags(flags); cli();
 				*priv->port = *priv->shadow &= ~clk_mask;
 				if (data & 1<<i)
@@ -190,7 +197,7 @@
 				restore_flags(flags);
 			}
 		} else {
-			for (i = 0; i<=7;i++) {
+			for (i = 0; i <= 7;i++) {
 				save_flags(flags); cli();
 				*priv->port = *priv->shadow &= ~clk_mask;
 				if (data & 1<<i)
@@ -212,13 +219,13 @@
 	struct gpio_private *priv;
 	int p = MINOR(inode->i_rdev);
 
-	if(p >= NUM_PORTS && p != LEDS)
+	if (p >= NUM_PORTS && p != LEDS)
 		return -EINVAL;
 
 	priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private), 
 					      GFP_KERNEL);
 
-	if(!priv)
+	if (!priv)
 		return -ENOMEM;
 
 	priv->minor = p;
@@ -254,10 +261,10 @@
 
 	/* unlink from alarmlist and free the private structure */
 
-	if(p == todel) {
+	if (p == todel) {
 		alarmlist = todel->next;
 	} else {
-		while(p->next != todel)
+		while (p->next != todel)
 			p = p->next;
 		p->next = todel->next;
 	}
@@ -280,7 +287,7 @@
 {
 	unsigned long flags;
 	struct gpio_private *priv = (struct gpio_private *)file->private_data;
-	if(_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
+	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
 		return -EINVAL;
 	}
 
@@ -353,7 +360,7 @@
 			if (!((priv->clk_mask & priv->changeable_bits) &&
 			      (priv->data_mask & priv->changeable_bits) &&
 			      (priv->clk_mask & *priv->dir_shadow) &&
-			      (priv->data_mask & *priv->dir_shadow)) )
+			      (priv->data_mask & *priv->dir_shadow)))
 			{
 				priv->clk_mask = 0;
 				priv->data_mask = 0;
@@ -361,7 +368,7 @@
 			}
 			break;
 		default:
-			if(priv->minor == LEDS)
+			if (priv->minor == LEDS)
 				return gpio_leds_ioctl(cmd, arg);
                         else
 				return -EINVAL;
@@ -375,6 +382,7 @@
 {
 	unsigned char green;
 	unsigned char red;
+
 	switch (_IOC_NR(cmd)) {
 		case IO_LEDACTIVE_SET:
 			green = ((unsigned char) arg) & 1;
@@ -382,14 +390,20 @@
 			LED_ACTIVE_SET_G(green);
 			LED_ACTIVE_SET_R(red);
 			break;
-                case IO_LED_SETBIT:                 
-                        LED_BIT_SET(arg);
-                       break;
-                case IO_LED_CLRBIT:
-                        LED_BIT_CLR(arg);
+
+		case IO_LED_SETBIT:                 
+			LED_BIT_SET(arg);
+			break;
+
+		case IO_LED_CLRBIT:
+			LED_BIT_CLR(arg);
+			break;
+
 		default:
 			return -EINVAL;
 	}
+
+	return 0;
 }
 
 struct file_operations gpio_fops = {
@@ -406,30 +420,32 @@
 static __init int
 gpio_init(void)
 {
-	int res,i;
+	extern void init_ioremap(void);
+	int res;
+#if defined (CONFIG_ETRAX_CSP0_LEDS)
+	int i;
+#endif
 
 	/* do the formalities */
 
 	res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
-	if(res < 0) {
+	if (res < 0) {
 		printk(KERN_ERR "gpio: couldn't get a major number.\n");
 		return res;
 	}
 
         /* Clear all leds */
-#if defined (CONFIG_ETRAX_CSP0_LEDS) ||  defined (CONFIG_ETRAX_PA_LEDS)         || defined (CONFIG_ETRAX_PB_LEDS) 
-
-        init_ioremap();
-        LED_NETWORK_SET(0);
-        LED_ACTIVE_SET(0);
-        LED_DISK_READ(0);
-        LED_DISK_WRITE(0);        
+#if defined (CONFIG_ETRAX_CSP0_LEDS) ||  defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS) 
+	init_ioremap();
+	LED_NETWORK_SET(0);
+	LED_ACTIVE_SET(0);
+	LED_DISK_READ(0);
+	LED_DISK_WRITE(0);        
 
 #if defined (CONFIG_ETRAX_CSP0_LEDS)
-        for( i = 0; i < 32; i ++)
-        {
-            LED_BIT_SET(i);
-        }
+	for (i = 0; i < 32; i++) {
+		LED_BIT_SET(i);
+	}
 #endif
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/i2c.c linux/arch/cris/drivers/i2c.c
--- v2.5.2/linux/arch/cris/drivers/i2c.c	Sat May 19 17:43:05 2001
+++ linux/arch/cris/drivers/i2c.c	Mon Jan 21 16:00:39 2002
@@ -12,6 +12,9 @@
 *!                                 don't use PB_I2C if DS1302 uses same bits,
 *!                                 use PB.
 *! $Log: i2c.c,v $
+*! Revision 1.1.1.1  2001/12/17 13:59:27  bjornw
+*! Import of Linux 2.5.1
+*!
 *! Revision 1.7  2001/04/04 13:11:36  markusl
 *! Updated according to review remarks
 *!
@@ -43,7 +46,7 @@
 *! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
-/* $Id: i2c.c,v 1.7 2001/04/04 13:11:36 markusl Exp $ */
+/* $Id: i2c.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ */
 /****************** INCLUDE FILES SECTION ***********************************/
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/i2c.h linux/arch/cris/drivers/i2c.h
--- v2.5.2/linux/arch/cris/drivers/i2c.h	Sat May 19 17:43:05 2001
+++ linux/arch/cris/drivers/i2c.h	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: i2c.h,v 1.3 2001/03/19 12:43:01 markusl Exp $ */
+/* $Id: i2c.h,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ */
 
 /* High level I2C actions */
 int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue);
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/ide.c linux/arch/cris/drivers/ide.c
--- v2.5.2/linux/arch/cris/drivers/ide.c	Wed Jul  4 11:50:38 2001
+++ linux/arch/cris/drivers/ide.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: ide.c,v 1.19 2001/05/09 12:53:16 johana Exp $
+/* $Id: ide.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  *
  * Etrax specific IDE functions, like init and PIO-mode setting etc.
  * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
@@ -8,6 +8,9 @@
  *             Mikael Starvik     (pio setup stuff)
  *
  * $Log: ide.c,v $
+ * Revision 1.1.1.1  2001/12/17 13:59:27  bjornw
+ * Import of Linux 2.5.1
+ *
  * Revision 1.19  2001/05/09 12:53:16  johana
  * Added #include <asm/dma.h>
  *
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/lpslave/bintocarr.pl linux/arch/cris/drivers/lpslave/bintocarr.pl
--- v2.5.2/linux/arch/cris/drivers/lpslave/bintocarr.pl	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/drivers/lpslave/bintocarr.pl	Mon Jan 21 16:00:39 2002
@@ -1,5 +1,5 @@
 #!/usr/bin/perl -w
-# $Id: bintocarr.pl,v 1.4 2001/08/08 08:18:13 bjarne Exp $
+# $Id: bintocarr.pl,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
 # Copy of mkjulbin.pl made by Olof
 # convert a binary stdin to a C-file containing a char array of the input
 # first argument is the symbol name
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/lpslave/e100lpslave.S linux/arch/cris/drivers/lpslave/e100lpslave.S
--- v2.5.2/linux/arch/cris/drivers/lpslave/e100lpslave.S	Thu Jul 26 15:10:06 2001
+++ linux/arch/cris/drivers/lpslave/e100lpslave.S	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-	;; $Id: e100lpslave.S,v 1.3 2001/06/21 16:55:26 olof Exp $
+	;; $Id: e100lpslave.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
 	;;
 	;; Etrax100 slave network<->parport forwarder
 	;;
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/lpslave/e100lpslavenet.c linux/arch/cris/drivers/lpslave/e100lpslavenet.c
--- v2.5.2/linux/arch/cris/drivers/lpslave/e100lpslavenet.c	Thu Jul 26 15:10:06 2001
+++ linux/arch/cris/drivers/lpslave/e100lpslavenet.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: e100lpslavenet.c,v 1.4 2001/06/21 16:55:26 olof Exp $
+/* $Id: e100lpslavenet.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  *
  * e100lpslavenet.c: A network driver for the ETRAX 100LX slave controller.
  *
@@ -7,6 +7,9 @@
  * The outline of this driver comes from skeleton.c.
  *
  * $Log: e100lpslavenet.c,v $
+ * Revision 1.1.1.1  2001/12/17 13:59:27  bjornw
+ * Import of Linux 2.5.1
+ *
  * Revision 1.4  2001/06/21 16:55:26  olof
  * Minimized par port setup time to gain bandwidth
  *
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/parport.c linux/arch/cris/drivers/parport.c
--- v2.5.2/linux/arch/cris/drivers/parport.c	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/drivers/parport.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: parport.c,v 1.8 2001/09/26 11:51:52 bjornw Exp $
+/* $Id: parport.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  * 
  * Elinux parallel port driver
  * NOTE!
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c
--- v2.5.2/linux/arch/cris/drivers/serial.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/drivers/serial.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: serial.c,v 1.23 2001/10/30 17:53:26 pkj Exp $
+/* $Id: serial.c,v 1.3 2001/12/19 10:32:35 johana Exp $
  *
  * Serial port driver for the ETRAX 100LX chip
  *
@@ -7,6 +7,34 @@
  *      Many, many authors. Based once upon a time on serial.c for 16x50.
  *
  * $Log: serial.c,v $
+ * Revision 1.3  2001/12/19 10:32:35  johana
+ * Cleaned up write_rs485() - now it works correctly without padding extra
+ * char.
+ * Added sane default initialisation of rs485.
+ * Added #ifdef around dummy variables.
+ *
+ * Revision 1.27  2001/11/29 17:00:41  pkj
+ * 2kB seems to be too small a buffer when using 921600 bps,
+ * so increase it to 4kB (this was already done for the elinux
+ * version of the serial driver).
+ *
+ * Revision 1.26  2001/11/19 14:20:41  pkj
+ * Minor changes to comments and unused code.
+ *
+ * Revision 1.25  2001/11/12 20:03:43  pkj
+ * Fixed compiler warnings.
+ *
+ * Revision 1.24  2001/11/12 15:10:05  pkj
+ * Total redesign of the receiving part of the serial driver.
+ * Uses eight chained descriptors to write to a 4kB buffer.
+ * This data is then serialised into a 2kB buffer. From there it
+ * is copied into the TTY's flip buffers when they become available.
+ * A lot of copying, and the sizes of the buffers might need to be
+ * tweaked, but all in all it should work better than the previous
+ * version, without the need to modify the TTY code in any way.
+ * Also note that erroneous bytes are now correctly marked in the
+ * flag buffers (instead of always marking the first byte).
+ *
  * Revision 1.23  2001/10/30 17:53:26  pkj
  * * Set info->uses_dma to 0 when a port is closed.
  * * Mark the timer1 interrupt as a fast one (SA_INTERRUPT).
@@ -123,12 +151,12 @@
  * Changed %ul to %lu in printf's
  *
  * Revision 1.47  2000/10/18 15:06:53  pkj
- * Compile correctly with CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST and
- * CONFIG_SERIAL_PROC_ENTRY together.
+ * Compile correctly with CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST and
+ * CONFIG_ETRAX_SERIAL_PROC_ENTRY together.
  * Some clean-up of the /proc/serial file.
  *
  * Revision 1.46  2000/10/16 12:59:40  johana
- * Added CONFIG_SERIAL_PROC_ENTRY for statistics and debug info.
+ * Added CONFIG_ETRAX_SERIAL_PROC_ENTRY for statistics and debug info.
  *
  * Revision 1.45  2000/10/13 17:10:59  pkj
  * Do not flush DMAs while flipping TTY buffers.
@@ -171,7 +199,7 @@
  * Uncomment definition of SERIAL_HANDLE_EARLY_ERRORS.
  *
  * Revision 1.36  2000/09/20 13:12:52  johana
- * Support for CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS:
+ * Support for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS:
  *   Number of timer ticks between flush of receive fifo (1 tick = 10ms).
  *   Try 0-3 for low latency applications. Approx 5 for high load
  *   applications (e.g. PPP). Maybe this should be more adaptive some day...
@@ -255,7 +283,7 @@
  *
  */
 
-static char *serial_version = "$Revision: 1.23 $";
+static char *serial_version = "$Revision: 1.3 $";
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -272,6 +300,7 @@
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #if (LINUX_VERSION_CODE >= 131343)
 #include <linux/init.h>
 #endif
@@ -302,6 +331,8 @@
 #include "serial_compat.h"
 #endif
 
+#define _INLINE_ inline
+
 static DECLARE_TASK_QUEUE(tq_serial);
 
 struct tty_driver serial_driver, callout_driver;
@@ -313,11 +344,6 @@
 #define SERIAL_TYPE_CALLOUT	2
 #endif
 
-#define DEBUG_LOG(line, string, value)
-
-/* Add an x here to log a lot of timer stuff */
-#define TIMERD(x)
-
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
@@ -337,6 +363,14 @@
 
 #define TTY_THROTTLE_LIMIT (TTY_FLIPBUF_SIZE/10)
 
+#define SERIAL_RECV_SIZE      4096
+#define SERIAL_DESCR_BUF_SIZE 512
+
+/* Add an x here to log a lot of timer stuff */
+#define TIMERD(x)
+
+#define DEBUG_LOG(line, string, value)
+
 #ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
 /* Default number of timer ticks before flushing rx fifo 
  * When using "little data, low latency applications: use 0
@@ -345,8 +379,6 @@
 #define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 
 #endif
 
-#define _INLINE_ inline
-
 static void change_speed(struct e100_serial *info);
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 static int rs_write(struct tty_struct * tty, int from_user,
@@ -403,9 +435,9 @@
 static struct e100_serial rs_table[] = {
 	{ DEF_BAUD, (unsigned char *)R_SERIAL0_CTRL, 1U << 12, /* uses DMA 6 and 7 */
 	  R_DMA_CH6_CLR_INTR, R_DMA_CH6_FIRST, R_DMA_CH6_CMD,
-	  R_DMA_CH6_STATUS, R_DMA_CH6_HWSW,
+	  R_DMA_CH6_STATUS, R_DMA_CH6_HWSW, R_DMA_CH6_DESCR,
 	  R_DMA_CH7_CLR_INTR, R_DMA_CH7_FIRST, R_DMA_CH7_CMD,
-	  R_DMA_CH7_STATUS, R_DMA_CH7_HWSW,
+	  R_DMA_CH7_STATUS, R_DMA_CH7_HWSW, R_DMA_CH7_DESCR,
 	  STD_FLAGS, DEF_RX, DEF_TX, 2,
 #ifdef CONFIG_ETRAX_SERIAL_PORT0
           1
@@ -416,9 +448,9 @@
 #ifndef CONFIG_SVINTO_SIM
 	{ DEF_BAUD, (unsigned char *)R_SERIAL1_CTRL, 1U << 16, /* uses DMA 8 and 9 */
 	  R_DMA_CH8_CLR_INTR, R_DMA_CH8_FIRST, R_DMA_CH8_CMD,
-	  R_DMA_CH8_STATUS, R_DMA_CH8_HWSW,
+	  R_DMA_CH8_STATUS, R_DMA_CH8_HWSW, R_DMA_CH8_DESCR,
 	  R_DMA_CH9_CLR_INTR, R_DMA_CH9_FIRST, R_DMA_CH9_CMD,
-	  R_DMA_CH9_STATUS, R_DMA_CH9_HWSW,
+	  R_DMA_CH9_STATUS, R_DMA_CH9_HWSW, R_DMA_CH9_DESCR,
 	  STD_FLAGS, DEF_RX, DEF_TX, 3 ,
 #ifdef CONFIG_ETRAX_SERIAL_PORT1
           1
@@ -429,9 +461,9 @@
 
 	{ DEF_BAUD, (unsigned char *)R_SERIAL2_CTRL, 1U << 4,  /* uses DMA 2 and 3 */
 	  R_DMA_CH2_CLR_INTR, R_DMA_CH2_FIRST, R_DMA_CH2_CMD,
-	  R_DMA_CH2_STATUS, R_DMA_CH2_HWSW,
+	  R_DMA_CH2_STATUS, R_DMA_CH2_HWSW, R_DMA_CH2_DESCR,
 	  R_DMA_CH3_CLR_INTR, R_DMA_CH3_FIRST, R_DMA_CH3_CMD,
-	  R_DMA_CH3_STATUS, R_DMA_CH3_HWSW,
+	  R_DMA_CH3_STATUS, R_DMA_CH3_HWSW, R_DMA_CH3_DESCR,
 	  STD_FLAGS, DEF_RX, DEF_TX, 0,
 #ifdef CONFIG_ETRAX_SERIAL_PORT2
           1
@@ -442,9 +474,9 @@
 
 	{ DEF_BAUD, (unsigned char *)R_SERIAL3_CTRL, 1U << 8,  /* uses DMA 4 and 5 */
 	  R_DMA_CH4_CLR_INTR, R_DMA_CH4_FIRST, R_DMA_CH4_CMD,
-	  R_DMA_CH4_STATUS, R_DMA_CH4_HWSW,
+	  R_DMA_CH4_STATUS, R_DMA_CH4_HWSW, R_DMA_CH4_DESCR,
 	  R_DMA_CH5_CLR_INTR, R_DMA_CH5_FIRST, R_DMA_CH5_CMD,
-	  R_DMA_CH5_STATUS, R_DMA_CH5_HWSW,
+	  R_DMA_CH5_STATUS, R_DMA_CH5_HWSW, R_DMA_CH5_DESCR,
 	  STD_FLAGS, DEF_RX, DEF_TX, 1,
 #ifdef CONFIG_ETRAX_SERIAL_PORT3
           1
@@ -462,9 +494,9 @@
 static struct termios *serial_termios[NR_PORTS];
 static struct termios *serial_termios_locked[NR_PORTS];
 
-#ifdef CONFIG_SERIAL_PROC_ENTRY
+#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
 #define PROCSTAT(x) x
-struct ser_statistics_type{
+struct ser_statistics_type {
 	int overrun_cnt;
 	int early_errors_cnt;
 	int ser_ints_ok_cnt;
@@ -484,7 +516,7 @@
 
 #define PROCSTAT(x)
 
-#endif /* CONFIG_SERIAL_PROC_ENTRY */
+#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
 
 /* RS-485 */
 #if defined(CONFIG_ETRAX_RS485)
@@ -497,14 +529,20 @@
 /* For now we assume that all bits are on the same port for each serial port */
 
 /* Dummy shadow variables */
+#if !defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
 static unsigned char dummy_ser0 = 0x00;
-static unsigned char dummy_ser1 = 0x00;
-static unsigned char dummy_ser2 = 0x00;
-static unsigned char dummy_ser3 = 0x00;
-
 static unsigned char dummy_dir_ser0 = 0x00;
+#endif
+#if !defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
+static unsigned char dummy_ser1 = 0x00;
 static unsigned char dummy_dir_ser1 = 0x00;
+#endif
+#if !defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
+static unsigned char dummy_ser2 = 0x00;
 static unsigned char dummy_dir_ser2 = 0x00;
+#endif
+
+static unsigned char dummy_ser3 = 0x00;
 static unsigned char dummy_dir_ser3 = 0x00;
 
 /* Info needed for each ports extra control/status signals.
@@ -523,52 +561,56 @@
 
 static const struct control_pins e100_modem_pins[NR_PORTS] = 
 {
-/* Ser 0 */
-  {
+	/* Ser 0 */
+	{
 #if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
-    R_PORT_PB_DATA,  &port_pb_data_shadow,  &port_pb_dir_shadow,
-    CONFIG_ETRAX_SER0_DTR_ON_PB_BIT,
-    CONFIG_ETRAX_SER0_RI_ON_PB_BIT, 
-    CONFIG_ETRAX_SER0_DSR_ON_PB_BIT, 
-    CONFIG_ETRAX_SER0_CD_ON_PB_BIT
+		R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
+		CONFIG_ETRAX_SER0_DTR_ON_PB_BIT,
+		CONFIG_ETRAX_SER0_RI_ON_PB_BIT,
+		CONFIG_ETRAX_SER0_DSR_ON_PB_BIT,
+		CONFIG_ETRAX_SER0_CD_ON_PB_BIT
 #else
-    &dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3
-#endif   
-  },
-/* Ser 1 */
-  {
+		&dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3
+#endif
+	},
+
+	/* Ser 1 */
+	{
 #if defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
-    R_PORT_PB_DATA,  &port_pb_data_shadow,  &port_pb_dir_shadow,
-    CONFIG_ETRAX_SER1_DTR_ON_PB_BIT,
-    CONFIG_ETRAX_SER1_RI_ON_PB_BIT, 
-    CONFIG_ETRAX_SER1_DSR_ON_PB_BIT, 
-    CONFIG_ETRAX_SER1_CD_ON_PB_BIT
+		R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
+		CONFIG_ETRAX_SER1_DTR_ON_PB_BIT,
+		CONFIG_ETRAX_SER1_RI_ON_PB_BIT,
+		CONFIG_ETRAX_SER1_DSR_ON_PB_BIT,
+		CONFIG_ETRAX_SER1_CD_ON_PB_BIT
 #else
-    &dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3
-#endif   
-  },  
-/* Ser 2 */
-  {
+		&dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3
+#endif
+	},
+
+	/* Ser 2 */
+	{
 #if defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
-    R_PORT_PA_DATA,  &port_pa_data_shadow,  &port_pa_dir_shadow,
-    CONFIG_ETRAX_SER2_DTR_ON_PA_BIT,
-    CONFIG_ETRAX_SER2_RI_ON_PA_BIT, 
-    CONFIG_ETRAX_SER2_DSR_ON_PA_BIT, 
-    CONFIG_ETRAX_SER2_CD_ON_PA_BIT
+		R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow,
+		CONFIG_ETRAX_SER2_DTR_ON_PA_BIT,
+		CONFIG_ETRAX_SER2_RI_ON_PA_BIT,
+		CONFIG_ETRAX_SER2_DSR_ON_PA_BIT,
+		CONFIG_ETRAX_SER2_CD_ON_PA_BIT
 #else
-    &dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3
-#endif   
-  },
-/* Ser 3 */
-  {
-    &dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3
-  }
+		&dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3
+#endif
+	},
+
+	/* Ser 3 */
+	{
+		&dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3
+	}
 };
 
 #if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA)
 unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT;
 #endif
 
+
 #define E100_RTS_MASK 0x20
 #define E100_CTS_MASK 0x40
 
@@ -840,8 +882,8 @@
 {
 #ifndef CONFIG_SVINTO_SIM
 	/* disable the receiver */
-	info->port[REG_REC_CTRL] = info->rx_ctrl &=
-		~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable);
+	info->port[REG_REC_CTRL] =
+		(info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
 #endif
 }
 
@@ -850,8 +892,8 @@
 {
 #ifndef CONFIG_SVINTO_SIM
 	/* enable the receiver */
-	info->port[REG_REC_CTRL] = info->rx_ctrl |=
-		IO_MASK(R_SERIAL0_REC_CTRL, rec_enable);
+	info->port[REG_REC_CTRL] =
+		(info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
 #endif
 }
 
@@ -943,13 +985,8 @@
 static int
 e100_write_rs485(struct tty_struct *tty,struct rs485_write *r)
 {
-	int stop_delay;
-	int total, i;
-	int max_j, delay_ms, bits;
-	tcflag_t cflags;
-	int size = (*r).outc_size;
+	int total;
 	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-	struct wait_queue wait = { current, NULL };
 
 	/* If we are in RS-485 mode, we need to toggle RTS and disable
 	 * the receiver before initiating a DMA transfer
@@ -975,44 +1012,20 @@
 	 * enable the receiver
 	 */	
 
-	/* wait on transmit shift register */
-	/* All is sent, check if we should wait more before toggling rts */
-	
-	/* calc. number of bits / data byte */
-	cflags = info->tty->termios->c_cflag;
-
-	/* databits + startbit and 1 stopbit */
-	if ((cflags & CSIZE) == CS7)
-		bits = 9;
-	else
-		bits = 10;  
-
-	if (cflags & CSTOPB)     /* 2 stopbits ? */
-		bits++;
-
-	if (cflags & PARENB)     /* parity bit ? */
-		bits++;
-	
-	/* calc timeout */
-	delay_ms = ((bits * size * 1000) / info->baud) + 1;
-	max_j = jiffies + (delay_ms * HZ)/1000 + 10;
-
-	while (jiffies < max_j) {
-		if (info->port[REG_STATUS] &
-		    IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) {
-			for (i = 0; i < 100; i++)
-				;
-			if (info->port[REG_STATUS] &
-			    IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) {
-				/* ~25 for loops per usec */
-				stop_delay = 1000000 / info->baud;
-				if (cflags & CSTOPB) 
-					stop_delay *= 2;
-				udelay(stop_delay);
-				break;
-			}
-		}
+	/* Sleep until all sent */
+	tty_wait_until_sent(tty, 0);
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+	/* Now sleep a little more so that shift register is empty */
+	schedule_usleep(info->char_time_usec * 2);
+#else
+	{
+		unsigned int val;
+		/* wait on transmit shift register */
+		do{
+			get_lsr_info(info, &val);
+		}while (!(val & TIOCSER_TEMT));
 	}
+#endif
 
 	e100_rts(info, info->rs485.rts_after_sent);
 	
@@ -1118,7 +1131,7 @@
 	}
 	return;
 #endif
-	/* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */
+	/* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
 	*info->oclrintradr =
 		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
 		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
@@ -1168,14 +1181,14 @@
 
 #if defined(CONFIG_ETRAX_RS485)
 		/* Check if we should toggle RTS now */
-		if (info->rs485.enabled)
-		{
+		if (info->rs485.enabled) {
 			/* Make sure fifo is empty */
-			int in_fifo = 0 ;
-			do{
+			int in_fifo = 0;
+
+			do {
 				in_fifo = IO_EXTRACT(R_DMA_CH6_STATUS, avail,
-						    *info->ostatusadr);
-			}  while (in_fifo > 0) ;
+						     *info->ostatusadr);
+			}  while (in_fifo > 0);
 			/* Any way to really check transmitter empty? (TEMT) */
 			/* Control RTS to set to RX mode */
 			e100_rts(info, info->rs485.rts_after_sent); 
@@ -1201,7 +1214,6 @@
 	*info->ocmdadr = 1;       /* dma command start -> R_DMAx_CMD */
 	
 	/* DMA is now running (hopefully) */
-
 }
 
 static void 
@@ -1220,13 +1232,122 @@
 	transmit_chars(info);
 }
 
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static int serial_fast_timer_started = 0;
+static int serial_fast_timer_expired = 0;
+static void flush_timeout_function(unsigned long data);
+#define START_FLUSH_FAST_TIMER(info, string) {\
+  unsigned long timer_flags; \
+  save_flags(timer_flags); \
+  cli(); \
+  if (fast_timers[info->line].function == NULL) { \
+    serial_fast_timer_started++; \
+    TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
+    TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \
+    start_one_shot_timer(&fast_timers[info->line], \
+                         flush_timeout_function, \
+                         (unsigned long)info, \
+                         info->char_time_usec*4, \
+                         string); \
+  } \
+  else { \
+    TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \
+  } \
+  restore_flags(timer_flags); \
+}
+
+#else
+#define START_FLUSH_FAST_TIMER(info, string)
+#endif
+
+static int
+add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag)
+{
+	if (!CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE))
+		return 0;
+
+	info->recv.buf[info->recv.head] = data;
+	info->flag_buf[info->recv.head] = flag;
+	info->recv.head = (info->recv.head + 1) & (SERIAL_RECV_SIZE - 1);
+
+	info->icount.rx++;
+
+	return 1;
+}
+
+static _INLINE_ unsigned int
+copy_descr_data(struct e100_serial *info, unsigned int recvl, unsigned char *buf)
+{
+	unsigned int count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE);
+	unsigned int length = 0;
+
+	 while (length < recvl && count) {
+		if (length + count > recvl)
+			count = recvl - length;
+
+		memcpy(info->recv.buf + info->recv.head, buf + length, count);
+		memset(info->flag_buf + info->recv.head, '\0', count);
+		info->recv.head = (info->recv.head + count) & (SERIAL_RECV_SIZE - 1);
+		length += count;
+
+		count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE);
+	}
+
+	if (length != recvl) { 
+		printk(__FUNCTION__ ": Buffer overflow! %d byte(s) did not fit.\n", recvl - length);
+		PROCSTAT(ser_stat[info->line].overrun_cnt += recvl - length);
+	}
+
+	return length;
+}
+
+static _INLINE_ unsigned int
+copy_all_descr_data(struct e100_serial *info)
+{
+	struct etrax_dma_descr *descr;
+	unsigned int recvl;
+	unsigned int ret = 0;
+
+	while (1)
+	{
+		descr = &info->rec_descr[info->cur_rec_descr];
+
+		if (descr == phys_to_virt(*info->idescradr))
+			break;
+
+		if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS)
+			info->cur_rec_descr = 0;
+	
+		/* find out how many bytes were read */
+
+		/* if the eop bit was not set, all data has been received */
+		if (!(descr->status & d_eop)) {
+			recvl = descr->sw_len;
+		} else {
+			/* otherwise we find the amount of data received here */
+			recvl = descr->hw_len;
+		}
+
+		/* Reset the status information */
+		descr->status = 0;
+
+		DEBUG_LOG(info->line, "recvl %lu\n", recvl);
+
+		/* update stats */
+		info->icount.rx += recvl;
+
+		ret += copy_descr_data(info, recvl, phys_to_virt(descr->buf));
+	}
+
+	return ret;
+}
+
 static _INLINE_ void 
 receive_chars(struct e100_serial *info)
 {
 	struct tty_struct *tty;
 	unsigned char rstat;
-	unsigned int recvl;
-	struct etrax_dma_descr *descr;
+	unsigned int old_head;
 
 #ifdef CONFIG_SVINTO_SIM
 	/* No receive in the simulator.  Will probably be when the rest of
@@ -1235,168 +1356,96 @@
 	return;
 #endif
 
-	tty = info->tty;
-
-	/* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */
-
-	// ?
+	/* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
 	*info->iclrintradr =
 		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
 		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
 
-	if (!tty) /* something wrong... */
+	tty = info->tty;
+	if (!tty) /* Something wrong... */
 		return;
 
-	descr = &info->rec_descr;
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+	e100_enable_serial_data_irq(info);
+#endif	
 
-	/* find out how many bytes were read */
+	if (info->errorcode == ERRCODE_INSERT_BREAK)
+		add_char_and_flag(info, '\0', TTY_BREAK);
 
-	/* if the eop bit was not set, all data has been received */
-	if (!(descr->status & d_eop)) {
-		recvl = descr->sw_len;
-	} else {
-		/* otherwise we find the amount of data received here */
-		recvl = descr->hw_len;
-	}
+	old_head = info->recv.head;
+	
+	if (copy_all_descr_data(info) && info->errorcode == ERRCODE_SET_BREAK)
+		info->flag_buf[old_head] = TTY_BREAK;
 
-	/* read the status register so we can detect errors,
-	 * but we can't really do anything about those errors
-	 * anyway, since we have the DMA in "force eop at error" mode
-	 * the fault characters are not in the buffer anyway.
-	 */
+	info->errorcode = 0;
 
+	/* Read the status register to detect errors */
 	rstat = info->port[REG_STATUS];
 
-	if ((rstat & SER_ERROR_MASK) != 0) {
-		unsigned char data;
-		/* if we got an error, we must reset it by reading the
+	if (rstat & SER_ERROR_MASK) {
+		/* If we got an error, we must reset it by reading the
 		 * data_in field
 		 */
-		data = info->port[REG_DATA];
+		unsigned char data = info->port[REG_DATA];
+
 		PROCSTAT(ser_stat[info->line].errors_cnt++);
-		DEBUG_LOG(info->line, " #dERR: s d 0x%04X\n",
+		DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",
 			  ((rstat & SER_ERROR_MASK) << 8) | data);
-		/* Only handle the saved error code, that indicates that we got
-		 * the last character of a break that looks like it's ok, but
-		 * is not
-		 */
 
-		if (info->errorcode == 0) {
-			*tty->flip.flag_buf_ptr = TTY_NORMAL;
-		} else {
-			unsigned char data;
-			data = info->port[REG_DATA];
-			if (info->errorcode & ERRCODE_INSERT) {
-				unsigned char *currbuf;
-				/* Get the current buffer */
-				if (tty->flip.buf_num) {
-					currbuf = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
-				} else {
-					currbuf = tty->flip.char_buf;
-				}
-				/* We should insert a character in the buffer! */
-				if (recvl == 0) {
-					recvl = 1;
-					DEBUG_LOG(info->line, "insert to %lu\n", recvl);
-				} else {
-					/* Move stuff around.. */
-					DEBUG_LOG(info->line, "#insert to %lu!\n", recvl);
-					if (recvl < TTY_FLIPBUF_SIZE) {
-						int i;
-						/* Move the data 1 step right */
-						i = recvl;
-						while (i) {
-							currbuf[i] = currbuf[i-1];
-							i--;
-						}
-						recvl++;
-					} else {
-						/* We can't move it all! Skip break! */
-						/* TODO: Handle full buffer? */
-						DEBUG_LOG(info->line, "#BRK skipped! %lu!\n", recvl);
-						info->errorcode = 0;
-					}
-				}
-			}
-	    
-			PROCSTAT(ser_stat[info->line].errors_cnt++);
-			DEBUG_LOG(info->line, " #bERR: s d 0x%04X\n",
-				  ((rstat & SER_ERROR_MASK) << 8) | data);
-			*tty->flip.flag_buf_ptr = (info->errorcode & 0xFF);
-			info->errorcode = 0;
-#if 0
-			printk("SERERR: 0x%02X data: 0x%02X\n", rstat & SER_ERROR_MASK, data);
-#endif
-			/* we only ever write errors into the first byte in
-			 * the flip flag buffer, so we dont have to clear it
-			 * all every time
-			 */
-		}
+		if (rstat & SER_PAR_ERR_MASK)
+			add_char_and_flag(info, data, TTY_PARITY);
+		else if (rstat & SER_OVERRUN_MASK)
+			add_char_and_flag(info, data, TTY_OVERRUN);
+		else if (rstat & SER_FRAMING_ERR_MASK)
+			add_char_and_flag(info, data, TTY_FRAME);
 	}
 
-	DEBUG_LOG(info->line, "recvl %lu\n", recvl);
-
-	if (recvl) {
-		unsigned char *buf;
-		struct async_icount *icount = &info->icount;
-
-		/* update stats */
-		icount->rx += recvl;
-
-		/* use the flip buffer next in turn to restart DMA into */
-
-		if (tty->flip.buf_num) {
-			buf = tty->flip.char_buf;
-		} else {
-			buf = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
-		}
+	if (!E100_RTS_GET(info) &&
+	    CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) < TTY_THROTTLE_LIMIT)
+		info->tty->driver.throttle(info->tty);
+	
+	START_FLUSH_FAST_TIMER(info, "receive_chars");
 
-		if (buf == phys_to_virt(descr->buf)) {
-			printk("ttyS%d flip-buffer overrun!\n", info->line);
-			icount->overrun++;
-			*tty->flip.flag_buf_ptr = TTY_OVERRUN;
-			/* restart old buffer */
-		} else {
-			descr->buf = virt_to_phys(buf);
+	/* Restart the receiving DMA */
+	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
+}
 
-			/* schedule or push a flip of the buffer */
+static _INLINE_ int
+start_recv_dma(struct e100_serial *info)
+{
+	struct etrax_dma_descr *descr = info->rec_descr;
+	unsigned char *buf = info->recv.buf + 2*SERIAL_RECV_SIZE;
+        int i;
 
-			info->tty->flip.count = recvl;
+	/* Set up the receiving descriptors */
+	for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
+		descr[i].ctrl = d_int;
+		descr[i].buf = virt_to_phys(buf);
+		descr[i].sw_len = SERIAL_DESCR_BUF_SIZE;
+		descr[i].hw_len = 0;
+		descr[i].status = 0;
+		descr[i].next = virt_to_phys(&descr[i+1]);
 
-#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
-			/* this includes a check for low-latency */
-			tty_flip_buffer_push(tty);
-#else
-			queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
-#endif	
-		}
+		buf += SERIAL_DESCR_BUF_SIZE;
 	}
 
-	/* restart the receiving dma */
+	/* Link the last descriptor to the first */
+	descr[i-1].next = virt_to_phys(&descr[0]);
 
-	descr->sw_len = TTY_FLIPBUF_SIZE;
-	descr->ctrl = d_int | d_eol | d_eop;
-	descr->hw_len = 0;
-	descr->status = 0;
+	/* Start with the first descriptor in the list */
+	info->cur_rec_descr = 0;
 
-	*info->ifirstadr = virt_to_phys(descr);
+	/* Start the DMA */
+	*info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]);
 	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
 
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-	e100_enable_serial_data_irq(info);
-#endif	
-	/* input dma should be running now */
-
-	/* unthrottle if we have throttled */
-	if (E100_RTS_GET(info))
-		tty->driver.unthrottle(info->tty);
+	/* Input DMA should be running now */
+	return 1;
 }
 
 static void 
 start_receive(struct e100_serial *info)
 {
-	struct etrax_dma_descr *descr;
-	
 #ifdef CONFIG_SVINTO_SIM
 	/* No receive in the simulator.  Will probably be when the rest of
 	 * the serial interface works, and this piece will just be removed.
@@ -1410,21 +1459,10 @@
 	while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
 	       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
 
-	descr = &info->rec_descr;
-	
-	/* start the receiving dma into the flip buffer */
-	
-	descr->ctrl = d_int | d_eol | d_eop;
-	descr->sw_len = TTY_FLIPBUF_SIZE;
-	descr->buf = virt_to_phys(info->tty->flip.char_buf_ptr);
-	descr->hw_len = 0;
-	descr->status = 0;
-	
 	info->tty->flip.count = 0;
 
-	*info->ifirstadr = virt_to_phys(descr);
-	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
-
+	start_recv_dma(info);
+	
 #ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
 	start_flush_timer();
 #endif
@@ -1474,9 +1512,16 @@
 		info = rs_table + i;
 		if (!info->uses_dma) 
 			continue; 
-		/* check for dma_descr (dont need to check for dma_eop in output dma for serial */
+		/* check for dma_descr (don't need to check for dma_eop in output dma for serial */
 		if (ireg & info->irq) {  
 			/* we can send a new dma bunch. make it so. */
+			DEBUG_LOG(info->line, "tr_interrupt %i\n", i);
+			/* Read jiffies_usec first, 
+			 * we want this time to be as late as possible
+			 */
+ 			PROCSTAT(ser_stat[info->line].tx_dma_ints++);
+			info->last_tx_active_usec = GET_JIFFIES_USEC();
+			info->last_tx_active = jiffies;
 			transmit_chars(info);
 		}
 		
@@ -1524,77 +1569,26 @@
 	}
 }
 
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-static int serial_fast_timer_started = 0;
-static int serial_fast_timer_expired = 0;
-static void flush_timeout_function(unsigned long data);
-#define START_FLUSH_FAST_TIMER(info, string) {\
-  unsigned long timer_flags; \
-  save_flags(timer_flags); \
-  cli(); \
-  TIMERD(DEBUG_LOG(info->line, "start_timer? %i ", info->line)); \
-  if (fast_timers[info->line].function == NULL) { \
-    serial_fast_timer_started++; \
-    TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
-    TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \
-    start_one_shot_timer(&fast_timers[info->line], \
-                         flush_timeout_function, \
-                         (unsigned long)info, \
-                         info->char_time_usec*4, \
-                         string); \
-  } \
-  else { \
-    /* DEBUG_LOG(info->line, " ## timer %i running ##\n", info->line); */ \
-  } \
-  restore_flags(timer_flags); \
-}
-
-#else
-#define START_FLUSH_FAST_TIMER(info, string)
-#endif
-
-void _INLINE_ check_flush_timeout(struct e100_serial *info)
+static _INLINE_ int
+force_eop_if_needed(struct e100_serial *info)
 {
-	unsigned char rstat;
-	unsigned int magic;
-
-	if (0 /*info->tty->processing_flip*/) {
-		if (!E100_RTS_GET(info)) {
-			int left = (*info->ihwswadr >> 16) - (*info->istatusadr & 0x3F);
-
-			if (left < TTY_THROTTLE_LIMIT)
-				info->tty->driver.throttle(info->tty);
-		}
-
-		PROCSTAT(ser_stat[info->line].processing_flip++);
-		START_FLUSH_FAST_TIMER(info, "flip");
-		return;
-	}
-
 	/* We check data_avail bit to determine if data has 
 	 * arrived since last time
 	 */ 
-	magic = info->fifo_magic;
-#ifdef SERIAL_DEBUG_DATA
-	if (info->fifo_magic || info->fifo_didmagic) {
-		DEBUG_LOG(info->line, "timeout_int: did fifo_magic %03X\n",
-		    (info->fifo_didmagic << 8) | info->fifo_magic);
-	}
-#endif
-	rstat = info->port[REG_STATUS];
+	unsigned char rstat = info->port[REG_STATUS];
+
 	/* error or datavail? */
 	if (rstat & SER_ERROR_MASK) { 
-		/* Some error has occured */
-		/* If there has been valid data, 
-		 * an EOP interrupt will be made automatically.
-		 * If no data, the normal ser_interrupt should be enabled 
-		 * and handle it.
+		/* Some error has occurred. If there has been valid data, an
+		 * EOP interrupt will be made automatically. If no data, the
+		 * normal ser_interrupt should be enabled and handle it.
 		 * So do nothing!
 		 */
 		DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n",
 		          rstat | (info->line << 8));
-		return;
+		return 0;
 	}
+
 	if (rstat & SER_DATA_AVAIL_MASK) { 
 		/* Ok data, no error, count it */
 		TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n",
@@ -1602,32 +1596,87 @@
 		/* Read data to clear status flags */
 		(void)info->port[REG_DATA];
 
-		magic++;
+		info->forced_eop = 0;
+		START_FLUSH_FAST_TIMER(info, "magic");
+		return 0;
 	}
 
-	if (magic != info->fifo_magic) {
-		info->fifo_magic = magic;
-		info->fifo_didmagic = 0;
-		START_FLUSH_FAST_TIMER(info, "magic");
-	} else {
-		/* hit the timeout, force an EOP for the input
-		 * dma channel if we haven't already
-		 */
-		if (!info->fifo_didmagic && magic) {
-			info->fifo_didmagic = 1;
-			info->fifo_magic = 0;
-			PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
-			DEBUG_LOG(info->line, "timeout EOP %i\n", info->line);
-			TIMERD(DEBUG_LOG(info->line, "timeout magic %i\n", magic));
-			FORCE_EOP(info);
-		}
+	/* hit the timeout, force an EOP for the input
+	 * dma channel if we haven't already
+	 */
+	if (!info->forced_eop) {
+		info->forced_eop = 1;
+		PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
+		DEBUG_LOG(info->line, "timeout EOP %i\n", info->line);
+		FORCE_EOP(info);
 	}
-} /* check_flush_timeout */
+
+	return 1;
+}
+
+static _INLINE_ void
+flush_to_flip_buffer(struct e100_serial *info)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned int count = CIRC_CNT_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE);
+	unsigned int length;
+	unsigned long flags;
+
+	if (!count)
+		return;
+
+	save_flags(flags);
+	cli();
+
+	length = tty->flip.count;
+	
+	do {
+		if (length + count > TTY_FLIPBUF_SIZE)
+			count = TTY_FLIPBUF_SIZE - length;
+
+		memcpy(tty->flip.char_buf_ptr + length, info->recv.buf + info->recv.tail, count);
+		memcpy(tty->flip.flag_buf_ptr + length, info->flag_buf + info->recv.tail, count);
+		info->recv.tail = ((info->recv.tail + count) & (SERIAL_RECV_SIZE-1));
+		length += count;
+		
+		count = CIRC_CNT_TO_END(info->recv.head,
+					info->recv.tail,
+					SERIAL_RECV_SIZE);
+	} while (length < TTY_FLIPBUF_SIZE && count);
+
+	tty->flip.count = length;
+
+	restore_flags(flags);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,66)
+	/* this includes a check for low-latency */
+	tty_flip_buffer_push(tty);
+#else
+	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+#endif
+
+	/* unthrottle if we have throttled */
+	if (E100_RTS_GET(info) &&
+	    CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) > TTY_THROTTLE_LIMIT)
+		tty->driver.unthrottle(info->tty);
+}
+
+static _INLINE_ void
+check_flush_timeout(struct e100_serial *info)
+{
+	force_eop_if_needed(info);
+
+	flush_to_flip_buffer(info);
+
+	if (CIRC_CNT(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE))
+		START_FLUSH_FAST_TIMER(info, "flip");
+}
 
 #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
 static void flush_timeout_function(unsigned long data)
 {
 	struct e100_serial *info = (struct e100_serial *)data;
+
 	fast_timers[info->line].function = NULL;
 	serial_fast_timer_expired++;
 	TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line));
@@ -1681,7 +1730,6 @@
 {
 	struct e100_serial *info;
 	int i;
-	unsigned int magic;
 
 #ifdef CONFIG_SVINTO_SIM
 	return;
@@ -1689,35 +1737,8 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (!info->enabled || !(info->flags & ASYNC_INITIALIZED))
-			continue;
-
-		/* istatusadr (bit 6-0) hold number of bytes in fifo 
-		 * ihwswadr (bit 31-16) holds number of bytes in dma buffer
-		 * ihwswadr (bit 15-0) specifies size of dma buffer
-		 */
-
-		magic = (*info->istatusadr & 0x3f);
-		magic += ((*info->ihwswadr & 0xffff) - (*info->ihwswadr >> 16));
-
-		/* if magic is equal to fifo_magic (magic in previous
-		 * timeout_interrupt) then no new data has arrived since last
-		 * interrupt and we'll force eop to flush fifo+dma buffers
-		 */
-
-		if (magic != info->fifo_magic) {
-			info->fifo_magic = magic;
-			info->fifo_didmagic = 0;
-		} else {
-			/* hit the timeout, force an EOP for the input
-			 * dma channel if we haven't already
-			 */
-			if (!info->fifo_didmagic && magic) {
-				info->fifo_didmagic = 1;
-				info->fifo_magic = 0;
-				FORCE_EOP(info);
-			}
-		}
+		if (info->uses_dma) 
+			check_flush_timeout(info);
 	}
 
 	/* restart flush timer */
@@ -1770,7 +1791,7 @@
 
 Multiple frame errors with data == 0x00 (B),
 but the part of the break trigs is interpreted as a start bit (and possibly
-som 0 bits followed by a number of 1 bits and a stop bit).
+some 0 bits followed by a number of 1 bits and a stop bit).
 Depending on parity settings etc. this last character can be either
 a fake "valid" char (F) or have a parity error (E).
 
@@ -1805,19 +1826,20 @@
 /*	DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
 	if (rstat & SER_ERROR_MASK) {
 		unsigned char data;
+
 		info->last_rx_active_usec = GET_JIFFIES_USEC();
 		info->last_rx_active = jiffies;
-		/* if we got an error, we must reset it by
-		 * reading the data_in field
+		/* If we got an error, we must reset it by reading the
+		 * data_in field
 		 */
 		data = info->port[REG_DATA];
 
-		if ((data == 0x00) && (rstat & SER_FRAMING_ERR_MASK)) {
-			/* Most likely a break, but we get 
-			 * interrupts over and over again.
+		if (!data && (rstat & SER_FRAMING_ERR_MASK)) {
+			/* Most likely a break, but we get interrupts over and
+			 * over again.
 			 */
 
-			if (info->break_detected_cnt == 0) {
+			if (!info->break_detected_cnt) {
 				DEBUG_LOG(info->line, "#BRK start\n", 0);
 			}
 			if (rstat & SER_RXD_MASK) {
@@ -1833,46 +1855,46 @@
 			}
 			info->break_detected_cnt++;
 		} else {
-			/* Error doesn't look like a break,
-			 * but could be end of a break 
+			/* The error does not look like a break, but could be
+			 * the end of one
 			 */
 			if (info->break_detected_cnt) {
 				DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
 				info->errorcode = ERRCODE_INSERT_BREAK;
+			} else {
+				if (info->errorcode == ERRCODE_INSERT_BREAK)
+					add_char_and_flag(info, '\0', TTY_BREAK);
+
+				if (rstat & SER_PAR_ERR_MASK)
+					add_char_and_flag(info, data, TTY_PARITY);
+				else if (rstat & SER_OVERRUN_MASK)
+					add_char_and_flag(info, data, TTY_OVERRUN);
+				else if (rstat & SER_FRAMING_ERR_MASK)
+					add_char_and_flag(info, data, TTY_FRAME);
+				info->errorcode = 0;
 			}
 			info->break_detected_cnt = 0;
 			DEBUG_LOG(info->line, "#iERR s d %04X\n",
 				  ((rstat & SER_ERROR_MASK) << 8) | data);
 		}
 		PROCSTAT(ser_stat[info->line].early_errors_cnt++);
-
-#if 0
-		/* Reset DMA before starting */
-		*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-		while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
-		       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-#endif
-	} else { /* it was a valid byte, now let the dma do the rest */
-		unsigned char data;
+	} else { /* It was a valid byte, now let the DMA do the rest */
 		unsigned long curr_time_u = GET_JIFFIES_USEC();
 		unsigned long curr_time = jiffies;
 		
 		if (info->break_detected_cnt) {
-			/* Detect if this character is a new
-			 * valid char or the last char in a
-			 * break sequence:
-			 * If LSBits are 0 and MSBits are high
-			 * AND the time is close to the
-			 * previous interrupt we should discard
-			 * it.
+			/* Detect if this character is a new valid char or the
+			 * last char in a break sequence: If LSBits are 0 and
+			 * MSBits are high AND the time is close to the
+			 * previous interrupt we should discard it.
 			 */
 			long elapsed_usec = 
-			  (curr_time - info->last_rx_active) * (1000000/HZ) + 
-			  curr_time_u - info->last_rx_active_usec;
-			if (elapsed_usec<2*info->char_time_usec) {
+				(curr_time - info->last_rx_active) * (1000000/HZ) + 
+				curr_time_u - info->last_rx_active_usec;
+			if (elapsed_usec < 2*info->char_time_usec) {
 				DEBUG_LOG(info->line, "FBRK %i\n", info->line);
-				/* Report as BREAK (error) and 
-				 * let receive_chars handle it
+				/* Report as BREAK (error) and let
+				 * receive_chars() handle it
 				 */
 				info->errorcode = ERRCODE_SET_BREAK;
 			} else {
@@ -1880,22 +1902,19 @@
 			}
 			DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt);
 		}
-		/* Reset data_avail by
-		 * reading the data_in field
-		 */
-		data = info->port[REG_DATA];
-		info->break_detected_cnt = 0;
-		info->fifo_magic++; /* Count received chars */
+
 #ifdef SERIAL_DEBUG_INTR
 		printk("** OK, disabling ser_interupts\n");
 #endif
-		PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
-		DEBUG_LOG(info->line, " ser_int OK %03X\n",
-		          (info->line << 8) | data);
 		e100_disable_serial_data_irq(info);
+
+		info->break_detected_cnt = 0;
+
+		PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
+		DEBUG_LOG(info->line, "ser_int OK %d\n", info->line);
 	}
 
-	/* restart the DMA never hurts */
+	/* Restarting the DMA never hurts */
 	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
 	START_FLUSH_FAST_TIMER(info, "ser_int");
 } /* handle_ser_interrupt */
@@ -1973,7 +1992,7 @@
 {
 	struct e100_serial	*info = (struct e100_serial *) private_;
 	struct tty_struct	*tty;
-	
+
 	tty = info->tty;
 	if (!tty)
 		return;
@@ -1985,43 +2004,46 @@
 startup(struct e100_serial * info)
 {
 	unsigned long flags;
-	unsigned long page;
+	unsigned long xmit_page;
+	unsigned char *recv_page;
+
+	xmit_page = get_zeroed_page(GFP_KERNEL);
+	if (!xmit_page)
+		return -ENOMEM;
 
-	page = get_zeroed_page(GFP_KERNEL);
-	if (!page)
+	recv_page = kmalloc(2 * SERIAL_RECV_SIZE + SERIAL_RECV_DESCRIPTORS * SERIAL_DESCR_BUF_SIZE, GFP_KERNEL);
+	if (!recv_page) {
+		free_page(xmit_page);
 		return -ENOMEM;
+	}
 
 	save_flags(flags); cli();
 
 	/* if it was already initialized, skip this */
-	
+
 	if (info->flags & ASYNC_INITIALIZED) {
-		free_page(page);
 		restore_flags(flags);
+		free_page(xmit_page);
+		kfree(recv_page);
 		return 0;
 	}
-	
+
 	if (info->xmit.buf)
-		free_page(page);
+		free_page(xmit_page);
 	else
-		info->xmit.buf = (unsigned char *) page;
-		
-#ifdef SERIAL_DEBUG_OPEN
-	printk("starting up ttyS%d (xmit_buf 0x%x)...\n", info->line, info->xmit.buf);
-#endif
-
-	if (info->tty) {
-
-		/* clear the tty flip flag buffer since we will not
-		 * be using it (we only use the first byte..)
-		 */
+		info->xmit.buf = (unsigned char *) xmit_page;
 
-		memset(info->tty->flip.flag_buf, 0, TTY_FLIPBUF_SIZE * 2);
+	if (info->recv.buf)
+		kfree(recv_page);
+	else {
+		info->recv.buf = (unsigned char *) recv_page;
+		info->flag_buf = info->recv.buf + SERIAL_RECV_SIZE;
 	}
 
-	save_flags(flags);
-	cli();
-	
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttyS%d (xmit_buf 0x%p, recv_buf 0x%p)...\n", info->line, info->xmit.buf, info->recv.buf);
+#endif
+
 #ifdef CONFIG_SVINTO_SIM
 	/* Bits and pieces collected from below.  Better to have them
 	   in one ifdef:ed clause than to mix in a lot of ifdefs,
@@ -2029,7 +2051,8 @@
 	if (info->tty)
 		clear_bit(TTY_IO_ERROR, &info->tty->flags);
 	info->xmit.head = info->xmit.tail = 0;
-	
+	info->recv.head = info->recv.tail = 0;
+
 	/* No real action in the simulator, but may set info important
 	   to ioctl. */
 	change_speed(info);
@@ -2039,33 +2062,35 @@
 	 * Clear the FIFO buffers and disable them
 	 * (they will be reenabled in change_speed())
 	 */
-	
+
 	/*
 	 * Reset the DMA channels and make sure their interrupts are cleared
 	 */
-	
+
 	info->uses_dma = 1;
 	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
 	*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
 
-	/* wait until reset cycle is complete */
+	/* Wait until reset cycle is complete */
 	while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
 	       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
 
 	while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) ==
 	       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-	
+
+	/* Make sure the irqs are cleared */
 	*info->iclrintradr =
 		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
 		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
 	*info->oclrintradr =
 		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
 		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-	
+
 	if (info->tty)
 		clear_bit(TTY_IO_ERROR, &info->tty->flags);
 
-        info->xmit.head = info->xmit.tail = 0;
+	info->xmit.head = info->xmit.tail = 0;
+	info->recv.head = info->recv.tail = 0;
 	
 	/*
 	 * and set the speed and other flags of the serial port
@@ -2085,7 +2110,7 @@
 	e100_enable_txdma_irq(info);
 	e100_enable_rxdma_irq(info);
 
-	info->tr_running = 0;  /* to be sure we dont lock up the transmitter */
+	info->tr_running = 0; /* to be sure we don't lock up the transmitter */
 
 	/* setup the dma input descriptor and start dma */
 	
@@ -2120,7 +2145,7 @@
 	unsigned long flags;
 
 #ifndef CONFIG_SVINTO_SIM	
-	/* shut down the transmitter and receiver  */
+	/* shut down the transmitter and receiver */
 
 	e100_disable_rx(info);
 	info->port[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40);
@@ -2150,9 +2175,14 @@
 	cli(); /* Disable interrupts */
 	
 	if (info->xmit.buf) {
-		unsigned long pg = (unsigned long) info->xmit.buf;
-		info->xmit.buf = 0;
-		free_page(pg);
+		free_page((unsigned long)info->xmit.buf);
+		info->xmit.buf = NULL;
+	}
+
+	if (info->recv.buf) {
+		kfree(info->recv.buf);
+		info->recv.buf = NULL;
+		info->flag_buf = NULL;
 	}
 
 	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
@@ -2258,11 +2288,11 @@
 	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
 	unsigned long flags;
 
-	if (info->tr_running
-	    || info->xmit.head == info->xmit.tail
-	    || tty->stopped
-	    || tty->hw_stopped
-	    || !info->xmit.buf)
+	if (info->tr_running ||
+	    info->xmit.head == info->xmit.tail ||
+	    tty->stopped ||
+	    tty->hw_stopped ||
+	    !info->xmit.buf)
 		return;
 
 #ifdef SERIAL_DEBUG_FLOW
@@ -2299,7 +2329,7 @@
 #ifdef CONFIG_SVINTO_SIM
 	/* Really simple.  The output is here and now. */
 	SIMCOUT(buf, count);
-	return;
+	return count;
 #endif
 	save_flags(flags);
 	
@@ -2370,8 +2400,8 @@
 	 * the IRQ's are not running anyway for this port.
 	 */
 	
-	if (info->xmit.head != info->xmit.tail
-	    && !tty->stopped &&
+	if (info->xmit.head != info->xmit.tail &&
+	    !tty->stopped &&
 	    !tty->hw_stopped &&
 	    !info->tr_running) {
 		start_transmit(info);
@@ -2528,20 +2558,20 @@
 	tmp.flags = info->flags;
 	tmp.close_delay = info->close_delay;
 	tmp.closing_wait = info->closing_wait;
-	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
 		return -EFAULT;
 	return 0;
 }
 
 static int
-set_serial_info(struct e100_serial * info,
-		struct serial_struct * new_info)
+set_serial_info(struct e100_serial *info,
+		struct serial_struct *new_info)
 {
 	struct serial_struct new_serial;
 	struct e100_serial old_info;
-	int 			retval = 0;
+	int retval = 0;
 
-	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
 		return -EFAULT;
 
 	old_info = *info;
@@ -2636,6 +2666,7 @@
 char *get_control_state_str(int MLines, char *s)
 {
 	int i = 0;
+
 	s[0]='\0';
 	while (control_state_str[i].str != NULL) {
 		if (MLines & control_state_str[i].state) {
@@ -2805,9 +2836,13 @@
 rs_ioctl(struct tty_struct *tty, struct file * file,
 	 unsigned int cmd, unsigned long arg)
 {
-	int error;
 	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+#if defined(CONFIG_ETRAX_RS485) || (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+	int error;
+#endif
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
 	int retval;
+#endif
 	
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
@@ -3108,7 +3143,7 @@
 		struct e100_serial *info)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	unsigned long   flags;
+	unsigned long	flags;
 	int		retval;
 	int		do_clocal = 0, extra_count = 0;
 	
@@ -3292,7 +3327,7 @@
 	}
 
 	/*
-	 * If the port is the middle of closing, bail out now
+	 * If the port is in the middle of closing, bail out now
 	 */
 	if (tty_hung_up_p(filp) ||
 	    (info->flags & ASYNC_CLOSING)) {
@@ -3346,12 +3381,11 @@
 
 static inline int line_info(char *buf, struct e100_serial *info)
 {
-	char	stat_buf[30], control, status;
+	char	stat_buf[30];
 	int	ret;
-	unsigned long flags;
 
 	ret = sprintf(buf, "%d: uart:E100 port:%lX irq:%d",
-		      info->line, info->port, info->irq);
+		      info->line, (unsigned long)info->port, info->irq);
 
 	if (!info->port || (info->type == PORT_UNKNOWN)) {
 		ret += sprintf(buf+ret, "\n");
@@ -3376,19 +3410,24 @@
 	ret += sprintf(buf+ret, " baud:%d", info->baud);
 
 	ret += sprintf(buf+ret, " tx:%lu rx:%lu",
-		       info->icount.tx, info->icount.rx);
+		       (unsigned long)info->icount.tx,
+		       (unsigned long)info->icount.rx);
 
 	if (info->icount.frame)
-		ret += sprintf(buf+ret, " fe:%lu", info->icount.frame);
+		ret += sprintf(buf+ret, " fe:%lu",
+			       (unsigned long)info->icount.frame);
 	
 	if (info->icount.parity)
-		ret += sprintf(buf+ret, " pe:%lu", info->icount.parity);
+		ret += sprintf(buf+ret, " pe:%lu",
+			       (unsigned long)info->icount.parity);
 	
 	if (info->icount.brk)
-		ret += sprintf(buf+ret, " brk:%lu", info->icount.brk);	
+		ret += sprintf(buf+ret, " brk:%lu",
+			       (unsigned long)info->icount.brk);	
 
 	if (info->icount.overrun)
-		ret += sprintf(buf+ret, " oe:%lu", info->icount.overrun);
+		ret += sprintf(buf+ret, " oe:%lu",
+			       (unsigned long)info->icount.overrun);
 
 	/*
 	 * Last thing is the RS-232 status lines
@@ -3526,8 +3565,7 @@
 		info->tty = 0;
 		info->type = PORT_ETRAX;
 		info->tr_running = 0;
-		info->fifo_magic = 0;
-		info->fifo_didmagic = 0;
+		info->forced_eop = 0;
 		info->flags = 0;
 		info->close_delay = 5*HZ/10;
 		info->closing_wait = 30*HZ;
@@ -3541,8 +3579,21 @@
 		info->normal_termios = serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
-		info->xmit.buf = 0;
+		info->xmit.buf = NULL;
 		info->xmit.tail = info->xmit.head = 0;
+		info->recv.buf = NULL;
+		info->recv.tail = info->recv.head = 0;
+		info->flag_buf = NULL;
+		info->last_tx_active_usec = 0;
+		info->last_tx_active = 0;
+
+#if defined(CONFIG_ETRAX_RS485)
+		/* Set sane defaults */
+		info->rs485.rts_on_send = 0;
+		info->rs485.rts_after_sent = 1;
+		info->rs485.delay_rts_before_send = 0;
+		info->rs485.enabled = 0;
+#endif
 
 		if (info->enabled) {
 			printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n",
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/serial.h linux/arch/cris/drivers/serial.h
--- v2.5.2/linux/arch/cris/drivers/serial.h	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/drivers/serial.h	Mon Jan 21 16:00:39 2002
@@ -23,81 +23,90 @@
  * For definitions of the flags field, see tty.h
  */
 
+#define SERIAL_RECV_DESCRIPTORS 8
+
 struct e100_serial {
-	int                   baud;
-	volatile u8 *port;             /* R_SERIALx_CTRL */
-	u32 irq;                       /* bitnr in R_IRQ_MASK2 for dmaX_descr */
-
-	volatile u8 *oclrintradr;      /* adr to R_DMA_CHx_CLR_INTR, output */
-	volatile u32 *ofirstadr;       /* adr to R_DMA_CHx_FIRST, output */
-	volatile u8 *ocmdadr;          /* adr to R_DMA_CHx_CMD, output */
-	const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS, output */
-	volatile u32 *ohwswadr;        /* adr to R_DMA_CHx_HWSW, output */
-
-	volatile u8 *iclrintradr;      /* adr to R_DMA_CHx_CLR_INTR, input */
-	volatile u32 *ifirstadr;       /* adr to R_DMA_CHx_FIRST, input */
-	volatile u8 *icmdadr;          /* adr to R_DMA_CHx_CMD, input */
-	const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS, input */
-	volatile u32 *ihwswadr;        /* adr to R_DMA_CHx_HWSW, input */
-
-	int			flags; 		/* defined in tty.h */
-
-	u8           rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
-	u8           tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
-	u8           iseteop; /* bit number for R_SET_EOP for the input dma */
-	int          enabled;    /* Set to 1 if the port is enabled in HW config */
-  
+	int			baud;
+	volatile u8		*port; /* R_SERIALx_CTRL */
+	u32			irq;  /* bitnr in R_IRQ_MASK2 for dmaX_descr */
+
+	/* Output registers */
+	volatile u8		*oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
+	volatile u32		*ofirstadr;   /* adr to R_DMA_CHx_FIRST */
+	volatile u8		*ocmdadr;     /* adr to R_DMA_CHx_CMD */
+	const volatile u8	*ostatusadr;  /* adr to R_DMA_CHx_STATUS */
+	volatile u32		*ohwswadr;    /* adr to R_DMA_CHx_HWSW */
+	volatile u32		*odescradr;   /* adr to R_DMA_CHx_DESCR */
+
+	/* Input registers */
+	volatile u8		*iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
+	volatile u32		*ifirstadr;   /* adr to R_DMA_CHx_FIRST */
+	volatile u8		*icmdadr;     /* adr to R_DMA_CHx_CMD */
+	const volatile u8	*istatusadr;  /* adr to R_DMA_CHx_STATUS */
+	volatile u32		*ihwswadr;    /* adr to R_DMA_CHx_HWSW */
+	volatile u32		*idescradr;   /* adr to R_DMA_CHx_DESCR */
+
+	int			flags;	/* defined in tty.h */
+
+	u8			rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
+	u8			tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
+	u8			iseteop; /* bit number for R_SET_EOP for the input dma */
+
+	int			enabled; /* Set to 1 if the port is enabled in HW config */
   
-/* end of fields defined in rs_table[] in .c-file */
-	int          uses_dma; /* Set to 1 if DMA should be used */
-	unsigned char           fifo_didmagic; /* a fifo eop has been forced */
+	/* end of fields defined in rs_table[] in .c-file */
 
-	struct etrax_dma_descr tr_descr, rec_descr;
+	int			uses_dma; /* Set to 1 if DMA should be used */
+	unsigned char           forced_eop; /* a fifo eop has been forced */
 
-	int                     fifo_magic; /* fifo amount - bytes left in dma buffer */
+	struct etrax_dma_descr	tr_descr;
+	struct etrax_dma_descr	rec_descr[SERIAL_RECV_DESCRIPTORS];
+	int			cur_rec_descr;
 
-	volatile int            tr_running; /* 1 if output is running */
+	volatile int		tr_running; /* 1 if output is running */
 
-	struct tty_struct 	*tty;
+	struct tty_struct	*tty;
 	int			read_status_mask;
 	int			ignore_status_mask;
 	int			x_char;	/* xon/xoff character */
 	int			close_delay;
-	unsigned short	        closing_wait;
-	unsigned short	        closing_wait2;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
 	unsigned long		event;
 	unsigned long		last_active;
 	int			line;
-	int                     type;  /* PORT_ETRAX */
+	int			type;  /* PORT_ETRAX */
 	int			count;	    /* # of fd on device */
 	int			blocked_open; /* # of blocked opens */
 	long			session; /* Session of opening process */
 	long			pgrp; /* pgrp of opening process */
-	struct circ_buf         xmit;
+	struct circ_buf		xmit;
+	struct circ_buf		recv;
+	unsigned char		*flag_buf;
 
 	struct tq_struct	tqueue;
-	struct async_icount     icount;   /* error-statistics etc.*/
-	struct termios	        normal_termios;
-	struct termios	        callout_termios;
+	struct async_icount	icount;   /* error-statistics etc.*/
+	struct termios		normal_termios;
+	struct termios		callout_termios;
 #ifdef DECLARE_WAITQUEUE
-	wait_queue_head_t       open_wait;
-        wait_queue_head_t       close_wait;
-#else   
-        struct wait_queue       *open_wait;
-        struct wait_queue       *close_wait;
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
+#else
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
 #endif  
 
-	unsigned long char_time_usec;       /* The time for 1 char, in usecs */
-	unsigned long last_tx_active_usec;  /* Last tx usec in the jiffies */
-	unsigned long last_tx_active;       /* Last tx time in jiffies */
-	unsigned long last_rx_active_usec;  /* Last rx usec in the jiffies */
-	unsigned long last_rx_active;       /* Last rx time in jiffies */
+	unsigned long		char_time_usec;       /* The time for 1 char, in usecs */
+	unsigned long		last_tx_active_usec;  /* Last tx usec in the jiffies */
+	unsigned long		last_tx_active;       /* Last tx time in jiffies */
+	unsigned long		last_rx_active_usec;  /* Last rx usec in the jiffies */
+	unsigned long		last_rx_active;       /* Last rx time in jiffies */
 
-	int break_detected_cnt;
-	int errorcode;
+	int			break_detected_cnt;
+	int			errorcode;
 
 #ifdef CONFIG_RS485
-	struct rs485_control    rs485;  /* RS-485 support */
+	struct rs485_control	rs485;  /* RS-485 support */
 #endif
 };
 
@@ -116,4 +125,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif /* !(_ETRAX_SERIAL_H) */
+#endif /* !_ETRAX_SERIAL_H */
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/sync_serial.c linux/arch/cris/drivers/sync_serial.c
--- v2.5.2/linux/arch/cris/drivers/sync_serial.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/drivers/sync_serial.c	Mon Jan 21 16:00:39 2002
@@ -711,7 +711,7 @@
 {
 	port->out_descr.hw_len = 0;
 	port->out_descr.next = 0;
-	port->out_descr.ctrl = d_int | d_eol | d_eop;
+	port->out_descr.ctrl = d_int | d_eol | d_eop | d_wait;
 	port->out_descr.sw_len = count;
 	port->out_descr.buf = virt_to_phys(port->out_buffer);
 	port->out_descr.status = 0;
diff -u --recursive --new-file v2.5.2/linux/arch/cris/drivers/usb-host.c linux/arch/cris/drivers/usb-host.c
--- v2.5.2/linux/arch/cris/drivers/usb-host.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/cris/drivers/usb-host.c	Mon Jan 21 15:44:21 2002
@@ -192,15 +192,15 @@
 static USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
 static USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));
 
-static urb_t *URB_List[NBR_OF_EP_DESC];
+static struct urb *URB_List[NBR_OF_EP_DESC];
 static kmem_cache_t *usb_desc_cache;
 static struct usb_bus *etrax_usb_bus;
 
 static void dump_urb (struct urb *urb);
 static void init_rx_buffers(void);
-static int etrax_rh_unlink_urb (urb_t *urb);
-static void etrax_rh_send_irq(urb_t *urb);
-static void etrax_rh_init_int_timer(urb_t *urb);
+static int etrax_rh_unlink_urb (struct urb *urb);
+static void etrax_rh_send_irq(struct urb *urb);
+static void etrax_rh_init_int_timer(struct urb *urb);
 static void etrax_rh_int_timer_do(unsigned long ptr);
 
 static void etrax_usb_setup_epid(char epid, char devnum, char endpoint,
@@ -210,13 +210,13 @@
 static void etrax_usb_free_epid(char epid);
 static void cleanup_sb(USB_SB_Desc_t *sb);
 
-static int etrax_usb_do_ctrl_hw_add(urb_t *urb, char epid, char maxlen);
-static int etrax_usb_do_bulk_hw_add(urb_t *urb, char epid, char maxlen);
+static int etrax_usb_do_ctrl_hw_add(struct urb *urb, char epid, char maxlen);
+static int etrax_usb_do_bulk_hw_add(struct urb *urb, char epid, char maxlen);
 
-static int etrax_usb_submit_ctrl_urb(urb_t *urb);
+static int etrax_usb_submit_ctrl_urb(struct urb *urb);
 
-static int etrax_usb_submit_urb(urb_t *urb);
-static int etrax_usb_unlink_urb(urb_t *urb);
+static int etrax_usb_submit_urb(struct urb *urb);
+static int etrax_usb_unlink_urb(struct urb *urb);
 static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
 static int etrax_usb_allocate_dev(struct usb_device *usb_dev);
 static int etrax_usb_deallocate_dev(struct usb_device *usb_dev);
@@ -225,7 +225,7 @@
 static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);
 static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs);
 
-static int etrax_rh_submit_urb (urb_t *urb);
+static int etrax_rh_submit_urb (struct urb *urb);
 
 static int etrax_usb_hc_init(void);
 static void etrax_usb_hc_cleanup(void);
@@ -421,7 +421,7 @@
 }
 
 
-static int etrax_usb_unlink_intr_urb(urb_t *urb)
+static int etrax_usb_unlink_intr_urb(struct urb *urb)
 {
 	struct usb_device *usb_dev = urb->dev;
 	etrax_hc_t *hc = usb_dev->bus->hcpriv;
@@ -512,7 +512,7 @@
 	} while (tmp_ep != first_ep);
 }
 
-static int etrax_usb_submit_intr_urb(urb_t *urb)
+static int etrax_usb_submit_intr_urb(struct urb *urb)
 {
 	USB_EP_Desc_t *tmp_ep;
 	USB_EP_Desc_t *first_ep;
@@ -643,7 +643,7 @@
 
 static int handle_intr_transfer_attn(char epid, int status)
 {
-	urb_t *old_urb;
+	struct urb *old_urb;
 
 	DBFENTER;
 
@@ -696,7 +696,7 @@
 	DBFEXIT;
 }
 
-static int etrax_rh_unlink_urb (urb_t *urb)
+static int etrax_rh_unlink_urb (struct urb *urb)
 {
 	etrax_hc_t *hc;
 	
@@ -713,7 +713,7 @@
 	return 0;
 }
 
-static void etrax_rh_send_irq(urb_t *urb)
+static void etrax_rh_send_irq(struct urb *urb)
 {
 	__u16 data = 0;
 	etrax_hc_t *hc = urb->dev->bus->hcpriv;
@@ -746,7 +746,7 @@
 /*	DBFEXIT; */
 }
 
-static void etrax_rh_init_int_timer(urb_t *urb)
+static void etrax_rh_init_int_timer(struct urb *urb)
 {
 	etrax_hc_t *hc;
 	
@@ -765,12 +765,12 @@
 
 static void etrax_rh_int_timer_do(unsigned long ptr)
 {
-	urb_t *urb;
+	struct urb *urb;
 	etrax_hc_t *hc;
 	
 /*	DBFENTER; */
 	
-	urb = (urb_t*)ptr;
+	urb = (struct urb *)ptr;
 	hc = urb->dev->bus->hcpriv;
 	
 	if (hc->rh.send) {
@@ -904,7 +904,7 @@
 	return -1;
 }
 
-static int etrax_usb_submit_bulk_urb(urb_t *urb)
+static int etrax_usb_submit_bulk_urb(struct urb *urb)
 {
 	char epid;
 	char devnum;
@@ -912,7 +912,7 @@
 	char maxlen;
 	char slow;
 
-	urb_t *tmp_urb;
+	struct urb *tmp_urb;
 	
 	etrax_urb_priv_t *urb_priv;
 	unsigned long flags;
@@ -962,7 +962,7 @@
 	return 0;
 }
 
-static int etrax_usb_do_bulk_hw_add(urb_t *urb, char epid, char maxlen)
+static int etrax_usb_do_bulk_hw_add(struct urb *urb, char epid, char maxlen)
 {
 	USB_SB_Desc_t *sb_desc_1;
 
@@ -1080,7 +1080,7 @@
 
 static int handle_bulk_transfer_attn(char epid, int status)
 {
-	urb_t *old_urb;
+	struct urb *old_urb;
 	etrax_urb_priv_t *hc_priv;
 	unsigned long flags;
 
@@ -1159,7 +1159,7 @@
 
 /* ---------------------------------------------------------------------------- */
 
-static int etrax_usb_submit_ctrl_urb(urb_t *urb)
+static int etrax_usb_submit_ctrl_urb(struct urb *urb)
 {
 	char epid;
 	char devnum;
@@ -1167,7 +1167,7 @@
 	char maxlen;
 	char slow;
 
-	urb_t *tmp_urb;
+	struct urb *tmp_urb;
 	
 	etrax_urb_priv_t *urb_priv;
 	unsigned long flags;
@@ -1217,7 +1217,7 @@
 	return 0;
 }
 
-static int etrax_usb_do_ctrl_hw_add(urb_t *urb, char epid, char maxlen)
+static int etrax_usb_do_ctrl_hw_add(struct urb *urb, char epid, char maxlen)
 {
 	USB_SB_Desc_t *sb_desc_1;
 	USB_SB_Desc_t *sb_desc_2;
@@ -1358,7 +1358,7 @@
 	DBFEXIT;
 }
 
-static int etrax_usb_submit_urb(urb_t *urb)
+static int etrax_usb_submit_urb(struct urb *urb)
 {
 	etrax_hc_t *hc;
 	int rval = -EINVAL;
@@ -1403,7 +1403,7 @@
 	return rval;
 }
 
-static int etrax_usb_unlink_urb(urb_t *urb)
+static int etrax_usb_unlink_urb(struct urb *urb)
 {
 	etrax_hc_t *hc = urb->dev->bus->hcpriv;
 	int epid;
@@ -1448,7 +1448,7 @@
 	cli();
 	
 	for (epid = 0; epid < 32; epid++) {
-		urb_t *u = URB_List[epid];
+		struct urb *u = URB_List[epid];
 		pos = 0;
 
 		for (; u; u = u->next) {
@@ -1474,7 +1474,7 @@
 					URB_List[epid] = u->next;
 				
 				} else {
-					urb_t *up;
+					struct urb *up;
 					for (up = URB_List[epid]; up->next != u; up = up->next);
 					up->next = u->next;
 				}
@@ -1522,7 +1522,7 @@
 	etrax_hc_t *hc = (etrax_hc_t *)vhc;
 	int epid;
 	char eol;
-	urb_t *urb;
+	struct urb *urb;
 	USB_EP_Desc_t *tmp_ep;
 	USB_SB_Desc_t *tmp_sb;
 	
@@ -1551,7 +1551,7 @@
 static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs)
 {
 	int epid = 0;
-	urb_t *urb;
+	struct urb *urb;
 	etrax_urb_priv_t *urb_priv;
 		
 	*R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
@@ -1649,7 +1649,7 @@
 
 static int handle_control_transfer_attn(char epid, int status)
 {
-	urb_t *old_urb;
+	struct urb *old_urb;
 	etrax_urb_priv_t *hc_priv;	
 
 	DBFENTER;
@@ -1710,7 +1710,7 @@
 static void etrax_usb_hc_intr_bottom_half(void *data)
 {
 	struct usb_reg_context *reg = (struct usb_reg_context *)data;
-	urb_t *old_urb;
+	struct urb *old_urb;
 	
 	int error_code;
 	int epid;
@@ -1976,7 +1976,7 @@
 	DBFEXIT;
 }
 
-static int etrax_rh_submit_urb(urb_t *urb)
+static int etrax_rh_submit_urb(struct urb *urb)
 {
 	struct usb_device *usb_dev = urb->dev;
 	etrax_hc_t *hc = usb_dev->bus->hcpriv;
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/Makefile linux/arch/cris/kernel/Makefile
--- v2.5.2/linux/arch/cris/kernel/Makefile	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/kernel/Makefile	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.9 2001/10/22 13:10:21 pkj Exp $
+# $Id: Makefile,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
 #
 # Makefile for the linux kernel.
 #
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/debugport.c linux/arch/cris/kernel/debugport.c
--- v2.5.2/linux/arch/cris/kernel/debugport.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/kernel/debugport.c	Mon Jan 21 16:00:39 2002
@@ -12,6 +12,9 @@
  *    init_etrax_debug()
  *
  * $Log: debugport.c,v $
+ * Revision 1.2  2002/01/21 15:21:50  bjornw
+ * Update for kdev_t changes
+ *
  * Revision 1.6  2001/04/17 13:58:39  orjanf
  * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
  *
@@ -214,7 +217,7 @@
 static kdev_t 
 console_device(struct console *c)
 {
-         return MKDEV(TTY_MAJOR, 64 + c->index);
+         return mk_kdev(TTY_MAJOR, 64 + c->index);
 }
 
 static int __init 
@@ -224,17 +227,16 @@
 }
 
 static struct console sercons = {
-        "ttyS",
-        console_write,
-        NULL,
-        console_device,
-        NULL,
-	NULL,
-	console_setup,
-	CON_PRINTBUFFER,
-	DEBUG_PORT_IDX,
-	0,
-	NULL
+        name:    "ttyS",
+        write:   console_write,
+        read:    NULL,
+        device:  console_device,
+        unblank: NULL,
+	setup:   console_setup,
+	flags:   CON_PRINTBUFFER,
+	index:   DEBUG_PORT_IDX,
+	cflag:   0,
+	next:    NULL
 };
 
 /*
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S
--- v2.5.2/linux/arch/cris/kernel/entry.S	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/kernel/entry.S	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.35 2001/10/30 17:10:15 bjornw Exp $
+/* $Id: entry.S,v 1.3 2002/01/21 15:22:20 bjornw Exp $
  *
  *  linux/arch/cris/entry.S
  *
@@ -7,6 +7,18 @@
  *  Authors:	Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: entry.S,v $
+ *  Revision 1.3  2002/01/21 15:22:20  bjornw
+ *  NICE_DOGGY fix from 2.4 arch/cris
+ *
+ *  Revision 1.37  2001/12/07 17:03:55  bjornw
+ *  Call a c-hook called watchdog_bite_hook instead of show_registers directly
+ *
+ *  Revision 1.36  2001/11/22 13:36:36  bjornw
+ *  * In ret_from_intr, check regs->dccr for usermode reentrance instead of
+ *    DCCR explicitely (because the latter might not reflect current reality)
+ *  * In mmu_bus_fault, set $r9 _after_ calling the C-code instead of before
+ *    since $r9 is call-clobbered and is potentially needed afterwards
+ *
  *  Revision 1.35  2001/10/30 17:10:15  bjornw
  *  Add some syscalls
  *
@@ -217,8 +229,11 @@
 	
 ret_from_intr:
 	;; check for resched only if we're going back to user-mode
-
-	move	$ccr, $r0
+	;; this test matches the user_regs(regs) macro
+	;; we cannot simply test $dccr, because that does not necessarily
+	;; reflect what mode we'll return into.
+	
+	move.d	[$sp + LDCCR], $r0; regs->dccr
 	btstq	8, $r0		; U-flag
 	bpl	_Rexit		; go back directly
 	nop
@@ -468,8 +483,6 @@
 	moveq	1, $r10
 	push	$r10		; frametype == 1, BUSFAULT frame type
 
-	moveq	0, $r9		; busfault is equivalent to an irq
-		
 	move.d	$sp, $r10	; pt_regs argument to handle_mmu_bus_fault
 		
 	jsr	handle_mmu_bus_fault  ; in arch/cris/mm/fault.c
@@ -479,6 +492,8 @@
 	;; process due to a SEGV, scheduled due to a page blocking or
 	;; whatever.
 
+	moveq	0, $r9		; busfault is equivalent to an irq
+		
 	ba	ret_from_intr
 	nop
 		
@@ -559,6 +574,17 @@
 ;; We'll see this in ksymoops dumps.
 Watchdog_bite:
 
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+       ;; We just restart the watchdog here to be sure we dont get
+       ;; hit while printing the watchdogmsg below
+       ;; This restart is compatible with the rest of the C-code, so
+       ;; the C-code can keep restarting the watchdog after this point.
+       ;; The non-NICE_DOGGY code below though, disables the possibility
+       ;; to restart since it changes the watchdog key, to avoid any
+       ;; buggy loops etc. keeping the watchdog alive after this.
+       jsr     reset_watchdog
+#else
+
 ;; We need to extend the 3.3ms after the NMI at watchdog bite, so we have
 ;; time for an oops-dump over a 115k2 serial wire.  Another 100ms should do.
 
@@ -576,6 +602,8 @@
 		| IO_STATE (R_WATCHDOG, enable, start), $r10
 	move.d	$r10, [$r11]
 
+#endif
+	
 ;; Note that we don't do "setf m" here (or after two necessary NOPs),
 ;; since *not* doing that saves us from re-entrancy checks.  We don't want
 ;; to get here again due to possible subsequent NMIs; we want the watchdog
@@ -585,7 +613,7 @@
 	jsr	printk
 
 	move.d	$sp, $r10
-	jsr	show_registers
+	jsr	watchdog_bite_hook
 
 ;; This nop is here so we see the "Watchdog_bite" label in ksymoops dumps
 ;; rather than "spurious_interrupt".
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/entryoffsets.c linux/arch/cris/kernel/entryoffsets.c
--- v2.5.2/linux/arch/cris/kernel/entryoffsets.c	Thu Jul 26 15:10:06 2001
+++ linux/arch/cris/kernel/entryoffsets.c	Mon Jan 28 15:14:22 2002
@@ -33,9 +33,9 @@
   VAL (NAME, offsetof (TYPE, MEMBER))
 
 /* task_struct offsets.  */
-OF (LTASK_SIGPENDING, struct task_struct, sigpending)
-OF (LTASK_NEEDRESCHED, struct task_struct, need_resched)
-OF (LTASK_PTRACE, struct task_struct, ptrace)
+#error OF (LTASK_SIGPENDING, struct task_struct, sigpending)
+#error OF (LTASK_NEEDRESCHED, struct task_struct, need_resched)
+#error OF (LTASK_PTRACE, struct task_struct, ptrace)
 OF (LTASK_PID, struct task_struct, pid)
 
 /* pt_regs offsets.  */
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/head.S linux/arch/cris/kernel/head.S
--- v2.5.2/linux/arch/cris/kernel/head.S	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/kernel/head.S	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.41 2001/10/29 14:55:58 pkj Exp $
+/* $Id: head.S,v 1.2 2001/12/18 13:35:19 bjornw Exp $
  * 
  * Head of the kernel - alter with care
  *
@@ -7,6 +7,15 @@
  * Authors:	Bjorn Wesen (bjornw@axis.com)
  * 
  * $Log: head.S,v $
+ * Revision 1.2  2001/12/18 13:35:19  bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.43  2001/11/08 15:09:43  starvik
+ * Only start MII clock if Ethernet is configured
+ *
+ * Revision 1.42  2001/11/08 14:37:34  starvik
+ * Start MII clock early to make sure that it is running at tranceiver reset
+ *
  * Revision 1.41  2001/10/29 14:55:58  pkj
  * Corrected pa$r0 to par0.
  *
@@ -156,7 +165,10 @@
 
 #define CRAMFS_MAGIC 0x28cd3d45
 #define RAM_INIT_MAGIC 0x56902387
-		
+
+#define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\
+                             IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk)
+				
 	;; exported symbols
 		
 	.globl	etrax_irv
@@ -301,6 +313,12 @@
 	;; after init.
 	.section ".text.init"
 _inflash:
+#ifdef CONFIG_ETRAX_ETHERNET	
+	;; Start MII clock to make sure it is running when tranceiver is reset
+	move.d START_ETHERNET_CLOCK, $r0
+	move.d $r0, [R_NETWORK_GEN_CONFIG]
+#endif
+		
 	;; We need to initialze DRAM registers before we start using the DRAM
 
 	cmp.d	RAM_INIT_MAGIC, $r8	; Already initialized?
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/irq.c linux/arch/cris/kernel/irq.c
--- v2.5.2/linux/arch/cris/kernel/irq.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/cris/kernel/irq.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.17 2001/07/25 16:08:01 bjornw Exp $
+/* $Id: irq.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $
  *
  *	linux/arch/cris/kernel/irq.c
  *
@@ -138,7 +138,7 @@
 /* IRQ0 and 1 are special traps */
 void hwbreakpoint(void);
 void IRQ1_interrupt(void);
-BUILD_IRQ(2, 0x04)             /* the timer interrupt */
+BUILD_TIMER_IRQ(2, 0x04)       /* the timer interrupt is somewhat special */
 BUILD_IRQ(3, 0x08)
 BUILD_IRQ(4, 0x10)
 BUILD_IRQ(5, 0x20)
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/kgdb.c linux/arch/cris/kernel/kgdb.c
--- v2.5.2/linux/arch/cris/kernel/kgdb.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/kernel/kgdb.c	Mon Jan 21 16:00:39 2002
@@ -18,6 +18,9 @@
 *! Jul 21 1999  Bjorn Wesen     eLinux port
 *!
 *! $Log: kgdb.c,v $
+*! Revision 1.1.1.1  2001/12/17 13:59:27  bjornw
+*! Import of Linux 2.5.1
+*!
 *! Revision 1.6  2001/10/09 13:10:03  matsfg
 *! Added $ on registers and removed some underscores
 *!
@@ -55,7 +58,7 @@
 *!
 *!---------------------------------------------------------------------------
 *!
-*! $Id: kgdb.c,v 1.6 2001/10/09 13:10:03 matsfg Exp $
+*! $Id: kgdb.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
 *!
 *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
 *!
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/ksyms.c linux/arch/cris/kernel/ksyms.c
--- v2.5.2/linux/arch/cris/kernel/ksyms.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/kernel/ksyms.c	Mon Jan 21 16:00:39 2002
@@ -23,34 +23,45 @@
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern unsigned long get_cmos_time(void);
+extern void __Udiv(void);
 extern void __ashrdi3(void);
 extern void iounmap(void *addr);
 
-/* platform dependent support */
-
+/* Platform dependent support */
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(get_cmos_time);
+EXPORT_SYMBOL(loops_per_usec);
 
+/* String functions */
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(simple_strtol);
 EXPORT_SYMBOL(strstr);
-
+EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strcmp);
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strncmp);
+
+/* Math functions */
+EXPORT_SYMBOL(__Udiv);
 EXPORT_SYMBOL(__ashrdi3);
 
+/* Memory functions */
 EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
 
-/* export shadow registers for the CPU I/O pins */
+/* Semaphore functions */
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
 
+/* Export shadow registers for the CPU I/O pins */
 EXPORT_SYMBOL(genconfig_shadow);
 EXPORT_SYMBOL(port_pa_data_shadow);
 EXPORT_SYMBOL(port_pa_dir_shadow);
@@ -59,8 +70,7 @@
 EXPORT_SYMBOL(port_pb_config_shadow);
 EXPORT_SYMBOL(port_g_data_shadow);
 
-/* other stuff */
-
+/* Userspace access functions */
 EXPORT_SYMBOL(strncpy_from_user);
 EXPORT_SYMBOL(__strncpy_from_user);
 EXPORT_SYMBOL(__generic_copy_from_user);
@@ -71,8 +81,8 @@
 
 #undef memcpy
 #undef memset
-extern void * memset(void *,int,__kernel_size_t);
-extern void * memcpy(void *,const void *,__kernel_size_t);
+extern void * memset(void *, int, __kernel_size_t);
+extern void * memcpy(void *, const void *, __kernel_size_t);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
 
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c
--- v2.5.2/linux/arch/cris/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/cris/kernel/process.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.20 2001/10/03 08:21:39 jonashg Exp $
+/* $Id: process.c,v 1.3 2002/01/21 15:22:49 bjornw Exp $
  * 
  *  linux/arch/cris/kernel/process.c
  *
@@ -8,6 +8,15 @@
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: process.c,v $
+ *  Revision 1.3  2002/01/21 15:22:49  bjornw
+ *  current->counter is gone
+ *
+ *  Revision 1.22  2001/11/13 09:40:43  orjanf
+ *  Added dump_fpu (needed for core dumps).
+ *
+ *  Revision 1.21  2001/11/12 18:26:21  pkj
+ *  Fixed compiler warnings.
+ *
  *  Revision 1.20  2001/10/03 08:21:39  jonashg
  *  cause_of_death does not exist if CONFIG_SVINTO_SIM is defined.
  *
@@ -57,6 +66,7 @@
 #include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
+#include <linux/elfcore.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 
@@ -77,7 +87,6 @@
  * setup.
  */
 
-static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
@@ -135,14 +144,15 @@
 	 * code to know about it than the watchdog handler in entry.S and
 	 * this code, implementing hard reset through the watchdog.
 	 */
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
 	extern int cause_of_death;
+#endif
 
 	printk("*** HARD RESET ***\n");
 	cli();
 
 #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
 	cause_of_death = 0xbedead;
-
 #else
 	/* Since we dont plan to keep on reseting the watchdog,
 	   the key can be arbitrary hence three */
@@ -243,9 +253,10 @@
  */
 void dump_thread(struct pt_regs * regs, struct user * dump)
 {
-	int i;
 #if 0
-/* changed the size calculations - should hopefully work better. lbt */
+	int i;
+
+	/* changed the size calculations - should hopefully work better. lbt */
 	dump->magic = CMAGIC;
 	dump->start_code = 0;
 	dump->start_stack = regs->esp & ~(PAGE_SIZE - 1);
@@ -263,6 +274,12 @@
 
 	dump->u_fpvalid = dump_fpu (regs, &dump->i387);
 #endif 
+}
+
+/* Fill in the fpu structure for a core dump. */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
+{
+        return 0;
 }
 
 /* 
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/ptrace.c linux/arch/cris/kernel/ptrace.c
--- v2.5.2/linux/arch/cris/kernel/ptrace.c	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/kernel/ptrace.c	Mon Jan 21 16:00:39 2002
@@ -8,6 +8,12 @@
  * Authors:   Bjorn Wesen
  *
  * $Log: ptrace.c,v $
+ * Revision 1.2  2001/12/18 13:35:20  bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.8  2001/11/12 18:26:21  pkj
+ * Fixed compiler warnings.
+ *
  * Revision 1.7  2001/09/26 11:53:49  bjornw
  * PTRACE_DETACH works more simple in 2.4.10
  *
@@ -74,8 +80,6 @@
 static inline int put_reg(struct task_struct *task, unsigned int regno,
 			  unsigned long data)
 {
-	unsigned long *addr;
-
 	if (regno == PT_USP)
 		task->thread.usp = data;
 	else if (regno < PT_MAX)
@@ -207,9 +211,7 @@
 			break;
 
 		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
-		case PTRACE_CONT: { /* restart after signal. */
-			long tmp;
-
+		case PTRACE_CONT: /* restart after signal. */
 			ret = -EIO;
 			if ((unsigned long) data > _NSIG)
 				break;
@@ -222,16 +224,13 @@
 			wake_up_process(child);
 			ret = 0;
 			break;
-		}
 
 /*
  * make the child exit.  Best I can do is send it a sigkill. 
  * perhaps it should be put in the status that it wants to 
  * exit.
  */
-		case PTRACE_KILL: {
-			long tmp;
-
+		case PTRACE_KILL:
 			ret = 0;
 			if (child->state == TASK_ZOMBIE) /* already dead */
 				break;
@@ -239,11 +238,8 @@
 			/* TODO: make sure any pending breakpoint is killed */
 			wake_up_process(child);
 			break;
-		}
-
-		case PTRACE_SINGLESTEP: {  /* set the trap flag. */
-			long tmp;
 
+		case PTRACE_SINGLESTEP: /* set the trap flag. */
 			ret = -EIO;
 			if ((unsigned long) data > _NSIG)
 				break;
@@ -256,7 +252,6 @@
 			wake_up_process(child);
 			ret = 0;
 			break;
-		}
 
 		case PTRACE_DETACH:
 			ret = ptrace_detach(child, data);
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/setup.c linux/arch/cris/kernel/setup.c
--- v2.5.2/linux/arch/cris/kernel/setup.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/kernel/setup.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.22 2001/10/23 17:42:58 pkj Exp $
+/* $Id: setup.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $
  *
  *  linux/arch/cris/kernel/setup.c
  *
@@ -26,10 +26,12 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/bootmem.h>
+#include <linux/seq_file.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/smp.h>
+#include <asm/pgtable.h>
 #include <asm/types.h>
 #include <asm/svinto.h>
 
@@ -72,10 +74,10 @@
 void __init 
 setup_arch(char **cmdline_p)
 {
-        unsigned long bootmap_size;
+	extern void init_etrax_debug(void);
+	unsigned long bootmap_size;
 	unsigned long start_pfn, max_pfn;
 	unsigned long memory_start;
-	extern void console_print_etrax(const char *b);
 
  	/* register an initial console printing routine for printk's */
 
@@ -87,12 +89,12 @@
 
 	if(romfs_in_flash || !romfs_length) {
 		/* if we have the romfs in flash, or if there is no rom filesystem,
-		 * our free area starts directly after the BSS 
+		 * our free area starts directly after the BSS
 		 */
 		memory_start = (unsigned long) &_end;
 	} else {
 		/* otherwise the free area starts after the ROM filesystem */
-		printk("ROM fs in RAM, size %d bytes\n", romfs_length);
+		printk("ROM fs in RAM, size %lu bytes\n", romfs_length);
 		memory_start = romfs_start + romfs_length;
 	}
 
@@ -193,7 +195,7 @@
 #define HAS_ATA		0x0020
 #define HAS_USB		0x0040
 #define HAS_IRQ_BUG	0x0080
-#define HAS_MMU_BUG     0x0100
+#define HAS_MMU_BUG	0x0100
 
 static struct cpu_info {
 	char *model;
@@ -213,50 +215,27 @@
 	{ "ETRAX 100",       8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG },
 	{ "ETRAX 100",       8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA },
 	{ "ETRAX 100LX",     8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG },
-	{ "ETRAX 100LX v2",  8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU },
+	{ "ETRAX 100LX v2",  8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU  },
 	{ "Unknown",         0, 0 }  /* This entry MUST be the last */
 };
 
-/*
- * get_cpuinfo - Get information on one CPU for use by the procfs.
- *
- *	Prints info on the next CPU into buffer.  Beware, doesn't check for
- *	buffer overflow.  Current implementation of procfs assumes that the
- *	resulting data is <= 1K.
- *
- *	BUFFER is PAGE_SIZE - 1K bytes long.
- *
- * Args:
- *	buffer	-- you guessed it, the data buffer
- *	cpu_np	-- Input: next cpu to get (start at 0).  Output: Updated.
- *
- *	Returns number of bytes written to buffer.
- */
-int get_cpuinfo(char *buffer, unsigned *cpu_np)
+static int show_cpuinfo(struct seq_file *m, void *v)
 {
-	int revision;
- 	struct cpu_info *info;
-	unsigned n;
+	unsigned long revision;
+	struct cpu_info *info;
 
 	/* read the version register in the CPU and print some stuff */
 
 	revision = rdvr();
 
-	if (revision < 0 || revision >= sizeof cpu_info/sizeof *cpu_info) {
+	if (revision >= sizeof cpu_info/sizeof *cpu_info)
 		info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1];
-	} else
+	else
 		info = &cpu_info[revision];
 
-  	/* No SMP at the moment, so just toggle 0/1 */
-	n = *cpu_np;
-	*cpu_np = 1;
-	if (n != 0) {
-		return (0);
-	}
-
-	return sprintf(buffer,
+	return seq_printf(m,
 		       "cpu\t\t: CRIS\n"
-		       "cpu revision\t: %d\n"
+		       "cpu revision\t: %lu\n"
 		       "cpu model\t: %s\n"
 		       "cache size\t: %d kB\n"
 		       "fpu\t\t: %s\n"
@@ -283,4 +262,28 @@
 		       (loops_per_jiffy * HZ + 500) / 500000,
 		       ((loops_per_jiffy * HZ + 500) / 5000) % 100);
 }
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	/* We only got one CPU... */
+	return *pos < 1 ? (void *)1 : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return NULL;
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op = {
+	start:  c_start,
+	next:   c_next,
+	stop:   c_stop,
+	show:   show_cpuinfo,
+};
+
 #endif /* CONFIG_PROC_FS */
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/shadows.c linux/arch/cris/kernel/shadows.c
--- v2.5.2/linux/arch/cris/kernel/shadows.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/kernel/shadows.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: shadows.c,v 1.2 2001/03/15 14:25:16 bjornw Exp $
+/* $Id: shadows.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  * 
  * Various shadow registers. Defines for these are in include/asm-etrax100/io.h
  */
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c
--- v2.5.2/linux/arch/cris/kernel/sys_cris.c	Thu Jul 26 15:10:06 2001
+++ linux/arch/cris/kernel/sys_cris.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: sys_cris.c,v 1.10 2001/06/27 21:16:15 hp Exp $
+/* $Id: sys_cris.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  *
  * linux/arch/cris/kernel/sys_cris.c
  *
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/time.c linux/arch/cris/kernel/time.c
--- v2.5.2/linux/arch/cris/kernel/time.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/kernel/time.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.9 2001/10/25 10:26:37 johana Exp $
+/* $Id: time.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $
  *
  *  linux/arch/cris/kernel/time.c
  *
@@ -18,6 +18,7 @@
  * Linux/CRIS specific code:
  *
  * Authors:    Bjorn Wesen
+ *             Johan Adolfsson  
  *
  */
 
@@ -61,6 +62,7 @@
 static unsigned long do_slow_gettimeoffset(void)
 {
 	unsigned long count;
+	unsigned long usec_count = 0;
 
 	static unsigned long count_p = LATCH;    /* for the first call after boot */
 	static unsigned long jiffies_p = 0;
@@ -93,16 +95,20 @@
  */
 	if( jiffies_t == jiffies_p ) {
 		if( count > count_p ) {
+			/* Timer wrapped */
+			count = count_p;
+			usec_count = 1000000/CLOCK_TICK_RATE/2;
 		}
 	} else
 		jiffies_p = jiffies_t;
-
         count_p = count;
-
+	/* Convert timer value to usec using table lookup */
+	usec_count += cris_timer0_value_us[count];
+#if 0
 	count = ((LATCH-1) - count) * TICK_SIZE;
 	count = (count + LATCH/2) / LATCH;
-
-	return count;
+#endif
+	return usec_count;
 }
 
 static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
@@ -160,9 +166,8 @@
 {
 	int retval = 0;
 	int real_seconds, real_minutes, cmos_minutes;
-	unsigned char save_control, save_freq_select;
 
-	printk("set_rtc_mmss(%d)\n", nowtime);
+	printk("set_rtc_mmss(%lu)\n", nowtime);
 
 	if(!have_rtc)
 		return 0;
@@ -225,7 +230,9 @@
 /* right now, starting the watchdog is the same as resetting it */
 #define start_watchdog reset_watchdog
 
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
 static int watchdog_key = 0;  /* arbitrary number */
+#endif
 
 /* number of pages to consider "out of memory". it is normal that the memory
  * is used though, so put this really low.
@@ -306,12 +313,12 @@
 	if ((time_status & STA_UNSYNC) == 0 &&
 	    xtime.tv_sec > last_rtc_update + 660 &&
 	    xtime.tv_usec > 500000 - (tick >> 1) &&
-	    xtime.tv_usec < 500000 + (tick >> 1))
+	    xtime.tv_usec < 500000 + (tick >> 1)) {
 		if (set_rtc_mmss(xtime.tv_sec) == 0)
 			last_rtc_update = xtime.tv_sec;
 		else
 			last_rtc_update = xtime.tv_sec - 600;
-	
+	}
 }
 
 #if 0
@@ -322,6 +329,7 @@
 {
 	unsigned long flags;
 	unsigned int newjiff;
+
 	save_flags(flags);
 	cli();
 	newjiff = (myjiff << 16) | (unsigned short)(-*R_TIMER01_DATA); 
@@ -337,7 +345,6 @@
 get_cmos_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
-	int i;
 
 	sec = CMOS_READ(RTC_SECONDS);
 	min = CMOS_READ(RTC_MINUTES);
diff -u --recursive --new-file v2.5.2/linux/arch/cris/kernel/traps.c linux/arch/cris/kernel/traps.c
--- v2.5.2/linux/arch/cris/kernel/traps.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/kernel/traps.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.15 2001/07/18 14:02:37 bjornw Exp $
+/* $Id: traps.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $
  *
  *  linux/arch/cris/traps.c
  *
@@ -30,6 +30,55 @@
 
 int kstack_depth_to_print = 24;
 
+void show_trace(unsigned long * stack)
+{
+	unsigned long addr, module_start, module_end;
+	extern char _stext, _etext;
+	int i;
+
+        printk("\nCall Trace: ");
+
+        i = 1;
+        module_start = VMALLOC_START;
+        module_end = VMALLOC_END;
+
+        while (((long) stack & (THREAD_SIZE-1)) != 0) {
+		if (__get_user (addr, stack)) {
+			/* This message matches "failing address" marked
+			   s390 in ksymoops, so lines containing it will
+			   not be filtered out by ksymoops.  */
+			printk ("Failing address 0x%lx\n", (unsigned long)stack);
+			break;
+		}
+		stack++;
+
+                /*
+                 * If the address is either in the text segment of the
+                 * kernel, or in the region which contains vmalloc'ed
+                 * memory, it *may* be the address of a calling
+                 * routine; if so, print it so that someone tracing
+                 * down the cause of the crash will be able to figure
+                 * out the call path that was taken.
+                 */
+                if (((addr >= (unsigned long) &_stext) &&
+                     (addr <= (unsigned long) &_etext)) ||
+                    ((addr >= module_start) && (addr <= module_end))) {
+                        if (i && ((i % 8) == 0))
+                                printk("\n       ");
+                        printk("[<%08lx>] ", addr);
+                        i++;
+                }
+        }
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+	/* TODO, this is not really useful since its called from
+	 * SysRq-T and we don't have a keyboard.. :) 
+	 */
+}
+
+
 /*
  * These constants are for searching for possible module text
  * segments. MODULE_RANGE is a guess of how much space is likely
@@ -48,9 +97,8 @@
 void 
 show_stack(unsigned long *sp)
 {
-        unsigned long *stack, addr, module_start, module_end;
+        unsigned long *stack, addr;
         int i;
-	extern char _stext, _etext;
 
 	/*
 	 * debugging aid: "show_stack(NULL);" prints a
@@ -62,7 +110,7 @@
 
         stack = sp;
 
-	printk("\nStack from %08lx:\n       ", stack);
+	printk("\nStack from %08lx:\n       ", (unsigned long)stack);
         for(i = 0; i < kstack_depth_to_print; i++) {
                 if (((long) stack & (THREAD_SIZE-1)) == 0)
                         break;
@@ -72,45 +120,13 @@
 			/* This message matches "failing address" marked
 			   s390 in ksymoops, so lines containing it will
 			   not be filtered out by ksymoops.  */
-			printk ("Failing address 0x%lx\n", stack);
+			printk ("Failing address 0x%lx\n", (unsigned long)stack);
 			break;
 		}
 		stack++;
 		printk("%08lx ", addr);
         }
-
-        printk("\nCall Trace: ");
-        stack = sp;
-        i = 1;
-        module_start = VMALLOC_START;
-        module_end = VMALLOC_END;
-        while (((long) stack & (THREAD_SIZE-1)) != 0) {
-		if (__get_user (addr, stack)) {
-			/* This message matches "failing address" marked
-			   s390 in ksymoops, so lines containing it will
-			   not be filtered out by ksymoops.  */
-			printk ("Failing address 0x%lx\n", stack);
-			break;
-		}
-		stack++;
-
-                /*
-                 * If the address is either in the text segment of the
-                 * kernel, or in the region which contains vmalloc'ed
-                 * memory, it *may* be the address of a calling
-                 * routine; if so, print it so that someone tracing
-                 * down the cause of the crash will be able to figure
-                 * out the call path that was taken.
-                 */
-                if (((addr >= (unsigned long) &_stext) &&
-                     (addr <= (unsigned long) &_etext)) ||
-                    ((addr >= module_start) && (addr <= module_end))) {
-                        if (i && ((i % 8) == 0))
-                                printk("\n       ");
-                        printk("[<%08lx>] ", addr);
-                        i++;
-                }
-        }
+	show_trace(sp);
 }
 
 #if 0
@@ -148,7 +164,7 @@
 	       regs->r8, regs->r9, regs->r10, regs->r11);
 	printk("r12: %08lx r13: %08lx oR10: %08lx\n",
 	       regs->r12, regs->r13, regs->orig_r10);
-	printk("R_MMU_CAUSE: %08lx\n", *R_MMU_CAUSE);
+	printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE);
 	printk("Process %s (pid: %d, stackpage=%08lx)\n",
 	       current->comm, current->pid, (unsigned long)current);
 
@@ -195,25 +211,56 @@
         }
 }
 
+/* Called from entry.S when the watchdog has bitten
+ * We print out something resembling an oops dump, and if
+ * we have the nice doggy development flag set, we halt here
+ * instead of rebooting.
+ */
+
+void
+watchdog_bite_hook(struct pt_regs *regs)
+{
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+	cli();
+	stop_watchdog();
+	show_registers(regs);
+	while(1) /* nothing */;
+#else
+	show_registers(regs);
+#endif	
+}
+
+/* This is normally the 'Oops' routine */
+
 void 
 die_if_kernel(const char * str, struct pt_regs * regs, long err)
 {
+	extern void reset_watchdog(void);
+	extern void stop_watchdog(void);
+
 	if(user_mode(regs))
 		return;
 
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+	/* This printout might take too long and trigger the 
+	 * watchdog normally. If we're in the nice doggy
+	 * development mode, stop the watchdog during printout.
+	 */
 	stop_watchdog();
+#endif
 
 	printk("%s: %04lx\n", str, err & 0xffff);
 
 	show_registers(regs);
 
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
 	reset_watchdog();
-
+#endif
 	do_exit(SIGSEGV);
 }
 
 void __init 
 trap_init(void)
 {
-  /* Nothing needs to be done */
+	/* Nothing needs to be done */
 }
diff -u --recursive --new-file v2.5.2/linux/arch/cris/lib/checksum.S linux/arch/cris/lib/checksum.S
--- v2.5.2/linux/arch/cris/lib/checksum.S	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/lib/checksum.S	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: checksum.S,v 1.6 2001/10/01 14:47:35 bjornw Exp $
+/* $Id: checksum.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  * A fast checksum routine using movem
  * Copyright (c) 1998-2001 Axis Communications AB
  *
diff -u --recursive --new-file v2.5.2/linux/arch/cris/lib/checksumcopy.S linux/arch/cris/lib/checksumcopy.S
--- v2.5.2/linux/arch/cris/lib/checksumcopy.S	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/lib/checksumcopy.S	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: checksumcopy.S,v 1.7 2001/10/01 14:47:35 bjornw Exp $
+/* $Id: checksumcopy.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  * A fast checksum+copy routine using movem
  * Copyright (c) 1998, 2001 Axis Communications AB
  *
diff -u --recursive --new-file v2.5.2/linux/arch/cris/lib/dmacopy.c linux/arch/cris/lib/dmacopy.c
--- v2.5.2/linux/arch/cris/lib/dmacopy.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/lib/dmacopy.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: dmacopy.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $ 
+/* $Id: dmacopy.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ 
  *
  * memcpy for large blocks, using memory-memory DMA channels 6 and 7 in Etrax
  */
diff -u --recursive --new-file v2.5.2/linux/arch/cris/lib/dram_init.S linux/arch/cris/lib/dram_init.S
--- v2.5.2/linux/arch/cris/lib/dram_init.S	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/lib/dram_init.S	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: dram_init.S,v 1.10 2001/10/04 12:00:21 martinnn Exp $
+/* $Id: dram_init.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  * 
  * DRAM/SDRAM initialization - alter with care
  * This file is intended to be included from other assembler files
@@ -11,6 +11,9 @@
  * Authors:  Mikael Starvik (starvik@axis.com)	
  * 
  * $Log: dram_init.S,v $
+ * Revision 1.1.1.1  2001/12/17 13:59:27  bjornw
+ * Import of Linux 2.5.1
+ *
  * Revision 1.10  2001/10/04 12:00:21  martinnn
  * Added missing underscores.
  *
diff -u --recursive --new-file v2.5.2/linux/arch/cris/lib/hw_settings.S linux/arch/cris/lib/hw_settings.S
--- v2.5.2/linux/arch/cris/lib/hw_settings.S	Wed Jul  4 11:50:39 2001
+++ linux/arch/cris/lib/hw_settings.S	Mon Jan 21 16:00:39 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: hw_settings.S,v 1.3 2001/04/21 17:02:46 bjornw Exp $
+ * $Id: hw_settings.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  * 
  * This table is used by some tools to extract hardware parameters.
  * The table should be included in the kernel and the decompressor.
diff -u --recursive --new-file v2.5.2/linux/arch/cris/lib/old_checksum.c linux/arch/cris/lib/old_checksum.c
--- v2.5.2/linux/arch/cris/lib/old_checksum.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/lib/old_checksum.c	Mon Jan 21 16:00:39 2002
@@ -1,4 +1,4 @@
-/* $Id: old_checksum.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $
+/* $Id: old_checksum.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $
  *
  * INET		An implementation of the TCP/IP protocol suite for the LINUX
  *		operating system.  INET is implemented using the  BSD Socket
diff -u --recursive --new-file v2.5.2/linux/arch/cris/mm/extable.c linux/arch/cris/mm/extable.c
--- v2.5.2/linux/arch/cris/mm/extable.c	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/mm/extable.c	Mon Jan 21 16:00:39 2002
@@ -2,6 +2,9 @@
  * linux/arch/cris/mm/extable.c
  *
  * $Log: extable.c,v $
+ * Revision 1.1.1.1  2001/12/17 13:59:27  bjornw
+ * Import of Linux 2.5.1
+ *
  * Revision 1.3  2001/09/27 13:52:40  bjornw
  * Harmonize underscore-ness with other parts
  *
diff -u --recursive --new-file v2.5.2/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c
--- v2.5.2/linux/arch/cris/mm/fault.c	Thu Jul 26 15:10:06 2001
+++ linux/arch/cris/mm/fault.c	Mon Jan 21 16:00:39 2002
@@ -6,6 +6,20 @@
  *  Authors:  Bjorn Wesen 
  * 
  *  $Log: fault.c,v $
+ *  Revision 1.2  2001/12/18 13:35:22  bjornw
+ *  Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ *  Revision 1.20  2001/11/22 13:34:06  bjornw
+ *  * Bug workaround (LX TR89): force a rerun of the whole of an interrupted
+ *    unaligned write, because the second half of the write will be corrupted
+ *    otherwise. Affected unaligned writes spanning not-yet mapped pages.
+ *  * Optimization: use the wr_rd bit in R_MMU_CAUSE to know whether a miss
+ *    was due to a read or a write (before we didn't know this until the next
+ *    restart of the interrupted instruction, thus wasting one fault-irq)
+ *
+ *  Revision 1.19  2001/11/12 19:02:10  pkj
+ *  Fixed compiler warnings.
+ *
  *  Revision 1.18  2001/07/18 22:14:32  bjornw
  *  Enable interrupts in the bulk of do_page_fault
  *
@@ -78,7 +92,14 @@
 			      int error_code);
 
 /* debug of low-level TLB reload */
+#undef DEBUG
+
+#ifdef DEBUG
+#define D(x) x
+#else
 #define D(x)
+#endif
+
 /* debug of higher-level faults */
 #define DPG(x)
 
@@ -94,9 +115,12 @@
 handle_mmu_bus_fault(struct pt_regs *regs)
 {
 	int cause, select;
+#ifdef DEBUG
 	int index;
 	int page_id;
-	int miss, we, acc, inv;  
+	int acc, inv;
+#endif
+	int miss, we, writeac;
 	pmd_t *pmd;
 	pte_t pte;
 	int errcode;
@@ -106,75 +130,83 @@
 	select = *R_TLB_SELECT;
 
 	address = cause & PAGE_MASK; /* get faulting address */
-	
-	D(page_id = IO_EXTRACT(R_MMU_CAUSE,  page_id,   cause));
-	D(acc     = IO_EXTRACT(R_MMU_CAUSE,  acc_excp,  cause));
-	D(inv     = IO_EXTRACT(R_MMU_CAUSE,  inv_excp,  cause));  
-	D(index  =  IO_EXTRACT(R_TLB_SELECT, index,     select));
+
+#ifdef DEBUG
+	page_id = IO_EXTRACT(R_MMU_CAUSE,  page_id,   cause);
+	acc     = IO_EXTRACT(R_MMU_CAUSE,  acc_excp,  cause);
+	inv     = IO_EXTRACT(R_MMU_CAUSE,  inv_excp,  cause);  
+	index   = IO_EXTRACT(R_TLB_SELECT, index,     select);
+#endif
 	miss    = IO_EXTRACT(R_MMU_CAUSE,  miss_excp, cause);
 	we      = IO_EXTRACT(R_MMU_CAUSE,  we_excp,   cause);
+	writeac = IO_EXTRACT(R_MMU_CAUSE,  wr_rd,     cause);
+
+	/* ETRAX 100LX TR89 bugfix: if the second half of an unaligned
+	 * write causes a MMU-fault, it will not be restarted correctly.
+	 * This could happen if a write crosses a page-boundary and the
+	 * second page is not yet COW'ed or even loaded. The workaround
+	 * is to clear the unaligned bit in the CPU status record, so 
+	 * that the CPU will rerun both the first and second halves of
+	 * the instruction. This will not have any sideeffects unless
+	 * the first half goes to any device or memory that can't be
+	 * written twice, and which is mapped through the MMU.
+	 *
+	 * We only need to do this for writes.
+	 */
+
+	if(writeac)
+		regs->csrinstr &= ~(1 << 5);
 	
-	/* Note: the reason we don't set errcode's r/w flag here
-	 * using the 'we' flag, is because the latter is only given
-	 * if there is a write-protection exception, not given as a
-	 * general r/w access mode flag. It is currently not possible
-	 * to get this from the MMU (TODO: check if this is the case
-	 * for LXv2).
-	 * 
-	 * The page-fault code won't care, but there will be two page-
-	 * faults instead of one for the case of a write to a non-tabled
-	 * page (miss, then write-protection).
+	/* Set errcode's R/W flag according to the mode which caused the
+	 * fault
 	 */
 
-	errcode = 0;
+	errcode = writeac << 1;
 
-	D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, "
-		 "idx %d pid %d\n",
+	D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n",
 		 regs->irp, address, miss, inv, we, acc, index, page_id));
 
 	/* for a miss, we need to reload the TLB entry */
 
-	if(miss) {
-
+	if (miss) {
 		/* see if the pte exists at all
 		 * refer through current_pgd, dont use mm->pgd
 		 */
-		
+
 		pmd = (pmd_t *)(current_pgd + pgd_index(address));
-		if(pmd_none(*pmd))
+		if (pmd_none(*pmd))
 			goto dofault;
-		if(pmd_bad(*pmd)) {
-			printk("bad pgdir entry 0x%x at 0x%x\n", *pmd, pmd);
+		if (pmd_bad(*pmd)) {
+			printk("bad pgdir entry 0x%lx at 0x%p\n", *(unsigned long*)pmd, pmd);
 			pmd_clear(pmd);
 			return;
 		}
 		pte = *pte_offset(pmd, address);
-		if(!pte_present(pte))
+		if (!pte_present(pte))
 			goto dofault;
-		
-		D(printk(" found pte %x pg %x ", pte_val(pte), pte_page(pte)));
-		D(
-		  {
-			  if(pte_val(pte) & _PAGE_SILENT_WRITE)
-				  printk("Silent-W ");
-			  if(pte_val(pte) & _PAGE_KERNEL)
-				  printk("Kernel ");
-			  if(pte_val(pte) & _PAGE_SILENT_READ)
-				  printk("Silent-R ");
-			  if(pte_val(pte) & _PAGE_GLOBAL)
-				  printk("Global ");
-			  if(pte_val(pte) & _PAGE_PRESENT)
-				  printk("Present ");
-			  if(pte_val(pte) & _PAGE_ACCESSED)
-				  printk("Accessed ");
-			  if(pte_val(pte) & _PAGE_MODIFIED)
-				  printk("Modified ");
-			  if(pte_val(pte) & _PAGE_READ)
-				  printk("Readable ");
-			  if(pte_val(pte) & _PAGE_WRITE)
-				  printk("Writeable ");
-			  printk("\n");
-		  });
+
+#ifdef DEBUG
+		printk(" found pte %lx pg %p ", pte_val(pte), pte_page(pte));
+		if (pte_val(pte) & _PAGE_SILENT_WRITE)
+			printk("Silent-W ");
+		if (pte_val(pte) & _PAGE_KERNEL)
+			printk("Kernel ");
+		if (pte_val(pte) & _PAGE_SILENT_READ)
+			printk("Silent-R ");
+		if (pte_val(pte) & _PAGE_GLOBAL)
+			printk("Global ");
+		if (pte_val(pte) & _PAGE_PRESENT)
+			printk("Present ");
+		if (pte_val(pte) & _PAGE_ACCESSED)
+			printk("Accessed ");
+		if (pte_val(pte) & _PAGE_MODIFIED)
+			printk("Modified ");
+		if (pte_val(pte) & _PAGE_READ)
+			printk("Readable ");
+		if (pte_val(pte) & _PAGE_WRITE)
+			printk("Writeable ");
+		printk("\n");
+#endif
 
 		/* load up the chosen TLB entry
 		 * this assumes the pte format is the same as the TLB_LO layout.
@@ -189,10 +221,10 @@
 	} 
 
 	errcode = 1 | (we << 1);
-	
+
  dofault:
 	/* leave it to the MM system fault handler below */
-	D(printk("do_page_fault %p errcode %d\n", address, errcode));
+	D(printk("do_page_fault %lx errcode %d\n", address, errcode));
 	do_page_fault(address, regs, errcode);
 }
 
@@ -221,20 +253,19 @@
 	struct mm_struct *mm;
 	struct vm_area_struct * vma;
 	int writeaccess;
-	int fault;
 	unsigned long fixup;
 	siginfo_t info;
 
 	tsk = current;
 
-        /*
-         * We fault-in kernel-space virtual memory on-demand. The
-         * 'reference' page table is init_mm.pgd.
-         *
-         * NOTE! We MUST NOT take any locks for this case. We may
-         * be in an interrupt or a critical region, and should
-         * only copy the information from the master page table,
-         * nothing more.
+	/*
+	 * We fault-in kernel-space virtual memory on-demand. The
+	 * 'reference' page table is init_mm.pgd.
+	 *
+	 * NOTE! We MUST NOT take any locks for this case. We may
+	 * be in an interrupt or a critical region, and should
+	 * only copy the information from the master page table,
+	 * nothing more.
 	 *
 	 * NOTE2: This is done so that, when updating the vmalloc
 	 * mappings we don't have to walk all processes pgdirs and
@@ -243,13 +274,13 @@
 	 * bit set so sometimes the TLB can use a lingering entry.
 	 *
 	 * This verifies that the fault happens in kernel space
-         * and that the fault was not a protection error (error_code & 1).
-         */
+	 * and that the fault was not a protection error (error_code & 1).
+	 */
 
-        if (address >= VMALLOC_START &&
+	if (address >= VMALLOC_START &&
 	    !(error_code & 1) &&
 	    !user_mode(regs))
-                goto vmalloc_fault;
+		goto vmalloc_fault;
 
 	/* we can and should enable interrupts at this point */
 	sti();
@@ -312,28 +343,27 @@
 	 */
 
 	switch (handle_mm_fault(mm, vma, address, writeaccess)) {
-        case 1:
-                tsk->min_flt++;
-                break;
-        case 2:
-                tsk->maj_flt++;
-                break;
-        case 0:
-                goto do_sigbus;
-        default:
-                goto out_of_memory;
+	case 1:
+		tsk->min_flt++;
+		break;
+	case 2:
+		tsk->maj_flt++;
+		break;
+	case 0:
+		goto do_sigbus;
+	default:
+		goto out_of_memory;
 	}
 
 	up_read(&mm->mmap_sem);
 	return;
-	
+
 	/*
 	 * Something tried to access memory that isn't in our memory map..
 	 * Fix it, but check if it's kernel or user first..
 	 */
 
  bad_area:
-
 	up_read(&mm->mmap_sem);
 
  bad_area_nosemaphore:
@@ -361,10 +391,10 @@
 	 *  code)
 	 */
 
-        if ((fixup = search_exception_table(regs->irp)) != 0) {
+	if ((fixup = search_exception_table(regs->irp)) != 0) {
 		/* Adjust the instruction pointer in the stackframe */
 
-                regs->irp = fixup;
+		regs->irp = fixup;
 
 		/* We do not want to return by restoring the CPU-state
 		 * anymore, so switch frame-types (see ptrace.h)
@@ -372,9 +402,9 @@
 
 		regs->frametype = CRIS_FRAME_NORMAL;
 
-		D(printk("doing fixup to 0x%x\n", fixup));
-                return;
-        }
+		D(printk("doing fixup to 0x%lx\n", fixup));
+		return;
+	}
 
 	/*
 	 * Oops. The kernel tried to access some bad page. We'll have to
@@ -397,9 +427,9 @@
 	 */
 
  out_of_memory:
-        up_read(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
-	if(user_mode(regs))
+	if (user_mode(regs))
 		do_exit(SIGKILL);
 	goto no_context;
 
@@ -407,40 +437,40 @@
 	up_read(&mm->mmap_sem);
 
 	/*
-         * Send a sigbus, regardless of whether we were in kernel
-         * or user mode.
-         */
+	 * Send a sigbus, regardless of whether we were in kernel
+	 * or user mode.
+	 */
 	info.si_code = SIGBUS;
 	info.si_errno = 0;
 	info.si_code = BUS_ADRERR;
 	info.si_addr = (void *)address;
 	force_sig_info(SIGBUS, &info, tsk);
-	
-        /* Kernel mode? Handle exceptions or die */
-        if (!user_mode(regs))
-                goto no_context;
-        return;
+
+	/* Kernel mode? Handle exceptions or die */
+	if (!user_mode(regs))
+		goto no_context;
+	return;
 
 vmalloc_fault:
-        {
-                /*
-                 * Synchronize this task's top level page-table
-                 * with the 'reference' page table.
+	{
+		/*
+		 * Synchronize this task's top level page-table
+		 * with the 'reference' page table.
 		 *
 		 * Use current_pgd instead of tsk->active_mm->pgd
 		 * since the latter might be unavailable if this
 		 * code is executed in a misfortunately run irq
 		 * (like inside schedule() between switch_mm and
 		 *  switch_to...).
-                 */
+		 */
 
-                int offset = pgd_index(address);
-                pgd_t *pgd, *pgd_k;
-                pmd_t *pmd, *pmd_k;
+		int offset = pgd_index(address);
+		pgd_t *pgd, *pgd_k;
+		pmd_t *pmd, *pmd_k;
 		pte_t *pte_k;
 
-                pgd = current_pgd + offset;
-                pgd_k = init_mm.pgd + offset;
+		pgd = (pgd_t *)current_pgd + offset;
+		pgd_k = init_mm.pgd + offset;
 
 		/* Since we're two-level, we don't need to do both
 		 * set_pgd and set_pmd (they do the same thing). If
@@ -454,13 +484,13 @@
 		 * it exists.
 		 */
 
-                pmd = pmd_offset(pgd, address);
-                pmd_k = pmd_offset(pgd_k, address);
+		pmd = pmd_offset(pgd, address);
+		pmd_k = pmd_offset(pgd_k, address);
 
-                if (!pmd_present(*pmd_k))
-                        goto bad_area_nosemaphore;
+		if (!pmd_present(*pmd_k))
+			goto bad_area_nosemaphore;
 
-                set_pmd(pmd, *pmd_k);
+		set_pmd(pmd, *pmd_k);
 
 		/* Make sure the actual PTE exists as well to
 		 * catch kernel vmalloc-area accesses to non-mapped
@@ -468,10 +498,10 @@
 		 * silently loop forever.
 		 */
 
-                pte_k = pte_offset(pmd_k, address);
-                if (!pte_present(*pte_k))
-                        goto no_context;
+		pte_k = pte_offset(pmd_k, address);
+		if (!pte_present(*pte_k))
+			goto no_context;
 
-                return;
-        }
+		return;
+	}
 }
diff -u --recursive --new-file v2.5.2/linux/arch/cris/mm/init.c linux/arch/cris/mm/init.c
--- v2.5.2/linux/arch/cris/mm/init.c	Thu Jul 26 15:10:06 2001
+++ linux/arch/cris/mm/init.c	Mon Jan 21 16:00:39 2002
@@ -7,6 +7,15 @@
  *  Authors:  Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: init.c,v $
+ *  Revision 1.2  2001/12/18 13:35:22  bjornw
+ *  Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ *  Revision 1.31  2001/11/13 16:22:00  bjornw
+ *  Skip calculating totalram and sharedram in si_meminfo
+ *
+ *  Revision 1.30  2001/11/12 19:02:10  pkj
+ *  Fixed compiler warnings.
+ *
  *  Revision 1.29  2001/07/25 16:09:50  bjornw
  *  val->sharedram will stay 0
  *
@@ -459,29 +468,18 @@
                 free_page(addr);
                 totalram_pages++;
         }
-        printk ("Freeing unused kernel memory: %dk freed\n", 
+        printk ("Freeing unused kernel memory: %luk freed\n", 
 		(&__init_end - &__init_begin) >> 10);
 }
 
 void 
 si_meminfo(struct sysinfo *val)
 {
-	int i;
-
-	i = max_mapnr;
-	val->totalram = 0;
-	val->sharedram = 0;
-	val->freeram = nr_free_pages();
-	val->bufferram = atomic_read(&buffermem_pages);
-	while (i-- > 0)  {
-		if (PageReserved(mem_map+i))
-			continue;
-		val->totalram++;
-		if (!atomic_read(&mem_map[i].count))
-			continue;
-		val->sharedram += atomic_read(&mem_map[i].count) - 1;
-	}
-	val->mem_unit = PAGE_SIZE;
-	val->totalhigh = 0;
-	val->freehigh = 0;
+        val->totalram = totalram_pages;
+        val->sharedram = 0;
+        val->freeram = nr_free_pages();
+        val->bufferram = atomic_read(&buffermem_pages);
+        val->totalhigh = 0;
+        val->freehigh = 0;
+        val->mem_unit = PAGE_SIZE;
 }
diff -u --recursive --new-file v2.5.2/linux/arch/cris/mm/tlb.c linux/arch/cris/mm/tlb.c
--- v2.5.2/linux/arch/cris/mm/tlb.c	Thu Jul 26 15:10:06 2001
+++ linux/arch/cris/mm/tlb.c	Tue Jan 15 10:56:35 2002
@@ -159,10 +159,11 @@
 /* invalidate a page range */
 
 void
-flush_tlb_range(struct mm_struct *mm, 
+flush_tlb_range(struct vm_area_struct *vma,
 		unsigned long start,
 		unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	int page_id = mm->context;
 	int i;
 	unsigned long flags;
diff -u --recursive --new-file v2.5.2/linux/arch/i386/Config.help linux/arch/i386/Config.help
--- v2.5.2/linux/arch/i386/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/Config.help	Fri Jan 25 16:04:31 2002
@@ -0,0 +1,892 @@
+CONFIG_SMP
+  This enables support for systems with more than one CPU. If you have
+  a system with only one CPU, like most personal computers, say N. If
+  you have a system with more than one CPU, say Y.
+
+  If you say N here, the kernel will run on single and multiprocessor
+  machines, but will use only one CPU of a multiprocessor machine. If
+  you say Y here, the kernel will run on many, but not all,
+  singleprocessor machines. On a singleprocessor machine, the kernel
+  will run faster if you say N here.
+
+  Note that if you say Y here and choose architecture "586" or
+  "Pentium" under "Processor family", the kernel will not work on 486
+  architectures. Similarly, multiprocessor kernels for the "PPro"
+  architecture may not work on all Pentium based boards.
+
+  People using multiprocessor machines who say Y here should also say
+  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+  Management" code will be disabled if you say Y here.
+
+  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-HOWTO available at
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you don't know what to do here, say N.
+
+CONFIG_X86
+  This is Linux's home port.  Linux was originally native to the Intel
+  386, and runs on all the later x86 processors including the Intel
+  486, 586, Pentiums, and various instruction-set-compatible chips by
+  AMD, Cyrix, and others.
+
+CONFIG_MULTIQUAD
+  This option is used for getting Linux to run on a (IBM/Sequent) NUMA 
+  multiquad box. This changes the way that processors are bootstrapped,
+  and uses Clustered Logical APIC addressing mode instead of Flat Logical.
+  You will need a new lynxer.elf file to flash your firmware with - send
+  email to Martin.Bligh@us.ibm.com
+
+CONFIG_X86_UP_IOAPIC
+  An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an
+  SMP-capable replacement for PC-style interrupt controllers. Most
+  SMP systems and a small number of uniprocessor systems have one.
+  If you have a single-CPU system with an IO-APIC, you can say Y here
+  to use it. If you say Y here even though your machine doesn't have
+  an IO-APIC, then the kernel will still run with no slowdown at all.
+
+  If you have a system with several CPUs, you do not need to say Y
+  here: the IO-APIC will be used automatically.
+
+CONFIG_X86_UP_APIC
+  A local APIC (Advanced Programmable Interrupt Controller) is an
+  integrated interrupt controller in the CPU. If you have a single-CPU
+  system which has a processor with a local APIC, you can say Y here to
+  enable and use it. If you say Y here even though your machine doesn't
+  have a local APIC, then the kernel will still run with no slowdown at
+  all. The local APIC supports CPU-generated self-interrupts (timer,
+  performance counters), and the NMI watchdog which detects hard lockups.
+
+  If you have a system with several CPUs, you do not need to say Y
+  here: the local APIC will be used automatically.
+
+CONFIG_MATH_EMULATION
+  Linux can emulate a math coprocessor (used for floating point
+  operations) if you don't have one. 486DX and Pentium processors have
+  a math coprocessor built in, 486SX and 386 do not, unless you added
+  a 487DX or 387, respectively. (The messages during boot time can
+  give you some hints here ["man dmesg"].) Everyone needs either a
+  coprocessor or this emulation.
+
+  If you don't have a math coprocessor, you need to say Y here; if you
+  say Y here even though you have a coprocessor, the coprocessor will
+  be used nevertheless. (This behavior can be changed with the kernel
+  command line option "no387", which comes handy if your coprocessor
+  is broken. Try "man bootparam" or see the documentation of your boot
+  loader (lilo or loadlin) about how to pass options to the kernel at
+  boot time.) This means that it is a good idea to say Y here if you
+  intend to use this kernel on different machines.
+
+  More information about the internals of the Linux math coprocessor
+  emulation can be found in <file:arch/i386/math-emu/README>.
+
+  If you are not sure, say Y; apart from resulting in a 66 KB bigger
+  kernel, it won't hurt.
+
+CONFIG_NOHIGHMEM
+  Linux can use up to 64 Gigabytes of physical memory on x86 systems.
+  However, the address space of 32-bit x86 processors is only 4
+  Gigabytes large. That means that, if you have a large amount of
+  physical memory, not all of it can be "permanently mapped" by the
+  kernel. The physical memory that's not permanently mapped is called
+  "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
+  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
+  by the kernel to permanently map as much physical memory as
+  possible.
+
+  If the machine has between 1 and 4 Gigabytes physical RAM, then
+  answer "4GB" here.
+
+  If more than 4 Gigabytes is used then answer "64GB" here. This
+  selection turns Intel PAE (Physical Address Extension) mode on.
+  PAE implements 3-level paging on IA32 processors. PAE is fully
+  supported by Linux, PAE mode is implemented on all recent Intel
+  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
+  kernel at boot time.)
+
+  If unsure, say "off".
+
+CONFIG_HIGHMEM4G
+  Select this if you have a 32-bit processor and between 1 and 4
+  gigabytes of physical RAM.
+
+CONFIG_HIGHMEM64G
+  Select this if you have a 32-bit processor and more than 4
+  gigabytes of physical RAM.
+
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_PCI
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_PCI_GOBIOS
+  On PCI systems, the BIOS can be used to detect the PCI devices and
+  determine their configuration. However, some old PCI motherboards
+  have BIOS bugs and may crash if this is done. Also, some embedded
+  PCI-based systems don't have any BIOS at all. Linux can also try to
+  detect the PCI hardware directly without using the BIOS.
+
+  With this option, you can specify how Linux should detect the PCI
+  devices. If you choose "BIOS", the BIOS will be used, if you choose
+  "Direct", the BIOS won't be used, and if you choose "Any", the
+  kernel will try the direct access method and falls back to the BIOS
+  if that doesn't work. If unsure, go with the default, which is
+  "Any".
+
+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
+  powered up and running.  The file system pcihpfs must be mounted
+  in order to interact with any PCI Hotplug controllers.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pci_hotplug.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+  When in doubt, say N.
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_VISWS
+  The SGI Visual Workstation series is an IA32-based workstation
+  based on SGI systems chips with some legacy PC hardware attached.
+  Say Y here to create a kernel to run on the SGI 320 or 540.
+  A kernel compiled for the Visual Workstation will not run on other
+  PC boards and vice versa.
+  See <file:Documentation/sgi-visws.txt> for more.
+
+CONFIG_HOTPLUG
+  Say Y here if you want to plug devices into your computer while
+  the system is running, and be able to use them quickly.  In many
+  cases, the devices can likewise be unplugged at any time too.
+
+  One well known example of this is PCMCIA- or PC-cards, credit-card
+  size devices such as network cards, modems or hard drives which are
+  plugged into slots found on all modern laptop computers.  Another
+  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.
+  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.
+
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+  computer.  These are credit-card size devices such as network cards,
+  modems or hard drives often used with laptops computers.  There are
+  actually two varieties of these cards: the older 16 bit PCMCIA cards
+  and the newer 32 bit CardBus cards.  If you want to use CardBus
+  cards, you need to say Y here and also to "CardBus support" below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  Please also read the PCMCIA-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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_KCORE_AOUT
+  Not necessary unless you're using a very out-of-date binutils
+  version.  You probably want KCORE_ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_AOUT
+  A.out (Assembler.OUTput) is a set of formats for libraries and
+  executables used in the earliest versions of UNIX. Linux used the
+  a.out formats QMAGIC and ZMAGIC until they were replaced with the
+  ELF format.
+
+  As more and more programs are converted to ELF, the use for a.out
+  will gradually diminish. If you disable this option it will reduce
+  your kernel by one page. This is not much and by itself does not
+  warrant removing support. However its removal is a good idea if you
+  wish to ensure that absolutely none of your programs will use this
+  older executable format. If you don't know what to answer at this
+  point then answer Y. If someone told you "You need a kernel with
+  QMAGIC support" then you'll have to say Y here. You may answer M to
+  compile a.out support as a module and later load the module when you
+  want to use a program or library in a.out format. The module will be
+  called binfmt_aout.o. Saying M or N here is dangerous though,
+  because some crucial programs on your system might still be in A.OUT
+  format.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_M386
+  This is the processor type of your CPU. This information is used for
+  optimizing purposes. In order to compile a kernel that can run on
+  all x86 CPU types (albeit not optimally fast), you can specify
+  "386" here.
+
+  The kernel will not necessarily run on earlier architectures than
+  the one you have chosen, e.g. a Pentium optimized kernel will run on
+  a PPro, but not necessarily on a i486.
+
+  Here are the settings recommended for greatest speed:
+   - "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI
+     486DLC/DLC2, UMC 486SX-S and NexGen Nx586.  Only "386" kernels
+     will run on a 386 class machine.
+   - "486" for the AMD/Cyrix/IBM/Intel 486DX/DX2/DX4 or
+     SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or U5S.
+   - "586" for generic Pentium CPUs, possibly lacking the TSC
+     (time stamp counter) register.
+   - "Pentium-Classic" for the Intel Pentium.
+   - "Pentium-MMX" for the Intel Pentium MMX.
+   - "Pentium-Pro" for the Intel Pentium Pro/Celeron/Pentium II.
+   - "Pentium-III" for the Intel Pentium III
+     and Celerons based on the Coppermine core.
+   - "Pentium-4" for the Intel Pentium 4.
+   - "K6" for the AMD K6, K6-II and K6-III (aka K6-3D).
+   - "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird).
+   - "Crusoe" for the Transmeta Crusoe series.
+   - "Winchip-C6" for original IDT Winchip.
+   - "Winchip-2" for IDT Winchip 2.
+   - "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
+   - "CyrixIII" for VIA Cyrix III or VIA C3.
+
+  If you don't know what to do, choose "386".
+
+CONFIG_M486
+  Select this for a x486 processor, ether Intel or one of the
+  compatible processors from AMD, Cyrix, IBM, or Intel.  Includes DX,
+  DX2, and DX4 variants; also SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or
+  U5S.
+
+CONFIG_M586
+  Select this for an x586 or x686 processor such as the AMD K5, the
+  Intel 5x86 or 6x86, or the Intel 6x86MX.  This choice does not
+  assume the RDTSC instruction.
+
+CONFIG_M586TSC
+  Select this for a Pentium Classic processor with the RDTSC (Read
+  Time Stamp Counter) instruction for benchmarking.
+
+CONFIG_VGA_CONSOLE
+  Saying Y here will allow you to use Linux in text mode through a
+  display that complies with the generic VGA standard. Virtually
+  everyone wants that.
+
+  The program SVGATextMode can be used to utilize SVGA video cards to
+  their full potential in text mode. Download it from
+  <ftp://ibiblio.org/pub/Linux/utils/console/>.
+
+  Say Y.
+
+CONFIG_VIDEO_SELECT
+  This enables support for text mode selection on kernel startup. If
+  you want to take advantage of some high-resolution text mode your
+  card's BIOS offers, but the traditional Linux utilities like
+  SVGATextMode don't, you can say Y here and set the mode using the
+  "vga=" option from your boot loader (lilo or loadlin) or set
+  "vga=ask" which brings up a video mode menu on kernel startup. (Try
+  "man bootparam" or see the documentation of your boot loader about
+  how to pass options to the kernel.)
+
+  Read the file <file:Documentation/svga.txt> for more information
+  about the Video mode selection support. If unsure, say N.
+
+CONFIG_MDA_CONSOLE
+  Say Y here if you have an old MDA or monochrome Hercules graphics
+  adapter in your system acting as a second head ( = video card). You
+  will then be able to use two monitors with your Linux system. Do not
+  say Y here if your MDA card is the primary card in your system; the
+  normal VGA driver will handle it.
+
+  This driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want).
+  The module will be called mdacon.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+  If unsure, say N.
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_CD_NO_IDESCSI
+  If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y
+  here, otherwise N. Read the CD-ROM-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about these CD-ROM drives. If you are unsure what you
+  have, say Y and find out whether you have one of the following
+  drives.
+
+  For each of these drivers, a file Documentation/cdrom/{driver_name}
+  exists. Especially in cases where you do not know exactly which kind
+  of drive you have you should read there. Most of these drivers use a
+  file drivers/cdrom/{driver_name}.h where you can define your
+  interface parameters and switch some internal goodies.
+
+  All these CD-ROM drivers are also usable as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want). If you want to compile them as module, say M instead of Y and
+  read <file:Documentation/modules.txt>.
+
+  If you want to use any of these CD-ROM drivers, you also have to
+  answer Y or M to "ISO 9660 CD-ROM file system support" below (this
+  answer will get "defaulted" for you if you enable any of the Linux
+  CD-ROM drivers).
+
+CONFIG_MTRR
+  On Intel P6 family processors (Pentium Pro, Pentium II and later)
+  the Memory Type Range Registers (MTRRs) may be used to control
+  processor access to memory ranges. This is most useful if you have
+  a video (VGA) card on a PCI or AGP bus. Enabling write-combining
+  allows bus write transfers to be combined into a larger transfer
+  before bursting over the PCI/AGP bus. This can increase performance
+  of image write operations 2.5 times or more. Saying Y here creates a
+  /proc/mtrr file which may be used to manipulate your processor's
+  MTRRs. Typically the X server should use this.
+
+  This code has a reasonably generic interface so that similar
+  control registers on other processors can be easily supported
+  as well:
+
+  The Cyrix 6x86, 6x86MX and M II processors have Address Range
+  Registers (ARRs) which provide a similar functionality to MTRRs. For
+  these, the ARRs are used to emulate the MTRRs.
+  The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
+  MTRRs. The Centaur C6 (WinChip) has 8 MCRs, allowing
+  write-combining. All of these processors are supported by this code
+  and it makes sense to say Y here if you have one of them.
+
+  Saying Y here also fixes a problem with buggy SMP BIOSes which only
+  set the MTRRs for the boot CPU and not for the secondary CPUs. This
+  can lead to all sorts of problems, so it's good to say Y here.
+
+  You can safely say Y even if your machine doesn't have MTRRs, you'll
+  just add about 9 KB to your kernel.
+
+  See <file:Documentation/mtrr.txt> for more information.
+
+CONFIG_PM
+  "Power Management" means that parts of your computer are shut
+  off or put into a power conserving "sleep" mode if they are not
+  being used.  There are two competing standards for doing this: APM
+  and ACPI.  If you want to use either one, say Y here and then also
+  to the requisite support below.
+
+  Power Management is most important for battery powered laptop
+  computers; if you have a laptop, check out the Linux Laptop home
+  page on the WWW at
+  <http://www.cs.utexas.edu/users/kharker/linux-laptop/> and the
+  Battery Powered Linux mini-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that, even if you say N here, Linux on the x86 architecture
+  will issue the hlt instruction if nothing is to be done, thereby
+  sending the processor to sleep and saving power.
+
+CONFIG_ACPI
+  ACPI/OSPM support for Linux is currently under development. As such,
+  this support is preliminary and EXPERIMENTAL.  Configuring ACPI
+  support enables kernel interfaces that allow higher level software
+  (OSPM) to manipulate ACPI defined hardware and software interfaces,
+  including the evaluation of ACPI control methods.  If unsure, choose
+  N here.  Note, this option will enlarge your kernel by about 120K.
+
+  This support requires an ACPI compliant platform (hardware/firmware).
+  If both ACPI and Advanced Power Management (APM) support are
+  configured, whichever is loaded first shall be used.
+
+  This code DOES NOT currently provide a complete OSPM implementation
+  -- it has not yet reached APM's level of functionality.  When fully
+  implemented, Linux ACPI/OSPM will provide a more robust functional
+  replacement for legacy configuration and power management
+  interfaces, including the Plug-and-Play BIOS specification (PnP
+  BIOS), the Multi-Processor Specification (MPS), and the Advanced
+  Power Management specification (APM).
+
+  Linux support for ACPI/OSPM is based on Intel Corporation's ACPI
+  Component Architecture (ACPI CA). The latest ACPI CA source code,
+  documentation, debug builds, and implementation status information
+  can be downloaded from:
+  <http://developer.intel.com/technology/iapc/acpi/downloads.htm>.
+
+  The ACPI Sourceforge project may also be of interest:
+  <http://sf.net/projects/acpi/>
+
+CONFIG_APM
+  APM is a BIOS specification for saving power using several different
+  techniques. This is mostly useful for battery powered laptops with
+  APM compliant BIOSes. If you say Y here, the system time will be
+  reset after a RESUME operation, the /proc/apm device will provide
+  battery status information, and user-space programs will receive
+  notification of APM "events" (e.g. battery status change).
+
+  If you select "Y" here, you can disable actual use of the APM
+  BIOS by passing the "apm=off" option to the kernel at boot time.
+
+  Note that the APM support is almost completely disabled for
+  machines with more than one CPU.
+
+  In order to use APM, you will need supporting software. For location
+  and more information, read <file:Documentation/pm.txt> and the
+  Battery Powered Linux mini-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver does not spin down disk drives (see the hdparm(8)
+  manpage ("man 8 hdparm") for that), and it doesn't turn off
+  VESA-compliant "green" monitors.
+
+  This driver does not support the TI 4000M TravelMate and the ACER
+  486/DX4/75 because they don't have compliant BIOSes. Many "green"
+  desktop machines also don't have compliant BIOSes, and this driver
+  may cause those machines to panic during the boot phase.
+
+  Generally, if you don't have a battery in your machine, there isn't
+  much point in using this driver and you should say N. If you get
+  random kernel OOPSes or reboots that don't seem to be related to
+  anything, try disabling/enabling this option (or disabling/enabling
+  APM in your BIOS).
+
+  Some other things you should try when experiencing seemingly random,
+  "weird" problems:
+
+   1) make sure that you have enough swap space and that it is
+      enabled.
+   2) pass the "no-hlt" option to the kernel
+   3) switch on floating point emulation in the kernel and pass
+      the "no387" option to the kernel
+   4) pass the "floppy=nodma" option to the kernel
+   5) pass the "mem=4M" option to the kernel (thereby disabling
+      all but the first 4 MB of RAM)
+   6) make sure that the CPU is not over clocked.
+   7) read the sig11 FAQ at <http://www.bitwizard.nl/sig11/>
+   8) disable the cache from your BIOS settings
+   9) install a fan for the video card or exchange video RAM
+   10) install a better fan for the CPU
+   11) exchange RAM chips
+   12) exchange the motherboard.
+
+  To compile this driver as a module ( = code which can be inserted in
+  and removed from the running kernel whenever you want), say M here
+  and read <file:Documentation/modules.txt>. The module will be called
+  apm.o.
+
+CONFIG_APM_IGNORE_USER_SUSPEND
+  This option will ignore USER SUSPEND requests. On machines with a
+  compliant APM BIOS, you want to say N. However, on the NEC Versa M
+  series notebooks, it is necessary to say Y because of a BIOS bug.
+
+CONFIG_APM_DO_ENABLE
+  Enable APM features at boot time. From page 36 of the APM BIOS
+  specification: "When disabled, the APM BIOS does not automatically
+  power manage devices, enter the Standby State, enter the Suspend
+  State, or take power saving steps in response to CPU Idle calls."
+  This driver will make CPU Idle calls when Linux is idle (unless this
+  feature is turned off -- see "Do CPU IDLE calls", below). This
+  should always save battery power, but more complicated APM features
+  will be dependent on your BIOS implementation. You may need to turn
+  this option off if your computer hangs at boot time when using APM
+  support, or if it beeps continuously instead of suspending. Turn
+  this off if you have a NEC UltraLite Versa 33/C or a Toshiba
+  T400CDT. This is off by default since most machines do fine without
+  this feature.
+
+CONFIG_APM_CPU_IDLE
+  Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop.
+  On some machines, this can activate improved power savings, such as
+  a slowed CPU clock rate, when the machine is idle. These idle calls
+  are made after the idle loop has run for some length of time (e.g.,
+  333 mS). On some machines, this will cause a hang at boot time or
+  whenever the CPU becomes idle. (On machines with more than one CPU,
+  this option does nothing.)
+
+CONFIG_APM_DISPLAY_BLANK
+  Enable console blanking using the APM. Some laptops can use this to
+  turn off the LCD backlight when the screen blanker of the Linux
+  virtual console blanks the screen. Note that this is only used by
+  the virtual console screen blanker, and won't turn off the backlight
+  when using the X Window system. This also doesn't have anything to
+  do with your VESA-compliant power-saving monitor. Further, this
+  option doesn't work for all laptops -- it might not turn off your
+  backlight at all, or it might print a lot of errors to the console,
+  especially if you are using gpm.
+
+CONFIG_APM_RTC_IS_GMT
+  Say Y here if your RTC (Real Time Clock a.k.a. hardware clock)
+  stores the time in GMT (Greenwich Mean Time). Say N if your RTC
+  stores localtime.
+
+  It is in fact recommended to store GMT in your RTC, because then you
+  don't have to worry about daylight savings time changes. The only
+  reason not to use GMT in your RTC is if you also run a broken OS
+  that doesn't understand GMT.
+
+CONFIG_APM_ALLOW_INTS
+  Normally we disable external interrupts while we are making calls to
+  the APM BIOS as a measure to lessen the effects of a badly behaving
+  BIOS implementation.  The BIOS should reenable interrupts if it
+  needs to.  Unfortunately, some BIOSes do not -- especially those in
+  many of the newer IBM Thinkpads.  If you experience hangs when you
+  suspend, try setting this to Y.  Otherwise, say N.
+
+CONFIG_APM_REAL_MODE_POWER_OFF
+  Use real mode APM BIOS calls to switch off the computer. This is
+  a work-around for a number of buggy BIOSes. Switch this option on if
+  your computer crashes instead of powering off properly.
+
+CONFIG_TOSHIBA
+  This adds a driver to safely access the System Management Mode of
+  the CPU on Toshiba portables with a genuine Toshiba BIOS. It does
+  not work on models with a Pheonix BIOS. The System Management Mode
+  is used to set the BIOS and power saving options on Toshiba portables.
+
+  For information on utilities to make use of this driver see the
+  Toshiba Linux utilities web site at:
+  <http://www.buzzard.org.uk/toshiba/>.
+
+  Say Y if you intend to run this kernel on a Toshiba portable.
+  Say N otherwise.
+
+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/>
+
+  Say Y if you intend to run this kernel on a Dell Inspiron 8000.
+  Say N otherwise.
+
+CONFIG_MICROCODE
+  If you say Y here and also to "/dev file system support" in the
+  'File systems' section, you will be able to update the microcode on
+  Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II,
+  Pentium III, Pentium 4, Xeon etc.  You will obviously need the
+  actual microcode binary data itself which is not shipped with the
+  Linux kernel.
+
+  For latest news and information on obtaining all the required
+  ingredients for this driver, check:
+  <http://www.urbanmyth.org/microcode/>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called microcode.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.  If
+  you use modprobe or kmod you may also want to add the line
+  'alias char-major-10-184 microcode' to your /etc/modules.conf file.
+
+CONFIG_X86_MSR
+  This device gives privileged processes access to the x86
+  Model-Specific Registers (MSRs).  It is a character device with
+  major 202 and minors 0 to 31 for /dev/cpu/0/msr to /dev/cpu/31/msr.
+  MSR accesses are directed to a specific CPU on multi-processor
+  systems.
+
+CONFIG_X86_CPUID
+  This device gives processes access to the x86 CPUID instruction to
+  be executed on a specific processor.  It is a character device
+  with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to
+  /dev/cpu/31/cpuid.
+
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y.  Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. General information about
+  the modular sound system is contained in the files
+  <file:Documentation/sound/Introduction>.  The file
+  <file:Documentation/sound/README.OSS> contains some slightly
+  outdated but still useful information as well.
+
+  If you have a PnP sound card and you want to configure it at boot
+  time using the ISA PnP tools (read
+  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished.  To do
+  this, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/sound/README.modules>; the module will be
+  called soundcore.o.
+
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and supporting utilities to do that are in the pcsp
+  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_ISDN
+  ISDN ("Integrated Services Digital Networks", called RNIS in France)
+  is a special type of fully digital telephone service; it's mostly
+  used to connect to your Internet service provider (with SLIP or
+  PPP).  The main advantage is that the speed is higher than ordinary
+  modem/telephone connections, and that you can have voice
+  conversations while downloading stuff.  It only works if your
+  computer is equipped with an ISDN card and both you and your service
+  provider purchased an ISDN line from the phone company.  For
+  details, read <http://alumni.caltech.edu/~dank/isdn/> on the WWW.
+
+  This driver allows you to use an ISDN-card for networking
+  connections and as dialin/out device.  The isdn-tty's have a built
+  in AT-compatible modem emulator.  Network devices support autodial,
+  channel-bundling, callback and caller-authentication without having
+  a daemon running.  A reduced T.70 protocol is supported with tty's
+  suitable for German BTX.  On D-Channel, the protocols EDSS1
+  (Euro-ISDN) and 1TR6 (German style) are supported.  See
+  <file:Documentation/isdn/README> for more information.
+
+  If you want to compile the ISDN code 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 isdn.o. If unsure, say N.
+
+CONFIG_DEBUG_HIGHMEM
+  This options enables addition error checking for high memory systems.
+  Disable for production systems.
+
+CONFIG_DEBUG_KERNEL
+  Say Y here if you are developing drivers or trying to debug and
+  identify kernel problems.
+
+CONFIG_DEBUG_SLAB
+  Say Y here to have the kernel do limited verification on memory
+  allocation as well as poisoning memory on free to catch use of freed
+  memory.
+
+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()
+  calls are forgotten.  Memory mapped I/O will go through an extra
+  check to catch access to unmapped ISA addresses, an access method
+  that can still be used by old drivers that are being ported from
+  2.0/2.2.
+
+CONFIG_DEBUG_SPINLOCK
+  Say Y here and build SMP to catch missing spinlock initialization
+  and certain other kinds of spinlock errors commonly made.  This is
+  best used in conjunction with the NMI watchdog so that spinlock
+  deadlocks are also debuggable.
+
+CONFIG_DEBUG_BUGVERBOSE
+  Say Y here to make BUG() panics output the file name and line number
+  of the BUG call as well as the EIP and oops trace.  This aids
+  debugging but costs about 70-100K of memory.
+
diff -u --recursive --new-file v2.5.2/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.5.2/linux/arch/i386/boot/setup.S	Tue Dec 18 14:56:34 2001
+++ linux/arch/i386/boot/setup.S	Thu Jan 24 11:06:16 2002
@@ -50,7 +50,8 @@
 #include <linux/compile.h>
 #include <asm/boot.h>
 #include <asm/e820.h>
-
+#include <asm/page.h>
+	
 /* Signature words to ensure LILO loaded us right */
 #define SIG1	0xAA55
 #define SIG2	0x5A5A
@@ -79,7 +80,7 @@
 # This is the setup header, and it must start at %cs:2 (old 0x9020:2)
 
 		.ascii	"HdrS"		# header signature
-		.word	0x0202		# header version number (>= 0x0105)
+		.word	0x0203		# header version number (>= 0x0105)
 					# or else old loadlin-1.5 will fail)
 realmode_swtch:	.word	0, 0		# default_switch, SETUPSEG
 start_sys_seg:	.word	SYSSEG
@@ -152,6 +153,10 @@
 					# 0x90000 segment; the setup
 					# can be located anywhere in
 					# low memory 0x10000 or higher.
+
+ramdisk_max:	.long __MAXMEM-1	# (Header version 0x0203 or later)
+					# The highest safe address for
+					# the contents of an initrd
 
 trampoline:	call	start_of_setup
 		.space	1024
diff -u --recursive --new-file v2.5.2/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.5.2/linux/arch/i386/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/i386/config.in	Thu Jan 24 12:18:54 2002
@@ -10,19 +10,7 @@
 
 define_bool CONFIG_UID16 y
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'Processor type and features'
@@ -198,9 +186,7 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'General setup'
-
-bool 'Networking support' CONFIG_NET
+comment 'General options'
 
 # Visual Workstation support is utterly broken.
 # If you want to see it working mail an VW540 to hch@infradead.org 8)
@@ -249,9 +235,6 @@
    define_bool CONFIG_HOTPLUG_PCI n
 fi
 
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
 if [ "$CONFIG_PROC_FS" = "y" ]; then
    choice 'Kernel core (/proc/kcore) format' \
 	"ELF		CONFIG_KCORE_ELF	\
diff -u --recursive --new-file v2.5.2/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.5.2/linux/arch/i386/defconfig	Mon Jan 14 18:25:08 2002
+++ linux/arch/i386/defconfig	Tue Jan 29 21:35:08 2002
@@ -7,6 +7,14 @@
 CONFIG_UID16=y
 
 #
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
 # Code maturity level options
 #
 # CONFIG_EXPERIMENTAL is not set
@@ -64,9 +72,8 @@
 CONFIG_HAVE_DEC_LOCK=y
 
 #
-# General setup
+# General options
 #
-CONFIG_NET=y
 CONFIG_X86_IO_APIC=y
 CONFIG_X86_LOCAL_APIC=y
 CONFIG_PCI=y
@@ -95,9 +102,6 @@
 # CONFIG_HOTPLUG_PCI is not set
 # CONFIG_HOTPLUG_PCI_COMPAQ is not set
 # CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
 CONFIG_BINFMT_AOUT=y
@@ -154,7 +158,7 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK is not set
+# CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
@@ -205,6 +209,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -219,6 +224,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+CONFIG_IDE_TASK_IOCTL=y
 
 #
 # IDE chipset support/bugfixes
@@ -230,12 +236,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -252,6 +261,7 @@
 CONFIG_PIIX_TUNING=y
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC_ADMA is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
 # CONFIG_PDC202XX_BURST is not set
 # CONFIG_PDC202XX_FORCE is not set
@@ -485,8 +495,6 @@
 # CONFIG_PCMCIA_XIRTULIP is not set
 CONFIG_NET_PCMCIA_RADIO=y
 CONFIG_PCMCIA_RAYCS=y
-# CONFIG_PCMCIA_NETWAVE is not set
-# CONFIG_PCMCIA_WAVELAN is not set
 # CONFIG_AIRONET4500_CS is not set
 
 #
@@ -673,7 +681,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -732,6 +739,7 @@
 # USB Host Controller Drivers
 #
 # CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
 CONFIG_USB_UHCI_ALT=y
 # CONFIG_USB_OHCI is not set
 
@@ -837,3 +845,5 @@
 # Library routines
 #
 # CONFIG_CRC32 is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c
--- v2.5.2/linux/arch/i386/kernel/apic.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/i386/kernel/apic.c	Mon Jan 28 13:12:04 2002
@@ -88,8 +88,12 @@
 		apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
 	if (maxlvt >= 4)
 		apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
-	apic_write(APIC_ESR, 0);
-	v = apic_read(APIC_ESR);
+	v = GET_APIC_VERSION(apic_read(APIC_LVR));
+	if (APIC_INTEGRATED(v)) {	/* !82489DX */
+		if (maxlvt > 3)
+			apic_write(APIC_ESR, 0);
+		apic_read(APIC_ESR);
+	}
 }
 
 void __init connect_bsp_APIC(void)
@@ -918,6 +922,26 @@
 	smp_call_function(setup_APIC_timer, (void *)calibration_result, 1, 1);
 }
 
+void __init disable_APIC_timer(void)
+{
+	if (using_apic_timer) {
+		unsigned long v;
+
+		v = apic_read(APIC_LVTT);
+		apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
+	}
+}
+
+void enable_APIC_timer(void)
+{
+	if (using_apic_timer) {
+		unsigned long v;
+
+		v = apic_read(APIC_LVTT);
+		apic_write_around(APIC_LVTT, v & ~APIC_LVT_MASKED);
+	}
+}
+
 /*
  * the frequency of the profiling timer can be changed
  * by writing a multiplier value into /proc/profile.
@@ -1014,7 +1038,7 @@
  */
 unsigned int apic_timer_irqs [NR_CPUS];
 
-void smp_apic_timer_interrupt(struct pt_regs * regs)
+void smp_apic_timer_interrupt(struct pt_regs regs)
 {
 	int cpu = smp_processor_id();
 
@@ -1034,7 +1058,7 @@
 	 * interrupt lock, which is the WrongThing (tm) to do.
 	 */
 	irq_enter(cpu, 0);
-	smp_local_timer_interrupt(regs);
+	smp_local_timer_interrupt(&regs);
 	irq_exit(cpu, 0);
 
 	if (softirq_pending(cpu))
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- v2.5.2/linux/arch/i386/kernel/apm.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/i386/kernel/apm.c	Tue Jan 15 13:53:50 2002
@@ -766,14 +766,14 @@
 
 	start_idle = jiffies;
 	while (1) {
-		if (!current->need_resched) {
+		if (!need_resched()) {
 			if (jiffies - start_idle < HARD_IDLE_TIMEOUT) {
 				if (!current_cpu_data.hlt_works_ok)
 					continue;
 				if (hlt_counter)
 					continue;
 				__cli();
-				if (!current->need_resched)
+				if (!need_resched())
 					safe_halt();
 				else
 					__sti();
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/bluesmoke.c linux/arch/i386/kernel/bluesmoke.c
--- v2.5.2/linux/arch/i386/kernel/bluesmoke.c	Mon Nov 12 09:59:43 2001
+++ linux/arch/i386/kernel/bluesmoke.c	Tue Jan 29 10:31:17 2002
@@ -47,7 +47,7 @@
 			{
 				rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
 				printk(" at %08x%08x", 
-					high, low);
+					ahigh, alow);
 			}
 			printk("\n");
 			/* Clear it */
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.5.2/linux/arch/i386/kernel/entry.S	Fri Nov  2 17:18:49 2001
+++ linux/arch/i386/kernel/entry.S	Tue Jan 29 18:50:30 2002
@@ -72,12 +72,15 @@
  */
 state		=  0
 flags		=  4
-sigpending	=  8
+work		=  8
+need_resched	= work+0
+syscall_trace	= work+1
+sigpending	= work+2
+notify_resume	= work+3
 addr_limit	= 12
 exec_domain	= 16
-need_resched	= 20
 tsk_ptrace	= 24
-processor	= 52
+cpu		= 32
 
 ENOSYS = 38
 
@@ -151,7 +154,7 @@
 	call *%edx
 	addl $4, %esp
 	popl %eax
-	jmp ret_from_sys_call
+	jmp resume_userspace
 
 ENTRY(lcall27)
 	pushfl			# We get a different stack layout with call gates,
@@ -172,7 +175,7 @@
 	call *%edx
 	addl $4, %esp
 	popl %eax
-	jmp ret_from_sys_call
+	jmp resume_userspace
 
 
 ENTRY(ret_from_fork)
@@ -180,9 +183,7 @@
 	call SYMBOL_NAME(schedule_tail)
 	addl $4, %esp
 	GET_CURRENT(%ebx)
-	testb $0x02,tsk_ptrace(%ebx)	# PT_TRACESYS
-	jne tracesys_exit
-	jmp	ret_from_sys_call
+	jmp syscall_exit
 
 /*
  * Return to user mode is not as complex as all this looks,
@@ -191,73 +192,105 @@
  * less clear than it otherwise should be.
  */
 
+	# userspace resumption stub bypassing syscall exit tracing
+	ALIGN
+ENTRY(ret_from_intr)
+	GET_CURRENT(%ebx)
+ret_from_exception:
+	movl EFLAGS(%esp),%eax		# mix EFLAGS and CS
+	movb CS(%esp),%al
+	testl $(VM_MASK | 3),%eax
+	jz restore_all			# returning to kernel-space or vm86-space
+ENTRY(resume_userspace)
+	cli				# make sure need_resched and sigpending don't change
+					# between sampling and the iret
+	movl work(%ebx),%ecx
+	andl $0xffff00ff,%ecx		# current->work (ignoring syscall_trace)
+	jne work_pending
+	jmp restore_all
+
+	# system call handler stub
+	ALIGN
 ENTRY(system_call)
 	pushl %eax			# save orig_eax
 	SAVE_ALL
 	GET_CURRENT(%ebx)
-	testb $0x02,tsk_ptrace(%ebx)	# PT_TRACESYS
-	jne tracesys
 	cmpl $(NR_syscalls),%eax
-	jae badsys
+	jae syscall_badsys
+	testb $0xff,syscall_trace(%ebx)	# system call tracing in operation
+	jnz syscall_trace_entry
+syscall_traced:
 	call *SYMBOL_NAME(sys_call_table)(,%eax,4)
-	movl %eax,EAX(%esp)		# save the return value
-ENTRY(ret_from_sys_call)
-	cli				# need_resched and signals atomic test
-	cmpl $0,need_resched(%ebx)
-	jne reschedule
-	cmpl $0,sigpending(%ebx)
-	jne signal_return
+	movl %eax,EAX(%esp)		# store the return value
+syscall_exit:
+	cli				# make sure need_resched and sigpending don't change
+					# between sampling and the iret
+	movl work(%ebx),%ecx
+	testl %ecx,%ecx			# current->work
+	jne syscall_exit_work
 restore_all:
 	RESTORE_ALL
 
+	# perform work that needs to be done immediately before resumption
 	ALIGN
-signal_return:
-	sti				# we can get here from an interrupt handler
+work_pending:
+	testb %cl,%cl			# current->work.need_resched
+	jz work_notifysig
+work_resched:
+	call SYMBOL_NAME(schedule)
+	cli				# make sure need_resched and sigpending don't change
+					# between sampling and the iret
+	movl work(%ebx),%ecx
+	andl $0xffff00ff,%ecx		# ignore the syscall trace counter
+	jz restore_all
+	testb %cl,%cl			# current->work.need_resched
+	jnz work_resched
+
+work_notifysig:				# deal with pending signals and notify-resume requests
 	testl $(VM_MASK),EFLAGS(%esp)
 	movl %esp,%eax
-	jne v86_signal_return
+	jne work_notifysig_v86		# returning to kernel-space or vm86-space
 	xorl %edx,%edx
-	call SYMBOL_NAME(do_signal)
+	call SYMBOL_NAME(do_notify_resume)
 	jmp restore_all
 
 	ALIGN
-v86_signal_return:
+work_notifysig_v86:
+	pushl %ecx
 	call SYMBOL_NAME(save_v86_state)
+	popl %ecx
 	movl %eax,%esp
 	xorl %edx,%edx
-	call SYMBOL_NAME(do_signal)
+	call SYMBOL_NAME(do_notify_resume)
 	jmp restore_all
 
+	# perform syscall exit tracing
 	ALIGN
-tracesys:
+syscall_trace_entry:
 	movl $-ENOSYS,EAX(%esp)
-	call SYMBOL_NAME(syscall_trace)
+	movl %esp,%eax
+	xorl %edx,%edx
+	call SYMBOL_NAME(do_syscall_trace)
 	movl ORIG_EAX(%esp),%eax
 	cmpl $(NR_syscalls),%eax
-	jae tracesys_exit
-	call *SYMBOL_NAME(sys_call_table)(,%eax,4)
-	movl %eax,EAX(%esp)		# save the return value
-tracesys_exit:
-	call SYMBOL_NAME(syscall_trace)
-	jmp ret_from_sys_call
-badsys:
-	movl $-ENOSYS,EAX(%esp)
-	jmp ret_from_sys_call
+	jnae syscall_traced
+	jmp syscall_exit
 
+	# perform syscall exit tracing
 	ALIGN
-ENTRY(ret_from_intr)
-	GET_CURRENT(%ebx)
-ret_from_exception:
-	movl EFLAGS(%esp),%eax		# mix EFLAGS and CS
-	movb CS(%esp),%al
-	testl $(VM_MASK | 3),%eax	# return to VM86 mode or non-supervisor?
-	jne ret_from_sys_call
-	jmp restore_all
+syscall_exit_work:
+	testb %ch,%ch			# current->work.syscall_trace
+	jz work_pending
+	sti				# could let do_syscall_trace() call schedule() instead
+	movl %esp,%eax
+	movl $1,%edx
+	call SYMBOL_NAME(do_syscall_trace)
+	jmp resume_userspace
 
 	ALIGN
-reschedule:
-	call SYMBOL_NAME(schedule)    # test
-	jmp ret_from_sys_call
+syscall_badsys:
+	movl $-ENOSYS,EAX(%esp)
+	jmp resume_userspace
 
 ENTRY(divide_error)
 	pushl $0		# no error code
@@ -622,6 +655,18 @@
 	.long SYMBOL_NAME(sys_ni_syscall)	/* Reserved for Security */
 	.long SYMBOL_NAME(sys_gettid)
 	.long SYMBOL_NAME(sys_readahead)	/* 225 */
+	.long SYMBOL_NAME(sys_setxattr)
+	.long SYMBOL_NAME(sys_lsetxattr)
+	.long SYMBOL_NAME(sys_fsetxattr)
+	.long SYMBOL_NAME(sys_getxattr)
+	.long SYMBOL_NAME(sys_lgetxattr)	/* 230 */
+	.long SYMBOL_NAME(sys_fgetxattr)
+	.long SYMBOL_NAME(sys_listxattr)
+	.long SYMBOL_NAME(sys_llistxattr)
+	.long SYMBOL_NAME(sys_flistxattr)
+	.long SYMBOL_NAME(sys_removexattr)	/* 235 */
+	.long SYMBOL_NAME(sys_lremovexattr)
+	.long SYMBOL_NAME(sys_fremovexattr)
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.5.2/linux/arch/i386/kernel/head.S	Wed Jun 20 11:00:53 2001
+++ linux/arch/i386/kernel/head.S	Tue Jan 29 18:24:01 2002
@@ -445,6 +445,16 @@
 	.quad 0x00409a0000000000	/* 0x48 APM CS    code */
 	.quad 0x00009a0000000000	/* 0x50 APM CS 16 code (16 bit) */
 	.quad 0x0040920000000000	/* 0x58 APM DS    data */
+	/* Segments used for calling PnP BIOS */
+	.quad 0x00c09a0000000000	/* 0x60 32-bit code */
+	.quad 0x00809a0000000000	/* 0x68 16-bit code */
+	.quad 0x0080920000000000	/* 0x70 16-bit data */
+	.quad 0x0080920000000000	/* 0x78 16-bit data */
+	.quad 0x0080920000000000	/* 0x80 16-bit data */
+	.quad 0x0000000000000000	/* 0x88 not used */
+	.quad 0x0000000000000000	/* 0x90 not used */
+	.quad 0x0000000000000000	/* 0x98 not used */
+	/* Per CPU segments */
 	.fill NR_CPUS*4,8,0		/* space for TSS's and LDT's */
 		
 /*
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/i8259.c linux/arch/i386/kernel/i8259.c
--- v2.5.2/linux/arch/i386/kernel/i8259.c	Mon Sep 17 23:03:09 2001
+++ linux/arch/i386/kernel/i8259.c	Wed Jan 23 23:54:01 2002
@@ -79,6 +79,7 @@
  * through the ICC by us (IPIs)
  */
 #ifdef CONFIG_SMP
+BUILD_SMP_INTERRUPT(task_migration_interrupt,TASK_MIGRATION_VECTOR)
 BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
 BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR)
 BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
@@ -92,7 +93,7 @@
  * a much simpler SMP time architecture:
  */
 #ifdef CONFIG_X86_LOCAL_APIC
-BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
+BUILD_SMP_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
 BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
 BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
 #endif
@@ -472,6 +473,9 @@
 	 * IPI, driven by wakeup.
 	 */
 	set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
+
+	/* IPI for task migration */
+	set_intr_gate(TASK_MIGRATION_VECTOR, task_migration_interrupt);
 
 	/* IPI for invalidation */
 	set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/init_task.c linux/arch/i386/kernel/init_task.c
--- v2.5.2/linux/arch/i386/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/i386/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,6 +1,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c
--- v2.5.2/linux/arch/i386/kernel/mca.c	Thu Aug 24 12:52:32 2000
+++ linux/arch/i386/kernel/mca.c	Wed Jan 23 10:54:42 2002
@@ -311,6 +311,8 @@
 #endif
 }
 
+subsys_initcall(mca_init);
+
 /*--------------------------------------------------------------------*/
 
 static void mca_handle_nmi_slot(int slot, int check_flag)
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.5.2/linux/arch/i386/kernel/mtrr.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/i386/kernel/mtrr.c	Thu Jan 24 13:36:29 2002
@@ -378,10 +378,8 @@
 static int arr3_protected;
 
 /*  Put the processor into a state where MTRRs can be safely set  */
-static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
+static void set_mtrr_prepare_save (struct set_mtrr_context *ctxt)
 {
-    unsigned long tmp;
-
     /*  Disable interrupts locally  */
     __save_flags (ctxt->flags); __cli ();
 
@@ -404,16 +402,27 @@
     }
 
     if ( mtrr_if == MTRR_IF_INTEL ) {
-	/*  Disable MTRRs, and set the default type to uncached  */
+	/*  Save MTRR state */
 	rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+    } else {
+	/* Cyrix ARRs - everything else were excluded at the top */
+	ctxt->ccr3 = getCx86 (CX86_CCR3);
+    }
+}   /*  End Function set_mtrr_prepare_save  */
+
+static void set_mtrr_cache_disable (struct set_mtrr_context *ctxt)
+{
+    if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR )
+	 return;
+
+    if ( mtrr_if == MTRR_IF_INTEL ) {
+	/*  Disable MTRRs, and set the default type to uncached  */
 	wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
     } else {
 	/* Cyrix ARRs - everything else were excluded at the top */
-	tmp = getCx86 (CX86_CCR3);
-	setCx86 (CX86_CCR3, (tmp & 0x0f) | 0x10);
-	ctxt->ccr3 = tmp;
+	setCx86 (CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10);
     }
-}   /*  End Function set_mtrr_prepare  */
+}   /*  End Function set_mtrr_cache_disable  */
 
 /*  Restore the processor after a set_mtrr_prepare  */
 static void set_mtrr_done (struct set_mtrr_context *ctxt)
@@ -674,7 +683,10 @@
 {
     struct set_mtrr_context ctxt;
 
-    if (do_safe) set_mtrr_prepare (&ctxt);
+    if (do_safe) {
+	set_mtrr_prepare_save (&ctxt);
+	set_mtrr_cache_disable (&ctxt);
+	}
     if (size == 0)
     {
 	/* The invalid bit is kept in the mask, so we simply clear the
@@ -726,7 +738,10 @@
 	}
     }
 
-    if (do_safe) set_mtrr_prepare (&ctxt);
+    if (do_safe) {
+	set_mtrr_prepare_save (&ctxt);
+	set_mtrr_cache_disable (&ctxt);
+    }
     base <<= PAGE_SHIFT;
     setCx86(arr,    ((unsigned char *) &base)[3]);
     setCx86(arr+1,  ((unsigned char *) &base)[2]);
@@ -750,7 +765,10 @@
     u32 regs[2];
     struct set_mtrr_context ctxt;
 
-    if (do_safe) set_mtrr_prepare (&ctxt);
+    if (do_safe) {
+	set_mtrr_prepare_save (&ctxt);
+	set_mtrr_cache_disable (&ctxt);
+    }
     /*
      *	Low is MTRR0 , High MTRR 1
      */
@@ -788,7 +806,10 @@
     struct set_mtrr_context ctxt;
     unsigned long low, high;
 
-    if (do_safe) set_mtrr_prepare( &ctxt );
+    if (do_safe) {
+	set_mtrr_prepare_save (&ctxt);
+	set_mtrr_cache_disable (&ctxt);
+    }
     if (size == 0)
     {
         /*  Disable  */
@@ -985,6 +1006,7 @@
 
 
 static atomic_t undone_count;
+static volatile int wait_barrier_cache_disable = FALSE;
 static volatile int wait_barrier_execute = FALSE;
 static volatile int wait_barrier_cache_enable = FALSE;
 
@@ -1003,18 +1025,21 @@
 {
     struct set_mtrr_data *data = info;
     struct set_mtrr_context ctxt;
-
-    set_mtrr_prepare (&ctxt);
+    set_mtrr_prepare_save (&ctxt);
     /*  Notify master that I've flushed and disabled my cache  */
     atomic_dec (&undone_count);
-    while (wait_barrier_execute) barrier ();
+    while (wait_barrier_cache_disable) { rep_nop(); barrier(); }
+    set_mtrr_cache_disable (&ctxt);
+    /*  Notify master that I've flushed and disabled my cache  */
+    atomic_dec (&undone_count);
+    while (wait_barrier_execute) { rep_nop(); barrier(); }
     /*  The master has cleared me to execute  */
     (*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size,
 		    data->smp_type, FALSE);
     /*  Notify master CPU that I've executed the function  */
     atomic_dec (&undone_count);
     /*  Wait for master to clear me to enable cache and return  */
-    while (wait_barrier_cache_enable) barrier ();
+    while (wait_barrier_cache_enable) { rep_nop(); barrier(); }
     set_mtrr_done (&ctxt);
 }   /*  End Function ipi_handler  */
 
@@ -1028,6 +1053,7 @@
     data.smp_base = base;
     data.smp_size = size;
     data.smp_type = type;
+    wait_barrier_cache_disable = TRUE;
     wait_barrier_execute = TRUE;
     wait_barrier_cache_enable = TRUE;
     atomic_set (&undone_count, smp_num_cpus - 1);
@@ -1035,15 +1061,22 @@
     if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
 	panic ("mtrr: timed out waiting for other CPUs\n");
     /* Flush and disable the local CPU's cache */
-    set_mtrr_prepare (&ctxt);
+    set_mtrr_prepare_save (&ctxt);
+    /*  Wait for all other CPUs to flush and disable their caches  */
+    while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
+    /* Set up for completion wait and then release other CPUs to change MTRRs*/
+    atomic_set (&undone_count, smp_num_cpus - 1);
+    wait_barrier_cache_disable = FALSE;
+    set_mtrr_cache_disable (&ctxt);
+
     /*  Wait for all other CPUs to flush and disable their caches  */
-    while (atomic_read (&undone_count) > 0) barrier ();
+    while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
     /* Set up for completion wait and then release other CPUs to change MTRRs*/
     atomic_set (&undone_count, smp_num_cpus - 1);
     wait_barrier_execute = FALSE;
     (*set_mtrr_up) (reg, base, size, type, FALSE);
     /*  Now wait for other CPUs to complete the function  */
-    while (atomic_read (&undone_count) > 0) barrier ();
+    while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
     /*  Now all CPUs should have finished the function. Release the barrier to
 	allow them to re-enable their caches and return from their interrupt,
 	then enable the local cache and return  */
@@ -1887,7 +1920,9 @@
     struct set_mtrr_context ctxt;
     int i;
 
-    set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */
+    /* flush cache and enable MAPEN */
+    set_mtrr_prepare_save (&ctxt);
+    set_mtrr_cache_disable (&ctxt);
 
      /* the CCRs are not contiguous */
     for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]);
@@ -1924,7 +1959,9 @@
     int i;
 #endif
 
-    set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */
+    /* flush cache and enable MAPEN */
+    set_mtrr_prepare_save (&ctxt);
+    set_mtrr_cache_disable (&ctxt);
 
     /* Save all CCRs locally */
     ccr[0] = getCx86 (CX86_CCR0);
@@ -2073,7 +2110,8 @@
 {
     struct set_mtrr_context ctxt;
 
-    set_mtrr_prepare (&ctxt);
+    set_mtrr_prepare_save (&ctxt);
+    set_mtrr_cache_disable (&ctxt);
 
     if(boot_cpu_data.x86_model==4)
     	centaur_mcr0_init();
@@ -2190,7 +2228,8 @@
     /*  Note that this is not ideal, since the cache is only flushed/disabled
 	for this CPU while the MTRRs are changed, but changing this requires
 	more invasive changes to the way the kernel boots  */
-    set_mtrr_prepare (&ctxt);
+    set_mtrr_prepare_save (&ctxt);
+    set_mtrr_cache_disable (&ctxt);
     mask = set_mtrr_state (&smp_mtrr_state, &ctxt);
     set_mtrr_done (&ctxt);
     /*  Use the atomic bitops to update the global mask  */
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/pci-i386.c linux/arch/i386/kernel/pci-i386.c
--- v2.5.2/linux/arch/i386/kernel/pci-i386.c	Sun Nov  4 09:31:58 2001
+++ linux/arch/i386/kernel/pci-i386.c	Tue Jan 15 10:56:35 2002
@@ -375,7 +375,7 @@
 	/* Write-combine setting is ignored, it is changed via the mtrr
 	 * interfaces on this platform.
 	 */
-	if (remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+	if (remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
 			     vma->vm_end - vma->vm_start,
 			     vma->vm_page_prot))
 		return -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.5.2/linux/arch/i386/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/i386/kernel/process.c	Mon Jan 28 15:11:45 2002
@@ -42,7 +42,6 @@
 #include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/desc.h>
-#include <asm/mmu_context.h>
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
@@ -81,7 +80,7 @@
 {
 	if (current_cpu_data.hlt_works_ok && !hlt_counter) {
 		__cli();
-		if (!current->need_resched)
+		if (!need_resched())
 			safe_halt();
 		else
 			__sti();
@@ -90,7 +89,7 @@
 
 /*
  * On SMP it's slightly faster (but much more power-consuming!)
- * to poll the ->need_resched flag instead of waiting for the
+ * to poll the ->work.need_resched flag instead of waiting for the
  * cross-CPU IPI to arrive. Use this option with caution.
  */
 static void poll_idle (void)
@@ -103,15 +102,15 @@
 	 * Deal with another CPU just having chosen a thread to
 	 * run here:
 	 */
-	oldval = xchg(&current->need_resched, -1);
+	oldval = xchg(&current->work.need_resched, -1);
 
 	if (!oldval)
 		asm volatile(
 			"2:"
-			"cmpl $-1, %0;"
+			"cmpb $-1, %0;"
 			"rep; nop;"
 			"je 2b;"
-				: :"m" (current->need_resched));
+				: :"m" (current->work.need_resched));
 }
 
 /*
@@ -127,7 +126,7 @@
 		void (*idle)(void) = pm_idle;
 		if (!idle)
 			idle = default_idle;
-		while (!current->need_resched)
+		while (!need_resched())
 			idle();
 		schedule();
 		check_pgt_cache();
@@ -690,15 +689,17 @@
 	asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
 
 	/*
-	 * Restore %fs and %gs.
+	 * Restore %fs and %gs if needed.
 	 */
-	loadsegment(fs, next->fs);
-	loadsegment(gs, next->gs);
+	if (unlikely(prev->fs | prev->gs | next->fs | next->gs)) {
+		loadsegment(fs, next->fs);
+		loadsegment(gs, next->gs);
+	}
 
 	/*
 	 * Now maybe reload the debug registers
 	 */
-	if (next->debugreg[7]){
+	if (unlikely(next->debugreg[7])) {
 		loaddebug(next, 0);
 		loaddebug(next, 1);
 		loaddebug(next, 2);
@@ -708,7 +709,7 @@
 		loaddebug(next, 7);
 	}
 
-	if (prev->ioperm || next->ioperm) {
+	if (unlikely(prev->ioperm || next->ioperm)) {
 		if (next->ioperm) {
 			/*
 			 * 4 cachelines copy ... not good, but not that
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.5.2/linux/arch/i386/kernel/ptrace.c	Wed Nov 21 10:42:41 2001
+++ linux/arch/i386/kernel/ptrace.c	Mon Jan 28 15:11:45 2002
@@ -277,10 +277,18 @@
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			break;
-		if (request == PTRACE_SYSCALL)
-			child->ptrace |= PT_TRACESYS;
-		else
-			child->ptrace &= ~PT_TRACESYS;
+		if (request == PTRACE_SYSCALL) {
+			if (!(child->ptrace & PT_SYSCALLTRACE)) {
+				child->ptrace |= PT_SYSCALLTRACE;
+				child->work.syscall_trace++;
+			}
+		}
+		else {
+			if (child->ptrace & PT_SYSCALLTRACE) {
+				child->ptrace &= ~PT_SYSCALLTRACE;
+				child->work.syscall_trace--;
+			}
+		}
 		child->exit_code = data;
 	/* make sure the single step bit is not set. */
 		tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
@@ -315,7 +323,10 @@
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			break;
-		child->ptrace &= ~PT_TRACESYS;
+		if (child->ptrace & PT_SYSCALLTRACE) {
+			child->ptrace &= ~PT_SYSCALLTRACE;
+			child->work.syscall_trace--;
+		}
 		if ((child->ptrace & PT_DTRACE) == 0) {
 			/* Spurious delayed TF traps may occur */
 			child->ptrace |= PT_DTRACE;
@@ -439,10 +450,14 @@
 	return ret;
 }
 
-asmlinkage void syscall_trace(void)
+/* notification of system call entry/exit
+ * - triggered by current->work.syscall_trace
+ */
+__attribute__((regparm(3)))
+void do_syscall_trace(struct pt_regs *regs, int entryexit)
 {
-	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) !=
-			(PT_PTRACED|PT_TRACESYS))
+	if ((current->ptrace & (PT_PTRACED|PT_SYSCALLTRACE)) !=
+	    (PT_PTRACED|PT_SYSCALLTRACE))
 		return;
 	/* the 0x80 provides a way for the tracing parent to distinguish
 	   between a syscall stop and SIGTRAP delivery */
@@ -460,4 +475,16 @@
 		send_sig(current->exit_code, current, 1);
 		current->exit_code = 0;
 	}
+}
+
+/* notification of userspace execution resumption
+ * - triggered by current->work.notify_resume
+ */
+__attribute__((regparm(3)))
+void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
+		      struct task_work work_pending)
+{
+	/* deal with pending signal delivery */
+	if (work_pending.sigpending)
+		do_signal(regs,oldset);
 }
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.5.2/linux/arch/i386/kernel/setup.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/i386/kernel/setup.c	Sun Jan 27 11:21:34 2002
@@ -704,10 +704,8 @@
 #define PFN_PHYS(x)	((x) << PAGE_SHIFT)
 
 /*
- * 128MB for vmalloc and initrd
+ * Reserved space for vmalloc and iomap - defined in asm/page.h
  */
-#define VMALLOC_RESERVE	(unsigned long)(128 << 20)
-#define MAXMEM		(unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)
 #define MAXMEM_PFN	PFN_DOWN(MAXMEM)
 #define MAX_NONPAE_PFN	(1 << 20)
 
@@ -2805,9 +2803,10 @@
 	load_TR(nr);
 	load_LDT(&init_mm);
 
-	/*
-	 * Clear all 6 debug registers:
-	 */
+	/* Clear %fs and %gs. */
+	asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
+
+	/* Clear all 6 debug registers: */
 
 #define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) );
 
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.5.2/linux/arch/i386/kernel/signal.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/i386/kernel/signal.c	Mon Jan 28 15:11:45 2002
@@ -28,8 +28,6 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
-
 int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
 {
 	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.5.2/linux/arch/i386/kernel/smp.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/i386/kernel/smp.c	Mon Jan 21 15:46:50 2002
@@ -485,6 +485,35 @@
 	do_flush_tlb_all_local();
 }
 
+static spinlock_t migration_lock = SPIN_LOCK_UNLOCKED;
+static task_t *new_task;
+
+/*
+ * This function sends a 'task migration' IPI to another CPU.
+ * Must be called from syscall contexts, with interrupts *enabled*.
+ */
+void smp_migrate_task(int cpu, task_t *p)
+{
+	/*
+	 * The target CPU will unlock the migration spinlock:
+	 */
+	spin_lock(&migration_lock);
+	new_task = p;
+	send_IPI_mask(1 << cpu, TASK_MIGRATION_VECTOR);
+}
+
+/*
+ * Task migration callback.
+ */
+asmlinkage void smp_task_migration_interrupt(void)
+{
+	task_t *p;
+
+	ack_APIC_irq();
+	p = new_task;
+	spin_unlock(&migration_lock);
+	sched_task_migrated(p);
+}
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c
--- v2.5.2/linux/arch/i386/kernel/smpboot.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/i386/kernel/smpboot.c	Mon Jan 28 13:12:04 2002
@@ -435,6 +435,7 @@
 	 */
  	smp_store_cpu_info(cpuid);
 
+	disable_APIC_timer();
 	/*
 	 * Allow the master to continue.
 	 */
@@ -465,13 +466,13 @@
 	smp_callin();
 	while (!atomic_read(&smp_commenced))
 		rep_nop();
+	enable_APIC_timer();
 	/*
 	 * low-memory mappings have been cleared, flush them from
 	 * the local TLBs too.
 	 */
 	local_flush_tlb();
 
-	init_idle();
 	return cpu_idle();
 }
 
@@ -804,7 +805,7 @@
 	if (!idle)
 		panic("No idle process for CPU %d", cpu);
 
-	idle->cpu = cpu;
+	init_idle(idle, cpu);
 
 	map_cpu_to_boot_apicid(cpu, apicid);
 
@@ -923,6 +924,7 @@
 }
 
 cycles_t cacheflush_time;
+unsigned long cache_decay_ticks;
 
 static void smp_tune_scheduling (void)
 {
@@ -956,9 +958,13 @@
 		cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth;
 	}
 
+	cache_decay_ticks = (long)cacheflush_time/cpu_khz * HZ / 1000;
+
 	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
 		(long)cacheflush_time/(cpu_khz/1000),
 		((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
+	printk("task migration cache decay timeout: %ld msecs.\n",
+		(cache_decay_ticks + 1) * 1000 / HZ);
 }
 
 /*
@@ -1017,7 +1023,7 @@
 	boot_cpu_logical_apicid = logical_smp_processor_id();
 	map_cpu_to_boot_apicid(0, boot_cpu_apicid);
 
-	global_irq_holder = 0;
+	global_irq_holder = NO_PROC_ID;
 	current->cpu = 0;
 	smp_tune_scheduling();
 
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.5.2/linux/arch/i386/kernel/time.c	Sun Nov 11 10:20:21 2001
+++ linux/arch/i386/kernel/time.c	Wed Jan 23 15:28:39 2002
@@ -681,7 +681,6 @@
 #ifndef do_gettimeoffset
 			do_gettimeoffset = do_fast_gettimeoffset;
 #endif
-			do_get_fast_time = do_gettimeofday;
 
 			/* report CPU clock rate in Hz.
 			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.5.2/linux/arch/i386/kernel/traps.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/i386/kernel/traps.c	Tue Jan 29 18:24:01 2002
@@ -271,6 +271,22 @@
 {
 	if (vm86 && regs->eflags & VM_MASK)
 		goto vm86_trap;
+
+#ifdef CONFIG_PNPBIOS		
+	if (regs->xcs == 0x60 || regs->xcs == 0x68)
+	{
+		extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
+		extern u32 pnp_bios_is_utter_crap;
+		pnp_bios_is_utter_crap = 1;
+		printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n");
+		__asm__ volatile(
+			"movl %0, %%esp\n\t"
+			"jmp %1\n\t"
+			: "=a" (pnp_bios_fault_esp), "=b" (pnp_bios_fault_eip));
+		panic("do_trap: can't hit this");
+	}
+#endif	
+
 	if (!(regs->xcs & 3))
 		goto kernel_trap;
 
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v2.5.2/linux/arch/i386/kernel/vm86.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/i386/kernel/vm86.c	Mon Jan 28 15:11:45 2002
@@ -212,7 +212,7 @@
 	info->regs.__null_ds = 0;
 	info->regs.__null_es = 0;
 
-/* we are clearing fs,gs later just before "jmp ret_from_sys_call",
+/* we are clearing fs,gs later just before "jmp resume_userspace",
  * because starting with Linux 2.1.x they aren't no longer saved/restored
  */
 
@@ -255,7 +255,7 @@
 	__asm__ __volatile__(
 		"xorl %%eax,%%eax; movl %%eax,%%fs; movl %%eax,%%gs\n\t"
 		"movl %0,%%esp\n\t"
-		"jmp ret_from_sys_call"
+		"jmp resume_userspace"
 		: /* no outputs */
 		:"r" (&info->regs), "b" (tsk) : "ax");
 	/* we never return here */
@@ -268,7 +268,7 @@
 	regs32 = save_v86_state(regs16);
 	regs32->eax = retval;
 	__asm__ __volatile__("movl %0,%%esp\n\t"
-		"jmp ret_from_sys_call"
+		"jmp resume_userspace"
 		: : "r" (regs32), "b" (current));
 }
 
diff -u --recursive --new-file v2.5.2/linux/arch/i386/math-emu/fpu_entry.c linux/arch/i386/math-emu/fpu_entry.c
--- v2.5.2/linux/arch/i386/math-emu/fpu_entry.c	Fri Apr  6 10:42:47 2001
+++ linux/arch/i386/math-emu/fpu_entry.c	Tue Jan 15 13:53:50 2002
@@ -559,7 +559,7 @@
   RE_ENTRANT_CHECK_ON;
 #endif /* DEBUG */
 
-  if (FPU_lookahead && !current->need_resched)
+  if (FPU_lookahead && !need_resched())
     {
       FPU_ORIG_EIP = FPU_EIP - code_base;
       if ( valid_prefix(&byte1, (u_char **)&FPU_EIP,
diff -u --recursive --new-file v2.5.2/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds
--- v2.5.2/linux/arch/i386/vmlinux.lds	Mon Jul  2 14:40:14 2001
+++ linux/arch/i386/vmlinux.lds	Wed Jan 23 10:54:42 2002
@@ -48,7 +48,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/Config.help linux/arch/ia64/Config.help
--- v2.5.2/linux/arch/ia64/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/Config.help	Fri Jan 25 16:04:31 2002
@@ -0,0 +1,580 @@
+CONFIG_SMP
+  This enables support for systems with more than one CPU. If you have
+  a system with only one CPU, like most personal computers, say N. If
+  you have a system with more than one CPU, say Y.
+
+  If you say N here, the kernel will run on single and multiprocessor
+  machines, but will use only one CPU of a multiprocessor machine. If
+  you say Y here, the kernel will run on many, but not all,
+  singleprocessor machines. On a singleprocessor machine, the kernel
+  will run faster if you say N here.
+
+  Note that if you say Y here and choose architecture "586" or
+  "Pentium" under "Processor family", the kernel will not work on 486
+  architectures. Similarly, multiprocessor kernels for the "PPro"
+  architecture may not work on all Pentium based boards.
+
+  People using multiprocessor machines who say Y here should also say
+  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+  Management" code will be disabled if you say Y here.
+
+  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-HOWTO available at
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you don't know what to do here, say N.
+
+CONFIG_IA64
+  The Itanium is Intel's 64-bit successor to the 32-bit X86 line.  As
+  of early 2001 it is not yet in widespread production use.  The Linux
+  IA-64 project has a home page at <http://www.linuxia64.org/>.
+
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+CONFIG_DISCONTIGMEM
+  Say Y to upport efficient handling of discontiguous physical memory,
+  for architectures which are either NUMA (Non-Uniform Memory Access)
+  or have huge holes in the physical address space for other reasons.
+  See <file:Documentation/vm/numa> for more.
+
+CONFIG_NUMA
+  Say Y to compile the kernel to support NUMA (Non-Uniform Memory
+  Access).  This option is for configuring high-end multiprocessor
+  server machines.  If in doubt, say N.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_PCI
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_HOTPLUG
+  Say Y here if you want to plug devices into your computer while
+  the system is running, and be able to use them quickly.  In many
+  cases, the devices can likewise be unplugged at any time too.
+
+  One well known example of this is PCMCIA- or PC-cards, credit-card
+  size devices such as network cards, modems or hard drives which are
+  plugged into slots found on all modern laptop computers.  Another
+  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.
+  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.
+
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+  computer.  These are credit-card size devices such as network cards,
+  modems or hard drives often used with laptops computers.  There are
+  actually two varieties of these cards: the older 16 bit PCMCIA cards
+  and the newer 32 bit CardBus cards.  If you want to use CardBus
+  cards, you need to say Y here and also to "CardBus support" below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  Please also read the PCMCIA-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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_VGA_CONSOLE
+  Saying Y here will allow you to use Linux in text mode through a
+  display that complies with the generic VGA standard. Virtually
+  everyone wants that.
+
+  The program SVGATextMode can be used to utilize SVGA video cards to
+  their full potential in text mode. Download it from
+  <ftp://ibiblio.org/pub/Linux/utils/console/>.
+
+  Say Y.
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_CD_NO_IDESCSI
+  If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y
+  here, otherwise N. Read the CD-ROM-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about these CD-ROM drives. If you are unsure what you
+  have, say Y and find out whether you have one of the following
+  drives.
+
+  For each of these drivers, a file Documentation/cdrom/{driver_name}
+  exists. Especially in cases where you do not know exactly which kind
+  of drive you have you should read there. Most of these drivers use a
+  file drivers/cdrom/{driver_name}.h where you can define your
+  interface parameters and switch some internal goodies.
+
+  All these CD-ROM drivers are also usable as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want). If you want to compile them as module, say M instead of Y and
+  read <file:Documentation/modules.txt>.
+
+  If you want to use any of these CD-ROM drivers, you also have to
+  answer Y or M to "ISO 9660 CD-ROM file system support" below (this
+  answer will get "defaulted" for you if you enable any of the Linux
+  CD-ROM drivers).
+
+CONFIG_DEVFS_FS
+  This is support for devfs, a virtual file system (like /proc) which
+  provides the file system interface to device drivers, normally found
+  in /dev. Devfs does not depend on major and minor number
+  allocations. Device drivers register entries in /dev which then
+  appear automatically, which means that the system administrator does
+  not have to create character and block special device files in the
+  /dev directory using the mknod command (or MAKEDEV script) anymore.
+
+  This is work in progress. If you want to use this, you *must* read
+  the material in <file:Documentation/filesystems/devfs/>, especially
+  the file README there.
+
+  If unsure, say N.
+
+CONFIG_DEVFS_DEBUG
+  If you say Y here, then the /dev file system code will generate
+  debugging messages. See the file
+  <file:Documentation/filesystems/devfs/boot-options> for more
+  details.
+
+  If unsure, say N.
+
+CONFIG_PM
+  "Power Management" means that parts of your computer are shut
+  off or put into a power conserving "sleep" mode if they are not
+  being used.  There are two competing standards for doing this: APM
+  and ACPI.  If you want to use either one, say Y here and then also
+  to the requisite support below.
+
+  Power Management is most important for battery powered laptop
+  computers; if you have a laptop, check out the Linux Laptop home
+  page on the WWW at
+  <http://www.cs.utexas.edu/users/kharker/linux-laptop/> and the
+  Battery Powered Linux mini-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that, even if you say N here, Linux on the x86 architecture
+  will issue the hlt instruction if nothing is to be done, thereby
+  sending the processor to sleep and saving power.
+
+CONFIG_ACPI
+  ACPI/OSPM support for Linux is currently under development. As such,
+  this support is preliminary and EXPERIMENTAL.  Configuring ACPI
+  support enables kernel interfaces that allow higher level software
+  (OSPM) to manipulate ACPI defined hardware and software interfaces,
+  including the evaluation of ACPI control methods.  If unsure, choose
+  N here.  Note, this option will enlarge your kernel by about 120K.
+
+  This support requires an ACPI compliant platform (hardware/firmware).
+  If both ACPI and Advanced Power Management (APM) support are
+  configured, whichever is loaded first shall be used.
+
+  This code DOES NOT currently provide a complete OSPM implementation
+  -- it has not yet reached APM's level of functionality.  When fully
+  implemented, Linux ACPI/OSPM will provide a more robust functional
+  replacement for legacy configuration and power management
+  interfaces, including the Plug-and-Play BIOS specification (PnP
+  BIOS), the Multi-Processor Specification (MPS), and the Advanced
+  Power Management specification (APM).
+
+  Linux support for ACPI/OSPM is based on Intel Corporation's ACPI
+  Component Architecture (ACPI CA). The latest ACPI CA source code,
+  documentation, debug builds, and implementation status information
+  can be downloaded from:
+  <http://developer.intel.com/technology/iapc/acpi/downloads.htm>.
+
+  The ACPI Sourceforge project may also be of interest:
+  <http://sf.net/projects/acpi/>
+
+CONFIG_ACPI_KERNEL_CONFIG
+  If you say `Y' here, Linux's ACPI support will use the
+  hardware-level system descriptions found on IA64 machines.
+
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y.  Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. General information about
+  the modular sound system is contained in the files
+  <file:Documentation/sound/Introduction>.  The file
+  <file:Documentation/sound/README.OSS> contains some slightly
+  outdated but still useful information as well.
+
+  If you have a PnP sound card and you want to configure it at boot
+  time using the ISA PnP tools (read
+  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished.  To do
+  this, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/sound/README.modules>; the module will be
+  called soundcore.o.
+
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and supporting utilities to do that are in the pcsp
+  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_ISDN
+  ISDN ("Integrated Services Digital Networks", called RNIS in France)
+  is a special type of fully digital telephone service; it's mostly
+  used to connect to your Internet service provider (with SLIP or
+  PPP).  The main advantage is that the speed is higher than ordinary
+  modem/telephone connections, and that you can have voice
+  conversations while downloading stuff.  It only works if your
+  computer is equipped with an ISDN card and both you and your service
+  provider purchased an ISDN line from the phone company.  For
+  details, read <http://alumni.caltech.edu/~dank/isdn/> on the WWW.
+
+  This driver allows you to use an ISDN-card for networking
+  connections and as dialin/out device.  The isdn-tty's have a built
+  in AT-compatible modem emulator.  Network devices support autodial,
+  channel-bundling, callback and caller-authentication without having
+  a daemon running.  A reduced T.70 protocol is supported with tty's
+  suitable for German BTX.  On D-Channel, the protocols EDSS1
+  (Euro-ISDN) and 1TR6 (German style) are supported.  See
+  <file:Documentation/isdn/README> for more information.
+
+  If you want to compile the ISDN code 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 isdn.o. If unsure, say N.
+
+CONFIG_ITANIUM
+  Select your IA64 processor type.  The default is Intel Itanium.
+
+CONFIG_MCKINLEY
+  Select this to configure for a McKinley processor.
+
+CONFIG_IA64_GENERIC
+  This selects the system type of your hardware.  A "generic" kernel
+  will run on any supported IA-64 system.  However, if you configure
+  a kernel for your specific system, it will be faster and smaller.
+
+  To find out what type of IA-64 system you have, you may want to
+  check the IA-64 Linux web site at <http://www.linux-ia64.org/>.
+  As of the time of this writing, most hardware is DIG compliant,
+  so the "DIG-compliant" option is usually the right choice.
+
+  HP-simulator   For the HP simulator
+                 (<http://software.hp.com/ia64linux/>).
+  SN1-simulator  For the SGI SN1 simulator.
+  DIG-compliant  For DIG ("Developer's Interface Guide") compliant
+                 system.
+
+  If you don't know what to do, choose "generic".
+
+CONFIG_IA64_PAGE_SIZE_4KB
+  This lets you select the page size of the kernel.  For best IA-64
+  performance, a page size of 8KB or 16KB is recommended.  For best
+  IA-32 compatibility, a page size of 4KB should be selected (the vast
+  majority of IA-32 binaries work perfectly fine with a larger page
+  size).  For Itanium systems, do NOT chose a page size larger than
+  16KB.
+
+  4KB                For best IA-32 compatibility
+  8KB                For best IA-64 performance
+  16KB               For best IA-64 performance
+  64KB               Not for Itanium.
+
+  If you don't know what to do, choose 8KB.
+
+CONFIG_ITANIUM_BSTEP_SPECIFIC
+  Select this option to build a kernel for an Itanium prototype system
+  with a B-step CPU.  You have a B-step CPU if the "revision" field in
+  /proc/cpuinfo has a value in the range from 1 to 4.
+
+CONFIG_IA64_MCA
+  Say Y here to enable machine check support for IA-64.  If you're
+  unsure, answer Y.
+
+CONFIG_DISABLE_VHPT
+  The Virtual Hash Page Table (VHPT) enhances virtual address
+  translation performance.  Normally you want the VHPT active but you
+  can select this option to disable the VHPT for debugging.  If you're
+  unsure, answer N.
+
+CONFIG_MCKINLEY_ASTEP_SPECIFIC
+  Select this option to build a kernel for an IA64 McKinley system
+  with any A-stepping CPU.
+
+CONFIG_MCKINLEY_A0_SPECIFIC
+  Select this option to build a kernel for an IA64 McKinley system
+  with an A0 or A1 stepping CPU.
+
+CONFIG_IA64_DEBUG_CMPXCHG
+  Selecting this option turns on bug checking for the IA64
+  compare-and-exchange instructions.  This is slow!  Itaniums
+  from step B3 or later don't have this problem. If you're unsure,
+  select N.
+
+CONFIG_IA64_DEBUG_IRQ
+  Selecting this option turns on bug checking for the IA64 irq_save
+  and restore instructions.  It's useful for tracking down spinlock
+  problems, but slow!  If you're unsure, select N.
+
+CONFIG_IA64_EARLY_PRINTK
+  Selecting this option uses the VGA screen for printk() output before
+  the consoles are initialised.  It is useful for debugging problems
+  early in the boot process, but only if you have a VGA screen
+  attached.  If you're unsure, select N.
+
+CONFIG_IA64_PRINT_HAZARDS
+  Selecting this option prints more information for Illegal Dependency
+  Faults, that is, for Read after Write, Write after Write or Write
+  after Read violations.  This option is ignored if you are compiling
+  for an Itanium A step processor (CONFIG_ITANIUM_ASTEP_SPECIFIC).  If
+  you're unsure, select Y.
+
+CONFIG_PERFMON
+  Selects whether support for the IA-64 performance monitor hardware
+  is included in the kernel.  This makes some kernel data-structures a
+  little bigger and slows down execution a bit, but it is still
+  usually a good idea to turn this on.  If you're unsure, say N.
+
+CONFIG_IA64_PALINFO
+  If you say Y here, you are able to get PAL (Processor Abstraction
+  Layer) information in /proc/pal.  This contains useful information
+  about the processors in your systems, such as cache and TLB sizes
+  and the PAL firmware version in use.
+
+  To use this option, you have to check that the "/proc file system
+  support" (CONFIG_PROC_FS) is enabled, too.
+
+CONFIG_IA32_SUPPORT
+  IA64 processors can run IA32 (that is, x86) binaries by emulating
+  the IA32 instruction set.  Say Y here to build in kernel support for
+  this.  If in doubt, say Y.
+
+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.
+
+  To use this option, you have to check that the "/proc file system
+  support" (CONFIG_PROC_FS) is enabled, too.
+
+CONFIG_DEBUG_KERNEL
+  Say Y here if you are developing drivers or trying to debug and
+  identify kernel problems.
+
+CONFIG_DEBUG_SLAB
+  Say Y here to have the kernel do limited verification on memory
+  allocation as well as poisoning memory on free to catch use of freed
+  memory.
+
+CONFIG_DEBUG_SPINLOCK
+  Say Y here and build SMP to catch missing spinlock initialization
+  and certain other kinds of spinlock errors commonly made.  This is
+  best used in conjunction with the NMI watchdog so that spinlock
+  deadlocks are also debuggable.
+
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/config.in linux/arch/ia64/config.in
--- v2.5.2/linux/arch/ia64/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/ia64/config.in	Thu Jan 24 11:29:38 2002
@@ -1,18 +1,6 @@
 mainmenu_name "Kernel configuration of Linux for IA-64 machines"
 
-mainmenu_option next_comment
- comment 'Code maturity level options'
- bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'General setup'
@@ -99,10 +87,6 @@
 tristate '/proc/pal support' CONFIG_IA64_PALINFO
 tristate '/proc/efi/vars support' CONFIG_EFI_VARS
 
-bool 'Networking support' CONFIG_NET
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S
--- v2.5.2/linux/arch/ia64/kernel/entry.S	Fri Nov  9 14:26:17 2001
+++ linux/arch/ia64/kernel/entry.S	Mon Jan 28 15:14:22 2002
@@ -433,7 +433,7 @@
 	.body
 	mov loc2=b6
 	;;
-	br.call.sptk.many rp=syscall_trace
+#error	br.call.sptk.many rp=syscall_trace
 .ret3:	mov rp=loc0
 	mov ar.pfs=loc1
 	mov b6=loc2
@@ -454,7 +454,7 @@
 
 GLOBAL_ENTRY(ia64_trace_syscall)
 	PT_REGS_UNWIND_INFO(0)
-	br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch syscall args
+#error	br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch syscall args
 .ret6:	br.call.sptk.many rp=b6			// do the syscall
 strace_check_retval:
 	cmp.lt p6,p0=r8,r0			// syscall failed?
@@ -467,7 +467,7 @@
 .mem.offset 0,0;	st8.spill [r2]=r8	// store return value in slot for r8
 .mem.offset 8,0;	st8.spill [r3]=r10	// clear error indication in slot for r10
 ia64_strace_leave_kernel:
-	br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch return value
+#error	br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch return value
 .rety:	br.cond.sptk ia64_leave_kernel
 
 strace_error:
@@ -530,14 +530,14 @@
 #ifdef CONFIG_PERFMON
 (pUser)	ld8 r19=[r19]				// load current->thread.pfm_must_block
 #endif
-(pUser)	ld8 r17=[r17]				// load current->need_resched
-(pUser)	ld4 r18=[r18]				// load current->sigpending
+#error (pUser)	ld8 r17=[r17]				// load current->need_resched
+#error (pUser)	ld4 r18=[r18]				// load current->sigpending
 	;;
 #ifdef CONFIG_PERFMON
 (pUser)	cmp.ne.unc p9,p0=r19,r0			// current->thread.pfm_must_block != 0?
 #endif
-(pUser)	cmp.ne.unc p7,p0=r17,r0			// current->need_resched != 0?
-(pUser)	cmp.ne.unc p8,p0=r18,r0			// current->sigpending != 0?
+#error (pUser)	cmp.ne.unc p7,p0=r17,r0			// current->need_resched != 0?
+#errror (pUser)	cmp.ne.unc p8,p0=r18,r0			// current->sigpending != 0?
 	;;
 	adds r2=PT(R8)+16,r12
 	adds r3=PT(R9)+16,r12
@@ -816,7 +816,7 @@
 	.spillpsp ar.unat, 16			// (note that offset is relative to psp+0x10!)
 	st8 [sp]=r9,-16				// allocate space for ar.unat and save it
 	.body
-	br.call.sptk.many rp=ia64_do_signal
+#error	br.call.sptk.many rp=ia64_do_signal
 .ret15:	.restore sp
 	adds sp=16,sp				// pop scratch stack space
 	;;
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/kernel/init_task.c linux/arch/ia64/kernel/init_task.c
--- v2.5.2/linux/arch/ia64/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/ia64/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/kernel/pci.c linux/arch/ia64/kernel/pci.c
--- v2.5.2/linux/arch/ia64/kernel/pci.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/ia64/kernel/pci.c	Tue Jan 15 10:56:35 2002
@@ -232,7 +232,7 @@
 	else
 		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-	if (remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+	if (remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
 			     vma->vm_end - vma->vm_start,
 			     vma->vm_page_prot))
 		return -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/kernel/perfmon.c linux/arch/ia64/kernel/perfmon.c
--- v2.5.2/linux/arch/ia64/kernel/perfmon.c	Fri Nov  9 14:26:17 2001
+++ linux/arch/ia64/kernel/perfmon.c	Tue Jan 15 10:56:35 2002
@@ -430,14 +430,14 @@
 }
 
 static int
-pfm_remap_buffer(unsigned long buf, unsigned long addr, unsigned long size)
+pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long addr, unsigned long size)
 {
 	unsigned long page;
 
 	while (size > 0) {
 		page = kvirt_to_pa(buf);
 
-		if (remap_page_range(addr, page, PAGE_SIZE, PAGE_SHARED)) return -ENOMEM;
+		if (remap_page_range(vma, addr, page, PAGE_SIZE, PAGE_SHARED)) return -ENOMEM;
 
 		addr  += PAGE_SIZE;
 		buf   += PAGE_SIZE;
@@ -502,13 +502,26 @@
 	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!vma) goto no_vma;
 
+	/*
+	 * initialize the vma for the sampling buffer
+	 */
+	vma->vm_mm	  = mm;
+	vma->vm_start	  = addr;
+	vma->vm_end	  = addr + size;
+	vma->vm_flags	  = VM_READ|VM_MAYREAD;
+	vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */
+	vma->vm_ops	  = NULL;
+	vma->vm_pgoff	  = 0;
+	vma->vm_file	  = NULL;
+	vma->vm_raend	  = 0;
+
 	/* XXX: see rvmalloc() for page alignment problem */
 	smpl_buf = rvmalloc(size);
 	if (smpl_buf == NULL) goto no_buffer;
 
 	DBprintk((" smpl_buf @%p\n", smpl_buf));
 
-	if (pfm_remap_buffer((unsigned long)smpl_buf, addr, size)) goto cant_remap;
+	if (pfm_remap_buffer(vma, (unsigned long)smpl_buf, addr, size)) goto cant_remap;
 
 	/* allocate sampling buffer descriptor now */
 	psb = vmalloc(sizeof(*psb));
@@ -539,19 +552,6 @@
 
 	/* link to perfmon context */
 	ctx->ctx_smpl_buf  = psb;
-
-	/*
-	 * initialize the vma for the sampling buffer
-	 */
-	vma->vm_mm	  = mm;
-	vma->vm_start	  = addr;
-	vma->vm_end	  = addr + size;
-	vma->vm_flags	  = VM_READ|VM_MAYREAD;
-	vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */
-	vma->vm_ops	  = NULL;
-	vma->vm_pgoff	  = 0;
-	vma->vm_file	  = NULL;
-	vma->vm_raend	  = 0;
 
 	vma->vm_private_data = ctx;	/* link to pfm_context(not yet used) */
 
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c
--- v2.5.2/linux/arch/ia64/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/ia64/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -117,10 +117,10 @@
 
 	while (1) {
 #ifdef CONFIG_SMP
-		if (!current->need_resched)
+		if (!need_resched())
 			min_xtp();
 #endif
-		while (!current->need_resched)
+		while (!need_resched())
 			continue;
 #ifdef CONFIG_SMP
 		normal_xtp();
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c
--- v2.5.2/linux/arch/ia64/kernel/time.c	Fri Nov  9 14:26:17 2001
+++ linux/arch/ia64/kernel/time.c	Wed Jan 23 15:28:39 2002
@@ -145,9 +145,6 @@
 	tv->tv_usec = usec;
 }
 
-/* XXX there should be a cleaner way for declaring an alias... */
-asm (".global get_fast_time; get_fast_time = do_gettimeofday");
-
 static void
 timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/mm/tlb.c linux/arch/ia64/mm/tlb.c
--- v2.5.2/linux/arch/ia64/mm/tlb.c	Fri Nov  9 14:26:17 2001
+++ linux/arch/ia64/mm/tlb.c	Tue Jan 15 10:56:35 2002
@@ -125,8 +125,9 @@
 }
 
 void
-flush_tlb_range (struct mm_struct *mm, unsigned long start, unsigned long end)
+flush_tlb_range (struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long size = end - start;
 	unsigned long nbits;
 
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/tools/print_offsets.c linux/arch/ia64/tools/print_offsets.c
--- v2.5.2/linux/arch/ia64/tools/print_offsets.c	Fri Nov  9 14:26:17 2001
+++ linux/arch/ia64/tools/print_offsets.c	Mon Jan 28 15:14:22 2002
@@ -51,9 +51,9 @@
     { "SIGFRAME_SIZE",			sizeof (struct sigframe) },
     { "UNW_FRAME_INFO_SIZE",		sizeof (struct unw_frame_info) },
     { "", 0 },			/* spacer */
-    { "IA64_TASK_PTRACE_OFFSET",	offsetof (struct task_struct, ptrace) },
-    { "IA64_TASK_SIGPENDING_OFFSET",	offsetof (struct task_struct, sigpending) },
-    { "IA64_TASK_NEED_RESCHED_OFFSET",	offsetof (struct task_struct, need_resched) },
+#error    { "IA64_TASK_PTRACE_OFFSET",	offsetof (struct task_struct, ptrace) },
+#error    { "IA64_TASK_SIGPENDING_OFFSET",	offsetof (struct task_struct, sigpending) },
+#error    { "IA64_TASK_NEED_RESCHED_OFFSET",	offsetof (struct task_struct, need_resched) },
     { "IA64_TASK_PROCESSOR_OFFSET",	offsetof (struct task_struct, processor) },
     { "IA64_TASK_THREAD_OFFSET",	offsetof (struct task_struct, thread) },
     { "IA64_TASK_THREAD_KSP_OFFSET",	offsetof (struct task_struct, thread.ksp) },
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/vmlinux.lds.S linux/arch/ia64/vmlinux.lds.S
--- v2.5.2/linux/arch/ia64/vmlinux.lds.S	Tue Jul 31 10:30:09 2001
+++ linux/arch/ia64/vmlinux.lds.S	Wed Jan 23 10:54:42 2002
@@ -104,8 +104,16 @@
         { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : AT(ADDR(.initcall.init) - PAGE_OFFSET)
-        { *(.initcall.init) }
+  .initcall.init : AT(ADDR(.initcall1.init) - PAGE_OFFSET)
+	{
+		 *(.initcall1.init) 
+		 *(.initcall2.init) 
+		 *(.initcall3.init) 
+		 *(.initcall4.init) 
+		 *(.initcall5.init) 
+		 *(.initcall6.init) 
+		 *(.initcall7.init) 
+	}
   __initcall_end = .;
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/m68k/Config.help linux/arch/m68k/Config.help
--- v2.5.2/linux/arch/m68k/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/Config.help	Fri Jan 25 16:04:25 2002
@@ -0,0 +1,1719 @@
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+CONFIG_WARPENGINE_SCSI
+  Support for MacroSystem Development's WarpEngine Amiga SCSI-2
+  controller. Info at
+  <http://www.lysator.liu.se/amiga/ar/guide/ar310.guide?FEATURE5>.
+
+CONFIG_HEARTBEAT
+  Use the power-on LED on your machine as a load meter.  The exact
+  behavior is platform-dependent, but normally the flash frequency is
+  a hyperbolic function of the 5-minute load average.
+
+CONFIG_SERIAL_EXTENDED
+  If you wish to use any non-standard features of the standard "dumb"
+  driver, say Y here. This includes HUB6 support, shared serial
+  interrupts, special multiport support, support for more than the
+  four COM 1/2/3/4 boards, etc.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about serial driver options. If unsure, say N.
+
+CONFIG_SERIAL_MANY_PORTS
+  Say Y here if you have dumb serial boards other than the four
+  standard COM 1/2/3/4 ports. This may happen if you have an AST
+  FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
+  from <http://www.linuxdoc.org/docs.html#howto>), or other custom
+  serial port hardware which acts similar to standard serial port
+  hardware. If you only use the standard COM 1/2/3/4 ports, you can
+  say N here to save some memory. You can also say Y if you have an
+  "intelligent" multiport card such as Cyclades, Digiboards, etc.
+
+CONFIG_SERIAL_SHARE_IRQ
+  Some serial boards have hardware support which allows multiple dumb
+  serial ports on the same board to share a single IRQ. To enable
+  support for this in the serial driver, say Y here.
+
+CONFIG_SERIAL_MULTIPORT
+  Some multiport serial ports have special ports which are used to
+  signal when there are any serial ports on the board which need
+  servicing. Say Y here to enable the serial driver to take advantage
+  of those special I/O ports.
+
+CONFIG_HUB6
+  Say Y here to enable support in the dumb serial driver to support
+  the HUB6 card.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_PCI
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+  computer.  These are credit-card size devices such as network cards,
+  modems or hard drives often used with laptops computers.  There are
+  actually two varieties of these cards: the older 16 bit PCMCIA cards
+  and the newer 32 bit CardBus cards.  If you want to use CardBus
+  cards, you need to say Y here and also to "CardBus support" below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  Please also read the PCMCIA-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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_KCORE_AOUT
+  Not necessary unless you're using a very out-of-date binutils
+  version.  You probably want KCORE_ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_AOUT
+  A.out (Assembler.OUTput) is a set of formats for libraries and
+  executables used in the earliest versions of UNIX. Linux used the
+  a.out formats QMAGIC and ZMAGIC until they were replaced with the
+  ELF format.
+
+  As more and more programs are converted to ELF, the use for a.out
+  will gradually diminish. If you disable this option it will reduce
+  your kernel by one page. This is not much and by itself does not
+  warrant removing support. However its removal is a good idea if you
+  wish to ensure that absolutely none of your programs will use this
+  older executable format. If you don't know what to answer at this
+  point then answer Y. If someone told you "You need a kernel with
+  QMAGIC support" then you'll have to say Y here. You may answer M to
+  compile a.out support as a module and later load the module when you
+  want to use a program or library in a.out format. The module will be
+  called binfmt_aout.o. Saying M or N here is dangerous though,
+  because some crucial programs on your system might still be in A.OUT
+  format.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_APOLLO
+  Say Y here if you want to run Linux on an MC680x0-based Apollo
+  Domain workstation such as the DN3500.
+
+CONFIG_APOLLO_ELPLUS
+  Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card.
+  If you don't have one made for Apollos, you can use one from a PC,
+  except that your Apollo won't be able to boot from it (because the
+  code in the ROM will be for a PC).
+
+CONFIG_PARPORT
+  If you want to use devices connected to your machine's parallel port
+  (the connector at the computer with 25 holes), e.g. printer, ZIP
+  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
+  <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
+  the WWW.
+
+  It is possible to share a single parallel port among several devices
+  and it is safe to compile all the corresponding drivers into the
+  kernel.  If you want to compile parallel port 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
+  parport.o.  If you have more than one parallel port and want to
+  specify which port and IRQ to be used by this driver at module load
+  time, take a look at <file:Documentation/parport.txt>.
+
+  If unsure, say Y.
+
+CONFIG_PARPORT_PC
+  You should say Y here if you have a PC-style parallel port. All IBM
+  PC compatible computers and some Alphas have PC-style parallel
+  ports.
+
+  This code is also available as a module.  If you want to compile it
+  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
+  parport_pc.o.
+
+  If unsure, say Y.
+
+CONFIG_PARPORT_AMIGA
+  Say Y here if you need support for the parallel port hardware on
+  Amiga machines. This code is also available as a module (say M),
+  called parport_amiga.o. If in doubt, saying N is the safe plan.
+
+CONFIG_PARPORT_ATARI
+  Say Y here if you need support for the parallel port hardware on
+  Atari machines. This code is also available as a module (say M),
+  called parport_atari.o. If in doubt, saying N is the safe plan.
+
+CONFIG_PARPORT_MFC3
+  Say Y here if you need parallel port support for the MFC3 card.
+  This code is also available as a module (say M), called
+  parport_mfc3.o. If in doubt, saying N is the safe plan.
+
+CONFIG_PARPORT_1284
+  If you have a printer that supports status readback or device ID, or
+  want to use a device that uses enhanced parallel port transfer modes
+  such as EPP and ECP, say Y here to enable advanced IEEE 1284
+  transfer modes. Also say Y if you want device ID information to
+  appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N.
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_BLK_DEV_SD
+  If you want to use a SCSI hard disk or the SCSI or parallel port
+  version of the IOMEGA ZIP drive under Linux, say Y and read the
+  SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. This is NOT for SCSI
+  CD-ROMs.
+
+  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 sd_mod.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  Do not compile this driver as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI disk. In this case, do not compile the driver
+  for your SCSI host adapter (below) as a module either.
+
+CONFIG_SD_EXTRA_DEVS
+  This controls the amount of additional space allocated in tables for
+  drivers that are loaded as modules after the kernel is booted.  In
+  the event that the SCSI core itself was loaded as a module, this
+  value is the number of additional disks that can be loaded after the
+  first host driver is loaded.
+
+  Admittedly this isn't pretty, but there are tons of race conditions
+  involved with resizing the internal arrays on the fly.  Someday this
+  flag will go away, and everything will work automatically.
+
+  If you don't understand what's going on, go with the default.
+
+CONFIG_ST_EXTRA_DEVS
+  This controls the amount of additional space allocated in tables for
+  drivers that are loaded as modules after the kernel is booted.  In
+  the event that the SCSI core itself was loaded as a module, this
+  value is the number of additional tapes that can be loaded after the
+  first host driver is loaded.
+
+  Admittedly this isn't pretty, but there are tons of race conditions
+  involved with resizing the internal arrays on the fly.  Someday this
+  flag will go away, and everything will work automatically.
+
+  If you don't understand what's going on, go with the default.
+
+CONFIG_CHR_DEV_ST
+  If you want to use a SCSI tape drive under Linux, say Y and read the
+  SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, and
+  <file:drivers/scsi/README.st> in the kernel source.  This is NOT for
+  SCSI CD-ROMs.
+
+  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 st.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_BLK_DEV_SR
+  If you want to use a SCSI CD-ROM under Linux, say Y and read the
+  SCSI-HOWTO and the CD-ROM-HOWTO at
+  <http://www.linuxdoc.org/docs.html#howto>. Also make sure to say Y
+  or M to "ISO 9660 CD-ROM file system support" later.
+
+  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 sr_mod.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_SR_EXTRA_DEVS
+  This controls the amount of additional space allocated in tables for
+  drivers that are loaded as modules after the kernel is booted. In
+  the event that the SCSI core itself was loaded as a module, this
+  value is the number of additional CD-ROMs that can be loaded after
+  the first host driver is loaded.
+
+  Admittedly this isn't pretty, but there are tons of race conditions
+  involved with resizing the internal arrays on the fly.  Someday this
+  flag will go away, and everything will work automatically.
+
+  If you don't understand what's going on, go with the default.
+
+CONFIG_BLK_DEV_SR_VENDOR
+  This enables the usage of vendor specific SCSI commands. This is
+  required to support multisession CDs with old NEC/TOSHIBA cdrom
+  drives (and HP Writers). If you have such a drive and get the first
+  session only, try saying Y here; everybody else says N.
+
+CONFIG_CHR_DEV_SG
+  If you want to use SCSI scanners, synthesizers or CD-writers or just
+  about anything having "SCSI" in its name other than hard disks,
+  CD-ROMs or tapes, say Y here. These won't be supported by the kernel
+  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 Cdrtools
+  (<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html>)
+  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.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>. The module will be called sg.o. If unsure,
+  say N.
+
+CONFIG_SCSI_MULTI_LUN
+  If you have a SCSI device that supports more than one LUN (Logical
+  Unit Number), e.g. a CD jukebox, and only one LUN is detected, you
+  can say Y here to force the SCSI driver to probe for multiple LUNs.
+  A SCSI device with multiple LUNs acts logically like multiple SCSI
+  devices. The vast majority of SCSI devices have only one LUN, and
+  so most people can say N here and should in fact do so, because it
+  is safer.
+
+CONFIG_SCSI_CONSTANTS
+  The error messages regarding your SCSI hardware will be easier to
+  understand if you say Y here; it will enlarge your kernel by about
+  12 KB. If in doubt, say Y.
+
+CONFIG_SCSI_LOGGING
+  This turns on a logging facility that can be used to debug a number
+  of SCSI related problems.
+
+  If you say Y here, no logging output will appear by default, but you
+  can enable logging by saying Y to "/proc file system support" and
+  "Sysctl support" below and executing the command
+
+     echo "scsi log token [level]" > /proc/scsi/scsi
+
+  at boot time after the /proc file system has been mounted.
+
+  There are a number of things that can be used for 'token' (you can
+  find them in the source: <file:drivers/scsi/scsi.c>), and this
+  allows you to select the types of information you want, and the
+  level allows you to select the level of verbosity.
+
+  If you say N here, it may be harder to track down some types of SCSI
+  problems. If you say Y here your kernel will be somewhat larger, but
+  there should be no noticeable performance impact as long as you have
+  logging turned off.
+
+CONFIG_SCSI_DEBUG
+  This is a host adapter simulator that can be programmed to simulate
+  a large number of conditions that could occur on a real bus. The
+  advantage is that many hard to reproduce problems can be tested in a
+  controlled environment where there is reduced risk of losing
+  important data. This is primarily of use to people trying to debug
+  the middle and upper layers of the SCSI subsystem. If unsure, say N.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_DUMMY
+  This is essentially a bit-bucket device (i.e. traffic you send to
+  this device is consigned into oblivion) with a configurable IP
+  address. It is most commonly used in order to make your currently
+  inactive SLIP address seem like a real address for local programs.
+  If you use SLIP or PPP, you might want to say Y here. Since this
+  thing often comes in handy, the default is Y. It won't enlarge your
+  kernel either. What a deal. Read about it in the Network
+  Administrator's Guide, available from
+  <http://www.linuxdoc.org/docs.html#guide>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called dummy.o.  If you want to use more than one dummy
+  device at a time, you need to compile this driver as a module.
+  Instead of 'dummy', the devices will then be called 'dummy0',
+  'dummy1' etc.
+
+CONFIG_SLIP
+  Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
+  connect to your Internet service provider or to connect to some
+  other local Unix box or if you want to configure your Linux box as a
+  Slip/CSlip server for other people to dial in. SLIP (Serial Line
+  Internet Protocol) is a protocol used to send Internet traffic over
+  serial connections such as telephone lines or null modem cables;
+  nowadays, the protocol PPP is more commonly used for this same
+  purpose.
+
+  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 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
+  <http://www.linuxdoc.org/docs.html#howto>, explains how to
+  configure SLIP. Note that you don't need this option if you just
+  want to run term (term is a program which gives you almost full
+  Internet connectivity if you have a regular dial up shell account on
+  some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). SLIP
+  support will enlarge your kernel by about 4 KB. If unsure, say N.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>. The module will be
+  called slip.o.
+
+CONFIG_SLIP_COMPRESSED
+  This protocol is faster than SLIP because it uses compression on the
+  TCP/IP headers (not on the data itself), but it has to be supported
+  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://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
+  CSLIP. This won't enlarge your kernel.
+
+CONFIG_SLIP_SMART
+  Adds additional capabilities to the SLIP driver to support the
+  RELCOM line fill and keepalive monitoring. Ideal on poor quality
+  analogue lines.
+
+CONFIG_SLIP_MODE_SLIP6
+  Just occasionally you may need to run IP over hostile serial
+  networks that don't pass all control characters or are only seven
+  bit. Saying Y here adds an extra mode you can use with SLIP:
+  "slip6". In this mode, SLIP will only send normal ASCII symbols over
+  the serial device. Naturally, this has to be supported at the other
+  end of the link as well. It's good enough, for example, to run IP
+  over the async ports of a Camtec JNT Pad. If unsure, say N.
+
+CONFIG_PPP
+  PPP (Point to Point Protocol) is a newer and better SLIP.  It serves
+  the same purpose: sending Internet traffic over telephone (and other
+  serial) lines.  Ask your access provider if they support it, because
+  otherwise you can't use it; most Internet access providers these
+  days support PPP rather than SLIP.
+
+  To use PPP, you need an additional program called pppd as described
+  in the PPP-HOWTO, available at
+  <http://www.linuxdoc.org/docs.html#howto>.  Make sure that you have
+  the version of pppd recommended in <file:Documentation/Changes>.
+  The PPP option enlarges your kernel by about 16 KB.
+
+  There are actually two versions of PPP: the traditional PPP for
+  asynchronous lines, such as regular analog phone lines, and
+  synchronous PPP which can be used over digital ISDN lines for
+  example.  If you want to use PPP over phone lines or other
+  asynchronous serial lines, you need to say Y (or M) here and also to
+  the next option, "PPP support for async serial ports".  For PPP over
+  synchronous lines, you should say Y (or M) here and to "Support
+  synchronous PPP", below.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you said Y to "Version information on all symbols" above, then
+  you cannot compile the PPP driver into the kernel; you can then only
+  compile it as a module.  The module will be called ppp_generic.o.
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_PLIP
+  PLIP (Parallel Line Internet Protocol) is used to create a
+  reasonably fast mini network consisting of two (or, rarely, more)
+  local machines.  A PLIP link from a Linux box is a popular means to
+  install a Linux distribution on a machine which doesn't have a
+  CD-ROM drive (a minimal system has to be transferred with floppies
+  first). The kernels on both machines need to have this PLIP option
+  enabled for this to work.
+
+  The PLIP driver has two modes, mode 0 and mode 1.  The parallel
+  ports (the connectors at the computers with 25 holes) are connected
+  with "null printer" or "Turbo Laplink" cables which can transmit 4
+  bits at a time (mode 0) or with special PLIP cables, to be used on
+  bidirectional parallel ports only, which can transmit 8 bits at a
+  time (mode 1); you can find the wiring of these cables in
+  <file:Documentation/networking/PLIP.txt>.  The cables can be up to
+  15m long.  Mode 0 works also if one of the machines runs DOS/Windows
+  and has some PLIP software installed, e.g. the Crynwr PLIP packet
+  driver (<http://oak.oakland.edu/simtel.net/msdos/pktdrvr-pre.html>)
+  and winsock or NCSA's telnet.
+
+  If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well
+  as the NET-3-HOWTO, both available from
+  <http://www.linuxdoc.org/docs.html#howto>.  Note that the PLIP
+  protocol has been changed and this PLIP driver won't work together
+  with the PLIP support in Linux versions 1.0.x.  This option enlarges
+  your kernel by about 8 KB.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called plip.o.  If unsure, say Y or M, in case you buy a laptop
+  later.
+
+CONFIG_EQUALIZER
+  If you have two serial connections to some other computer (this
+  usually requires two modems and two telephone lines) and you use
+  SLIP (the protocol for sending Internet traffic over telephone
+  lines) or PPP (a better SLIP) on them, you can make them behave like
+  one double speed connection using this driver.  Naturally, this has
+  to be supported at the other end as well, either with a similar EQL
+  Linux driver or with a Livingston Portmaster 2e.
+
+  Say Y if you want this and read
+  <file:Documentation/networking/eql.txt>.  You may also want to read
+  section 6.2 of the NET-3-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called eql.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.  If
+  unsure, say N.
+
+CONFIG_SMC9194
+  This is support for the SMC9xxx based Ethernet cards. Choose this
+  option if you have a DELL laptop with the docking station, or
+  another SMC9192/9194 based chipset.  Say Y if you want it compiled
+  into the kernel, and read the file
+  <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called smc9194.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_NE2000
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  Many Ethernet cards
+  without a specific driver are compatible with NE2000.
+
+  If you have a PCI NE2000 card however, say N here and Y to "PCI
+  NE2000 support", above. If you have a NE2000 card and are running on
+  an MCA system (a bus system used on some IBM PS/2 computers and
+  laptops), say N here and Y to "NE/2 (ne2000 MCA version) support",
+  below.
+
+  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 ne.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_SUN3LANCE
+  Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80)
+  featured an AMD Lance 10Mbit Ethernet controller on board; say Y
+  here to compile in the Linux driver for this and enable Ethernet.
+  General Linux information on the Sun 3 and 3x series (now
+  discontinued) is at
+  <http://www.angelfire.com/ca2/tech68k/sun3.html>.
+
+  If you're not building a kernel for a Sun 3, say N.
+
+CONFIG_SUN3_82586
+  This driver enables support for the on-board Intel 82586 based
+  Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards.  Note
+  that this driver does not support 82586-based adapters on additional
+  VME boards.
+
+CONFIG_INPUT_ADBHID
+  Say Y here if you want to have ADB (Apple Desktop Bus) HID devices
+  such as keyboards, mice, joysticks, or graphic tablets handled by
+  the input layer.  If you say Y here, make sure to say Y to the
+  corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV),
+  "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface
+  support" (CONFIG_INPUT_EVDEV) as well.
+
+  If you say N here, you still have the option of using the old ADB
+  keyboard and mouse drivers.
+
+  If unsure, say Y.
+
+CONFIG_VT
+  If you say Y here, you will get support for terminal devices with
+  display and keyboard devices. These are called "virtual" because you
+  can run several virtual terminals (also called virtual consoles) on
+  one physical terminal. This is rather useful, for example one
+  virtual terminal can collect system messages and warnings, another
+  one can be used for a text-mode user session, and a third could run
+  an X session, all in parallel. Switching between virtual terminals
+  is done with certain key combinations, usually Alt-<function key>.
+
+  The setterm command ("man setterm") can be used to change the
+  properties (such as colors or beeping) of a virtual terminal. The
+  man page console_codes(4) ("man console_codes") contains the special
+  character sequences that can be used to change those properties
+  directly. The fonts used on virtual terminals can be changed with
+  the setfont ("man setfont") command and the key bindings are defined
+  with the loadkeys ("man loadkeys") command.
+
+  You need at least one virtual terminal device in order to make use
+  of your keyboard and monitor. Therefore, only people configuring an
+  embedded system would want to say N here in order to save some
+  memory; the only way to log into such a system is then via a serial
+  or network connection.
+
+  If unsure, say Y, or else you won't be able to do much with your new
+  shiny Linux system :-)
+
+CONFIG_VT_CONSOLE
+  The system console is the device which receives all kernel messages
+  and warnings and which allows logins in single user mode. If you
+  answer Y here, a virtual terminal (the device used to interact with
+  a physical terminal) can be used as system console. This is the most
+  common mode of operations, so you should say Y here unless you want
+  the kernel messages be output only to a serial port (in which case
+  you should say Y to "Console on serial port", below).
+
+  If you do say Y here, by default the currently visible virtual
+  terminal (/dev/tty0) will be used as system console. You can change
+  that with a kernel command line option such as "console=tty3" which
+  would use the third virtual terminal as system console. (Try "man
+  bootparam" or see the documentation of your boot loader (lilo or
+  loadlin) about how to pass options to the kernel at boot time.)
+
+  If unsure, say Y.
+
+CONFIG_ADB
+  Apple Desktop Bus (ADB) support is for support of devices which
+  are connected to an ADB port.  ADB devices tend to have 4 pins.
+  If you have an Apple Macintosh prior to the iMac, or a
+  "Blue and White G3", you probably want to say Y here.  Otherwise
+  say N.
+
+CONFIG_ADB_CUDA
+  This provides support for CUDA based Power Macintosh systems.  This
+  includes most OldWorld PowerMacs, the first generation iMacs, the
+  Blue&White G3 and the Yikes G4 (PCI Graphics).  All later models
+  should use CONFIG_ADB_PMU instead.
+
+  If unsure say Y.
+
+CONFIG_ADB_KEYBOARD
+  This option allows you to use an ADB keyboard attached to your
+  machine. Note that this disables any other (ie. PS/2) keyboard
+  support, even if your machine is physically capable of using both at
+  the same time.
+
+  If you use an ADB keyboard (4 pin connector), say Y here.
+  If you use a PS/2 keyboard (6 pin connector), say N here.
+
+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
+  support for it, say 'Y' here.
+
+CONFIG_ADB_MACII
+  Say Y here if want your kernel to support Macintosh systems that use
+  the Mac II style ADB.  This includes the II, IIx, IIcx, SE/30, IIci,
+  Quadra 610, Quadra 650, Quadra 700, Quadra 800, Centris 610 and
+  Centris 650.
+
+CONFIG_ADB_MACIISI
+  Say Y here if want your kernel to support Macintosh systems that use
+  the Mac IIsi style ADB.  This includes the IIsi, IIvi, IIvx, Classic
+  II, LC, LC II, LC III, Performa 460, and the Performa 600.
+
+CONFIG_ADB_PMU68K
+  Say Y here if want your kernel to support the m68k based Powerbooks.
+  This includes the PowerBook 140, PowerBook 145, PowerBook 150,
+  PowerBook 160, PowerBook 165, PowerBook 165c, PowerBook 170,
+  PowerBook 180, PowerBook, 180c, PowerBook 190cs, PowerBook 520,
+  PowerBook Duo 210, PowerBook Duo 230, PowerBook Duo 250,
+  PowerBook Duo 270c, PowerBook Duo 280 and PowerBook Duo 280c.
+
+CONFIG_MAC8390
+  If you want to include a driver to support Nubus or LC-PDS
+  Ethernet cards using an NS8390 chipset or its equivalent, say Y
+  and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+CONFIG_MAC89x0
+  Support for CS89x0 chipset based Ethernet cards.  If you have a
+  Nubus or LC-PDS network (Ethernet) card of this type, say Y and
+  read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  This module will
+  be called mac89x0.o.
+
+CONFIG_MACMACE
+  Support for the onboard AMD 79C940 MACE Ethernet controller used in
+  the 660AV and 840AV Macintosh.  If you have one of these Macintoshes
+  say Y and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+CONFIG_MACSONIC
+  Support for NatSemi SONIC based Ethernet devices.  This includes
+  the onboard Ethernet in many Quadras as well as some LC-PDS,
+  a few Nubus and all known Comm Slot Ethernet cards.  If you have
+  one of these say Y and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  This module will
+  be called macsonic.o.
+
+CONFIG_MAC_SCSI
+  This is the NCR 5380 SCSI controller included on most of the 68030
+  based Macintoshes.  If you have one of these say Y and read the
+  SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+CONFIG_SCSI_MAC_ESP
+  This is the NCR 53c9x SCSI controller found on most of the 68040
+  based Macintoshes.  If you have one of these say Y and read the
+  SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called mac_esp.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SERIAL
+  This selects whether you want to include the driver for the standard
+  serial ports.  The standard answer is Y.  People who might say N
+  here are those that are setting up dedicated Ethernet WWW/FTP
+  servers, or users that have one of the various bus mice instead of a
+  serial mouse and don't intend to use their machine's standard serial
+  port for anything.  (Note that the Cyclades and Stallion multi
+  serial port drivers do not need this driver built in for them to
+  work.)
+
+  If you want to compile this driver as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  serial.o.
+  [WARNING: Do not compile this driver as a module if you are using
+  non-standard serial ports, since the configuration information will
+  be lost when the driver is unloaded.  This limitation may be lifted
+  in the future.]
+
+  BTW1: If you have a mouseman serial mouse which is not recognized by
+  the X window system, try running gpm first.
+
+  BTW2: If you intend to use a software modem (also called Winmodem)
+  under Linux, forget it.  These modems are crippled and require
+  proprietary drivers which are only available under Windows.
+
+  Most people will say Y or M here, so that they can use serial mice,
+  modems and similar devices connecting to the standard serial ports.
+
+CONFIG_SERIAL_CONSOLE
+  If you say Y here, it will be possible to use a serial port as the
+  system console (the system console is the device which receives all
+  kernel messages and warnings and which allows logins in single user
+  mode). This could be useful if some terminal or printer is connected
+  to that serial port.
+
+  Even if you say Y here, the currently visible virtual console
+  (/dev/tty0) will still be used as the system console by default, but
+  you can alter that using a kernel command line option such as
+  "console=ttyS1". (Try "man bootparam" or see the documentation of
+  your boot loader (lilo or loadlin) about how to pass options to the
+  kernel at boot time.)
+
+  If you don't have a VGA card installed and you say Y here, the
+  kernel will automatically use the first serial line, /dev/ttyS0, as
+  system console.
+
+  If unsure, say N.
+
+CONFIG_UNIX98_PTYS
+  A pseudo terminal (PTY) is a software device consisting of two
+  halves: a master and a slave. The slave device behaves identical to
+  a physical terminal; the master device is used by a process to
+  read data from and write data to the slave, thereby emulating a
+  terminal. Typical programs for the master side are telnet servers
+  and xterms.
+
+  Linux has traditionally used the BSD-like names /dev/ptyxx for
+  masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
+  has a number of problems. The GNU C library glibc 2.1 and later,
+  however, supports the Unix98 naming standard: in order to acquire a
+  pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
+  terminal is then made available to the process and the pseudo
+  terminal slave can be accessed as /dev/pts/<number>. What was
+  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
+
+  The entries in /dev/pts/ are created on the fly by a virtual
+  file system; therefore, if you say Y here you should say Y to
+  "/dev/pts file system for Unix98 PTYs" as well.
+
+  If you want to say Y here, you need to have the C library glibc 2.1
+  or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
+  Read the instructions in <file:Documentation/Changes> pertaining to
+  pseudo terminals. It's safe to say N.
+
+CONFIG_UNIX98_PTY_COUNT
+  The maximum number of Unix98 PTYs that can be used at any one time.
+  The default is 256, and should be enough for desktop systems. Server
+  machines which support incoming telnet/rlogin/ssh connections and/or
+  serve several X terminals may want to increase this: every incoming
+  connection and every xterm uses up one PTY.
+
+  When not in use, each additional set of 256 PTYs occupy
+  approximately 8 KB of kernel memory on 32-bit architectures.
+
+CONFIG_PRINTER
+  If you intend to attach a printer to the parallel port of your Linux
+  box (as opposed to using a serial printer; if the connector at the
+  printer has 9 or 25 holes ["female"], then it's serial), say Y.
+  Also read the Printing-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  It is possible to share one parallel port among several devices
+  (e.g. printer and ZIP drive) and it is safe to compile the
+  corresponding drivers into the kernel.  If you want to compile this
+  driver as a module however ( = code which can be inserted in and
+  removed from the running kernel whenever you want), say M here and
+  read <file:Documentation/modules.txt> and
+  <file:Documentation/parport.txt>.  The module will be called lp.o.
+
+  If you have several parallel ports, you can specify which ports to
+  use with the "lp" kernel command line option.  (Try "man bootparam"
+  or see the documentation of your boot loader (lilo or loadlin) about
+  how to pass options to the kernel at boot time.)  The syntax of the
+  "lp" command line option can be found in <file:drivers/char/lp.c>.
+
+  If you have more than 8 printers, you need to increase the LP_NO
+  macro in lp.c and the PARPORT_MAX macro in parport.h.
+
+CONFIG_BUSMOUSE
+  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 a laptop, you either have to check the documentation or
+  experiment a bit to find out whether the trackball is a serial mouse
+  or not; it's best to say Y here for you.
+
+  This is the generic bus mouse driver code. If you have a bus mouse,
+  you will have to say Y here and also to the specific driver for your
+  mouse below.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called busmouse.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_WATCHDOG
+  If you say Y here (and to one of the following options) and create a
+  character special file /dev/watchdog with major number 10 and minor
+  number 130 using mknod ("man mknod"), you will get a watchdog, i.e.:
+  subsequently opening the file and then failing to write to it for
+  longer than 1 minute will result in rebooting the machine. This
+  could be useful for a networked machine that needs to come back
+  online as fast as possible after a lock-up. There's both a watchdog
+  implementation entirely in software (which can sometimes fail to
+  reboot the machine) and a driver for hardware watchdog boards, which
+  are more robust and can also keep track of the temperature inside
+  your computer. For details, read <file:Documentation/watchdog.txt>
+  in the kernel source.
+
+  The watchdog is usually used together with the watchdog daemon
+  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.
+
+CONFIG_WATCHDOG_NOWAYOUT
+  The default watchdog behaviour (which you get if you say N here) is
+  to stop the timer if the process managing it closes the file
+  /dev/watchdog. It's always remotely possible that this process might
+  get killed. If you say Y here, the watchdog cannot be stopped once
+  it has been started.
+
+CONFIG_SOFT_WATCHDOG
+  A software monitoring watchdog. This will fail to reboot your system
+  from some situations that the hardware watchdog will recover
+  from. Equally it's a lot cheaper to install.
+
+  This driver is also available 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>. The module will be called
+   softdog.o.
+
+CONFIG_RTC
+  If you say Y here and create a character special file /dev/rtc with
+  major number 10 and minor number 135 using mknod ("man mknod"), you
+  will get access to the real time clock (or hardware clock) built
+  into your computer.
+
+  Every PC has such a clock built in. It can be used to generate
+  signals from as low as 1Hz up to 8192Hz, and can also be used
+  as a 24 hour alarm. It reports status information via the file
+  /proc/driver/rtc and its behaviour is set by various ioctls on
+  /dev/rtc.
+
+  If you run Linux on a multiprocessor machine and said Y to
+  "Symmetric Multi Processing" above, you should say Y here to read
+  and set the RTC in an SMP compatible fashion.
+
+  If you think you have a use for such a device (such as periodic data
+  sampling), then say Y here, and read <file:Documentation/rtc.txt>
+  for details.
+
+  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 is called rtc.o. If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_NVRAM
+  If you say Y here and create a character special file /dev/nvram
+  with major number 10 and minor number 144 using mknod ("man mknod"),
+  you get read and write access to the 50 bytes of non-volatile memory
+  in the real time clock (RTC), which is contained in every PC and
+  most Ataris.
+
+  This memory is conventionally called "CMOS RAM" on PCs and "NVRAM"
+  on Ataris. /dev/nvram may be used to view settings there, or to
+  change them (with some utility). It could also be used to frequently
+  save a few bits of very important data that may not be lost over
+  power-off and for which writing to disk is too insecure. Note
+  however that most NVRAM space in a PC belongs to the BIOS and you
+  should NEVER idly tamper with it. See Ralf Brown's interrupt list
+  for a guide to the use of CMOS bytes by your BIOS.
+
+  On Atari machines, /dev/nvram is always configured and does not need
+  to be selected.
+
+  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 nvram.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y.  Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. General information about
+  the modular sound system is contained in the files
+  <file:Documentation/sound/Introduction>.  The file
+  <file:Documentation/sound/README.OSS> contains some slightly
+  outdated but still useful information as well.
+
+  If you have a PnP sound card and you want to configure it at boot
+  time using the ISA PnP tools (read
+  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished.  To do
+  this, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/sound/README.modules>; the module will be
+  called soundcore.o.
+
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and supporting utilities to do that are in the pcsp
+  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_PROC_HARDWARE
+  Say Y here to support the /proc/hardware file, which gives you
+  access to information about the machine you're running on,
+  including the model, CPU, MMU, clock speed, BogoMIPS rating,
+  and memory size.
+
+CONFIG_AMIGA
+  This option enables support for the Amiga series of computers. If
+  you plan to use this kernel on an Amiga, say Y here and browse the
+  material available in <file:Documentation/m68k>; otherwise say N.
+
+CONFIG_A2232
+  This option supports the 2232 7-port serial card shipped with the
+  Amiga 2000 and other Zorro-bus machines, dating from 1989.  At
+  a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip
+  each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The
+  ports were connected with 8 pin DIN connectors on the card bracket,
+  for which 8 pin to DB25 adapters were supplied. The card also had
+  jumpers internally to toggle various pinning configurations.
+
+  This driver can be built as a module; but then "generic_serial.o"
+  will also be built as a module. This has to be loaded before
+  "ser_a2232.o". If you want to do this, answer M here and read
+  "<file:Documentation/modules.txt>".
+
+CONFIG_A4000T_SCSI
+  Support for the NCR53C710 SCSI controller on the Amiga 4000T.
+
+CONFIG_A4091_SCSI
+  Support for the NCR53C710 chip on the Amiga 4091 Z3 SCSI2 controller
+  (1993).  Very obscure -- the 4091 was part of an Amiga 4000 upgrade
+  plan at the time the Amiga business was sold to DKB.
+
+CONFIG_ATARI
+  This option enables support for the 68000-based Atari series of
+  computers (including the TT, Falcon and Medusa). If you plan to use
+  this kernel on an Atari, say Y here and browse the material
+  available in <file:Documentation/m68k>; otherwise say N.
+
+CONFIG_HADES
+  This option enables support for the Hades Atari clone. If you plan
+  to use this kernel on a Hades, say Y here; otherwise say N.
+
+CONFIG_MAC
+  This option enables support for the Apple Macintosh series of
+  computers (yes, there is experimental support now, at least for part
+  of the series).
+
+  Say N unless you're willing to code the remaining necessary support.
+  ;)
+
+CONFIG_HP300
+  This option enables support for the HP9000/300 series of
+  workstations. Support for these machines is still very experimental.
+  If you plan to try to use the kernel on such a machine say Y here.
+  Everybody else says N.
+
+CONFIG_Q40
+  The Q40 is a Motorola 68040-based successor to the Sinclair QL
+  manufactured in Germany.  There is an official Q40 home page at
+  <http://www.q40.de/>.  This option enables support for the Q40 and
+  Q60. Select your CPU below.  For 68LC060 don't forget to enable FPU
+  emulation.
+
+CONFIG_SUN3
+  This option enables support for the Sun 3 series of workstations.
+  Currently, only the Sun 3/80 is supported within the Sun 3x family.
+  You will also want to enable 68030 support.  General Linux
+  information on the Sun 3x series (now discontinued) is at
+  <http://www.angelfire.com/ca2/tech68k/sun3.html>.
+
+  If you don't want to compile a kernel for a Sun 3, say N.
+
+CONFIG_SUN3X
+  This option enables support for the Sun 3x series of workstations.
+  Be warned that this support is very experimental. You will also want
+  to say Y to 68020 support and N to the other processors below.
+  General Linux information on the Sun 3x series (now discontinued)
+  is at <http://www.angelfire.com/ca2/tech68k/sun3.html>.
+
+  If you don't want to compile a kernel for a Sun 3x, say N.
+
+CONFIG_SUN3X_ZS
+  ZS refers to a type of asynchronous serial port built in to the Sun3
+  and Sun3x workstations; if you have a Sun 3, you probably have
+  these.  Say 'Y' to support ZS ports directly.  This option must be
+  enabled in order to support the
+  keyboard and mouse ports.
+
+CONFIG_SUN_KEYBOARD
+  Say Y here to support the keyboard found on Sun 3 and 3x
+  workstations.  It can also be used support Sun Type-5 keyboards
+  through an adaptor.  See
+  <http://www.suse.cz/development/input/adapters.html> and
+  <http://sourceforge.net/projects/linuxconsole/> for details on the
+  latter.
+
+CONFIG_M68020
+  If you anticipate running this kernel on a computer with a MC68020
+  processor, say Y. Otherwise, say N. Note that the 68020 requires a
+  68851 MMU (Memory Management Unit) to run Linux/m68k, except on the
+  Sun 3, which provides its own version.
+
+CONFIG_M68030
+  If you anticipate running this kernel on a computer with a MC68030
+  processor, say Y. Otherwise, say N. Note that a MC68EC030 will not
+  work, as it does not include an MMU (Memory Management Unit).
+
+CONFIG_M68040
+  If you anticipate running this kernel on a computer with a MC68LC040
+  or MC68040 processor, say Y. Otherwise, say N. Note that an
+  MC68EC040 will not work, as it does not include an MMU (Memory
+  Management Unit).
+
+CONFIG_M68060
+  If you anticipate running this kernel on a computer with a MC68060
+  processor, say Y. Otherwise, say N.
+
+CONFIG_M68KFPU_EMU
+  At some point in the future, this will cause floating-point math
+  instructions to be emulated by the kernel on machines that lack a
+  floating-point math coprocessor.  Thrill-seekers and chronically
+  sleep-deprived psychotic hacker types can say Y now, everyone else
+  should probably wait a while.
+
+CONFIG_M68KFPU_EMU_ONLY
+  This option prevents any floating-point instructions from being
+  compiled into the kernel, thereby the kernel doesn't save any
+  floating point context anymore during task switches, so this
+  kernel will only be usable on machines without a floating-point
+  math coprocessor. This makes the kernel a bit faster as no tests
+  needs to be executed whether a floating-point instruction in the
+  kernel should be executed or not.
+
+CONFIG_M68KFPU_EMU_EXTRAPREC
+  The fpu uses normally a few bit more during calculations for
+  correct rounding, the emulator can (often) do the same but this
+  extra calculation can cost quite some time, so you can disable
+  it here. The emulator will then "only" calculate with a 64 bit
+  mantissa and round slightly incorrect, what is more then enough
+  for normal usage.
+
+CONFIG_ADVANCED
+  This gives you access to some advanced options for the CPU. The
+  defaults should be fine for most users, but these options may make
+  it possible for you to improve performance somewhat if you know what
+  you are doing.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about these options.
+
+  Most users should say N to this question.
+
+CONFIG_SINGLE_MEMORY_CHUNK
+  Ignore all but the first contiguous chunk of physical memory for VM
+  purposes.  This will save a few bytes kernel size and may speed up
+  some operations.  Say N if not sure.
+
+CONFIG_RMW_INSNS
+  This allows to use certain instructions that work with indivisible
+  read-modify-write bus cycles. While this is faster than the
+  workaround of disabling interrupts, it can conflict with DMA
+  ( = direct memory access) on many Amiga systems, and it is also said
+  to destabilize other machines. It is very likely that this will
+  cause serious problems on any Amiga or Atari Medusa if set. The only
+  configuration where it should work are 68030-based Ataris, where it
+  apparently improves performance. But you've been warned! Unless you
+  really know what you are doing, say N. Try Y only if you're quite
+  adventurous.
+
+CONFIG_ZORRO
+  This enables support for the Zorro bus in the Amiga. If you have
+  expansion cards in your Amiga that conform to the Amiga
+  AutoConfig(tm) specification, say Y, otherwise N. Note that even
+  expansion cards that do not fit in the Zorro slots but fit in e.g.
+  the CPU slot may fall in this category, so you have to say Y to let
+  Linux use these.
+
+CONFIG_AMIGA_PCMCIA
+  Include support in the kernel for pcmcia on Amiga 1200 and Amiga
+  600. If you intend to use pcmcia cards say Y; otherwise say N.
+
+CONFIG_WHIPPET_SERIAL
+  HiSoft has a web page at <http://www.hisoft.co.uk/>, but there
+  is no listing for the Whippet in their Amiga section.
+
+CONFIG_STRAM_SWAP
+  Some Atari 68k macines (including the 520STF and 1020STE) divide
+  their addressible memory into ST and TT sections.  The TT section
+  (up to 512MB) is the main memory; the ST section (up to 4MB) is
+  accessible to the built-in graphics board, runs slower, and is
+  present mainly for backward compatibility with older machines.
+
+  This enables support for using (parts of) ST-RAM as swap space,
+  instead of as normal system memory. This can first enhance system
+  performance if you have lots of alternate RAM (compared to the size
+  of ST-RAM), because executable code always will reside in faster
+  memory. ST-RAM will remain as ultra-fast swap space. On the other
+  hand, it allows much improved dynamic allocations of ST-RAM buffers
+  for device driver modules (e.g. floppy, ACSI, SLM printer, DMA
+  sound). The probability that such allocations at module load time
+  fail is drastically reduced.
+
+CONFIG_STRAM_PROC
+  Say Y here to report ST-RAM usage statistics in /proc/stram.  See
+  the help for CONFIG_STRAM_SWAP for discussion of ST-RAM and its
+  uses.
+
+CONFIG_A3000_SCSI
+  If you have an Amiga 3000 and have SCSI devices connected to the
+  built-in SCSI controller, say Y. Otherwise, say N. 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 is
+  called wd33c93.o. If you want to compile it as a module, say M here
+  and read <file:Documentation/modules.txt>.
+
+CONFIG_A2091_SCSI
+  If you have a Commodore A2091 SCSI controller, say Y. Otherwise,
+  say N. 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 is called wd33c93.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GVP11_SCSI
+  If you have a Great Valley Products Series II SCSI controller,
+  answer Y. Also say Y if you have a later model of GVP SCSI
+  controller (such as the GVP A4008 or a Combo board). Otherwise,
+  answer N. This driver does NOT work for the T-Rex series of
+  accelerators from TekMagic and GVP-M.
+
+  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 gvp11.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_CYBERSTORM_SCSI
+  If you have an Amiga with an original (MkI) Phase5 Cyberstorm
+  accelerator board and the optional Cyberstorm SCSI controller,
+  answer Y. Otherwise, say N.
+
+CONFIG_CYBERSTORMII_SCSI
+  If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board
+  and the optional Cyberstorm SCSI controller, say Y. Otherwise,
+  answer N.
+
+CONFIG_BLZ2060_SCSI
+  If you have an Amiga with a Phase5 Blizzard 2060 accelerator board
+  and want to use the onboard SCSI controller, say Y. Otherwise,
+  answer N.
+
+CONFIG_BLZ1230_SCSI
+  If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard
+  1260 accelerator, and the optional SCSI module, say Y. Otherwise,
+  say N.
+
+CONFIG_BLZ603EPLUS_SCSI
+  If you have an Amiga 1200 with a Phase5 Blizzard PowerUP 603e+
+  accelerator, say Y. Otherwise, say N.
+
+CONFIG_FASTLANE_SCSI
+  If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use
+  one in the near future, say Y to this question. Otherwise, say N.
+
+CONFIG_OKTAGON_SCSI
+  If you have the BSC Oktagon SCSI disk controller for the Amiga, say
+  Y to this question.  If you're in doubt about whether you have one,
+  see the picture at
+  <http://amiga.multigraph.com/photos/oktagon.html>.
+
+CONFIG_ATARI_SCSI
+  If you have an Atari with built-in NCR5380 SCSI controller (TT,
+  Falcon, ...) say Y to get it supported. Of course also, if you have
+  a compatible SCSI controller (e.g. for Medusa).  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 is called
+  atari_scsi.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.  This driver supports both
+  styles of NCR integration into the system: the TT style (separate
+  DMA), and the Falcon style (via ST-DMA, replacing ACSI).  It does
+  NOT support other schemes, like in the Hades (without DMA).
+
+CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+  This option increases the delay after a SCSI arbitration to
+  accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to
+  use a Toshiba CD-ROM drive; otherwise, the option is not needed and
+  would impact performance a bit, so say N.
+
+CONFIG_ATARI_SCSI_RESET_BOOT
+  Reset the devices on your Atari whenever it boots.  This makes the
+  boot process fractionally longer but may assist recovery from errors
+  that leave the devices with SCSI operations partway completed.
+
+CONFIG_TT_DMA_EMUL
+  This option enables code which emulates the TT SCSI DMA chip on the
+  Hades. This increases the SCSI transfer rates at least ten times
+  compared to PIO transfers.
+
+CONFIG_ARIADNE
+  If you have a Village Tronic Ariadne Ethernet adapter, say Y.
+  Otherwise, say N.
+
+  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 is called ariadne.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_ARIADNE2
+  This driver is for the Village Tronic Ariadne II and the Individual
+  Computers X-Surf Ethernet cards. If you have such a card, say Y.
+  Otherwise, say N.
+
+  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 ariadne2.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_A2065
+  If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise,
+  say N.
+
+  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 is called a2065.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_HYDRA
+  If you have a Hydra Ethernet adapter, say Y. Otherwise, say N.
+
+  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 is called hydra.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SUN3_SCSI
+  This option will enable support for the OBIO (onboard io) NCR5380
+  SCSI controller found in the Sun 3/50 and 3/60.  Note that this
+  driver does not provide support for VME SCSI boards.
+  General Linux information on the Sun 3 series (now discontinued)
+  is at <http://www.angelfire.com/ca2/tech68k/sun3.html>.
+
+CONFIG_SUN3X_ESP
+  The ESP was an on-board SCSI controller used on Sun 3/80
+  machines.  Say Y here to compile in support for it.
+
+CONFIG_APNE
+  If you have a PCMCIA NE2000 compatible adapter, say Y.  Otherwise,
+  say N.
+
+  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 is called apne.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_ATARILANCE
+  Say Y to include support for several Atari Ethernet adapters based
+  on the AMD Lance chipset: RieblCard (with or without battery), or
+  PAMCard VME (also the version by Rhotron, with different addresses).
+
+CONFIG_ATARI_BIONET
+  Say Y to include support for BioData's BioNet-100 Ethernet adapter
+  for the ACSI port. The driver works (has to work...) with a polled
+  I/O scheme, so it's rather slow :-(
+
+CONFIG_ATARI_PAMSNET
+  Say Y to include support for the PAMsNet Ethernet adapter for the
+  ACSI port ("ACSI node"). The driver works (has to work...) with a
+  polled I/O scheme, so it's rather slow :-(
+
+CONFIG_AMIGAMOUSE
+  If you want to be able to use an Amiga mouse in Linux, say Y.
+
+  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 is called amigamouse.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_ATARIMOUSE
+  If you want to be able to use an Atari mouse in Linux, say Y.
+
+  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 is called atarimouse.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_ATARI_MFPSER
+  If you like to use the MFP serial ports ("Modem1", "Serial1") under
+  Linux, say Y. The driver equally supports all kinds of MFP serial
+  ports and automatically detects whether Serial1 is available.
+
+  This driver is also available 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>.
+
+  Note for Falcon users: You also have an MFP port, it's just not
+  wired to the outside... But you could use the port under Linux.
+
+CONFIG_ATARI_SCC
+  If you have serial ports based on a Zilog SCC chip (Modem2, Serial2,
+  LAN) and like to use them under Linux, say Y. All built-in SCC's are
+  supported (TT, MegaSTE, Falcon), and also the ST-ESCC. If you have
+  two connectors for channel A (Serial2 and LAN), they are visible as
+  two separate devices.
+
+  This driver is also available 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>.
+
+CONFIG_ATARI_SCC_DMA
+  This enables DMA support for receiving data on channel A of the SCC.
+  If you have a TT you may say Y here and read
+  drivers/char/atari_SCC.README. All other users should say N here,
+  because only the TT has SCC-DMA, even if your machine keeps claiming
+  so at boot time.
+
+CONFIG_ATARI_MIDI
+  If you want to use your Atari's MIDI port in Linux, say Y.
+
+  This driver is also available 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>.
+
+CONFIG_ATARI_DSP56K
+  If you want to be able to use the DSP56001 in Falcons, say Y. This
+  driver is still experimental, and if you don't know what it is, or
+  if you don't have this processor, just say N.
+
+  This driver is also available 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>.
+
+CONFIG_AMIGA_BUILTIN_SERIAL
+  If you want to use your Amiga's built-in serial port in Linux,
+  answer Y.
+
+  This driver is also available 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>.
+
+CONFIG_GVPIOEXT
+  If you want to use a GVP IO-Extender serial card in Linux, say Y.
+  Otherwise, say N.
+
+CONFIG_GVPIOEXT_LP
+  Say Y to enable driving a printer from the parallel port on your
+  GVP IO-Extender card, N otherwise.
+
+CONFIG_GVPIOEXT_PLIP
+  Say Y to enable doing IP over the parallel port on your GVP
+  IO-Extender card, N otherwise.
+
+CONFIG_MULTIFACE_III_TTY
+  If you want to use a Multiface III card's serial port in Linux,
+  answer Y.
+
+  This driver is also available 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>.
+
+CONFIG_HPDCA
+  If you want to use the internal "DCA" serial ports on an HP300
+  machine, say Y here.
+
+CONFIG_HPLANCE
+  If you want to use the builtin "LANCE" Ethernet controller on an
+  HP300 machine, say Y here.
+
+CONFIG_DIO
+  Say Y here to enable support for the "DIO" expansion bus used in
+  HP300 machines. If you are using such a system you almost certainly
+  want this.
+
+CONFIG_MAC_ADBKEYCODES
+  This provides support for sending raw ADB keycodes to console
+  devices.  This is the default up to 2.4.0, but in future this may be
+  phased out in favor of generic Linux keycodes.  If you say Y here,
+  you can dynamically switch via the
+      /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes
+  sysctl and with the "keyboard_sends_linux_keycodes=" kernel
+  argument.
+
+  If unsure, say Y here.
+
+CONFIG_MAC_EMUMOUSEBTN
+  This provides generic support for emulating the 2nd and 3rd mouse
+  button with keypresses.  If you say Y here, the emulation is still
+  disabled by default.  The emulation is controlled by these sysctl
+  entries:
+      /proc/sys/dev/mac_hid/mouse_button_emulation
+      /proc/sys/dev/mac_hid/mouse_button2_keycode
+      /proc/sys/dev/mac_hid/mouse_button3_keycode
+
+CONFIG_VME
+  Say Y here if you want to build a kernel for a 680x0 based VME
+  board.  Boards currently supported include Motorola boards MVME147,
+  MVME162, MVME166, MVME167, MVME172, and MVME177.  BVME4000 and
+  BVME6000 boards from BVM Ltd are also supported.
+
+CONFIG_MVME147
+  Say Y to include support for early Motorola VME boards.  This will
+  build a kernel which can run on MVME147 single-board computers.  If
+  you select this option you will have to select the appropriate
+  drivers for SCSI, Ethernet and serial ports later on.
+
+CONFIG_MVME16x
+  Say Y to include support for Motorola VME boards.  This will build a
+  kernel which can run on MVME162, MVME166, MVME167, MVME172, and
+  MVME177 boards.  If you select this option you will have to select
+  the appropriate drivers for SCSI, Ethernet and serial ports later
+  on.
+
+CONFIG_BVME6000
+  Say Y to include support for VME boards from BVM Ltd.  This will
+  build a kernel which can run on BVME4000 and BVME6000 boards.  If
+  you select this option you will have to select the appropriate
+  drivers for SCSI, Ethernet and serial ports later on.
+
+CONFIG_060_WRITETHROUGH
+  The 68060 generally uses copyback caching of recently accessed data.
+  Copyback caching means that memory writes will be held in an on-chip
+  cache and only written back to memory some time later.  Saying Y
+  here will force supervisor (kernel) accesses to use writethrough
+  caching.  Writethrough caching means that data is written to memory
+  straight away, so that cache and memory data always agree.
+  Writethrough caching is less efficient, but is needed for some
+  drivers on 68060 based systems where the 68060 bus snooping signal
+  is hardwired on.  The 53c710 SCSI driver is known to suffer from
+  this problem.
+
+CONFIG_MVME147_SCSI
+  Support for the on-board SCSI controller on the Motorola MVME147
+  single-board computer.
+
+CONFIG_MVME147_SCC
+  This is the driver for the serial ports on the Motorola MVME147
+  boards.  Everyone using one of these boards should say Y here.
+
+CONFIG_MVME16x_SCSI
+  The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710
+  SCSI controller chip.  Almost everyone using one of these boards
+  will want to say Y to this question.
+
+CONFIG_BVME6000_SCSI
+  The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710
+  SCSI controller chip.  Almost everyone using one of these boards
+  will want to say Y to this question.
+
+CONFIG_MVME147_NET
+  Support for the on-board Ethernet interface on the Motorola MVME147
+  single-board computer.  Say Y here to include the
+  driver for this chip in your kernel.   If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MVME16x_NET
+  This is the driver for the Ethernet interface on the Motorola
+  MVME162, 166, 167, 172 and 177 boards.  Say Y here to include the
+  driver for this chip in your kernel.   If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_BVME6000_NET
+  This is the driver for the Ethernet interface on BVME4000 and
+  BVME6000 VME boards.  Say Y here to include the driver for this chip
+  in your kernel.   If you want to compile it as a module, say M here
+  and read <file:Documentation/modules.txt>.
+
+CONFIG_SERIAL167
+  This is the driver for the serial ports on the Motorola MVME166,
+  167, and 172 boards.  Everyone using one of these boards should say
+  Y here.
+
+CONFIG_MVME162_SCC
+  This is the driver for the serial ports on the Motorola MVME162 and
+  172 boards.  Everyone using one of these boards should say Y here.
+
+CONFIG_BVME6000_SCC
+  This is the driver for the serial ports on the BVME4000 and BVME6000
+  boards from BVM Ltd.  Everyone using one of these boards should say
+  Y here.
+
diff -u --recursive --new-file v2.5.2/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.5.2/linux/arch/m68k/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/m68k/config.in	Thu Jan 24 11:29:38 2002
@@ -9,19 +9,7 @@
 
 mainmenu_name "Linux/68k Kernel Configuration"
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'Platform dependent setup'
@@ -89,10 +77,6 @@
 mainmenu_option next_comment
 comment 'General setup'
 
-bool 'Networking support' CONFIG_NET
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
 if [ "$CONFIG_PROC_FS" = "y" ]; then
    choice 'Kernel core (/proc/kcore) format' \
 	"ELF		CONFIG_KCORE_ELF	\
diff -u --recursive --new-file v2.5.2/linux/arch/m68k/kernel/m68k_defs.c linux/arch/m68k/kernel/m68k_defs.c
--- v2.5.2/linux/arch/m68k/kernel/m68k_defs.c	Mon Nov 27 18:02:06 2000
+++ linux/arch/m68k/kernel/m68k_defs.c	Mon Jan 28 15:14:22 2002
@@ -25,8 +25,8 @@
 	DEFINE(TASK_STATE, offsetof(struct task_struct, state));
 	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
 	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
-	DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, sigpending));
-	DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, need_resched));
+#error	DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, work.sigpending));
+#error	DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, work.need_resched));
 	DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
 	DEFINE(TASK_MM, offsetof(struct task_struct, mm));
 	DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
diff -u --recursive --new-file v2.5.2/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.5.2/linux/arch/m68k/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/m68k/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -56,7 +56,7 @@
 static void default_idle(void)
 {
 	while(1) {
-		if (!current->need_resched)
+		if (!need_resched())
 #if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
 			/* block out HSYNC on the atari (falcon) */
 			__asm__("stop #0x2200" : : : "cc");
diff -u --recursive --new-file v2.5.2/linux/arch/m68k/vmlinux-sun3.lds linux/arch/m68k/vmlinux-sun3.lds
--- v2.5.2/linux/arch/m68k/vmlinux-sun3.lds	Mon Jul  2 14:40:14 2001
+++ linux/arch/m68k/vmlinux-sun3.lds	Wed Jan 23 10:54:42 2002
@@ -43,7 +43,15 @@
 	.setup.init : { *(.setup.init) }
 	__setup_end = .;
 	__initcall_start = .;
-	.initcall.init : { *(.initcall.init) }
+	.initcall.init : {
+		*(.initcall1.init) 
+		*(.initcall2.init) 
+		*(.initcall3.init) 
+		*(.initcall4.init) 
+		*(.initcall5.init) 
+		*(.initcall6.init) 
+		*(.initcall7.init)
+	}
 	__initcall_end = .;
 	. = ALIGN(8192);
 	__init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/m68k/vmlinux.lds linux/arch/m68k/vmlinux.lds
--- v2.5.2/linux/arch/m68k/vmlinux.lds	Mon Jul  2 14:40:14 2001
+++ linux/arch/m68k/vmlinux.lds	Wed Jan 23 10:54:42 2002
@@ -47,7 +47,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(8192);
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/mips/Config.help linux/arch/mips/Config.help
--- v2.5.2/linux/arch/mips/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/Config.help	Fri Jan 25 16:04:33 2002
@@ -0,0 +1,931 @@
+CONFIG_SMP
+  This enables support for systems with more than one CPU. If you have
+  a system with only one CPU, like most personal computers, say N. If
+  you have a system with more than one CPU, say Y.
+
+  If you say N here, the kernel will run on single and multiprocessor
+  machines, but will use only one CPU of a multiprocessor machine. If
+  you say Y here, the kernel will run on many, but not all,
+  singleprocessor machines. On a singleprocessor machine, the kernel
+  will run faster if you say N here.
+
+  Note that if you say Y here and choose architecture "586" or
+  "Pentium" under "Processor family", the kernel will not work on 486
+  architectures. Similarly, multiprocessor kernels for the "PPro"
+  architecture may not work on all Pentium based boards.
+
+  People using multiprocessor machines who say Y here should also say
+  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+  Management" code will be disabled if you say Y here.
+
+  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-HOWTO available at
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you don't know what to do here, say N.
+
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+CONFIG_ACER_PICA_61
+  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/>.
+
+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/>.
+
+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/>.
+
+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/>.
+
+  If you have one of the following DECstation Models you definitely
+  want to choose R4xx0 for the CPU Type:
+
+	DECstation 5000/50
+	DECstation 5000/150
+	DECstation 5000/260
+	DECsystem 5900/260
+
+  otherwise choose R3000.
+
+CONFIG_MOMENCO_OCELOT
+  The Ocelot is a MIPS-based Single Board Computer (SBC) made by
+  Momentum Computer <http://www.momenco.com/>.
+
+CONFIG_DDB5074
+  This enables support for the VR5000-based NEC DDB Vrc-5074
+  evaluation board.
+
+CONFIG_DDB5476
+  This enables support for the R5432-based NEC DDB Vrc-5476
+  evaluation board.
+
+  Features : kernel debugging, serial terminal, NFS root fs, on-board
+  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.
+
+CONFIG_DDB5477
+  This enables support for the R5432-based NEC DDB Vrc-5477
+  evaluation board.
+
+  Features : kernel debugging, serial terminal, NFS root fs, on-board
+  ether port (Need an additional patch at <http://linux.junsun.net/>),
+  USB, AC97, PCI, etc.
+
+CONFIG_MIPS_ATLAS
+  This enables support for the QED R5231-based MIPS Atlas evaluation
+  board.
+
+CONFIG_MIPS_MALTA
+  This enables support for the VR5000-based MIPS Malta evaluation
+  board.
+
+CONFIG_MIPS_MAGNUM_4000
+  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/>.
+
+CONFIG_QTRONIX_KEYBOARD
+  Images of Qtronix keyboards are at
+  <http://www.qtronix.com/keyboard.html>.
+
+CONFIG_OLIVETTI_M700
+  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/>.
+
+CONFIG_SNI_RM200_PCI
+  The SNI RM200 PCI was a MIPS-based platform manufactured by Siemens
+  Nixdorf Informationssysteme (SNI), parent company of Pyramid
+  Technology and now in turn merged with Fujitsu.  Say Y here to
+  support this machine type.
+
+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.
+
+CONFIG_MIPS_GT96100
+  Say Y here to support the Galileo Technology GT96100 communications
+  controller card.  There is a web page at <http://www.galileot.com/>.
+
+CONFIG_DZ
+  DZ11-family serial controllers for VAXstations, including the
+  DC7085, M7814, and M7819.
+
+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>.
+
+CONFIG_ZS
+  Documentation on the Zilog 85C350 serial communications controller
+  is downloadable at <http://www.zilog.com/pdfs/serial/z85c30.pdf>.
+
+CONFIG_CPU_R3000
+  Please make sure to pick the right CPU type. Linux/MIPS is not
+  designed to be generic, i.e. Kernels compiled for R3000 CPUs will
+  *not* work on R4000 machines and vice versa.  However, since most
+  of the supported machines have an R4000 (or similar) CPU, R4x00
+  might be a safe bet.  If the resulting kernel does not work,
+  try to recompile with R3000.
+
+  R3000    MIPS Technologies R3000-series processors,
+           including the 3041, 3051, and 3081.
+
+  R6000    MIPS Technologies R6000-series processors,
+           including the 64474, 64475, 64574 and 64575.
+
+  R4300    MIPS Technologies R4300-series processors.
+
+  R4x00    MIPS Technologies R4000-series processors other than 4300,
+           including the 4640, 4650, and 4700.
+
+  R5000    MIPS Technologies R5000-series processors other than the
+           Nevada.
+
+  R52xx    MIPS Technologies R52xx-series ("Nevada") processors.
+
+  R10000   MIPS Technologies R10000-series processors.
+
+CONFIG_CPU_R6000
+  MIPS Technologies R6000-series processors, including the 64474,
+  64475, 64574 and 64575.
+
+CONFIG_CPU_R4300
+  MIPS Technologies R4300-series processors.
+
+CONFIG_CPU_R4X00
+  MIPS Technologies R4000-series processors other than 4300, including
+  the 4640, 4650, and 4700.
+
+CONFIG_CPU_R5000
+  MIPS Technologies R5000-series processors other than the Nevada.
+
+CONFIG_CPU_NEVADA
+  MIPS Technologies R52x0-series ("Nevada") processors.
+
+CONFIG_CPU_R10000
+  MIPS Technologies R10000-series processors.
+
+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
+  kernel built with this option will not run on any other type of
+  processor or vice versa.
+
+CONFIG_CPU_ADVANCED
+  Saying yes here allows you to select support for various features
+  your CPU may or may not have.  Most people should say N here.
+
+CONFIG_CPU_HAS_LLSC
+  MIPS R4000 series and later provide the Load Linked (ll)
+  and Store Conditional (sc) instructions. More information is
+  available at <http://www.go-ecs.com/mips/miptek1.htm>.
+
+  Say Y here if your CPU has the ll and sc instructions.  Say Y here
+  for better performance, N if you don't know.  You must say Y here
+  for multiprocessor machines.
+
+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
+  you don't know.  You must say Y here for multiprocessor machines.
+
+CONFIG_CPU_HAS_WB
+  Say N here for slightly better performance.  You must say Y here for
+  machines which require flushing of write buffers in software.  Saying
+  Y is the safe option; N may result in kernel malfunction and crashes.
+
+CONFIG_CPU_LITTLE_ENDIAN
+  Some MIPS machines can be configured for either little or big endian
+  byte order. These modes require different kernels. Say Y if your
+  machine is little endian, N if it's a big endian machine.
+
+CONFIG_SGI_NEWPORT_CONSOLE
+  Say Y here if you want the console on the Newport aka XL graphics
+  card of your Indy.  Most people say Y here.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_PCI
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_HOTPLUG
+  Say Y here if you want to plug devices into your computer while
+  the system is running, and be able to use them quickly.  In many
+  cases, the devices can likewise be unplugged at any time too.
+
+  One well known example of this is PCMCIA- or PC-cards, credit-card
+  size devices such as network cards, modems or hard drives which are
+  plugged into slots found on all modern laptop computers.  Another
+  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.
+  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.
+
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+  computer.  These are credit-card size devices such as network cards,
+  modems or hard drives often used with laptops computers.  There are
+  actually two varieties of these cards: the older 16 bit PCMCIA cards
+  and the newer 32 bit CardBus cards.  If you want to use CardBus
+  cards, you need to say Y here and also to "CardBus support" below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  Please also read the PCMCIA-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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_AOUT
+  A.out (Assembler.OUTput) is a set of formats for libraries and
+  executables used in the earliest versions of UNIX. Linux used the
+  a.out formats QMAGIC and ZMAGIC until they were replaced with the
+  ELF format.
+
+  As more and more programs are converted to ELF, the use for a.out
+  will gradually diminish. If you disable this option it will reduce
+  your kernel by one page. This is not much and by itself does not
+  warrant removing support. However its removal is a good idea if you
+  wish to ensure that absolutely none of your programs will use this
+  older executable format. If you don't know what to answer at this
+  point then answer Y. If someone told you "You need a kernel with
+  QMAGIC support" then you'll have to say Y here. You may answer M to
+  compile a.out support as a module and later load the module when you
+  want to use a program or library in a.out format. The module will be
+  called binfmt_aout.o. Saying M or N here is dangerous though,
+  because some crucial programs on your system might still be in A.OUT
+  format.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_VGA_CONSOLE
+  Saying Y here will allow you to use Linux in text mode through a
+  display that complies with the generic VGA standard. Virtually
+  everyone wants that.
+
+  The program SVGATextMode can be used to utilize SVGA video cards to
+  their full potential in text mode. Download it from
+  <ftp://ibiblio.org/pub/Linux/utils/console/>.
+
+  Say Y.
+
+CONFIG_FB
+  The frame buffer device provides an abstraction for the graphics
+  hardware. It represents the frame buffer of some video hardware and
+  allows application software to access the graphics hardware through
+  a well-defined interface, so the software doesn't need to know
+  anything about the low-level (hardware register) stuff.
+
+  Frame buffer devices work identically across the different
+  architectures supported by Linux and make the implementation of
+  application programs easier and more portable; at this point, an X
+  server exists which uses the frame buffer device exclusively.
+  On several non-X86 architectures, the frame buffer device is the
+  only way to use the graphics hardware.
+
+  The device is accessed through special device nodes, usually located
+  in the /dev directory, i.e. /dev/fb*.
+
+  You need an utility program called fbset to make full use of frame
+  buffer devices. Please read <file:Documentation/fb/framebuffer.txt>
+  and the Framebuffer-HOWTO at
+  <http://www.tahallah.demon.co.uk/programming/prog.html> for more
+  information.
+
+  Say Y here and to the driver for your graphics board below if you
+  are compiling a kernel for a non-x86 architecture.
+
+  If you are compiling for the x86 architecture, you can say Y if you
+  want to play with it, but it is not essential. Please note that
+  running graphical applications that directly touch the hardware
+  (e.g. an accelerated X server) and that are not frame buffer
+  device-aware may cause unexpected results. If unsure, say N.
+
+CONFIG_FONT_8x16
+  This is the "high resolution" font for the VGA frame buffer (the one
+  provided by the VGA text console 80x25 mode.
+
+  If unsure, say Y.
+
+CONFIG_MDA_CONSOLE
+  Say Y here if you have an old MDA or monochrome Hercules graphics
+  adapter in your system acting as a second head ( = video card). You
+  will then be able to use two monitors with your Linux system. Do not
+  say Y here if your MDA card is the primary card in your system; the
+  normal VGA driver will handle it.
+
+  This driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want).
+  The module will be called mdacon.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+  If unsure, say N.
+
+CONFIG_MODULES
+  Kernel modules are small pieces of compiled code which can be
+  inserted in or removed from the running kernel, using the programs
+  insmod and rmmod. This is described in the file
+  <file:Documentation/modules.txt>, including the fact that you have
+  to say "make modules" in order to compile the modules that you chose
+  during kernel configuration.  Modules can be device drivers, file
+  systems, binary executable formats, and so on. If you think that you
+  may want to make use of modules with this kernel in the future, then
+  say Y here.  If unsure, say Y.
+
+CONFIG_MODVERSIONS
+  Usually, modules have to be recompiled whenever you switch to a new
+  kernel.  Saying Y here makes it possible, and safe, to use the
+  same modules even after compiling a new kernel; this requires the
+  program modprobe. All the software needed for module support is in
+  the modutils package (check the file <file:Documentation/Changes>
+  for location and latest version).  NOTE: if you say Y here but don't
+  have the program genksyms (which is also contained in the above
+  mentioned modutils package), then the building of your kernel will
+  fail.  If you are going to use modules that are generated from
+  non-kernel sources, you would benefit from this option.  Otherwise
+  it's not that important.  So, N ought to be a safe bet.
+
+CONFIG_KMOD
+  Normally when you have selected some drivers and/or file systems to
+  be created as loadable modules, you also have the responsibility to
+  load the corresponding modules (using the programs insmod or
+  modprobe) before you can use them. If you say Y here however, the
+  kernel will be able to load modules for itself: when a part of the
+  kernel needs a module, it runs modprobe with the appropriate
+  arguments, thereby loading the module if it is available. (This is a
+  replacement for kerneld.) Say Y here and read about configuring it
+  in <file:Documentation/kmod.txt>.
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_CD_NO_IDESCSI
+  If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y
+  here, otherwise N. Read the CD-ROM-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about these CD-ROM drives. If you are unsure what you
+  have, say Y and find out whether you have one of the following
+  drives.
+
+  For each of these drivers, a file Documentation/cdrom/{driver_name}
+  exists. Especially in cases where you do not know exactly which kind
+  of drive you have you should read there. Most of these drivers use a
+  file drivers/cdrom/{driver_name}.h where you can define your
+  interface parameters and switch some internal goodies.
+
+  All these CD-ROM drivers are also usable as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want). If you want to compile them as module, say M instead of Y and
+  read <file:Documentation/modules.txt>.
+
+  If you want to use any of these CD-ROM drivers, you also have to
+  answer Y or M to "ISO 9660 CD-ROM file system support" below (this
+  answer will get "defaulted" for you if you enable any of the Linux
+  CD-ROM drivers).
+
+CONFIG_VT
+  If you say Y here, you will get support for terminal devices with
+  display and keyboard devices. These are called "virtual" because you
+  can run several virtual terminals (also called virtual consoles) on
+  one physical terminal. This is rather useful, for example one
+  virtual terminal can collect system messages and warnings, another
+  one can be used for a text-mode user session, and a third could run
+  an X session, all in parallel. Switching between virtual terminals
+  is done with certain key combinations, usually Alt-<function key>.
+
+  The setterm command ("man setterm") can be used to change the
+  properties (such as colors or beeping) of a virtual terminal. The
+  man page console_codes(4) ("man console_codes") contains the special
+  character sequences that can be used to change those properties
+  directly. The fonts used on virtual terminals can be changed with
+  the setfont ("man setfont") command and the key bindings are defined
+  with the loadkeys ("man loadkeys") command.
+
+  You need at least one virtual terminal device in order to make use
+  of your keyboard and monitor. Therefore, only people configuring an
+  embedded system would want to say N here in order to save some
+  memory; the only way to log into such a system is then via a serial
+  or network connection.
+
+  If unsure, say Y, or else you won't be able to do much with your new
+  shiny Linux system :-)
+
+CONFIG_VT_CONSOLE
+  The system console is the device which receives all kernel messages
+  and warnings and which allows logins in single user mode. If you
+  answer Y here, a virtual terminal (the device used to interact with
+  a physical terminal) can be used as system console. This is the most
+  common mode of operations, so you should say Y here unless you want
+  the kernel messages be output only to a serial port (in which case
+  you should say Y to "Console on serial port", below).
+
+  If you do say Y here, by default the currently visible virtual
+  terminal (/dev/tty0) will be used as system console. You can change
+  that with a kernel command line option such as "console=tty3" which
+  would use the third virtual terminal as system console. (Try "man
+  bootparam" or see the documentation of your boot loader (lilo or
+  loadlin) about how to pass options to the kernel at boot time.)
+
+  If unsure, say Y.
+
+CONFIG_SERIAL
+  This selects whether you want to include the driver for the standard
+  serial ports.  The standard answer is Y.  People who might say N
+  here are those that are setting up dedicated Ethernet WWW/FTP
+  servers, or users that have one of the various bus mice instead of a
+  serial mouse and don't intend to use their machine's standard serial
+  port for anything.  (Note that the Cyclades and Stallion multi
+  serial port drivers do not need this driver built in for them to
+  work.)
+
+  If you want to compile this driver as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  serial.o.
+  [WARNING: Do not compile this driver as a module if you are using
+  non-standard serial ports, since the configuration information will
+  be lost when the driver is unloaded.  This limitation may be lifted
+  in the future.]
+
+  BTW1: If you have a mouseman serial mouse which is not recognized by
+  the X window system, try running gpm first.
+
+  BTW2: If you intend to use a software modem (also called Winmodem)
+  under Linux, forget it.  These modems are crippled and require
+  proprietary drivers which are only available under Windows.
+
+  Most people will say Y or M here, so that they can use serial mice,
+  modems and similar devices connecting to the standard serial ports.
+
+CONFIG_SERIAL_CONSOLE
+  If you say Y here, it will be possible to use a serial port as the
+  system console (the system console is the device which receives all
+  kernel messages and warnings and which allows logins in single user
+  mode). This could be useful if some terminal or printer is connected
+  to that serial port.
+
+  Even if you say Y here, the currently visible virtual console
+  (/dev/tty0) will still be used as the system console by default, but
+  you can alter that using a kernel command line option such as
+  "console=ttyS1". (Try "man bootparam" or see the documentation of
+  your boot loader (lilo or loadlin) about how to pass options to the
+  kernel at boot time.)
+
+  If you don't have a VGA card installed and you say Y here, the
+  kernel will automatically use the first serial line, /dev/ttyS0, as
+  system console.
+
+  If unsure, say N.
+
+CONFIG_UNIX98_PTYS
+  A pseudo terminal (PTY) is a software device consisting of two
+  halves: a master and a slave. The slave device behaves identical to
+  a physical terminal; the master device is used by a process to
+  read data from and write data to the slave, thereby emulating a
+  terminal. Typical programs for the master side are telnet servers
+  and xterms.
+
+  Linux has traditionally used the BSD-like names /dev/ptyxx for
+  masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
+  has a number of problems. The GNU C library glibc 2.1 and later,
+  however, supports the Unix98 naming standard: in order to acquire a
+  pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
+  terminal is then made available to the process and the pseudo
+  terminal slave can be accessed as /dev/pts/<number>. What was
+  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
+
+  The entries in /dev/pts/ are created on the fly by a virtual
+  file system; therefore, if you say Y here you should say Y to
+  "/dev/pts file system for Unix98 PTYs" as well.
+
+  If you want to say Y here, you need to have the C library glibc 2.1
+  or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
+  Read the instructions in <file:Documentation/Changes> pertaining to
+  pseudo terminals. It's safe to say N.
+
+CONFIG_UNIX98_PTY_COUNT
+  The maximum number of Unix98 PTYs that can be used at any one time.
+  The default is 256, and should be enough for desktop systems. Server
+  machines which support incoming telnet/rlogin/ssh connections and/or
+  serve several X terminals may want to increase this: every incoming
+  connection and every xterm uses up one PTY.
+
+  When not in use, each additional set of 256 PTYs occupy
+  approximately 8 KB of kernel memory on 32-bit architectures.
+
+CONFIG_MOUSE
+  This is for machines with a mouse which is neither a serial nor a
+  bus mouse. Examples are PS/2 mice (such as the track balls on some
+  laptops) and some digitizer pads. 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>. This HOWTO contains
+  information about all non-serial mice, not just bus mice.
+
+  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
+  or not; it's best to say Y here for you.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about non-serial mice. If unsure, say Y.
+
+CONFIG_PSMOUSE
+  The PS/2 mouse connects to a special mouse port that looks much like
+  the keyboard port (small circular connector with 6 pins). This way,
+  the mouse does not use any serial ports. This port can also be used
+  for other input devices like light pens, tablets, keypads. Compaq,
+  AST and IBM all use this as their mouse port on currently shipping
+  machines. The trackballs of some laptops are PS/2 mice also. In
+  particular, the C&T 82C710 mouse on TI Travelmates is a PS/2 mouse.
+
+  Although PS/2 mice are not technically bus mice, they are explained
+  in detail in the Busmouse-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  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://gnu.systemy.it/pub/gpm/>) solves this problem, or you can get
+  the "mconv2" utility from <ftp://ibiblio.org/pub/Linux/system/mouse/>.
+
+CONFIG_RTC
+  If you say Y here and create a character special file /dev/rtc with
+  major number 10 and minor number 135 using mknod ("man mknod"), you
+  will get access to the real time clock (or hardware clock) built
+  into your computer.
+
+  Every PC has such a clock built in. It can be used to generate
+  signals from as low as 1Hz up to 8192Hz, and can also be used
+  as a 24 hour alarm. It reports status information via the file
+  /proc/driver/rtc and its behaviour is set by various ioctls on
+  /dev/rtc.
+
+  If you run Linux on a multiprocessor machine and said Y to
+  "Symmetric Multi Processing" above, you should say Y here to read
+  and set the RTC in an SMP compatible fashion.
+
+  If you think you have a use for such a device (such as periodic data
+  sampling), then say Y here, and read <file:Documentation/rtc.txt>
+  for details.
+
+  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 is called rtc.o. If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y.  Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. General information about
+  the modular sound system is contained in the files
+  <file:Documentation/sound/Introduction>.  The file
+  <file:Documentation/sound/README.OSS> contains some slightly
+  outdated but still useful information as well.
+
+  If you have a PnP sound card and you want to configure it at boot
+  time using the ISA PnP tools (read
+  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished.  To do
+  this, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/sound/README.modules>; the module will be
+  called soundcore.o.
+
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and supporting utilities to do that are in the pcsp
+  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+CONFIG_CROSSCOMPILE
+  Say Y here if you are compiling the kernel on a different
+  architecture than the one it is intended to run on.
+
+CONFIG_MIPS_EV64120
+  This is an evaluation board based on the Galileo GT-64120
+  single-chip system controller that contains a MIPS R5000 compatible
+  core running at 75/100MHz.  Their website is located at
+  <http://www.galileot.com/>.  Say Y here if you wish to build a
+  kernel for this platform.
+
+CONFIG_MIPS_EV96100
+  This is an evaluation board based on the Galielo GT-96100 LAN/WAN
+  communications controllers containing a MIPS R5000 compatible core
+  running at 83MHz. Their website is <http://www.galileot.com/>. Say Y
+  here if you wish to build a kernel for this platform.
+
+CONFIG_MIPS_ITE8172
+  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
+  a kernel for this platform.
+
+CONFIG_MIPS_IVR
+  This is an evaluation board built by Globespan to showcase thir
+  iVR (Internet Video Recorder) design. It utilizes a QED RM5231
+  R5000 MIPS core. More information can be found out their website
+  located at <http://www.globespan.net/products/product4.html>P. Say Y
+  here if you wish to build a kernel for this platform.
+
+CONFIG_MIPS_PB1000
+  This is an evaluation board built by Alchemy Semiconducttor to
+  showcase their Au1000 Internet Edge Processor. It is SOC design
+  containing a MIPS32 core running at 266/400/500MHz with many
+  integrated peripherals. Further information can be found at their
+  website, <http://www.alchemysemi.com/>. Say Y here if you wish to
+  build a kernel for this platform.
+
+CONFIG_NINO
+  Say Y here to select a kernel for the Philips Nino Palm PC. The
+  website at <http://www.realitydiluted.com/projects/nino/index.html>
+  will have more information.
+
+CONFIG_NINO_16MB
+  Say Y here to build a kernel specifically for Nino 500/501 color
+  Palm PCs from Philips (INCOMPLETE).
+
+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.
+
+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.
+
+CONFIG_LL_DEBUG
+  Enable low-level debugging assertion macros in the kernel code.
+  Currently used only by the time services code in the MIPS port.
+  Don't turn this on unless you know what you are doing.
+
+CONFIG_REMOTE_DEBUG
+  If you say Y here, it will be possible to remotely debug the MIPS
+  kernel using gdb. This enlarges your kernel image disk size by
+  several megabytes and requires a machine with more than 16 MB,
+  better 32 MB RAM to avoid excessive linking time. This is only
+  useful for kernel hackers. If unsure, say N.
+
+CONFIG_MIPS_UNCACHED
+  If you say Y here there kernel will disable all CPU caches.  This will
+  reduce the system's performance dramatically but can help finding
+  otherwise hard to track bugs.  It can also useful if you're doing
+  hardware debugging with a logic analyzer and need to see all traffic
+  on the bus.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_ISDN
+  ISDN ("Integrated Services Digital Networks", called RNIS in France)
+  is a special type of fully digital telephone service; it's mostly
+  used to connect to your Internet service provider (with SLIP or
+  PPP).  The main advantage is that the speed is higher than ordinary
+  modem/telephone connections, and that you can have voice
+  conversations while downloading stuff.  It only works if your
+  computer is equipped with an ISDN card and both you and your service
+  provider purchased an ISDN line from the phone company.  For
+  details, read <http://alumni.caltech.edu/~dank/isdn/> on the WWW.
+
+  This driver allows you to use an ISDN-card for networking
+  connections and as dialin/out device.  The isdn-tty's have a built
+  in AT-compatible modem emulator.  Network devices support autodial,
+  channel-bundling, callback and caller-authentication without having
+  a daemon running.  A reduced T.70 protocol is supported with tty's
+  suitable for German BTX.  On D-Channel, the protocols EDSS1
+  (Euro-ISDN) and 1TR6 (German style) are supported.  See
+  <file:Documentation/isdn/README> for more information.
+
+  If you want to compile the ISDN code 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 isdn.o. If unsure, say N.
+
+CONFIG_GDB_CONSOLE
+  If you are using GDB for remote debugging over a serial port and
+  would like kernel messages to be formatted into GDB $O packets so
+  that GDB prints them as program output, say 'Y'.
+
diff -u --recursive --new-file v2.5.2/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.5.2/linux/arch/mips/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/mips/config.in	Thu Jan 24 11:29:38 2002
@@ -7,10 +7,7 @@
 
 mainmenu_name "Linux Kernel Configuration"
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'Machine selection'
@@ -306,8 +303,6 @@
 define_bool CONFIG_BINFMT_ELF y
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
-bool 'Networking support' CONFIG_NET
-
 source drivers/pci/Config.in
 
 bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
@@ -317,10 +312,6 @@
 else
    define_bool CONFIG_PCMCIA n
 fi
-
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
 
 if [ "$CONFIG_DECSTATION" = "y" ]; then
     bool 'TURBOchannel support' CONFIG_TC
diff -u --recursive --new-file v2.5.2/linux/arch/mips/kernel/entry.S linux/arch/mips/kernel/entry.S
--- v2.5.2/linux/arch/mips/kernel/entry.S	Sun Sep  9 10:43:01 2001
+++ linux/arch/mips/kernel/entry.S	Mon Jan 28 15:14:22 2002
@@ -36,7 +36,7 @@
 EXPORT(ret_from_fork)
 		move	a0, v0			# prev
 		jal	schedule_tail
-		lw	t0, TASK_PTRACE($28)	# syscall tracing enabled?
+#error		lw	t0, TASK_PTRACE($28)	# syscall tracing enabled?
 		andi	t0, PT_TRACESYS
 		bnez	t0, tracesys_exit
 		j	ret_from_sys_call
@@ -62,8 +62,8 @@
 		mtc0	t0, CP0_STATUS
 		nop; nop; nop
 
-		lw	v0, TASK_NEED_RESCHED($28)
-		lw	v1, TASK_SIGPENDING($28)
+#error		lw	v0, TASK_NEED_RESCHED($28)
+#error		lw	v1, TASK_SIGPENDING($28)
 		bnez	v0, reschedule
 		bnez	v1, signal_return
 restore_all:	.set	noat
@@ -80,7 +80,7 @@
 
 		move	a0, zero
 		move	a1, sp
-		jal	do_signal
+#error		jal	do_signal
 		b	restore_all
 
 /*
diff -u --recursive --new-file v2.5.2/linux/arch/mips/kernel/init_task.c linux/arch/mips/kernel/init_task.c
--- v2.5.2/linux/arch/mips/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/mips/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,5 +1,6 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c
--- v2.5.2/linux/arch/mips/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/mips/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -39,7 +39,7 @@
 	init_idle();
 
 	while (1) {
-		while (!current->need_resched)
+		while (!need_resched())
 			if (cpu_wait)
 				(*cpu_wait)();
 		schedule();
diff -u --recursive --new-file v2.5.2/linux/arch/mips/kernel/scall_o32.S linux/arch/mips/kernel/scall_o32.S
--- v2.5.2/linux/arch/mips/kernel/scall_o32.S	Sun Sep  9 10:43:01 2001
+++ linux/arch/mips/kernel/scall_o32.S	Mon Jan 28 15:14:22 2002
@@ -49,7 +49,7 @@
 
 stack_done:
         sw      a3, PT_R26(sp)          # save for syscall restart
-	lw	t0, TASK_PTRACE($28)	# syscall tracing enabled?
+#error	lw	t0, TASK_PTRACE($28)	# syscall tracing enabled?
 	andi	t0, PT_TRACESYS
 	bnez	t0, trace_a_syscall
 
@@ -70,9 +70,9 @@
 	xori	t0, t0, 1
 	mtc0	t0, CP0_STATUS
 
-	lw	t2, TASK_NEED_RESCHED($28)
+#error	lw	t2, TASK_NEED_RESCHED($28)
 	bnez	t2, o32_reschedule
-	lw	v0, TASK_SIGPENDING($28)
+#error	lw	v0, TASK_SIGPENDING($28)
 	bnez	v0, signal_return
 restore_all:
 	RESTORE_SOME
@@ -88,7 +88,7 @@
 
 	move	a0, zero
 	move	a1, sp
-	jal	do_signal
+#error	jal	do_signal
 	b	restore_all
 
 o32_reschedule:
@@ -101,7 +101,7 @@
 trace_a_syscall:
 	SAVE_STATIC
 	sw	t2, PT_R1(sp)
-	jal	syscall_trace
+#error	jal	syscall_trace
 	lw	t2, PT_R1(sp)
 
 	lw	a0, PT_R4(sp)		# Restore argument registers
@@ -119,7 +119,7 @@
 	sw	v0, PT_R0(sp)		# set flag for syscall restarting
 1:	sw	v0, PT_R2(sp)		# result
 
-	jal	syscall_trace
+#error	jal	syscall_trace
 	j	ret_from_sys_call
 
 /* ------------------------------------------------------------------------ */
diff -u --recursive --new-file v2.5.2/linux/arch/mips/kernel/smp.c linux/arch/mips/kernel/smp.c
--- v2.5.2/linux/arch/mips/kernel/smp.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/mips/kernel/smp.c	Mon Jan 28 15:14:22 2002
@@ -179,7 +179,7 @@
 
 static void reschedule_this_cpu(void *dummy)
 {
-	current->need_resched = 1;
+	current->work.need_resched = 1;
 }
 
 void FASTCALL(smp_send_reschedule(int cpu))
diff -u --recursive --new-file v2.5.2/linux/arch/mips/ld.script.in linux/arch/mips/ld.script.in
--- v2.5.2/linux/arch/mips/ld.script.in	Mon Jul  2 13:56:40 2001
+++ linux/arch/mips/ld.script.in	Wed Jan 23 10:54:42 2002
@@ -44,7 +44,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);	/* Align double page for init_task_union */
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/mips/math-emu/cp1emu.c linux/arch/mips/math-emu/cp1emu.c
--- v2.5.2/linux/arch/mips/math-emu/cp1emu.c	Sun Sep  9 10:43:01 2001
+++ linux/arch/mips/math-emu/cp1emu.c	Tue Jan 15 13:53:50 2002
@@ -1674,8 +1674,7 @@
 
 	oldepc = xcp->cp0_epc;
 	do {
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		prevepc = xcp->cp0_epc;
 		insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/andes.c linux/arch/mips/mm/andes.c
--- v2.5.2/linux/arch/mips/mm/andes.c	Sun Sep  9 10:43:02 2001
+++ linux/arch/mips/mm/andes.c	Tue Jan 15 10:56:35 2002
@@ -101,7 +101,7 @@
 	/* XXX */
 }
 
-static void andes_flush_cache_range(struct mm_struct *mm,
+static void andes_flush_cache_range(struct vm_area_struct *vma,
 				    unsigned long start,
 				    unsigned long end)
 {
@@ -147,7 +147,7 @@
 	/* XXX */
 }
 
-void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				  unsigned long end)
 {
 	/* XXX */
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/loadmmu.c linux/arch/mips/mm/loadmmu.c
--- v2.5.2/linux/arch/mips/mm/loadmmu.c	Sun Sep  9 10:43:02 2001
+++ linux/arch/mips/mm/loadmmu.c	Tue Jan 15 10:56:35 2002
@@ -25,7 +25,7 @@
 void (*_flush_cache_all)(void);
 void (*___flush_cache_all)(void);
 void (*_flush_cache_mm)(struct mm_struct *mm);
-void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start,
+void (*_flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
 			  unsigned long end);
 void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 void (*_flush_cache_sigtramp)(unsigned long addr);
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/mips32.c linux/arch/mips/mm/mips32.c
--- v2.5.2/linux/arch/mips/mm/mips32.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips/mm/mips32.c	Tue Jan 15 10:56:35 2002
@@ -176,11 +176,11 @@
 }
 
 static void
-mips32_flush_cache_range_sc(struct mm_struct *mm,
+mips32_flush_cache_range_sc(struct vm_area_struct *vma,
 			 unsigned long start,
 			 unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if(mm->context == 0)
@@ -190,8 +190,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if(mm->context != current->mm->context) {
 			mips32_flush_cache_all_sc();
 		} else {
@@ -214,10 +213,12 @@
 	}
 }
 
-static void mips32_flush_cache_range_pc(struct mm_struct *mm,
+static void mips32_flush_cache_range_pc(struct vm_area_struct *vma,
 				     unsigned long start,
 				     unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if(mm->context != 0) {
 		unsigned long flags;
 
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/r2300.c linux/arch/mips/mm/r2300.c
--- v2.5.2/linux/arch/mips/mm/r2300.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips/mm/r2300.c	Tue Jan 15 10:56:35 2002
@@ -336,10 +336,10 @@
 	}
 }
 
-static void r3k_flush_cache_range(struct mm_struct *mm, unsigned long start,
+static void r3k_flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 				  unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 
 	if (mm->context == 0) 
 		return;
@@ -348,10 +348,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if (!vma)
-		return;
-
 	if (mm->context != current->active_mm->context) {
 		flush_cache_all();
 	} else {
@@ -485,9 +481,11 @@
 	}
 }
 
-void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                      unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (mm->context != 0) {
 		unsigned long flags;
 		int size;
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/r4xx0.c linux/arch/mips/mm/r4xx0.c
--- v2.5.2/linux/arch/mips/mm/r4xx0.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips/mm/r4xx0.c	Tue Jan 15 10:56:35 2002
@@ -989,11 +989,11 @@
 }
 
 static void
-r4k_flush_cache_range_s16d16i16(struct mm_struct *mm,
+r4k_flush_cache_range_s16d16i16(struct vm_area_struct *vma,
                                 unsigned long start,
                                 unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1003,7 +1003,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if (vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s16d16i16();
@@ -1028,11 +1027,11 @@
 }
 
 static void
-r4k_flush_cache_range_s32d16i16(struct mm_struct *mm,
+r4k_flush_cache_range_s32d16i16(struct vm_area_struct *vma,
                                 unsigned long start,
                                 unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1042,7 +1041,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if (vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s32d16i16();
@@ -1066,11 +1064,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s64d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_s64d16i16(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1080,7 +1078,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if(vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s64d16i16();
@@ -1104,11 +1101,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s128d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_s128d16i16(struct vm_area_struct *vma,
 					     unsigned long start,
 					     unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1118,7 +1115,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if (vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s128d16i16();
@@ -1142,11 +1138,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s32d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_s32d32i32(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1156,7 +1152,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if (vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s32d32i32();
@@ -1180,11 +1175,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s64d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_s64d32i32(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1194,7 +1189,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if (vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s64d32i32();
@@ -1218,11 +1212,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s128d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_s128d32i32(struct vm_area_struct *vma,
 					     unsigned long start,
 					     unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1232,7 +1226,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if (vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s128d32i32();
@@ -1256,10 +1249,12 @@
 	}
 }
 
-static void r4k_flush_cache_range_d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_d16i16(struct mm_struct *vma,
 					 unsigned long start,
 					 unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (mm->context != 0) {
 		unsigned long flags;
 
@@ -1272,10 +1267,12 @@
 	}
 }
 
-static void r4k_flush_cache_range_d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_d32i32(struct vm_area_struct *vma,
 					 unsigned long start,
 					 unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (mm->context != 0) {
 		unsigned long flags;
 
@@ -2160,10 +2157,12 @@
 	}
 }
 
-void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				unsigned long end)
 {
-	if(mm->context != 0) {
+	struct mm_struct *mm = vma->vm_mm;
+
+	if (mm->context != 0) {
 		unsigned long flags;
 		int size;
 
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/r5432.c linux/arch/mips/mm/r5432.c
--- v2.5.2/linux/arch/mips/mm/r5432.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips/mm/r5432.c	Tue Jan 15 10:56:35 2002
@@ -366,10 +366,12 @@
 	blast_dcache32(); blast_icache32();
 }
 
-static void r5432_flush_cache_range_d32i32(struct mm_struct *mm,
+static void r5432_flush_cache_range_d32i32(struct vm_area_struct *vma,
 					 unsigned long start,
 					 unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (mm->context != 0) {
 #ifdef DEBUG_CACHE
 		printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/rm7k.c linux/arch/mips/mm/rm7k.c
--- v2.5.2/linux/arch/mips/mm/rm7k.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips/mm/rm7k.c	Tue Jan 15 10:56:35 2002
@@ -171,7 +171,7 @@
 	/* Yes! Caches that don't suck ...  */
 }
 
-static void rm7k_flush_cache_range_d32i32(struct mm_struct *mm,
+static void rm7k_flush_cache_range_d32i32(struct vm_area_struct *vma,
 					 unsigned long start,
 					 unsigned long end)
 {
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/sb1.c linux/arch/mips/mm/sb1.c
--- v2.5.2/linux/arch/mips/mm/sb1.c	Wed Jul  4 11:50:39 2001
+++ linux/arch/mips/mm/sb1.c	Tue Jan 15 10:56:35 2002
@@ -264,7 +264,7 @@
 	/* Don't need to do this, as the dcache is physically tagged */
 }
 
-static void sb1_flush_cache_range(struct mm_struct *mm, 
+static void sb1_flush_cache_range(struct vm_area_struct *vma,
 				  unsigned long start,
 				  unsigned long end)
 {
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/umap.c linux/arch/mips/mm/umap.c
--- v2.5.2/linux/arch/mips/mm/umap.c	Wed Jul  4 11:50:39 2001
+++ linux/arch/mips/mm/umap.c	Tue Jan 15 10:56:35 2002
@@ -88,20 +88,20 @@
  * range of active mappings at this point
  */
 void
-remove_mapping (struct task_struct *task, unsigned long start, unsigned long end)
+remove_mapping (struct vm_area_struct *vma, struct task_struct *task, unsigned long start, unsigned long end)
 {
 	unsigned long beg = start;
 	pgd_t *dir;
 
 	down_write (&task->mm->mmap_sem);
 	dir = pgd_offset (task->mm, start);
-	flush_cache_range (task->mm, beg, end);
+	flush_cache_range (vma, beg, end);
 	while (start < end){
 		remove_mapping_pmd_range (dir, start, end - start);
 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	flush_tlb_range (task->mm, beg, end);
+	flush_tlb_range (vma, beg, end);
 	up_write (&task->mm->mmap_sem);
 }
 
@@ -192,7 +192,7 @@
 }
 
 int
-vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr)
+vmap_page_range (struct vm_area_struct *vma, unsigned long from, unsigned long size, unsigned long vaddr)
 {
 	int error = 0;
 	pgd_t * dir;
@@ -201,7 +201,7 @@
 
 	vaddr -= from;
 	dir = pgd_offset(current->mm, from);
-	flush_cache_range(current->mm, beg, end);
+	flush_cache_range(vma, beg, end);
 	while (from < end) {
 		pmd_t *pmd = pmd_alloc(current->mm, dir, from);
 		error = -ENOMEM;
@@ -213,6 +213,6 @@
 		from = (from + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	flush_tlb_range(current->mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return error;
 }
diff -u --recursive --new-file v2.5.2/linux/arch/mips/tools/offset.c linux/arch/mips/tools/offset.c
--- v2.5.2/linux/arch/mips/tools/offset.c	Mon Jul  2 13:56:40 2001
+++ linux/arch/mips/tools/offset.c	Mon Jan 28 15:14:22 2002
@@ -79,9 +79,9 @@
 	text("/* MIPS task_struct offsets. */");
 	offset("#define TASK_STATE         ", struct task_struct, state);
 	offset("#define TASK_FLAGS         ", struct task_struct, flags);
-	offset("#define TASK_SIGPENDING    ", struct task_struct, sigpending);
-	offset("#define TASK_NEED_RESCHED  ", struct task_struct, need_resched);
-	offset("#define TASK_PTRACE        ", struct task_struct, ptrace);
+#error	offset("#define TASK_SIGPENDING    ", struct task_struct, work.sigpending);
+#error	offset("#define TASK_NEED_RESCHED  ", struct task_struct, work.need_resched);
+#error	offset("#define TASK_PTRACE        ", struct task_struct, ptrace);
 	offset("#define TASK_COUNTER       ", struct task_struct, counter);
 	offset("#define TASK_NICE          ", struct task_struct, nice);
 	offset("#define TASK_MM            ", struct task_struct, mm);
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/Config.help linux/arch/mips64/Config.help
--- v2.5.2/linux/arch/mips64/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips64/Config.help	Fri Jan 25 16:04:12 2002
@@ -0,0 +1,469 @@
+CONFIG_SMP
+  This enables support for systems with more than one CPU. If you have
+  a system with only one CPU, like most personal computers, say N. If
+  you have a system with more than one CPU, say Y.
+
+  If you say N here, the kernel will run on single and multiprocessor
+  machines, but will use only one CPU of a multiprocessor machine. If
+  you say Y here, the kernel will run on many, but not all,
+  singleprocessor machines. On a singleprocessor machine, the kernel
+  will run faster if you say N here.
+
+  Note that if you say Y here and choose architecture "586" or
+  "Pentium" under "Processor family", the kernel will not work on 486
+  architectures. Similarly, multiprocessor kernels for the "PPro"
+  architecture may not work on all Pentium based boards.
+
+  People using multiprocessor machines who say Y here should also say
+  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+  Management" code will be disabled if you say Y here.
+
+  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-HOWTO available at
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you don't know what to do here, say N.
+
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+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.
+
+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
+  here.
+
+CONFIG_SGI_SN0_N_MODE
+  The nodes of Origin 200, Origin 2000 and Onyx 2 systems can be
+  configured in either N-Modes which allows for more nodes or M-Mode
+  which allows for more memory.  Your system is most probably
+  running in M-Mode, so you should say N here.
+
+CONFIG_MIPS_FPU_EMULATOR
+  This option enables the MIPS software floatingpoint support.  Due to
+  the way floating point works you should always enable this option
+  unless you exactly know what you're doing.
+
+CONFIG_CPU_R4300
+  MIPS Technologies R4300-series processors.
+
+CONFIG_CPU_R4X00
+  MIPS Technologies R4000-series processors other than 4300, including
+  the 4640, 4650, and 4700.
+
+CONFIG_CPU_R5000
+  MIPS Technologies R5000-series processors other than the Nevada.
+
+CONFIG_CPU_NEVADA
+  MIPS Technologies R52x0-series ("Nevada") processors.
+
+CONFIG_CPU_R8000
+  MIPS Technologies R8000-series processors.
+
+CONFIG_CPU_R10000
+  MIPS Technologies R10000-series processors.
+
+CONFIG_DISCONTIGMEM
+  Say Y to upport efficient handling of discontiguous physical memory,
+  for architectures which are either NUMA (Non-Uniform Memory Access)
+  or have huge holes in the physical address space for other reasons.
+  See <file:Documentation/vm/numa> for more.
+
+CONFIG_MAPPED_KERNEL
+  Change the way a Linux kernel is loaded unto memory on a MIPS64
+  machine.  This is required in order to support text replication and
+  NUMA.  If you need to undersatand it, read the source code.
+
+CONFIG_REPLICATE_KTEXT
+  Say Y here to enable replicating the kernel text across multiple
+  nodes in a NUMA cluster.  This trades memory for speed.
+
+CONFIG_REPLICATE_EXHANDLERS
+  Say Y here to enable replicating the kernel exception handlers
+  across multiple nodes in a NUMA cluster. This trades memory for
+  speed.
+
+CONFIG_NUMA
+  Say Y to compile the kernel to support NUMA (Non-Uniform Memory
+  Access).  This option is for configuring high-end multiprocessor
+  server machines.  If in doubt, say N.
+
+CONFIG_MIPS_INSANE_LARGE
+  MIPS R10000 does support a 44 bit / 16TB address space as opposed to
+  previous 64-bit processors which only supported 40 bit / 1TB. If you
+  need processes of more than 1TB virtual address space, say Y here.
+  This will result in additional memory usage, so it is not
+  recommended for normal users.
+
+CONFIG_CPU_LITTLE_ENDIAN
+  Some MIPS machines can be configured for either little or big endian
+  byte order. These modes require different kernels. Say Y if your
+  machine is little endian, N if it's a big endian machine.
+
+CONFIG_SGI_NEWPORT_CONSOLE
+  Say Y here if you want the console on the Newport aka XL graphics
+  card of your Indy.  Most people say Y here.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_PCI
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_HOTPLUG
+  Say Y here if you want to plug devices into your computer while
+  the system is running, and be able to use them quickly.  In many
+  cases, the devices can likewise be unplugged at any time too.
+
+  One well known example of this is PCMCIA- or PC-cards, credit-card
+  size devices such as network cards, modems or hard drives which are
+  plugged into slots found on all modern laptop computers.  Another
+  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.
+  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.
+
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+  computer.  These are credit-card size devices such as network cards,
+  modems or hard drives often used with laptops computers.  There are
+  actually two varieties of these cards: the older 16 bit PCMCIA cards
+  and the newer 32 bit CardBus cards.  If you want to use CardBus
+  cards, you need to say Y here and also to "CardBus support" below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  Please also read the PCMCIA-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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_FONT_8x16
+  This is the "high resolution" font for the VGA frame buffer (the one
+  provided by the VGA text console 80x25 mode.
+
+  If unsure, say Y.
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_CD_NO_IDESCSI
+  If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y
+  here, otherwise N. Read the CD-ROM-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about these CD-ROM drives. If you are unsure what you
+  have, say Y and find out whether you have one of the following
+  drives.
+
+  For each of these drivers, a file Documentation/cdrom/{driver_name}
+  exists. Especially in cases where you do not know exactly which kind
+  of drive you have you should read there. Most of these drivers use a
+  file drivers/cdrom/{driver_name}.h where you can define your
+  interface parameters and switch some internal goodies.
+
+  All these CD-ROM drivers are also usable as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want). If you want to compile them as module, say M instead of Y and
+  read <file:Documentation/modules.txt>.
+
+  If you want to use any of these CD-ROM drivers, you also have to
+  answer Y or M to "ISO 9660 CD-ROM file system support" below (this
+  answer will get "defaulted" for you if you enable any of the Linux
+  CD-ROM drivers).
+
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y.  Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. General information about
+  the modular sound system is contained in the files
+  <file:Documentation/sound/Introduction>.  The file
+  <file:Documentation/sound/README.OSS> contains some slightly
+  outdated but still useful information as well.
+
+  If you have a PnP sound card and you want to configure it at boot
+  time using the ISA PnP tools (read
+  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished.  To do
+  this, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/sound/README.modules>; the module will be
+  called soundcore.o.
+
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and supporting utilities to do that are in the pcsp
+  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+CONFIG_CROSSCOMPILE
+  Say Y here if you are compiling the kernel on a different
+  architecture than the one it is intended to run on.
+
+CONFIG_MIPS32_COMPAT
+  Select this option if you want Linux/MIPS 32-bit binary
+  compatibility. Since all software available for Linux/MIPS is
+  currently 32-bit you should say Y here.
+
+CONFIG_MIPS_FPE_MODULE
+  Build the floating point exception handler module. This option is
+  only useful for people working on the floating point exception
+  handler. If you don't, say N.
+
+CONFIG_REMOTE_DEBUG
+  If you say Y here, it will be possible to remotely debug the MIPS
+  kernel using gdb. This enlarges your kernel image disk size by
+  several megabytes and requires a machine with more than 16 MB,
+  better 32 MB RAM to avoid excessive linking time. This is only
+  useful for kernel hackers. If unsure, say N.
+
+CONFIG_MIPS_UNCACHED
+  If you say Y here there kernel will disable all CPU caches.  This will
+  reduce the system's performance dramatically but can help finding
+  otherwise hard to track bugs.  It can also useful if you're doing
+  hardware debugging with a logic analyzer and need to see all traffic
+  on the bus.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_ISDN
+  ISDN ("Integrated Services Digital Networks", called RNIS in France)
+  is a special type of fully digital telephone service; it's mostly
+  used to connect to your Internet service provider (with SLIP or
+  PPP).  The main advantage is that the speed is higher than ordinary
+  modem/telephone connections, and that you can have voice
+  conversations while downloading stuff.  It only works if your
+  computer is equipped with an ISDN card and both you and your service
+  provider purchased an ISDN line from the phone company.  For
+  details, read <http://alumni.caltech.edu/~dank/isdn/> on the WWW.
+
+  This driver allows you to use an ISDN-card for networking
+  connections and as dialin/out device.  The isdn-tty's have a built
+  in AT-compatible modem emulator.  Network devices support autodial,
+  channel-bundling, callback and caller-authentication without having
+  a daemon running.  A reduced T.70 protocol is supported with tty's
+  suitable for German BTX.  On D-Channel, the protocols EDSS1
+  (Euro-ISDN) and 1TR6 (German style) are supported.  See
+  <file:Documentation/isdn/README> for more information.
+
+  If you want to compile the ISDN code 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 isdn.o. If unsure, say N.
+
+CONFIG_BINFMT_ELF32
+  This allows you to run 32-bit Linux/ELF binaries on your Ultra.
+  Everybody wants this; say Y.
+
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/config.in linux/arch/mips64/config.in
--- v2.5.2/linux/arch/mips64/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/mips64/config.in	Thu Jan 24 11:29:38 2002
@@ -4,10 +4,7 @@
 #
 mainmenu_name "Linux Kernel Configuration"
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'Machine selection'
@@ -101,8 +98,6 @@
    bool 'Kernel floating-point emulation' CONFIG_MIPS_FPU_EMULATOR
 fi
 
-bool 'Networking support' CONFIG_NET
-
 source drivers/pci/Config.in
 
 bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
@@ -113,10 +108,6 @@
    define_bool CONFIG_PCMCIA n
 fi
 
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
-
 if [ "$CONFIG_ARC32" = "y" ]; then
    bool 'ARC console support' CONFIG_ARC_CONSOLE
 fi
@@ -129,14 +120,6 @@
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
 endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
-   bool 'Kernel module loader' CONFIG_KMOD
-fi
 
 source drivers/pci/Config.in
 
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/kernel/entry.S linux/arch/mips64/kernel/entry.S
--- v2.5.2/linux/arch/mips64/kernel/entry.S	Sun Sep  9 10:43:01 2001
+++ linux/arch/mips64/kernel/entry.S	Mon Jan 28 15:14:22 2002
@@ -17,7 +17,7 @@
 #include <asm/stackframe.h>
 
 /* This duplicates the definition from <linux/sched.h> */
-#define PT_TRACESYS	0x00000002		/* tracing system calls */
+#error #define PT_TRACESYS	0x00000002		/* tracing system calls */
 
 #define KU_USER 0x10
 
@@ -26,8 +26,8 @@
 FEXPORT(ret_from_fork)
 		move	a0, v0			# prev
 		jal	schedule_tail
-		lw	t0, TASK_PTRACE($28)	# syscall tracing enabled?
-		andi	t0, PT_TRACESYS
+#error		lw	t0, TASK_PTRACE($28)	# syscall tracing enabled?
+#error		andi	t0, PT_TRACESYS
 		bnez	t0, tracesys_exit
 		j	ret_from_sys_call
 
@@ -50,8 +50,8 @@
 		xori	t0, t0, 1
 		mtc0	t0, CP0_STATUS
 
-		ld	v0, TASK_NEED_RESCHED($28)
-		lw	v1, TASK_SIGPENDING($28)
+#error		ld	v0, TASK_NEED_RESCHED($28)
+#error		lw	v1, TASK_SIGPENDING($28)
 		bnez	v0, reschedule
 		bnez	v1, signal_return
 
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/kernel/init_task.c linux/arch/mips64/kernel/init_task.c
--- v2.5.2/linux/arch/mips64/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/mips64/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,5 +1,6 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/kernel/process.c linux/arch/mips64/kernel/process.c
--- v2.5.2/linux/arch/mips64/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/mips64/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -35,7 +35,7 @@
 	init_idle();
 	current->nice = 20;
 	while (1) {
-		while (!current->need_resched)
+		while (!need_resched())
 			if (wait_available)
 				__asm__("wait");
 		schedule();
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/kernel/scall_64.S linux/arch/mips64/kernel/scall_64.S
--- v2.5.2/linux/arch/mips64/kernel/scall_64.S	Mon Oct  8 10:39:18 2001
+++ linux/arch/mips64/kernel/scall_64.S	Mon Jan 28 15:14:22 2002
@@ -69,9 +69,9 @@
 	ori	t0, t0, 1
 	mtc0	t0, CP0_STATUS
 
-	ld	t2, TASK_NEED_RESCHED($28)
+#error	ld	t2, TASK_NEED_RESCHED($28)
 	bnez	t2, reschedule
-	lw	v0, TASK_SIGPENDING($28)
+#error	lw	v0, TASK_SIGPENDING($28)
 	bnez	v0, signal_return
 
 restore_all:
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/kernel/scall_o32.S linux/arch/mips64/kernel/scall_o32.S
--- v2.5.2/linux/arch/mips64/kernel/scall_o32.S	Mon Oct  8 10:39:18 2001
+++ linux/arch/mips64/kernel/scall_o32.S	Mon Jan 28 15:14:23 2002
@@ -22,7 +22,7 @@
 #include <asm/sysmips.h>
 
 /* This duplicates the definition from <linux/sched.h> */
-#define PT_TRACESYS	0x00000002	/* tracing system calls */
+#error #define PT_TRACESYS	0x00000002	/* tracing system calls */
 
 /* This duplicates the definition from <asm/signal.h> */
 #define SIGILL		4		/* Illegal instruction (ANSI).  */
@@ -54,8 +54,8 @@
 	bgez	t0, stackargs
 
 stack_done:
-		ld	t0, TASK_PTRACE($28)	# syscall tracing enabled?
-		andi	t0, PT_TRACESYS
+#error		ld	t0, TASK_PTRACE($28)	# syscall tracing enabled?
+#error		andi	t0, PT_TRACESYS
 		bnez	t0, trace_a_syscall
 
 		jalr	t2			# Do The Real Thing (TM)
@@ -75,9 +75,9 @@
 		xori	t0, t0, 1
 		mtc0	t0, CP0_STATUS
 
-		ld	t2, TASK_NEED_RESCHED($28)
+#error		ld	t2, TASK_NEED_RESCHED($28)
 		bnez	t2, o32_reschedule
-		lw	v0, TASK_SIGPENDING($28)
+#error		lw	v0, TASK_SIGPENDING($28)
 		bnez	v0, signal_return
 
 restore_all:	RESTORE_SOME
@@ -92,7 +92,7 @@
 		move	a0, zero
 		move	a1, sp
 		SAVE_STATIC
-		jal	do_signal
+#error		jal	do_signal
 
 o32_reschedule:
 		SAVE_STATIC
@@ -130,7 +130,7 @@
 	sd	v0, PT_R0(sp)		# set flag for syscall restarting
 1:	sd	v0, PT_R2(sp)		# result
 
-	jal	syscall_trace
+#error	jal	syscall_trace
 	j	o32_ret_from_sys_call
 
 /* ------------------------------------------------------------------------ */
@@ -213,13 +213,13 @@
 1:	sd	v0, PT_R2(sp)		# result
 
 	/* Success, so skip usual error handling garbage.  */
-	ld	t0, TASK_PTRACE($28)	# syscall tracing enabled?
-	andi	t0, PT_TRACESYS
+#error	ld	t0, TASK_PTRACE($28)	# syscall tracing enabled?
+#error	andi	t0, PT_TRACESYS
 	bnez	t0, 1f
 	b	o32_ret_from_sys_call
 
 1:	SAVE_STATIC
-	jal	syscall_trace
+#error	jal	syscall_trace
 	li	a3, 0			# success
 	j	ret_from_sys_call
 
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/kernel/smp.c linux/arch/mips64/kernel/smp.c
--- v2.5.2/linux/arch/mips64/kernel/smp.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/mips64/kernel/smp.c	Tue Jan 15 10:56:35 2002
@@ -242,15 +242,15 @@
 {
 	struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
 
-	_flush_tlb_range(fd->mm, fd->addr1, fd->addr2);
+	_flush_tlb_range(fd->vma, fd->addr1, fd->addr2);
 }
 
-void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
 	if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
 		struct flush_tlb_data fd;
 
-		fd.mm = mm;
+		fd.vma = vma;
 		fd.addr1 = start;
 		fd.addr2 = end;
 		smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1, 1);
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/ld.script.elf32.S linux/arch/mips64/ld.script.elf32.S
--- v2.5.2/linux/arch/mips64/ld.script.elf32.S	Mon Jul  2 14:40:58 2001
+++ linux/arch/mips64/ld.script.elf32.S	Wed Jan 23 10:54:42 2002
@@ -40,7 +40,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);	/* Align double page for init_task_union */
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/ld.script.elf64 linux/arch/mips64/ld.script.elf64
--- v2.5.2/linux/arch/mips64/ld.script.elf64	Mon Jul  2 14:40:58 2001
+++ linux/arch/mips64/ld.script.elf64	Wed Jan 23 10:54:42 2002
@@ -49,7 +49,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);	/* Align double page for init_task_union */
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/math-emu/cp1emu.c linux/arch/mips64/math-emu/cp1emu.c
--- v2.5.2/linux/arch/mips64/math-emu/cp1emu.c	Sun Sep  9 10:43:02 2001
+++ linux/arch/mips64/math-emu/cp1emu.c	Tue Jan 15 13:53:50 2002
@@ -1707,8 +1707,7 @@
 
 	oldepc = xcp->cp0_epc;
 	do {
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		prevepc = xcp->cp0_epc;
 		insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/mm/andes.c linux/arch/mips64/mm/andes.c
--- v2.5.2/linux/arch/mips64/mm/andes.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips64/mm/andes.c	Tue Jan 15 10:56:35 2002
@@ -179,9 +179,11 @@
 }
 
 static void
-andes_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+andes_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                       unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
 		unsigned long flags;
 		int size;
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/mm/loadmmu.c linux/arch/mips64/mm/loadmmu.c
--- v2.5.2/linux/arch/mips64/mm/loadmmu.c	Sun Sep  9 10:43:02 2001
+++ linux/arch/mips64/mm/loadmmu.c	Tue Jan 15 10:56:35 2002
@@ -25,7 +25,7 @@
 
 /* Cache operations. */
 void (*_flush_cache_mm)(struct mm_struct *mm);
-void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start,
+void (*_flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
                            unsigned long end);
 void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 void (*_flush_page_to_ram)(struct page * page);
@@ -44,7 +44,7 @@
 /* TLB operations. */
 void (*_flush_tlb_all)(void);
 void (*_flush_tlb_mm)(struct mm_struct *mm);
-void (*_flush_tlb_range)(struct mm_struct *mm, unsigned long start,
+void (*_flush_tlb_range)(struct vm_area_struct *vma, unsigned long start,
 			unsigned long end);
 void (*_flush_tlb_page)(struct vm_area_struct *vma, unsigned long page);
 
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/mm/r4xx0.c linux/arch/mips64/mm/r4xx0.c
--- v2.5.2/linux/arch/mips64/mm/r4xx0.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips64/mm/r4xx0.c	Tue Jan 15 10:56:35 2002
@@ -776,11 +776,11 @@
 	__restore_flags(flags);
 }
 
-static void r4k_flush_cache_range_s16d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_s16d16i16(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
@@ -790,8 +790,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s16d16i16();
@@ -815,11 +814,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s32d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_s32d16i16(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
@@ -829,8 +828,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s32d16i16();
@@ -854,11 +852,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s64d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_s64d16i16(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
@@ -868,8 +866,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s64d16i16();
@@ -893,11 +890,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s128d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_s128d16i16(struct vm_area_struct *vma,
 					     unsigned long start,
 					     unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
@@ -907,8 +904,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s128d16i16();
@@ -932,11 +928,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s32d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_s32d32i32(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
@@ -946,8 +942,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s32d32i32();
@@ -971,11 +966,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s64d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_s64d32i32(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
@@ -985,8 +980,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s64d32i32();
@@ -1010,11 +1004,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s128d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_s128d32i32(struct vm_area_struct *vma,
 					     unsigned long start,
 					     unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) != 0)
@@ -1024,8 +1018,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s128d32i32();
@@ -1049,10 +1042,12 @@
 	}
 }
 
-static void r4k_flush_cache_range_d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_d16i16(struct vm_area_struct *vma,
 					 unsigned long start,
 					 unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
 		unsigned long flags;
 
@@ -1065,10 +1060,12 @@
 	}
 }
 
-static void r4k_flush_cache_range_d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_d32i32(struct vm_area_struct *vma,
 					 unsigned long start,
 					 unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
 		unsigned long flags;
 
@@ -1913,9 +1910,11 @@
 	}
 }
 
-static void r4k_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+static void r4k_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
 		unsigned long flags;
 		int size;
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/mm/umap.c linux/arch/mips64/mm/umap.c
--- v2.5.2/linux/arch/mips64/mm/umap.c	Sun Sep  9 10:43:02 2001
+++ linux/arch/mips64/mm/umap.c	Tue Jan 15 10:56:35 2002
@@ -86,7 +86,7 @@
  * This routine is called from the page fault handler to remove a
  * range of active mappings at this point
  */
-void remove_mapping (struct task_struct *task, unsigned long start,
+void remove_mapping (struct vm_area_struct *vma, struct task_struct *task, unsigned long start,
 		     unsigned long end)
 {
 	unsigned long beg = start;
@@ -94,13 +94,13 @@
 
 	down_write (&task->mm->mmap_sem);
 	dir = pgd_offset (task->mm, start);
-	flush_cache_range (task->mm, beg, end);
+	flush_cache_range (vma, beg, end);
 	while (start < end){
 		remove_mapping_pmd_range (dir, start, end - start);
 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	flush_tlb_range (task->mm, beg, end);
+	flush_tlb_range (vma, beg, end);
 	up_write (&task->mm->mmap_sem);
 }
 
@@ -190,7 +190,7 @@
 	return 0;
 }
 
-int vmap_page_range (unsigned long from, unsigned long size,
+int vmap_page_range (struct vm_area_struct *vma, unsigned long from, unsigned long size,
 		     unsigned long vaddr)
 {
 	int error = 0;
@@ -200,7 +200,7 @@
 
 	vaddr -= from;
 	dir = pgd_offset(current->mm, from);
-	flush_cache_range(current->mm, beg, end);
+	flush_cache_range(vma, beg, end);
 	while (from < end) {
 		pmd_t *pmd = pmd_alloc(current->mm, dir, from);
 		error = -ENOMEM;
@@ -212,6 +212,6 @@
 		from = (from + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	flush_tlb_range(current->mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return error;
 }
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/tools/offset.c linux/arch/mips64/tools/offset.c
--- v2.5.2/linux/arch/mips64/tools/offset.c	Thu Jul 27 18:36:54 2000
+++ linux/arch/mips64/tools/offset.c	Mon Jan 28 15:14:23 2002
@@ -76,9 +76,9 @@
 	text("/* MIPS task_struct offsets. */");
 	offset("#define TASK_STATE         ", struct task_struct, state);
 	offset("#define TASK_FLAGS         ", struct task_struct, flags);
-	offset("#define TASK_SIGPENDING    ", struct task_struct, sigpending);
-	offset("#define TASK_NEED_RESCHED  ", struct task_struct, need_resched);
-	offset("#define TASK_PTRACE        ", struct task_struct, ptrace);
+#error	offset("#define TASK_SIGPENDING    ", struct task_struct, sigpending);
+#error	offset("#define TASK_NEED_RESCHED  ", struct task_struct, need_resched);
+#error	offset("#define TASK_PTRACE        ", struct task_struct, ptrace);
 	offset("#define TASK_COUNTER       ", struct task_struct, counter);
 	offset("#define TASK_NICE          ", struct task_struct, nice);
 	offset("#define TASK_MM            ", struct task_struct, mm);
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/Config.help linux/arch/parisc/Config.help
--- v2.5.2/linux/arch/parisc/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/parisc/Config.help	Fri Jan 25 16:04:31 2002
@@ -0,0 +1,556 @@
+CONFIG_SMP
+  This enables support for systems with more than one CPU. If you have
+  a system with only one CPU, like most personal computers, say N. If
+  you have a system with more than one CPU, say Y.
+
+  If you say N here, the kernel will run on single and multiprocessor
+  machines, but will use only one CPU of a multiprocessor machine. If
+  you say Y here, the kernel will run on many, but not all,
+  singleprocessor machines. On a singleprocessor machine, the kernel
+  will run faster if you say N here.
+
+  Note that if you say Y here and choose architecture "586" or
+  "Pentium" under "Processor family", the kernel will not work on 486
+  architectures. Similarly, multiprocessor kernels for the "PPro"
+  architecture may not work on all Pentium based boards.
+
+  People using multiprocessor machines who say Y here should also say
+  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+  Management" code will be disabled if you say Y here.
+
+  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-HOWTO available at
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you don't know what to do here, say N.
+
+CONFIG_PARISC
+  The PA-RISC microprocessor is a RISC chip designed by
+  Hewlett-Packard and used in their line of workstations.  The PA-RISC
+  Linux project has a home page at <www.parisc-linux.org>.
+
+CONFIG_SCSI_ZALON
+  The Zalon is an interface chip that sits between the PA-RISC
+  processor and the NCR 53c720 SCSI controller on K-series PA-RISC
+  boards (these are used, among other places, on some HP 780
+  workstations).  Say Y here to make sure it gets initialized
+  correctly before the Linux kernel tries to talk to the controller.
+
+CONFIG_PCI
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_SOM
+  SOM is a binary executable format inherited from HP/UX.  Say Y here
+  to be able to load and execute SOM binaries directly.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_BINFMT_JAVA
+  If you say Y here, the kernel will load and execute Java J-code
+  binaries directly.  Note: this option is obsolete and scheduled for
+  removal, use CONFIG_BINFMT_MISC instead.
+
+CONFIG_PARPORT
+  If you want to use devices connected to your machine's parallel port
+  (the connector at the computer with 25 holes), e.g. printer, ZIP
+  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
+  <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
+  the WWW.
+
+  It is possible to share a single parallel port among several devices
+  and it is safe to compile all the corresponding drivers into the
+  kernel.  If you want to compile parallel port 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
+  parport.o.  If you have more than one parallel port and want to
+  specify which port and IRQ to be used by this driver at module load
+  time, take a look at <file:Documentation/parport.txt>.
+
+  If unsure, say Y.
+
+CONFIG_PARPORT_PC
+  You should say Y here if you have a PC-style parallel port. All IBM
+  PC compatible computers and some Alphas have PC-style parallel
+  ports.
+
+  This code is also available as a module.  If you want to compile it
+  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
+  parport_pc.o.
+
+  If unsure, say Y.
+
+CONFIG_PARPORT_PC_FIFO
+  Many parallel port chipsets provide hardware that can speed up
+  printing. Say Y here if you want to take advantage of that.
+
+  As well as actually having a FIFO, or DMA capability, the kernel
+  will need to know which IRQ the parallel port has.  By default,
+  parallel port interrupts will not be used, and so neither will the
+  FIFO.  See <file:Documentation/parport.txt> to find out how to
+  specify which IRQ/DMA to use.
+
+CONFIG_PARPORT_PC_SUPERIO
+  Saying Y here enables some probes for Super-IO chipsets in order to
+  find out things like base addresses, IRQ lines and DMA channels.  It
+  is safe to say N.
+
+CONFIG_PARPORT_OTHER
+  Say Y here if you want to be able to load driver modules to support
+  other non-standard types of parallel ports. This causes a
+  performance loss, so most people say N.
+
+CONFIG_PARPORT_1284
+  If you have a printer that supports status readback or device ID, or
+  want to use a device that uses enhanced parallel port transfer modes
+  such as EPP and ECP, say Y here to enable advanced IEEE 1284
+  transfer modes. Also say Y if you want device ID information to
+  appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N.
+
+CONFIG_MODULES
+  Kernel modules are small pieces of compiled code which can be
+  inserted in or removed from the running kernel, using the programs
+  insmod and rmmod. This is described in the file
+  <file:Documentation/modules.txt>, including the fact that you have
+  to say "make modules" in order to compile the modules that you chose
+  during kernel configuration.  Modules can be device drivers, file
+  systems, binary executable formats, and so on. If you think that you
+  may want to make use of modules with this kernel in the future, then
+  say Y here.  If unsure, say Y.
+
+CONFIG_MODVERSIONS
+  Usually, modules have to be recompiled whenever you switch to a new
+  kernel.  Saying Y here makes it possible, and safe, to use the
+  same modules even after compiling a new kernel; this requires the
+  program modprobe. All the software needed for module support is in
+  the modutils package (check the file <file:Documentation/Changes>
+  for location and latest version).  NOTE: if you say Y here but don't
+  have the program genksyms (which is also contained in the above
+  mentioned modutils package), then the building of your kernel will
+  fail.  If you are going to use modules that are generated from
+  non-kernel sources, you would benefit from this option.  Otherwise
+  it's not that important.  So, N ought to be a safe bet.
+
+CONFIG_KMOD
+  Normally when you have selected some drivers and/or file systems to
+  be created as loadable modules, you also have the responsibility to
+  load the corresponding modules (using the programs insmod or
+  modprobe) before you can use them. If you say Y here however, the
+  kernel will be able to load modules for itself: when a part of the
+  kernel needs a module, it runs modprobe with the appropriate
+  arguments, thereby loading the module if it is available. (This is a
+  replacement for kerneld.) Say Y here and read about configuring it
+  in <file:Documentation/kmod.txt>.
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_BLK_DEV_SD
+  If you want to use a SCSI hard disk or the SCSI or parallel port
+  version of the IOMEGA ZIP drive under Linux, say Y and read the
+  SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. This is NOT for SCSI
+  CD-ROMs.
+
+  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 sd_mod.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  Do not compile this driver as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI disk. In this case, do not compile the driver
+  for your SCSI host adapter (below) as a module either.
+
+CONFIG_SD_EXTRA_DEVS
+  This controls the amount of additional space allocated in tables for
+  drivers that are loaded as modules after the kernel is booted.  In
+  the event that the SCSI core itself was loaded as a module, this
+  value is the number of additional disks that can be loaded after the
+  first host driver is loaded.
+
+  Admittedly this isn't pretty, but there are tons of race conditions
+  involved with resizing the internal arrays on the fly.  Someday this
+  flag will go away, and everything will work automatically.
+
+  If you don't understand what's going on, go with the default.
+
+CONFIG_CHR_DEV_ST
+  If you want to use a SCSI tape drive under Linux, say Y and read the
+  SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, and
+  <file:drivers/scsi/README.st> in the kernel source.  This is NOT for
+  SCSI CD-ROMs.
+
+  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 st.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_BLK_DEV_SR
+  If you want to use a SCSI CD-ROM under Linux, say Y and read the
+  SCSI-HOWTO and the CD-ROM-HOWTO at
+  <http://www.linuxdoc.org/docs.html#howto>. Also make sure to say Y
+  or M to "ISO 9660 CD-ROM file system support" later.
+
+  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 sr_mod.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_SR_EXTRA_DEVS
+  This controls the amount of additional space allocated in tables for
+  drivers that are loaded as modules after the kernel is booted. In
+  the event that the SCSI core itself was loaded as a module, this
+  value is the number of additional CD-ROMs that can be loaded after
+  the first host driver is loaded.
+
+  Admittedly this isn't pretty, but there are tons of race conditions
+  involved with resizing the internal arrays on the fly.  Someday this
+  flag will go away, and everything will work automatically.
+
+  If you don't understand what's going on, go with the default.
+
+CONFIG_BLK_DEV_SR_VENDOR
+  This enables the usage of vendor specific SCSI commands. This is
+  required to support multisession CDs with old NEC/TOSHIBA cdrom
+  drives (and HP Writers). If you have such a drive and get the first
+  session only, try saying Y here; everybody else says N.
+
+CONFIG_CHR_DEV_SG
+  If you want to use SCSI scanners, synthesizers or CD-writers or just
+  about anything having "SCSI" in its name other than hard disks,
+  CD-ROMs or tapes, say Y here. These won't be supported by the kernel
+  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 Cdrtools
+  (<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html>)
+  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.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>. The module will be called sg.o. If unsure,
+  say N.
+
+CONFIG_SCSI_MULTI_LUN
+  If you have a SCSI device that supports more than one LUN (Logical
+  Unit Number), e.g. a CD jukebox, and only one LUN is detected, you
+  can say Y here to force the SCSI driver to probe for multiple LUNs.
+  A SCSI device with multiple LUNs acts logically like multiple SCSI
+  devices. The vast majority of SCSI devices have only one LUN, and
+  so most people can say N here and should in fact do so, because it
+  is safer.
+
+CONFIG_SCSI_CONSTANTS
+  The error messages regarding your SCSI hardware will be easier to
+  understand if you say Y here; it will enlarge your kernel by about
+  12 KB. If in doubt, say Y.
+
+CONFIG_SCSI_SYM53C8XX
+  This driver supports all the features of recent 53C8XX chips (used
+  in PCI SCSI controllers), notably the hardware phase mismatch
+  feature of the SYM53C896.
+
+  Older versions of the 53C8XX chips are not supported by this
+  driver.  If your system uses either a 810 rev. < 16, a 815, or a 825
+  rev. < 16 PCI SCSI processor, you must use the generic NCR53C8XX
+  driver ("NCR53C8XX SCSI support" above) or configure both the
+  NCR53C8XX and this SYM53C8XX drivers either as module or linked to
+  the kernel image.
+
+  When both drivers are linked into the kernel, the SYM53C8XX driver
+  is called first at initialization and you can use the 'excl=ioaddr'
+  driver boot option to exclude attachment of adapters by the
+  SYM53C8XX driver.  For example, entering
+  'sym53c8xx=excl:0xb400,excl=0xc000' at the lilo prompt prevents
+  adapters at io address 0xb400 and 0xc000 from being attached by the
+  SYM53C8XX driver, thus allowing the NCR53C8XX driver to attach them.
+  The 'excl' option is also supported by the NCR53C8XX driver.
+
+  Please read <file:drivers/scsi/README.ncr53c8xx> for more
+  information.
+
+CONFIG_SCSI_NCR53C8XX_SYNC
+  The SCSI Parallel Interface-2 Standard defines 5 classes of transfer
+  rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80.  The numbers
+  are respectively the maximum data transfer rates in mega-transfers
+  per second for each class.  For example, a FAST-20 Wide 16 device is
+  able to transfer data at 20 million 16 bit packets per second for a
+  total rate of 40 MB/s.
+
+  You may specify 0 if you want to only use asynchronous data
+  transfers. This is the safest and slowest option. Otherwise, specify
+  a value between 5 and 80, depending on the capability of your SCSI
+  controller.  The higher the number, the faster the data transfer.
+  Note that 80 should normally be ok since the driver decreases the
+  value automatically according to the controller's capabilities.
+
+  Your answer to this question is ignored for controllers with NVRAM,
+  since the driver will get this information from the user set-up.  It
+  also can be overridden using a boot setup option, as follows
+  (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate
+  for FAST-20 synchronous data transfer (20 mega-transfers per
+  second).
+
+  The normal answer therefore is not to go with the default but to
+  select the maximum value 80 allowing the driver to use the maximum
+  value supported by each controller. If this causes problems with
+  your SCSI devices, you should come back and decrease the value.
+
+  There is no safe option other than using good cabling, right
+  terminations and SCSI conformant devices.
+
+CONFIG_SCSI_NCR53C8XX_IOMAPPED
+  If you say Y here, the driver will use normal IO, as opposed to
+  memory mapped IO. Memory mapped IO has less latency than normal IO
+  and works for most Intel-based hardware. Under Linux/Alpha only
+  normal IO is currently supported by the driver and so, this option
+  has no effect on those systems.
+
+  The normal answer therefore is N; try Y only if you encounter SCSI
+  related problems.
+
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS
+  "Tagged command queuing" is a feature of SCSI-2 which improves
+  performance: the host adapter can send several SCSI commands to a
+  device's queue even if previous commands haven't finished yet.
+  Because the device is intelligent, it can optimize its operations
+  (like head positioning) based on its own request queue. Some SCSI
+  devices don't implement this properly; if you want to disable this
+  feature, enter 0 or 1 here (it doesn't matter which).
+
+  The default value is 8 and should be supported by most hard disks.
+  This value can be overridden from the boot command line using the
+  'tags' option as follows (example):
+  'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to
+  4, set queue depth to 16 for target 2 and target 3 on controller 0
+  and set queue depth to 10 for target 0 / lun 2 on controller 1.
+
+  The normal answer therefore is to go with the default 8 and to use
+  a boot command line option for devices that need to use a different
+  command queue depth.
+
+  There is no safe option other than using good SCSI devices.
+
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS
+  This option allows you to specify the maximum number of commands
+  that can be queued to any device, when tagged command queuing is
+  possible. The default value is 32. Minimum is 2, maximum is 64.
+  Modern hard disks are able to support 64 tags and even more, but
+  do not seem to be faster when more than 32 tags are being used.
+
+  So, the normal answer here is to go with the default value 32 unless
+  you are using very large hard disks with large cache (>= 1 MB) that
+  are able to take advantage of more than 32 tagged commands.
+
+  There is no safe option and the default answer is recommended.
+
+CONFIG_SCSI_NCR53C8XX_PROFILE
+  This option allows you to enable profiling information gathering.
+  These statistics are not very accurate due to the low frequency
+  of the kernel clock (100 Hz on i386) and have performance impact
+  on systems that use very fast devices.
+
+  The normal answer therefore is N.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_STI_CONSOLE
+  The STI console is the builtin display/keyboard on HP-PARISC
+  machines.  Say Y here to build support for it into your kernel.
+  The alternative is to use your primary serial port as a console.
+
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y.  Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. General information about
+  the modular sound system is contained in the files
+  <file:Documentation/sound/Introduction>.  The file
+  <file:Documentation/sound/README.OSS> contains some slightly
+  outdated but still useful information as well.
+
+  If you have a PnP sound card and you want to configure it at boot
+  time using the ISA PnP tools (read
+  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished.  To do
+  this, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/sound/README.modules>; the module will be
+  called soundcore.o.
+
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and supporting utilities to do that are in the pcsp
+  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_KWDB
+  Include in-kernel hooks for kdb, the source level debugger for the
+  PA-RISC port.
+
+CONFIG_IODC_CONSOLE
+  IODC is HP's pre-PCI standard for device identification (a la PCI
+  vendor, device IDs), detection, configuration, initialization and so
+  on.  It also can provide firmware function to do the actual IO,
+  which are slow, not really defined for runtime usage and generally
+  not desirable.
+
+  See <http://www.linuxhq.com/kernel/v2.4/doc/parisc/IODC.txt.html>
+  for the gory details.
+
+  Say Y here to enable use of the IODC firmware functions for console
+  I/O.  This is only useful on older PA-RISC workstations.  If in
+  doubt, say Y.
+
+CONFIG_IOMMU_CCIO
+  Say Y here to enable DMA management routines for the first
+  generation of PA-RISC cache-coherent machines.  Programs the
+  U2/Uturn chip in "Virtual Mode" and use the I/O MMU.
+
+CONFIG_PCI_LBA
+  Say Y here to give the PA-RISC kernel access to PCI configuration
+  and IO-port space on PA-RISC workstations equipped with a Lower Bus
+  Adapter (LBA).  This includes A, B, C, J, L, and N-class machines
+  with 4-digit model numbers, also the A300.
+
+CONFIG_GSC_LASI
+  Say Y here to directly support the LASI controller chip found on
+  PA-RISC workstations.  Linux-oriented documentation for this chip
+  can be found at <http://www.parisc-linux.org/documentation/>.
+
+CONFIG_PARPORT_GSC
+  Say Y here to build in low-level parallel-support for PC-style
+  hardware integrated in the LASI-Controller (on the GSC Bus) for
+  HP-PARISC workstations.
+
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/config.in linux/arch/parisc/config.in
--- v2.5.2/linux/arch/parisc/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/parisc/config.in	Thu Jan 24 11:29:38 2002
@@ -10,10 +10,7 @@
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'General options'
@@ -60,11 +57,6 @@
 mainmenu_option next_comment
 comment 'General setup'
 
-bool 'Networking support' CONFIG_NET
-
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
 tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/kernel/entry.S linux/arch/parisc/kernel/entry.S
--- v2.5.2/linux/arch/parisc/kernel/entry.S	Wed Dec  6 11:46:39 2000
+++ linux/arch/parisc/kernel/entry.S	Mon Jan 28 15:14:23 2002
@@ -650,14 +650,14 @@
 	copy    %r30,%r1
 	/* FIXME! depi below has hardcoded dependency on kernel stack size */
 	depi    0,31,14,%r1 /* get task pointer */
-	LDREG     TASK_NEED_RESCHED(%r1),%r19	/* sched.h: long need_resched */
+#error	LDREG     TASK_NEED_RESCHED(%r1),%r19	/* sched.h: long need_resched */
 	comib,<>,n 0,%r19,intr_do_resched /* forward */
 
 intr_check_sig:
 	/* As above */
 	copy    %r30,%r1
 	depi    0,31,14,%r1 /* get task pointer */
-	ldw	TASK_SIGPENDING(%r1),%r19	/* sched.h: int sigpending */
+#error	ldw	TASK_SIGPENDING(%r1),%r19	/* sched.h: int sigpending */
 	comib,<>,n 0,%r19,intr_do_signal /* forward */
 
 intr_restore:
@@ -719,7 +719,7 @@
 	copy	%r0, %r24			/* unsigned long in_syscall */
 	copy	%r16, %r25			/* struct pt_regs *regs */
 	ssm     PSW_SM_I, %r0
-	bl	do_signal,%r2
+#error	bl	do_signal,%r2
 	copy	%r0, %r26			/* sigset_t *oldset = NULL */
 
 	b	intr_restore
@@ -1699,20 +1699,20 @@
 
 	/* check for reschedule */
 
-	LDREG  TASK_NEED_RESCHED-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r19	/* long */
+#error	LDREG  TASK_NEED_RESCHED-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r19	/* long */
 	comib,<>,n 0,%r19,syscall_do_resched /* forward */
 
 syscall_check_sig:
 	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1         /* get task ptr */
 	/* check for pending signals */
-	ldw     TASK_SIGPENDING(%r1),%r19
+#error	ldw     TASK_SIGPENDING(%r1),%r19
 	comib,<>,n 0,%r19,syscall_do_signal  /* forward */
 
 syscall_restore:
 	/* disable interrupts while dicking with the kernel stack, */
 	/* or life can become unpleasant */
 	rsm	PSW_SM_I, %r20
-	LDREG	TASK_PTRACE(%r1), %r19		/* Are we being ptraced? */
+#error	LDREG	TASK_PTRACE(%r1), %r19		/* Are we being ptraced? */
 	bb,<,n	%r19,31,syscall_restore_rfi
 	LDREG	TASK_PT_GR20(%r1),%r19
 	mtctl	%r19, %cr27
@@ -1840,7 +1840,7 @@
 
 	ldi	1, %r24				/* unsigned long in_syscall */
 
-	bl	do_signal,%r2
+#error	bl	do_signal,%r2
 	copy	%r0, %r26			/* sigset_t *oldset = NULL */
 
 	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30), %r1     /* reload task ptr */
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/kernel/init_task.c linux/arch/parisc/kernel/init_task.c
--- v2.5.2/linux/arch/parisc/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/parisc/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,6 +1,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/kernel/process.c linux/arch/parisc/kernel/process.c
--- v2.5.2/linux/arch/parisc/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/parisc/kernel/process.c	Tue Jan 15 13:57:50 2002
@@ -73,8 +73,8 @@
 	current->nice = 20;
 
 	while (1) {
-		while (!current->need_resched) {
-		}
+		while (!need_resched())
+			barrier();
 		schedule();
 		check_pgt_cache();
 	}
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/mm/kmap.c linux/arch/parisc/mm/kmap.c
--- v2.5.2/linux/arch/parisc/mm/kmap.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/parisc/mm/kmap.c	Tue Jan 15 10:56:35 2002
@@ -128,11 +128,11 @@
 	switch (what) {
 	case IOMAP_FULL_CACHING:
 		iterate_pages(vaddr, size, set_cached, 0);
-		flush_tlb_range(&init_mm, vaddr, size);
+		flush_tlb_range(NULL, vaddr, size);
 		break;
 	case IOMAP_NOCACHE_SER:
 		iterate_pages(vaddr, size, set_uncached, 0);
-		flush_tlb_range(&init_mm, vaddr, size);
+		flush_tlb_range(NULL, vaddr, size);
 		break;
 	default:
 		printk(KERN_CRIT
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/mm/pa11.c linux/arch/parisc/mm/pa11.c
--- v2.5.2/linux/arch/parisc/mm/pa11.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/parisc/mm/pa11.c	Tue Jan 15 10:56:35 2002
@@ -28,7 +28,7 @@
 /* Cache operations. */
 static inline void pa11_flush_cache_all(void) { }
 static void pa11_flush_cache_mm(struct mm_struct *mm) { }
-static void pa11_flush_cache_range(struct mm_struct *mm,
+static void pa11_flush_cache_range(struct vm_area_struct *vma,
 				    unsigned long start,
 				    unsigned long end)
 {
@@ -65,10 +65,10 @@
 		pa11_flush_tlb_all();
 }
 
-static void pa11_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+static void pa11_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				  unsigned long end)
 {
-	if(mm == current->mm)
+	if (vma == NULL || vma->vm_mm == current->mm)
 		pa11_flush_tlb_all();
 }
 
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/mm/pa20.c linux/arch/parisc/mm/pa20.c
--- v2.5.2/linux/arch/parisc/mm/pa20.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/parisc/mm/pa20.c	Tue Jan 15 10:56:35 2002
@@ -28,7 +28,7 @@
 /* Cache operations. */
 static inline void pa20_flush_cache_all(void) { }
 static void pa20_flush_cache_mm(struct mm_struct *mm) { }
-static void pa20_flush_cache_range(struct mm_struct *mm,
+static void pa20_flush_cache_range(struct vm_area_struct *vma,
 				    unsigned long start,
 				    unsigned long end)
 {
@@ -65,10 +65,10 @@
 		pa20_flush_tlb_all();
 }
 
-static void pa20_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+static void pa20_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				  unsigned long end)
 {
-	if(mm == current->mm)
+	if (vma == NULL || vma->vm_mm == current->mm)
 		pa20_flush_tlb_all();
 }
 
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/tools/offset.c linux/arch/parisc/tools/offset.c
--- v2.5.2/linux/arch/parisc/tools/offset.c	Tue Dec  5 12:29:39 2000
+++ linux/arch/parisc/tools/offset.c	Mon Jan 28 15:14:23 2002
@@ -241,11 +241,11 @@
 	text("/* PARISC task_struct offsets. */");
 	offset("#define TASK_STATE         ", struct task_struct, state);
 	offset("#define TASK_FLAGS         ", struct task_struct, flags);
-	offset("#define TASK_SIGPENDING    ", struct task_struct, sigpending);
+#error	offset("#define TASK_SIGPENDING    ", struct task_struct, sigpending);
 	offset("#define TASK_SEGMENT       ", struct task_struct, addr_limit);
-	offset("#define TASK_NEED_RESCHED  ", struct task_struct, need_resched);
+#error	offset("#define TASK_NEED_RESCHED  ", struct task_struct, need_resched);
 	offset("#define TASK_COUNTER       ", struct task_struct, counter);
-	offset("#define TASK_PTRACE        ", struct task_struct, ptrace);
+#error	offset("#define TASK_PTRACE        ", struct task_struct, ptrace);
 	offset("#define TASK_NICE          ", struct task_struct, nice);
 	offset("#define TASK_MM            ", struct task_struct, mm);
 	offset("#define TASK_PROCESSOR     ", struct task_struct, processor);
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/vmlinux.lds linux/arch/parisc/vmlinux.lds
--- v2.5.2/linux/arch/parisc/vmlinux.lds	Mon Jul  2 14:40:58 2001
+++ linux/arch/parisc/vmlinux.lds	Wed Jan 23 10:54:42 2002
@@ -51,7 +51,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) } 
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   __init_end = .;
 
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/8260_io/Config.help linux/arch/ppc/8260_io/Config.help
--- v2.5.2/linux/arch/ppc/8260_io/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/8260_io/Config.help	Fri Jan 25 16:03:58 2002
@@ -0,0 +1,24 @@
+CONFIG_FEC_ENET
+  Enable Ethernet support via the Fast Ethernet Controller (FCC) on
+  the Motorola MPC8260.
+
+CONFIG_FCC1_ENET
+  Use MPC8260 fast Ethernet controller 1 to drive Ethernet (default).
+
+CONFIG_FCC2_ENET
+  Use MPC8260 fast Ethernet controller 2 to drive Ethernet.
+
+CONFIG_FCC3_ENET
+  Use MPC8260 fast Ethernet controller 3 to drive Ethernet.
+
+CONFIG_SCC_ENET
+  Enable Ethernet support via the Motorola MPC8xx serial
+  commmunications controller.
+
+CONFIG_SCC1_ENET
+  Use MPC8xx serial communications controller 1 to drive Ethernet
+  (default).
+
+CONFIG_SCC2_ENET
+  Use MPC8xx serial communications controller 2 to drive Ethernet.
+
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/8xx_io/Config.help linux/arch/ppc/8xx_io/Config.help
--- v2.5.2/linux/arch/ppc/8xx_io/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/8xx_io/Config.help	Fri Jan 25 16:04:16 2002
@@ -0,0 +1,72 @@
+CONFIG_USE_MDIO
+  On some boards the hardware configuration of the ethernet PHY can be
+  used without any software interaction over the MDIO interface, so
+  all MII code can be omitted. Say N here if unsure or if you don't
+  need link status reports.
+
+CONFIG_FEC_ENET
+  Enable Ethernet support via the Fast Ethernet Controller (FCC) on
+  the Motorola MPC8260.
+
+CONFIG_SCC_ENET
+  Enable Ethernet support via the Motorola MPC8xx serial
+  commmunications controller.
+
+CONFIG_SCC1_ENET
+  Use MPC8xx serial communications controller 1 to drive Ethernet
+  (default).
+
+CONFIG_SCC2_ENET
+  Use MPC8xx serial communications controller 2 to drive Ethernet.
+
+CONFIG_SCC3_ENET
+  Use MPC8xx serial communications controller 3 to drive Ethernet.
+
+CONFIG_ENET_BIG_BUFFERS
+  Allocate large buffers for MPC8xx Etherenet.  Increases throughput
+  and decreases the likelihood of dropped packets, but costs memory.
+
+CONFIG_8xx_COPYBACK
+  Saying Y here will cause the cache on an MPC8xx processor to be used
+  in Copy-Back mode.  If you say N here, it is used in Writethrough
+  mode.
+
+  If in doubt, say Y here.
+
+CONFIG_8xx_CPU6
+  MPC860 CPUs, prior to Rev C have some bugs in the silicon, which
+  require workarounds for Linux (and most other OSes to work).  If you
+  get a BUG() very early in boot, this might fix the problem.  For
+  more details read the document entitled "MPC860 Family Device Errata
+  Reference" on Motorola's website.  This option also incurs a
+  performance hit.
+
+  If in doubt, say N here.
+
+CONFIG_SMC2_UART
+  If you would like to use SMC2 as a serial port, say Y here.
+
+  If in doubt, say Y here.
+
+CONFIG_CONS_SMC2
+  If you are going to have a serial console on your device and are
+  using SMC2 for your serial port, say Y here, else say N.
+
+CONFIG_ALTSMC2
+  If you have an MPC823 or MPC850 and would like to use the alternate
+  SMC2 for I/O, say Y here.
+
+  If in doubt, say N here.
+
+CONFIG_USE_SCC_IO
+  If your MPC8xx board has other SCC ports that you would like to use
+  for for a serial port, say Y here.
+
+  If in doubt, say N here.
+
+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.
+
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/Config.help linux/arch/ppc/Config.help
--- v2.5.2/linux/arch/ppc/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/Config.help	Fri Jan 25 16:04:31 2002
@@ -0,0 +1,1088 @@
+CONFIG_SMP
+  This enables support for systems with more than one CPU. If you have
+  a system with only one CPU, like most personal computers, say N. If
+  you have a system with more than one CPU, say Y.
+
+  If you say N here, the kernel will run on single and multiprocessor
+  machines, but will use only one CPU of a multiprocessor machine. If
+  you say Y here, the kernel will run on many, but not all,
+  singleprocessor machines. On a singleprocessor machine, the kernel
+  will run faster if you say N here.
+
+  Note that if you say Y here and choose architecture "586" or
+  "Pentium" under "Processor family", the kernel will not work on 486
+  architectures. Similarly, multiprocessor kernels for the "PPro"
+  architecture may not work on all Pentium based boards.
+
+  People using multiprocessor machines who say Y here should also say
+  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+  Management" code will be disabled if you say Y here.
+
+  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-HOWTO available at
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you don't know what to do here, say N.
+
+CONFIG_PPC
+  The PowerPC is a very capable 32-bit RISC processor from Motorola,
+  the successor to their 68000 and 88000 series.  It powers recent
+  Macintoshes and also a widely-used series of single-board computers
+  from Motorola.  The Linux PowerPC port has a home page at
+  <http://penguinppc.org/>.
+
+CONFIG_MATH_EMULATION
+  Linux can emulate a math coprocessor (used for floating point
+  operations) if you don't have one. 486DX and Pentium processors have
+  a math coprocessor built in, 486SX and 386 do not, unless you added
+  a 487DX or 387, respectively. (The messages during boot time can
+  give you some hints here ["man dmesg"].) Everyone needs either a
+  coprocessor or this emulation.
+
+  If you don't have a math coprocessor, you need to say Y here; if you
+  say Y here even though you have a coprocessor, the coprocessor will
+  be used nevertheless. (This behavior can be changed with the kernel
+  command line option "no387", which comes handy if your coprocessor
+  is broken. Try "man bootparam" or see the documentation of your boot
+  loader (lilo or loadlin) about how to pass options to the kernel at
+  boot time.) This means that it is a good idea to say Y here if you
+  intend to use this kernel on different machines.
+
+  More information about the internals of the Linux math coprocessor
+  emulation can be found in <file:arch/i386/math-emu/README>.
+
+  If you are not sure, say Y; apart from resulting in a 66 KB bigger
+  kernel, it won't hurt.
+
+CONFIG_MAC_FLOPPY
+  If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple)
+  floppy controller, say Y here. Most commonly found in PowerMacs.
+
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+CONFIG_HEARTBEAT
+  Use the power-on LED on your machine as a load meter.  The exact
+  behavior is platform-dependent, but normally the flash frequency is
+  a hyperbolic function of the 5-minute load average.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_PCI
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_PCI_QSPAN
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_HOTPLUG
+  Say Y here if you want to plug devices into your computer while
+  the system is running, and be able to use them quickly.  In many
+  cases, the devices can likewise be unplugged at any time too.
+
+  One well known example of this is PCMCIA- or PC-cards, credit-card
+  size devices such as network cards, modems or hard drives which are
+  plugged into slots found on all modern laptop computers.  Another
+  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.
+  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.
+
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+  computer.  These are credit-card size devices such as network cards,
+  modems or hard drives often used with laptops computers.  There are
+  actually two varieties of these cards: the older 16 bit PCMCIA cards
+  and the newer 32 bit CardBus cards.  If you want to use CardBus
+  cards, you need to say Y here and also to "CardBus support" below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  Please also read the PCMCIA-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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_VGA_CONSOLE
+  Saying Y here will allow you to use Linux in text mode through a
+  display that complies with the generic VGA standard. Virtually
+  everyone wants that.
+
+  The program SVGATextMode can be used to utilize SVGA video cards to
+  their full potential in text mode. Download it from
+  <ftp://ibiblio.org/pub/Linux/utils/console/>.
+
+  Say Y.
+
+CONFIG_IRQ_ALL_CPUS
+  This option gives the kernel permission to distribute IRQs across
+  multiple CPUs.  Saying N here will route all IRQs to the first
+  CPU. Generally SMP PowerMacs can answer Y. SMP IBM CHRP boxes or
+  Power3 boxes should say N for now.
+
+CONFIG_FB
+  The frame buffer device provides an abstraction for the graphics
+  hardware. It represents the frame buffer of some video hardware and
+  allows application software to access the graphics hardware through
+  a well-defined interface, so the software doesn't need to know
+  anything about the low-level (hardware register) stuff.
+
+  Frame buffer devices work identically across the different
+  architectures supported by Linux and make the implementation of
+  application programs easier and more portable; at this point, an X
+  server exists which uses the frame buffer device exclusively.
+  On several non-X86 architectures, the frame buffer device is the
+  only way to use the graphics hardware.
+
+  The device is accessed through special device nodes, usually located
+  in the /dev directory, i.e. /dev/fb*.
+
+  You need an utility program called fbset to make full use of frame
+  buffer devices. Please read <file:Documentation/fb/framebuffer.txt>
+  and the Framebuffer-HOWTO at
+  <http://www.tahallah.demon.co.uk/programming/prog.html> for more
+  information.
+
+  Say Y here and to the driver for your graphics board below if you
+  are compiling a kernel for a non-x86 architecture.
+
+  If you are compiling for the x86 architecture, you can say Y if you
+  want to play with it, but it is not essential. Please note that
+  running graphical applications that directly touch the hardware
+  (e.g. an accelerated X server) and that are not frame buffer
+  device-aware may cause unexpected results. If unsure, say N.
+
+CONFIG_FB_COMPAT_XPMAC
+  If you use the Xpmac X server (common with mklinux), you'll need to
+  say Y here to use X. You should consider changing to XFree86 which
+  includes a server that supports the frame buffer device directly
+  (XF68_FBDev).
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_CD_NO_IDESCSI
+  If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y
+  here, otherwise N. Read the CD-ROM-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about these CD-ROM drives. If you are unsure what you
+  have, say Y and find out whether you have one of the following
+  drives.
+
+  For each of these drivers, a file Documentation/cdrom/{driver_name}
+  exists. Especially in cases where you do not know exactly which kind
+  of drive you have you should read there. Most of these drivers use a
+  file drivers/cdrom/{driver_name}.h where you can define your
+  interface parameters and switch some internal goodies.
+
+  All these CD-ROM drivers are also usable as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want). If you want to compile them as module, say M instead of Y and
+  read <file:Documentation/modules.txt>.
+
+  If you want to use any of these CD-ROM drivers, you also have to
+  answer Y or M to "ISO 9660 CD-ROM file system support" below (this
+  answer will get "defaulted" for you if you enable any of the Linux
+  CD-ROM drivers).
+
+CONFIG_INPUT_ADBHID
+  Say Y here if you want to have ADB (Apple Desktop Bus) HID devices
+  such as keyboards, mice, joysticks, or graphic tablets handled by
+  the input layer.  If you say Y here, make sure to say Y to the
+  corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV),
+  "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface
+  support" (CONFIG_INPUT_EVDEV) as well.
+
+  If you say N here, you still have the option of using the old ADB
+  keyboard and mouse drivers.
+
+  If unsure, say Y.
+
+CONFIG_PREP_RESIDUAL
+  Some PReP systems have residual data passed to the kernel by the
+  firmware.  This allows detection of memory size, devices present and
+  other useful pieces of information.  Sometimes this information is
+  not present or incorrect.
+
+  Unless you expect to boot on a PReP system, there is not need to
+  select Y.
+
+CONFIG_ADB
+  Apple Desktop Bus (ADB) support is for support of devices which
+  are connected to an ADB port.  ADB devices tend to have 4 pins.
+  If you have an Apple Macintosh prior to the iMac, or a
+  "Blue and White G3", you probably want to say Y here.  Otherwise
+  say N.
+
+CONFIG_ADB_CUDA
+  This provides support for CUDA based Power Macintosh systems.  This
+  includes most OldWorld PowerMacs, the first generation iMacs, the
+  Blue&White G3 and the Yikes G4 (PCI Graphics).  All later models
+  should use CONFIG_ADB_PMU instead.
+
+  If unsure say Y.
+
+CONFIG_ADB_PMU
+  On the PowerBook 3400 and 2400, the PMU is a 6805 microprocessor
+  core whose primary function is to control battery charging and
+  system power.  The PMU also controls the ADB (Apple Desktop Bus)
+  which connects to the keyboard and mouse, as well as the
+  non-volatile RAM and the RTC (real time clock) chip.  Say Y to
+  enable support for this device; you should do so if your machine
+  is one of these PowerBooks.
+
+CONFIG_ADB_MACIO
+  Say Y here to include direct support for the ADB controller in the
+  Hydra chip used on PowerPC Macintoshes of the CHRP type.  (The Hydra
+  also includes a MESH II SCSI controller, DBDMA controller, VIA chip,
+  OpenPIC controller and two RS422/Geoports.)
+
+CONFIG_ADB_KEYBOARD
+  This option allows you to use an ADB keyboard attached to your
+  machine. Note that this disables any other (ie. PS/2) keyboard
+  support, even if your machine is physically capable of using both at
+  the same time.
+
+  If you use an ADB keyboard (4 pin connector), say Y here.
+  If you use a PS/2 keyboard (6 pin connector), say N here.
+
+CONFIG_SERIAL_CONSOLE
+  If you say Y here, it will be possible to use a serial port as the
+  system console (the system console is the device which receives all
+  kernel messages and warnings and which allows logins in single user
+  mode). This could be useful if some terminal or printer is connected
+  to that serial port.
+
+  Even if you say Y here, the currently visible virtual console
+  (/dev/tty0) will still be used as the system console by default, but
+  you can alter that using a kernel command line option such as
+  "console=ttyS1". (Try "man bootparam" or see the documentation of
+  your boot loader (lilo or loadlin) about how to pass options to the
+  kernel at boot time.)
+
+  If you don't have a VGA card installed and you say Y here, the
+  kernel will automatically use the first serial line, /dev/ttyS0, as
+  system console.
+
+  If unsure, say N.
+
+CONFIG_MAC_SERIAL
+  If you have Macintosh style serial ports (8 pin mini-DIN), say Y
+  here. If you also have regular serial ports and enable the driver
+  for them, you can't currently use the serial console feature.
+
+CONFIG_BUSMOUSE
+  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 a laptop, you either have to check the documentation or
+  experiment a bit to find out whether the trackball is a serial mouse
+  or not; it's best to say Y here for you.
+
+  This is the generic bus mouse driver code. If you have a bus mouse,
+  you will have to say Y here and also to the specific driver for your
+  mouse below.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called busmouse.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MOUSE
+  This is for machines with a mouse which is neither a serial nor a
+  bus mouse. Examples are PS/2 mice (such as the track balls on some
+  laptops) and some digitizer pads. 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>. This HOWTO contains
+  information about all non-serial mice, not just bus mice.
+
+  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
+  or not; it's best to say Y here for you.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about non-serial mice. If unsure, say Y.
+
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y.  Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. General information about
+  the modular sound system is contained in the files
+  <file:Documentation/sound/Introduction>.  The file
+  <file:Documentation/sound/README.OSS> contains some slightly
+  outdated but still useful information as well.
+
+  If you have a PnP sound card and you want to configure it at boot
+  time using the ISA PnP tools (read
+  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished.  To do
+  this, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/sound/README.modules>; the module will be
+  called soundcore.o.
+
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and supporting utilities to do that are in the pcsp
+  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_ISDN
+  ISDN ("Integrated Services Digital Networks", called RNIS in France)
+  is a special type of fully digital telephone service; it's mostly
+  used to connect to your Internet service provider (with SLIP or
+  PPP).  The main advantage is that the speed is higher than ordinary
+  modem/telephone connections, and that you can have voice
+  conversations while downloading stuff.  It only works if your
+  computer is equipped with an ISDN card and both you and your service
+  provider purchased an ISDN line from the phone company.  For
+  details, read <http://alumni.caltech.edu/~dank/isdn/> on the WWW.
+
+  This driver allows you to use an ISDN-card for networking
+  connections and as dialin/out device.  The isdn-tty's have a built
+  in AT-compatible modem emulator.  Network devices support autodial,
+  channel-bundling, callback and caller-authentication without having
+  a daemon running.  A reduced T.70 protocol is supported with tty's
+  suitable for German BTX.  On D-Channel, the protocols EDSS1
+  (Euro-ISDN) and 1TR6 (German style) are supported.  See
+  <file:Documentation/isdn/README> for more information.
+
+  If you want to compile the ISDN code 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 isdn.o. If unsure, say N.
+
+CONFIG_PROC_HARDWARE
+  Say Y here to support the /proc/hardware file, which gives you
+  access to information about the machine you're running on,
+  including the model, CPU, MMU, clock speed, BogoMIPS rating,
+  and memory size.
+
+CONFIG_AMIGA
+  This option enables support for the Amiga series of computers. If
+  you plan to use this kernel on an Amiga, say Y here and browse the
+  material available in <file:Documentation/m68k>; otherwise say N.
+
+CONFIG_A2232
+  This option supports the 2232 7-port serial card shipped with the
+  Amiga 2000 and other Zorro-bus machines, dating from 1989.  At
+  a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip
+  each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The
+  ports were connected with 8 pin DIN connectors on the card bracket,
+  for which 8 pin to DB25 adapters were supplied. The card also had
+  jumpers internally to toggle various pinning configurations.
+
+  This driver can be built as a module; but then "generic_serial.o"
+  will also be built as a module. This has to be loaded before
+  "ser_a2232.o". If you want to do this, answer M here and read
+  "<file:Documentation/modules.txt>".
+
+CONFIG_ZORRO
+  This enables support for the Zorro bus in the Amiga. If you have
+  expansion cards in your Amiga that conform to the Amiga
+  AutoConfig(tm) specification, say Y, otherwise N. Note that even
+  expansion cards that do not fit in the Zorro slots but fit in e.g.
+  the CPU slot may fall in this category, so you have to say Y to let
+  Linux use these.
+
+CONFIG_AMIGA_PCMCIA
+  Include support in the kernel for pcmcia on Amiga 1200 and Amiga
+  600. If you intend to use pcmcia cards say Y; otherwise say N.
+
+CONFIG_WHIPPET_SERIAL
+  HiSoft has a web page at <http://www.hisoft.co.uk/>, but there
+  is no listing for the Whippet in their Amiga section.
+
+CONFIG_APNE
+  If you have a PCMCIA NE2000 compatible adapter, say Y.  Otherwise,
+  say N.
+
+  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 is called apne.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_AMIGAMOUSE
+  If you want to be able to use an Amiga mouse in Linux, say Y.
+
+  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 is called amigamouse.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_BOOTX_TEXT
+  Say Y here to see progress messages from the boot firmware in text
+  mode. Requires either BootX or Open Firmware.
+
+CONFIG_AMIGA_BUILTIN_SERIAL
+  If you want to use your Amiga's built-in serial port in Linux,
+  answer Y.
+
+  This driver is also available 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>.
+
+CONFIG_GVPIOEXT
+  If you want to use a GVP IO-Extender serial card in Linux, say Y.
+  Otherwise, say N.
+
+CONFIG_GVPIOEXT_LP
+  Say Y to enable driving a printer from the parallel port on your
+  GVP IO-Extender card, N otherwise.
+
+CONFIG_GVPIOEXT_PLIP
+  Say Y to enable doing IP over the parallel port on your GVP
+  IO-Extender card, N otherwise.
+
+CONFIG_MULTIFACE_III_TTY
+  If you want to use a Multiface III card's serial port in Linux,
+  answer Y.
+
+  This driver is also available 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>.
+
+CONFIG_6xx
+  There are four types of PowerPC chips supported.  The more common
+  types (601, 603, 604, 740, 750, 7400), the Motorola embedded
+  versions (821, 823, 850, 855, 860, 8260), the IBM embedded versions
+  (403 and 405) and the high end 64 bit Power processors (Power 3,
+  Power 4).  Unless you are building a kernel for one of the embedded
+  processor systems, or a 64 bit IBM RS/6000, choose 6xx.  Note that
+  the kernel runs in 32-bit mode even on 64-bit chips.  Also note that
+  because the 82xx family has a 603e core, specific support for that
+  chipset is asked later on.
+
+CONFIG_8260
+  The MPC8260 CPM (Communications Processor Module) is a typical
+  embedded CPU made by Motorola.  Selecting this option means that
+  you wish to build a kernel for a machine with specifically an 8260
+  for a CPU.
+
+  If in doubt, say N.
+
+CONFIG_OAK
+  Select Oak if you have an IBM 403GCX "Oak" Evaluation Board.
+
+  Select Walnut if you have an IBM 405GP "Walnut" Evaluation Board.
+
+  More information on these boards is available at:
+  <http://www.chips.ibm.com/products/powerpc/tools/evk_pn.html#GCX>.
+
+CONFIG_WALNUT
+  Select Walnut if you have an IBM 405GP "Walnut" Evaluation Board.
+
+CONFIG_PPC601_SYNC_FIX
+  Some versions of the PPC601 (the first PowerPC chip) have bugs which
+  mean that extra synchronization instructions are required near
+  certain instructions, typically those that make major changes to the
+  CPU state.  These extra instructions reduce performance slightly.
+  If you say N here, these extra instructions will not be included,
+  resulting in a kernel which will run faster but may not run at all
+  on some systems with the PPC601 chip.
+
+  If in doubt, say Y here.
+
+CONFIG_ALL_PPC
+  Linux currently supports several different kinds of PowerPC-based
+  machines: Apple Power Macintoshes and clones (such as the Motorola
+  Starmax series), PReP (PowerPC Reference Platform) machines (such
+  as the Motorola PowerStacks, Motorola cPCI/VME embedded systems,
+  and some IBM RS/6000 systems), CHRP (Common Hardware Reference
+  Platform), and several embedded PowerPC systems containing 4xx, 6xx,
+  7xx, 8xx, 74xx, and 82xx processors.  Currently, the default option
+  is to build a kernel which works on the first three.
+
+  Select PowerMac/PReP/MTX/CHRP if configuring for any of the above.
+
+  Select Gemini if configuring for a Synergy Microsystems' Gemini
+  series Single Board Computer.  More information is available at:
+  <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/>.
+
+CONFIG_GEMINI
+  Select Gemini if configuring for a Synergy Microsystems' Gemini
+  series Single Board Computer.  More information is available at:
+  <http://www.synergymicro.com/PressRel/97_10_15.html>.
+
+CONFIG_APUS
+  Select APUS if configuring for a PowerUP Amiga.
+  More information is available at:
+  <http://linux-apus.sourceforge.net/>.
+
+CONFIG_ALTIVEC
+  This option enables kernel support for the Altivec extensions to the
+  PowerPC processor. The kernel currently supports saving and restoring
+  altivec registers, and turning on the 'altivec enable' bit so user
+  processes can execute altivec instructions.
+
+  This option is only usefully if you have a processor that supports
+  altivec (G4, otherwise known as 74xx series), but does not have
+  any affect on a non-altivec cpu (it does, however add code to the
+  kernel).
+
+  If in doubt, say Y here.
+
+CONFIG_TAU
+  G3 and G4 processors have an on-chip temperature sensor called the
+  'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die
+  temperature within 2-4 degrees Celsius. This option shows the current
+  on-die temperature in /proc/cpuinfo if the cpu supports it.
+
+  Unfortunately, on some chip revisions, this sensor is very inaccurate
+  and in some cases, does not work at all, so don't assume the cpu
+  temp is actually what /proc/cpuinfo says it is.
+
+CONFIG_TAU_INT
+  The TAU supports an interrupt driven mode which causes an interrupt
+  whenever the temperature goes out of range. This is the fastest way
+  to get notified the temp has exceeded a range. With this option off,
+  a timer is used to re-check the temperature periodically.
+
+  However, on some cpus it appears that the TAU interrupt hardware
+  is buggy and can cause a situation which would lead unexplained hard
+  lockups.
+
+  Unless you are extending the TAU driver, or enjoy kernel/hardware
+  debugging, leave this option off.
+
+CONFIG_TAU_AVERAGE
+  The TAU hardware can compare the temperature to an upper and lower bound.
+  The default behavior is to show both the upper and lower bound in
+  /proc/cpuinfo. If the range is large, the temperature is either changing
+  a lot, or the TAU hardware is broken (likely on some G4's). If the range
+  is small (around 4 degrees), the temperature is relatively stable.
+
+CONFIG_PMAC_PBOOK
+  This provides support for putting a PowerBook to sleep; it also
+  enables media bay support.  Power management works on the
+  PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3. You
+  must get the power management daemon, pmud, to make it work and you
+  must have the /dev/pmu device (see the pmud README).
+
+  Get pmud from <ftp://ftp.samba.org/pub/ppclinux/pmud/>.
+
+  If you have a PowerBook, you should say Y.
+
+  You may also want to compile the dma sound driver as a module and
+  have it autoloaded. The act of removing the module shuts down the
+  sound hardware for more power savings.
+
+CONFIG_PMAC_BACKLIGHT
+  Say Y here to build in code to manage the LCD backlight on a
+  Macintosh PowerBook.  With this code, the backlight will be turned
+  on and off appropriately on power-management and lid-open/lid-closed
+  events; also, the PowerBook button device will be enabled so you can
+  change the screen brightness.
+
+CONFIG_RPXLITE
+  Single-board computers based around the PowerPC MPC8xx chips and
+  intended for embedded applications.  The following types are
+  supported:
+
+  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.
+
+CONFIG_RPXCLASSIC
+  The RPX-Classic is a single-board computer based on the Motorola
+  MPC860.  It features 16MB of DRAM and a variable amount of flash,
+  I2C EEPROM, thermal monitoring, a PCMCIA slot, a DIP switch and two
+  LEDs.  Variants with Ethernet ports exist.  Say Y here to support it
+  directly.
+
+CONFIG_BSEIP
+  Say Y here to support the Bright Star Engineering ipEngine SBC.
+  This is a credit-card-sized device featuring a MPC823 processor,
+  26MB DRAM, 4MB flash, Ethernet, a 16K-gate FPGA, USB, an LCD/video
+  controller, and two RS232 ports.
+
+CONFIG_TQM823L
+  Say Y here to support the TQM823L, one of an MPC8xx-based family of
+  mini SBCs (half credit-card size) from TQ Components first released
+  in late 1999.  Technical references are at
+  <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
+  <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
+  <http://www.denx.de/embedded-ppc-en.html>.
+
+CONFIG_TQM850L
+  Say Y here to support the TQM850L, one of an MPC8xx-based family of
+  mini SBCs (half credit-card size) from TQ Components first released
+  in late 1999.  Technical references are at
+  <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
+  <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
+  <http://www.denx.de/embedded-ppc-en.html>.
+
+CONFIG_TQM855L
+  Say Y here to support the TQM855L, one of an MPC8xx-based family of
+  mini SBCs (half credit-card size) from TQ Components first released
+  in late 1999.  Technical references are at
+  <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
+  <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
+  <http://www.denx.de/embedded-ppc-en.html>.
+
+CONFIG_TQM860L
+  Say Y here to support the TQM860L, one of an MPC8xx-based family of
+  mini SBCs (half credit-card size) from TQ Components first released
+  in late 1999.  Technical references are at
+  <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
+  <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
+  <http://www.denx.de/embedded-ppc-en.html>.
+
+CONFIG_TQM860
+  Say Y here to support the TQM860, one of an MPC8xx-based family of
+  SBCs (credit-card size) from TQ Components first released in 
+  mid-1999 and discontinued mid-2000.
+
+CONFIG_SM850
+  Say Y here to support the Service Module 850 from Dependable
+  Computer Systems, an SBC based on the TQM850L module by TQ
+  Components.  This board is no longer in production.  The
+  manufacturer's website is at <http://www.decomsys.com/>.
+
+CONFIG_SPD823TS
+  Say Y here to support the Speech Design 823 Tele-Server from Speech
+  Design, released in 2000.  The manufacturer's website is at
+  <http://www.speech-design.de/>.
+
+CONFIG_IVMS8
+  Say Y here to support the Integrated Voice-Mail Small 8-channel SBC
+  from Speech Design, released March 2001.  The manufacturer's website
+  is at <http://www.speech-design.de/>.
+
+CONFIG_IVML24
+  Say Y here to support the Integrated Voice-Mail Large 24-channel SBC
+  from Speech Design, released March 2001.  The manufacturer's website
+  is at <http://www.speech-design.de/>.
+
+CONFIG_MBX
+  MBX is a line of Motorola single-board computer based around the
+  MPC821 and MPC860 processors, and intended for embedded-controller
+  applications.  Say Y here to support these boards directly.
+
+CONFIG_WINCEPT
+  The Wincept 100/110 is a Motorola single-board computer based on the
+  MPC821 PowerPC, introduced in 1998 and designed to be used in
+  thin-client machines.  Say Y to support it directly.
+
+CONFIG_EST8260
+  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>
+
+CONFIG_MAC_ADBKEYCODES
+  This provides support for sending raw ADB keycodes to console
+  devices.  This is the default up to 2.4.0, but in future this may be
+  phased out in favor of generic Linux keycodes.  If you say Y here,
+  you can dynamically switch via the
+      /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes
+  sysctl and with the "keyboard_sends_linux_keycodes=" kernel
+  argument.
+
+  If unsure, say Y here.
+
+CONFIG_MAC_EMUMOUSEBTN
+  This provides generic support for emulating the 2nd and 3rd mouse
+  button with keypresses.  If you say Y here, the emulation is still
+  disabled by default.  The emulation is controlled by these sysctl
+  entries:
+      /proc/sys/dev/mac_hid/mouse_button_emulation
+      /proc/sys/dev/mac_hid/mouse_button2_keycode
+      /proc/sys/dev/mac_hid/mouse_button3_keycode
+
+CONFIG_PPC_RTC
+  If you say Y here and create a character special file /dev/rtc with
+  major number 10 and minor number 135 using mknod ("man mknod"), you
+  will get access to the real time clock (or hardware clock) built
+  into your computer.
+
+  If unsure, say Y here.
+
+CONFIG_PROC_DEVICETREE
+  This option adds a device-tree directory under /proc which contains
+  an image of the device tree that the kernel copies from Open
+  Firmware. If unsure, say Y here.
+
+CONFIG_PPC_RTAS
+  When you use this option, you will be able to use RTAS from
+  userspace.
+
+  RTAS stands for RunTime Abstraction Services and should
+  provide a portable way to access and set system information. This is
+  commonly used on RS/6000 (pSeries) computers.
+
+  You can access RTAS via the special proc file system entry rtas.
+  Don't confuse this rtas entry with the one in /proc/device-tree/rtas
+  which is readonly.
+
+  If you don't know if you can use RTAS look into
+  /proc/device-tree/rtas. If there are some entries, it is very likely
+  that you will be able to use RTAS.
+
+  You can do cool things with rtas. To print out information about
+  various sensors in the system, just do a
+
+    $ cat /proc/rtas/sensors
+
+  or if you power off your machine at night but want it running when
+  you enter your office at 7:45 am, do a
+
+    # date -d 'tomorrow 7:30' +%s > /proc/rtas/poweron
+
+  and shutdown.
+
+  If unsure, say Y.
+
+CONFIG_CMDLINE
+  On some architectures (EBSA110 and CATS), there is currently no way
+  for the boot loader to pass arguments to the kernel. For these
+  architectures, you should supply some command-line options at build
+  time by entering them here. As a minimum, you should specify the
+  memory size and the root device (e.g., mem=64M root=/dev/nfs).
+
+CONFIG_KGDB
+  Include in-kernel hooks for kgdb, the Linux kernel source level
+  debugger.  This project has a web page at
+  <http://kgdb.sourceforge.net/>.
+
+CONFIG_XMON
+  Include in-kernel hooks for the xmon kernel monitor/debugger
+  supported by the PPC port.
+
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.5.2/linux/arch/ppc/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/ppc/config.in	Thu Jan 24 11:29:38 2002
@@ -10,19 +10,7 @@
 
 mainmenu_name "Linux/PowerPC Kernel Configuration"
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'Platform support'
@@ -151,11 +139,6 @@
      fi
   fi
 fi
-
-bool 'Networking support' CONFIG_NET
-bool 'Sysctl support' CONFIG_SYSCTL
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 
 # only elf supported, a.out is not -- Cort
 if [ "$CONFIG_PROC_FS" = "y" ]; then
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S
--- v2.5.2/linux/arch/ppc/kernel/entry.S	Tue Aug 28 06:58:33 2001
+++ linux/arch/ppc/kernel/entry.S	Mon Jan 28 15:14:23 2002
@@ -261,9 +261,9 @@
 	.globl	ret_from_fork
 ret_from_fork:
 	bl	schedule_tail
-	lwz	r0,TASK_PTRACE(r2)
+#error	lwz	r0,TASK_PTRACE(r2)
 	andi.	r0,r0,PT_TRACESYS
-	bnel-	syscall_trace
+#error	bnel-	syscall_trace
 	b	ret_from_except
 
 	.globl	ret_from_intercept
@@ -279,16 +279,16 @@
 	lwz	r3,_MSR(r1)	/* Returning to user mode? */
 	andi.	r3,r3,MSR_PR
 	beq+	do_signal_ret	/* if so, check need_resched and signals */
-	lwz	r3,NEED_RESCHED(r2)
+#error	lwz	r3,NEED_RESCHED(r2)
 	cmpi	0,r3,0		/* check need_resched flag */
 	beq+	7f
 	bl	schedule
-7:	lwz	r5,SIGPENDING(r2) /* Check for pending unblocked signals */
+#error 7:	lwz	r5,SIGPENDING(r2) /* Check for pending unblocked signals */
 	cmpwi	0,r5,0
 	beq+	do_signal_ret
 	li	r3,0
 	addi	r4,r1,STACK_FRAME_OVERHEAD
-	bl	do_signal
+#error	bl	do_signal
 	.globl	do_signal_ret
 do_signal_ret:
 	.globl ret_to_user_hook	
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.5.2/linux/arch/ppc/kernel/idle.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/ppc/kernel/idle.c	Tue Jan 15 13:57:16 2002
@@ -66,15 +66,15 @@
 			int oldval = xchg(&current->need_resched, -1);
 
 			if (!oldval) {
-				while(current->need_resched == -1)
-					; /* Do Nothing */
+				while (need_resched())
+					barrier(); /* Do Nothing */
 			}
 		}
 #endif
-		if (do_power_save && !current->need_resched)
+		if (do_power_save && !need_resched())
 			power_save();
 
-		if (current->need_resched) {
+		if (need_resched()) {
 			schedule();
 			check_pgt_cache();
 		}
@@ -150,7 +150,7 @@
 
 	if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] )
 		return;
-	while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && (!current->need_resched) )
+	while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && !need_resched() )
 	{
 		/*
 		 * Mark a page as reserved so we can mess with it
@@ -161,8 +161,7 @@
 		if ( !pageptr )
 			return;
 		
-		if ( current->need_resched )
-			schedule();
+		cond_resched();
 		
 		/*
 		 * Make the page no cache so we don't blow our cache with 0's
@@ -181,8 +180,7 @@
 		 */
 		for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
 		{
-			if ( current->need_resched )
-				schedule();
+			cond_resched();
 			*(unsigned long *)(bytecount + pageptr) = 0;
 		}
 		
@@ -243,7 +241,7 @@
 	 *  -- Cort
 	 */
 	_nmask_and_or_msr(MSR_EE, 0);
-	if (!current->need_resched)
+	if (!need_resched())
 	{
 		asm("mfspr %0,1008" : "=r" (hid0) :);
 		hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c
--- v2.5.2/linux/arch/ppc/kernel/mk_defs.c	Tue Aug 28 06:58:33 2001
+++ linux/arch/ppc/kernel/mk_defs.c	Mon Jan 28 15:14:23 2002
@@ -39,7 +39,7 @@
 	DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
 	DEFINE(COUNTER, offsetof(struct task_struct, counter));
 	DEFINE(PROCESSOR, offsetof(struct task_struct, processor));
-	DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending));
+#error	DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending));
 	DEFINE(THREAD, offsetof(struct task_struct, thread));
 	DEFINE(MM, offsetof(struct task_struct, mm));
 	DEFINE(ACTIVE_MM, offsetof(struct task_struct, active_mm));
@@ -50,8 +50,8 @@
 	DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
 	DEFINE(PT_TRACESYS, PT_TRACESYS);
 	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
-	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
-	DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
+#error	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
+#error	DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
 	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
 	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
 #ifdef CONFIG_ALTIVEC
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.5.2/linux/arch/ppc/kernel/pci.c	Fri Nov 16 10:10:08 2001
+++ linux/arch/ppc/kernel/pci.c	Tue Jan 15 10:56:35 2002
@@ -1068,7 +1068,7 @@
 	__pci_mmap_set_flags(dev, vma, mmap_state);
 	__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
 
-	ret = remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+	ret = remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
 			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
 
 	return ret;
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.5.2/linux/arch/ppc/kernel/setup.c	Wed Nov 21 09:59:11 2001
+++ linux/arch/ppc/kernel/setup.c	Wed Jan 23 10:54:42 2002
@@ -535,6 +535,8 @@
 	}
 }
 
+subsys_initcall(ppc_init);
+
 /* Warning, IO base is not yet inited */
 void __init setup_arch(char **cmdline_p)
 {
@@ -689,8 +691,12 @@
 	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
 	id->word92         = __le16_to_cpu(id->word92);
 	id->hw_config      = __le16_to_cpu(id->hw_config);
-	for (i = 0; i < 32; i++)
-		id->words94_125[i]  = __le16_to_cpu(id->words94_125[i]);
+	id->acoustic       = __le16_to_cpu(id->acoustic);
+	for (i = 0; i < 5; i++)
+		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
+	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+	for (i = 0; i < 22; i++)
+		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
 	id->last_lun       = __le16_to_cpu(id->last_lun);
 	id->word127        = __le16_to_cpu(id->word127);
 	id->dlf            = __le16_to_cpu(id->dlf);
@@ -700,6 +706,12 @@
 	id->word156        = __le16_to_cpu(id->word156);
 	for (i = 0; i < 3; i++)
 		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	for (i = 0; i < 96; i++)
-		id->words160_255[i] = __le16_to_cpu(id->words160_255[i]);
+	id->cfa_power      = __le16_to_cpu(id->cfa_power);
+	for (i = 0; i < 14; i++)
+		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+	for (i = 0; i < 31; i++)
+		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+	for (i = 0; i < 48; i++)
+		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+	id->integrity_word  = __le16_to_cpu(id->integrity_word);
 }
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.5.2/linux/arch/ppc/kernel/smp.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/ppc/kernel/smp.c	Mon Jan 28 15:14:23 2002
@@ -106,7 +106,7 @@
 		smp_call_function_interrupt();
 		break;
 	case PPC_MSG_RESCHEDULE: 
-		current->need_resched = 1;
+		current->work.need_resched = 1;
 		break;
 	case PPC_MSG_INVALIDATE_TLB:
 		_tlbia();
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.5.2/linux/arch/ppc/kernel/time.c	Mon Oct  8 11:43:01 2001
+++ linux/arch/ppc/kernel/time.c	Wed Jan 23 15:28:39 2002
@@ -352,8 +352,6 @@
         	tz.tz_dsttime = 0;
         	do_sys_settimeofday(NULL, &tz);
         }
-
-       do_get_fast_time = do_gettimeofday;
 }
 
 #define TICK_SIZE tick
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/mm/tlb.c linux/arch/ppc/mm/tlb.c
--- v2.5.2/linux/arch/ppc/mm/tlb.c	Tue Aug 28 06:58:33 2001
+++ linux/arch/ppc/mm/tlb.c	Tue Jan 15 10:56:35 2002
@@ -39,7 +39,7 @@
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *
  * since the hardware hash table functions as an extension of the
  * tlb as far as the linux tables are concerned, flush it too.
@@ -53,6 +53,8 @@
 void
 local_flush_tlb_all(void)
 {
+	struct vm_area_struct vma;
+
 	/* aargh!!! */
 	/*
 	 * Just flush the kernel part of the address space, that's
@@ -61,7 +63,8 @@
 	 * we can and should dispense with flush_tlb_all().
 	 *  -- paulus.
 	 */
-	local_flush_tlb_range(&init_mm, TASK_SIZE, ~0UL);
+	vma.vm_mm = &init_mm;
+	local_flush_tlb_range(&vma, TASK_SIZE, ~0UL);
 
 #ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
@@ -84,9 +87,12 @@
 	if (mm->map_count) {
 		struct vm_area_struct *mp;
 		for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
-			local_flush_tlb_range(mm, mp->vm_start, mp->vm_end);
-	} else
-		local_flush_tlb_range(mm, 0, TASK_SIZE);
+			local_flush_tlb_range(mp, mp->vm_start, mp->vm_end);
+	} else {
+		struct vm_area_struct vma;
+		vma.vm_mm = mm;
+		local_flush_tlb_range(&vma, 0, TASK_SIZE);
+	}
 
 #ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
@@ -123,8 +129,9 @@
  * the corresponding HPTE.
  */
 void
-local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	pmd_t *pmd;
 	pte_t *pte;
 	unsigned long pmd_end;
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/vmlinux.lds linux/arch/ppc/vmlinux.lds
--- v2.5.2/linux/arch/ppc/vmlinux.lds	Tue Aug 28 06:58:33 2001
+++ linux/arch/ppc/vmlinux.lds	Wed Jan 23 10:54:42 2002
@@ -94,7 +94,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/s390/Config.help linux/arch/s390/Config.help
--- v2.5.2/linux/arch/s390/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/s390/Config.help	Fri Jan 25 16:04:19 2002
@@ -0,0 +1,171 @@
+CONFIG_SMP
+  This enables support for systems with more than one CPU. If you have
+  a system with only one CPU, like most personal computers, say N. If
+  you have a system with more than one CPU, say Y.
+
+  If you say N here, the kernel will run on single and multiprocessor
+  machines, but will use only one CPU of a multiprocessor machine. If
+  you say Y here, the kernel will run on many, but not all,
+  singleprocessor machines. On a singleprocessor machine, the kernel
+  will run faster if you say N here.
+
+  Note that if you say Y here and choose architecture "586" or
+  "Pentium" under "Processor family", the kernel will not work on 486
+  architectures. Similarly, multiprocessor kernels for the "PPro"
+  architecture may not work on all Pentium based boards.
+
+  People using multiprocessor machines who say Y here should also say
+  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+  Management" code will be disabled if you say Y here.
+
+  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-HOWTO available at
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you don't know what to do here, say N.
+
+CONFIG_MATHEMU
+  This option is required for IEEE compliant floating point arithmetic
+  on the Alpha. The only time you would ever not say Y is to say M in
+  order to debug the code. Say Y unless you know what you are doing.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_REMOTE_DEBUG
+  If you say Y here, it will be possible to remotely debug the MIPS
+  kernel using gdb. This enlarges your kernel image disk size by
+  several megabytes and requires a machine with more than 16 MB,
+  better 32 MB RAM to avoid excessive linking time. This is only
+  useful for kernel hackers. If unsure, say N.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_ARCH_S390
+  Select this option, if you want to run the Kernel on one of IBM's
+  mainframes of the S/390 generation. You should have installed the
+  s390-compiler released by IBM (based on gcc-2.95.1) before.
+
+CONFIG_IPL
+  If you want to use the produced kernel to IPL directly from a
+  device, you have to merge a bootsector specific to the device
+  into the first bytes of the kernel. You will have to select the
+  IPL device.
+
+CONFIG_IPL_TAPE
+  Select this option if you want to IPL the image from a Tape.
+
+CONFIG_FAST_IRQ
+  Select this option in order to get the interrupts processed faster
+  on your S/390 or zSeries machine.  If selected, after an interrupt
+  is processed, the channel subsystem will be asked for other pending
+  interrupts which will also be processed before leaving the interrupt
+  context.  This speeds up the I/O a lot. Say "Y".
+
+CONFIG_PROCESS_DEBUG
+  Say Y to print all process fault locations to the console.  This is
+  a debugging option; you probably do not want to set it unless you
+  are an S390 port maintainer.
+
diff -u --recursive --new-file v2.5.2/linux/arch/s390/config.in linux/arch/s390/config.in
--- v2.5.2/linux/arch/s390/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/s390/config.in	Thu Jan 24 11:29:38 2002
@@ -14,19 +14,7 @@
 mainmenu_name "Linux Kernel Configuration"
 define_bool CONFIG_ARCH_S390 y
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'Processor type and features'
@@ -43,10 +31,6 @@
           "tape                   CONFIG_IPL_TAPE \
            vm_reader              CONFIG_IPL_VM" tape
 fi
-bool 'Networking support' CONFIG_NET
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
 define_bool CONFIG_KCORE_ELF y
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
diff -u --recursive --new-file v2.5.2/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S
--- v2.5.2/linux/arch/s390/kernel/entry.S	Fri Nov  9 13:58:02 2001
+++ linux/arch/s390/kernel/entry.S	Mon Jan 28 15:14:23 2002
@@ -76,9 +76,9 @@
  */
 state        =  0
 flags        =  4
-sigpending   =  8
-need_resched = 24
-tsk_ptrace   = 28
+#error sigpending   =  8
+#error need_resched = 24
+#error tsk_ptrace   = 28
 processor    = 56
 
 /*
@@ -218,7 +218,7 @@
         stosm   24(%r15),0x03     # reenable interrupts
         sll     %r8,2
         l       %r8,sys_call_table-entry_base(8,%r13) # get address of system call
-        tm      tsk_ptrace+3(%r9),0x02 # PT_TRACESYS
+#error        tm      tsk_ptrace+3(%r9),0x02 # PT_TRACESYS
         bnz     BASED(sysc_tracesys)
         basr    %r14,%r8          # call sys_xxxx
         st      %r2,SP_R2(%r15)   # store return value (change R2 on stack)
@@ -231,9 +231,9 @@
 #
 # check, if reschedule is needed
 #
-        icm     %r0,15,need_resched(%r9) # get need_resched from task_struct
+#error        icm     %r0,15,need_resched(%r9) # get need_resched from task_struct
         bnz     BASED(sysc_reschedule)
-        icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
+#error        icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
         bnz     BASED(sysc_signal_return)
 sysc_leave:
 	tm      SP_PGM_OLD_ILC(%r15),0xff
@@ -744,9 +744,9 @@
 #
 # check, if reschedule is needed
 #
-        icm     %r0,15,need_resched(%r9) # get need_resched from task_struct
+#error        icm     %r0,15,need_resched(%r9) # get need_resched from task_struct
         bnz     BASED(io_reschedule)
-        icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
+#error        icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
         bnz     BASED(io_signal_return)
 io_leave:
         stnsm   24(%r15),0xfc            # disable I/O and ext. interrupts
@@ -874,7 +874,7 @@
  */
 .Ls390_mcck:   .long  s390_do_machine_check
 .Ldo_IRQ:      .long  do_IRQ
-.Ldo_signal:   .long  do_signal
+#error .Ldo_signal:   .long  do_signal
 .Ldo_softirq:  .long  do_softirq
 .Lentry_base:  .long  entry_base
 .Lext_hash:    .long  ext_int_hash
@@ -891,7 +891,7 @@
 .Lsigreturn:   .long  sys_sigreturn
 .Lsigsuspend:  .long  sys_sigsuspend
 .Lsigaltstack: .long  sys_sigaltstack
-.Ltrace:       .long  syscall_trace
+#error .Ltrace:       .long  syscall_trace
 .Lvfork:       .long  sys_vfork
 
 #ifdef CONFIG_SMP
diff -u --recursive --new-file v2.5.2/linux/arch/s390/kernel/init_task.c linux/arch/s390/kernel/init_task.c
--- v2.5.2/linux/arch/s390/kernel/init_task.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/s390/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -8,6 +8,7 @@
 
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c
--- v2.5.2/linux/arch/s390/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/s390/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -60,7 +60,7 @@
 	wait_psw.mask = _WAIT_PSW_MASK;
 	wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
 	while(1) {
-                if (current->need_resched) {
+                if (need_resched()) {
                         schedule();
                         check_pgt_cache();
                         continue;
diff -u --recursive --new-file v2.5.2/linux/arch/s390/kernel/time.c linux/arch/s390/kernel/time.c
--- v2.5.2/linux/arch/s390/kernel/time.c	Thu Oct 11 09:04:57 2001
+++ linux/arch/s390/kernel/time.c	Wed Jan 23 15:28:39 2002
@@ -249,7 +249,4 @@
         init_timer_cc -= 0x8126d60e46000000LL -
                          (0x3c26700LL*1000000*4096);
         tod_to_timeval(init_timer_cc, &xtime);
-
-	/* Set do_get_fast_time function pointer.  */
-	do_get_fast_time = do_gettimeofday;
 }
diff -u --recursive --new-file v2.5.2/linux/arch/s390/vmlinux-shared.lds linux/arch/s390/vmlinux-shared.lds
--- v2.5.2/linux/arch/s390/vmlinux-shared.lds	Sun Aug 12 10:38:48 2001
+++ linux/arch/s390/vmlinux-shared.lds	Wed Jan 23 10:54:42 2002
@@ -55,7 +55,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/s390/vmlinux.lds linux/arch/s390/vmlinux.lds
--- v2.5.2/linux/arch/s390/vmlinux.lds	Mon Jul  2 14:40:58 2001
+++ linux/arch/s390/vmlinux.lds	Wed Jan 23 10:54:42 2002
@@ -53,7 +53,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/s390x/Config.help linux/arch/s390x/Config.help
--- v2.5.2/linux/arch/s390x/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/s390x/Config.help	Fri Jan 25 16:04:19 2002
@@ -0,0 +1,176 @@
+CONFIG_SMP
+  This enables support for systems with more than one CPU. If you have
+  a system with only one CPU, like most personal computers, say N. If
+  you have a system with more than one CPU, say Y.
+
+  If you say N here, the kernel will run on single and multiprocessor
+  machines, but will use only one CPU of a multiprocessor machine. If
+  you say Y here, the kernel will run on many, but not all,
+  singleprocessor machines. On a singleprocessor machine, the kernel
+  will run faster if you say N here.
+
+  Note that if you say Y here and choose architecture "586" or
+  "Pentium" under "Processor family", the kernel will not work on 486
+  architectures. Similarly, multiprocessor kernels for the "PPro"
+  architecture may not work on all Pentium based boards.
+
+  People using multiprocessor machines who say Y here should also say
+  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+  Management" code will be disabled if you say Y here.
+
+  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-HOWTO available at
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you don't know what to do here, say N.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_REMOTE_DEBUG
+  If you say Y here, it will be possible to remotely debug the MIPS
+  kernel using gdb. This enlarges your kernel image disk size by
+  several megabytes and requires a machine with more than 16 MB,
+  better 32 MB RAM to avoid excessive linking time. This is only
+  useful for kernel hackers. If unsure, say N.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_BINFMT_ELF32
+  This allows you to run 32-bit Linux/ELF binaries on your Ultra.
+  Everybody wants this; say Y.
+
+CONFIG_ARCH_S390
+  Select this option, if you want to run the Kernel on one of IBM's
+  mainframes of the S/390 generation. You should have installed the
+  s390-compiler released by IBM (based on gcc-2.95.1) before.
+
+CONFIG_IPL
+  If you want to use the produced kernel to IPL directly from a
+  device, you have to merge a bootsector specific to the device
+  into the first bytes of the kernel. You will have to select the
+  IPL device.
+
+CONFIG_IPL_TAPE
+  Select this option if you want to IPL the image from a Tape.
+
+CONFIG_FAST_IRQ
+  Select this option in order to get the interrupts processed faster
+  on your S/390 or zSeries machine.  If selected, after an interrupt
+  is processed, the channel subsystem will be asked for other pending
+  interrupts which will also be processed before leaving the interrupt
+  context.  This speeds up the I/O a lot. Say "Y".
+
+CONFIG_S390_SUPPORT
+  Select this option if you want to enable your system kernel to
+  handle system-calls from ELF binaries for 31 bit ESA.  This option
+  (and some other stuff like libraries and such) is needed for
+  executing 31 bit applications.  It is safe to say "Y".
+
+CONFIG_PROCESS_DEBUG
+  Say Y to print all process fault locations to the console.  This is
+  a debugging option; you probably do not want to set it unless you
+  are an S390 port maintainer.
+
diff -u --recursive --new-file v2.5.2/linux/arch/s390x/config.in linux/arch/s390x/config.in
--- v2.5.2/linux/arch/s390x/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/s390x/config.in	Thu Jan 24 11:29:38 2002
@@ -14,11 +14,7 @@
 define_bool CONFIG_ARCH_S390 y
 define_bool CONFIG_ARCH_S390X y
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
+source init/Config.in
 mainmenu_option next_comment
 comment 'Processor type and features'
 bool 'Symmetric multi-processing support' CONFIG_SMP
@@ -29,15 +25,6 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
-  bool 'Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
-mainmenu_option next_comment
 comment 'General setup'
 bool 'Fast IRQ handling' CONFIG_FAST_IRQ
 bool 'Builtin IPL record support' CONFIG_IPL
@@ -46,10 +33,6 @@
           "tape                   CONFIG_IPL_TAPE \
            vm_reader              CONFIG_IPL_VM" tape
 fi
-bool 'Networking support' CONFIG_NET
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
 define_bool CONFIG_KCORE_ELF y
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
diff -u --recursive --new-file v2.5.2/linux/arch/s390x/kernel/entry.S linux/arch/s390x/kernel/entry.S
--- v2.5.2/linux/arch/s390x/kernel/entry.S	Fri Nov  9 13:58:02 2001
+++ linux/arch/s390x/kernel/entry.S	Mon Jan 28 15:14:23 2002
@@ -76,9 +76,9 @@
  */
 state        =  0
 flags        =  8
-sigpending   = 16
-need_resched = 32
-tsk_ptrace   = 40
+#error sigpending   = 16
+#error need_resched = 32
+#error tsk_ptrace   = 40
 processor    = 92
 
 /*
@@ -220,10 +220,10 @@
 #
 # check, if reschedule is needed
 #
-	lg      %r0,need_resched(%r9) # get need_resched from task_struct
+#error	lg      %r0,need_resched(%r9) # get need_resched from task_struct
 	ltgr    %r0,%r0
         jnz     sysc_reschedule
-        icm     %r0,15,sigpending(%r9)     # get sigpending from task_struct
+#error        icm     %r0,15,sigpending(%r9)     # get sigpending from task_struct
         jnz     sysc_signal_return
 sysc_leave:
         tm      SP_PGM_OLD_ILC(%r15),0xff
@@ -246,7 +246,7 @@
 sysc_tracesys:
 	lghi    %r2,-ENOSYS
 	stg     %r2,SP_R2(%r15)     # give sysc_trace an -ENOSYS retval
-        brasl   %r14,syscall_trace
+#error        brasl   %r14,syscall_trace
 	lg      %r2,SP_R2(%r15)
 	cghi    %r2,-ENOSYS
 	je      sysc_tracesys_dn1   
@@ -263,7 +263,7 @@
         basr    %r14,%r8            # call sys_xxx
         stg     %r2,SP_R2(%r15)     # store return value
 	larl    %r14,sysc_return
-        jg      syscall_trace       # return point is sysc_return
+#error        jg      syscall_trace       # return point is sysc_return
 
 #
 # call schedule with sysc_return as return-address
@@ -734,10 +734,10 @@
 #
 # check, if reschedule is needed
 #
-	lg      %r0,need_resched(%r9)  # get need_resched from task_struct
+#error	lg      %r0,need_resched(%r9)  # get need_resched from task_struct
 	ltgr    %r0,%r0
         jnz     io_reschedule
-        icm     %r0,15,sigpending(%r9) # get sigpending from task_struct
+#error        icm     %r0,15,sigpending(%r9) # get sigpending from task_struct
         jnz     io_signal_return
 io_leave:
         stnsm   48(%r15),0xfc          # disable I/O and ext. interrupts
diff -u --recursive --new-file v2.5.2/linux/arch/s390x/kernel/init_task.c linux/arch/s390x/kernel/init_task.c
--- v2.5.2/linux/arch/s390x/kernel/init_task.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/s390x/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -8,6 +8,7 @@
 
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/s390x/kernel/process.c linux/arch/s390x/kernel/process.c
--- v2.5.2/linux/arch/s390x/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/s390x/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -60,7 +60,7 @@
 	wait_psw.mask = _WAIT_PSW_MASK;
 	wait_psw.addr = (unsigned long) &&idle_wakeup;
 	while(1) {
-                if (current->need_resched) {
+                if (need_resched()) {
                         schedule();
                         check_pgt_cache();
                         continue;
diff -u --recursive --new-file v2.5.2/linux/arch/s390x/kernel/time.c linux/arch/s390x/kernel/time.c
--- v2.5.2/linux/arch/s390x/kernel/time.c	Thu Oct 11 09:04:57 2001
+++ linux/arch/s390x/kernel/time.c	Wed Jan 23 15:28:39 2002
@@ -255,7 +255,4 @@
         init_timer_cc -= 0x8126d60e46000000LL -
                          (0x3c26700LL*1000000*4096);
         tod_to_timeval(init_timer_cc, &xtime);
-
-	/* Set do_get_fast_time function pointer.  */
-	do_get_fast_time = do_gettimeofday;
 }
diff -u --recursive --new-file v2.5.2/linux/arch/s390x/vmlinux-shared.lds linux/arch/s390x/vmlinux-shared.lds
--- v2.5.2/linux/arch/s390x/vmlinux-shared.lds	Sun Aug 12 10:38:48 2001
+++ linux/arch/s390x/vmlinux-shared.lds	Wed Jan 23 10:54:42 2002
@@ -55,7 +55,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/s390x/vmlinux.lds linux/arch/s390x/vmlinux.lds
--- v2.5.2/linux/arch/s390x/vmlinux.lds	Mon Jul  2 14:40:58 2001
+++ linux/arch/s390x/vmlinux.lds	Wed Jan 23 10:54:42 2002
@@ -53,7 +53,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/sh/Config.help linux/arch/sh/Config.help
--- v2.5.2/linux/arch/sh/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/Config.help	Fri Jan 25 16:04:33 2002
@@ -0,0 +1,908 @@
+CONFIG_SUPERH
+  The SuperH is a RISC processor targeted for use in embedded systems
+  and consumer electronics; it was also used in the Sega Dreamcast
+  gaming console.  The SuperH port has a home page at
+  <http://www.sh-linux.org/>.
+
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+CONFIG_DISCONTIGMEM
+  Say Y to upport efficient handling of discontiguous physical memory,
+  for architectures which are either NUMA (Non-Uniform Memory Access)
+  or have huge holes in the physical address space for other reasons.
+  See <file:Documentation/vm/numa> for more.
+
+CONFIG_CPU_LITTLE_ENDIAN
+  Some MIPS machines can be configured for either little or big endian
+  byte order. These modes require different kernels. Say Y if your
+  machine is little endian, N if it's a big endian machine.
+
+CONFIG_HEARTBEAT
+  Use the power-on LED on your machine as a load meter.  The exact
+  behavior is platform-dependent, but normally the flash frequency is
+  a hyperbolic function of the 5-minute load average.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_PCI
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_PCI_GOBIOS
+  On PCI systems, the BIOS can be used to detect the PCI devices and
+  determine their configuration. However, some old PCI motherboards
+  have BIOS bugs and may crash if this is done. Also, some embedded
+  PCI-based systems don't have any BIOS at all. Linux can also try to
+  detect the PCI hardware directly without using the BIOS.
+
+  With this option, you can specify how Linux should detect the PCI
+  devices. If you choose "BIOS", the BIOS will be used, if you choose
+  "Direct", the BIOS won't be used, and if you choose "Any", the
+  kernel will try the direct access method and falls back to the BIOS
+  if that doesn't work. If unsure, go with the default, which is
+  "Any".
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_HOTPLUG
+  Say Y here if you want to plug devices into your computer while
+  the system is running, and be able to use them quickly.  In many
+  cases, the devices can likewise be unplugged at any time too.
+
+  One well known example of this is PCMCIA- or PC-cards, credit-card
+  size devices such as network cards, modems or hard drives which are
+  plugged into slots found on all modern laptop computers.  Another
+  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.
+  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.
+
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+  computer.  These are credit-card size devices such as network cards,
+  modems or hard drives often used with laptops computers.  There are
+  actually two varieties of these cards: the older 16 bit PCMCIA cards
+  and the newer 32 bit CardBus cards.  If you want to use CardBus
+  cards, you need to say Y here and also to "CardBus support" below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  Please also read the PCMCIA-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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_KCORE_AOUT
+  Not necessary unless you're using a very out-of-date binutils
+  version.  You probably want KCORE_ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_VGA_CONSOLE
+  Saying Y here will allow you to use Linux in text mode through a
+  display that complies with the generic VGA standard. Virtually
+  everyone wants that.
+
+  The program SVGATextMode can be used to utilize SVGA video cards to
+  their full potential in text mode. Download it from
+  <ftp://ibiblio.org/pub/Linux/utils/console/>.
+
+  Say Y.
+
+CONFIG_VIDEO_SELECT
+  This enables support for text mode selection on kernel startup. If
+  you want to take advantage of some high-resolution text mode your
+  card's BIOS offers, but the traditional Linux utilities like
+  SVGATextMode don't, you can say Y here and set the mode using the
+  "vga=" option from your boot loader (lilo or loadlin) or set
+  "vga=ask" which brings up a video mode menu on kernel startup. (Try
+  "man bootparam" or see the documentation of your boot loader about
+  how to pass options to the kernel.)
+
+  Read the file <file:Documentation/svga.txt> for more information
+  about the Video mode selection support. If unsure, say N.
+
+CONFIG_MDA_CONSOLE
+  Say Y here if you have an old MDA or monochrome Hercules graphics
+  adapter in your system acting as a second head ( = video card). You
+  will then be able to use two monitors with your Linux system. Do not
+  say Y here if your MDA card is the primary card in your system; the
+  normal VGA driver will handle it.
+
+  This driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want).
+  The module will be called mdacon.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+  If unsure, say N.
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_CD_NO_IDESCSI
+  If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y
+  here, otherwise N. Read the CD-ROM-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about these CD-ROM drives. If you are unsure what you
+  have, say Y and find out whether you have one of the following
+  drives.
+
+  For each of these drivers, a file Documentation/cdrom/{driver_name}
+  exists. Especially in cases where you do not know exactly which kind
+  of drive you have you should read there. Most of these drivers use a
+  file drivers/cdrom/{driver_name}.h where you can define your
+  interface parameters and switch some internal goodies.
+
+  All these CD-ROM drivers are also usable as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want). If you want to compile them as module, say M instead of Y and
+  read <file:Documentation/modules.txt>.
+
+  If you want to use any of these CD-ROM drivers, you also have to
+  answer Y or M to "ISO 9660 CD-ROM file system support" below (this
+  answer will get "defaulted" for you if you enable any of the Linux
+  CD-ROM drivers).
+
+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.
+
+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.
+
+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'.
+
+CONFIG_VT
+  If you say Y here, you will get support for terminal devices with
+  display and keyboard devices. These are called "virtual" because you
+  can run several virtual terminals (also called virtual consoles) on
+  one physical terminal. This is rather useful, for example one
+  virtual terminal can collect system messages and warnings, another
+  one can be used for a text-mode user session, and a third could run
+  an X session, all in parallel. Switching between virtual terminals
+  is done with certain key combinations, usually Alt-<function key>.
+
+  The setterm command ("man setterm") can be used to change the
+  properties (such as colors or beeping) of a virtual terminal. The
+  man page console_codes(4) ("man console_codes") contains the special
+  character sequences that can be used to change those properties
+  directly. The fonts used on virtual terminals can be changed with
+  the setfont ("man setfont") command and the key bindings are defined
+  with the loadkeys ("man loadkeys") command.
+
+  You need at least one virtual terminal device in order to make use
+  of your keyboard and monitor. Therefore, only people configuring an
+  embedded system would want to say N here in order to save some
+  memory; the only way to log into such a system is then via a serial
+  or network connection.
+
+  If unsure, say Y, or else you won't be able to do much with your new
+  shiny Linux system :-)
+
+CONFIG_VT_CONSOLE
+  The system console is the device which receives all kernel messages
+  and warnings and which allows logins in single user mode. If you
+  answer Y here, a virtual terminal (the device used to interact with
+  a physical terminal) can be used as system console. This is the most
+  common mode of operations, so you should say Y here unless you want
+  the kernel messages be output only to a serial port (in which case
+  you should say Y to "Console on serial port", below).
+
+  If you do say Y here, by default the currently visible virtual
+  terminal (/dev/tty0) will be used as system console. You can change
+  that with a kernel command line option such as "console=tty3" which
+  would use the third virtual terminal as system console. (Try "man
+  bootparam" or see the documentation of your boot loader (lilo or
+  loadlin) about how to pass options to the kernel at boot time.)
+
+  If unsure, say Y.
+
+CONFIG_SERIAL
+  This selects whether you want to include the driver for the standard
+  serial ports.  The standard answer is Y.  People who might say N
+  here are those that are setting up dedicated Ethernet WWW/FTP
+  servers, or users that have one of the various bus mice instead of a
+  serial mouse and don't intend to use their machine's standard serial
+  port for anything.  (Note that the Cyclades and Stallion multi
+  serial port drivers do not need this driver built in for them to
+  work.)
+
+  If you want to compile this driver as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  serial.o.
+  [WARNING: Do not compile this driver as a module if you are using
+  non-standard serial ports, since the configuration information will
+  be lost when the driver is unloaded.  This limitation may be lifted
+  in the future.]
+
+  BTW1: If you have a mouseman serial mouse which is not recognized by
+  the X window system, try running gpm first.
+
+  BTW2: If you intend to use a software modem (also called Winmodem)
+  under Linux, forget it.  These modems are crippled and require
+  proprietary drivers which are only available under Windows.
+
+  Most people will say Y or M here, so that they can use serial mice,
+  modems and similar devices connecting to the standard serial ports.
+
+CONFIG_SERIAL_CONSOLE
+  If you say Y here, it will be possible to use a serial port as the
+  system console (the system console is the device which receives all
+  kernel messages and warnings and which allows logins in single user
+  mode). This could be useful if some terminal or printer is connected
+  to that serial port.
+
+  Even if you say Y here, the currently visible virtual console
+  (/dev/tty0) will still be used as the system console by default, but
+  you can alter that using a kernel command line option such as
+  "console=ttyS1". (Try "man bootparam" or see the documentation of
+  your boot loader (lilo or loadlin) about how to pass options to the
+  kernel at boot time.)
+
+  If you don't have a VGA card installed and you say Y here, the
+  kernel will automatically use the first serial line, /dev/ttyS0, as
+  system console.
+
+  If unsure, say N.
+
+CONFIG_UNIX98_PTYS
+  A pseudo terminal (PTY) is a software device consisting of two
+  halves: a master and a slave. The slave device behaves identical to
+  a physical terminal; the master device is used by a process to
+  read data from and write data to the slave, thereby emulating a
+  terminal. Typical programs for the master side are telnet servers
+  and xterms.
+
+  Linux has traditionally used the BSD-like names /dev/ptyxx for
+  masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
+  has a number of problems. The GNU C library glibc 2.1 and later,
+  however, supports the Unix98 naming standard: in order to acquire a
+  pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
+  terminal is then made available to the process and the pseudo
+  terminal slave can be accessed as /dev/pts/<number>. What was
+  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
+
+  The entries in /dev/pts/ are created on the fly by a virtual
+  file system; therefore, if you say Y here you should say Y to
+  "/dev/pts file system for Unix98 PTYs" as well.
+
+  If you want to say Y here, you need to have the C library glibc 2.1
+  or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
+  Read the instructions in <file:Documentation/Changes> pertaining to
+  pseudo terminals. It's safe to say N.
+
+CONFIG_UNIX98_PTY_COUNT
+  The maximum number of Unix98 PTYs that can be used at any one time.
+  The default is 256, and should be enough for desktop systems. Server
+  machines which support incoming telnet/rlogin/ssh connections and/or
+  serve several X terminals may want to increase this: every incoming
+  connection and every xterm uses up one PTY.
+
+  When not in use, each additional set of 256 PTYs occupy
+  approximately 8 KB of kernel memory on 32-bit architectures.
+
+CONFIG_PRINTER
+  If you intend to attach a printer to the parallel port of your Linux
+  box (as opposed to using a serial printer; if the connector at the
+  printer has 9 or 25 holes ["female"], then it's serial), say Y.
+  Also read the Printing-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  It is possible to share one parallel port among several devices
+  (e.g. printer and ZIP drive) and it is safe to compile the
+  corresponding drivers into the kernel.  If you want to compile this
+  driver as a module however ( = code which can be inserted in and
+  removed from the running kernel whenever you want), say M here and
+  read <file:Documentation/modules.txt> and
+  <file:Documentation/parport.txt>.  The module will be called lp.o.
+
+  If you have several parallel ports, you can specify which ports to
+  use with the "lp" kernel command line option.  (Try "man bootparam"
+  or see the documentation of your boot loader (lilo or loadlin) about
+  how to pass options to the kernel at boot time.)  The syntax of the
+  "lp" command line option can be found in <file:drivers/char/lp.c>.
+
+  If you have more than 8 printers, you need to increase the LP_NO
+  macro in lp.c and the PARPORT_MAX macro in parport.h.
+
+CONFIG_LP_CONSOLE
+  If you want kernel messages to be printed out as they occur, you
+  can have a console on the printer. This option adds support for
+  doing that; to actually get it to happen you need to pass the
+  option "console=lp0" to the kernel at boot time.
+
+  If the printer is out of paper (or off, or unplugged, or too
+  busy..) the kernel will stall until the printer is ready again.
+  By defining CONSOLE_LP_STRICT to 0 (at your own risk) you
+  can make the kernel continue when this happens,
+  but it'll lose the kernel messages.
+
+  If unsure, say N.
+
+CONFIG_PPDEV
+  Saying Y to this adds support for /dev/parport device nodes.  This
+  is needed for programs that want portable access to the parallel
+  port, for instance deviceid (which displays Plug-and-Play device
+  IDs).
+
+  This is the parallel port equivalent of SCSI generic support (sg).
+  It is safe to say N to this -- it is not needed for normal printing
+  or parallel port CD-ROM/disk support.
+
+  This support is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  ppdev.o.
+
+  If unsure, say N.
+
+CONFIG_PSMOUSE
+  The PS/2 mouse connects to a special mouse port that looks much like
+  the keyboard port (small circular connector with 6 pins). This way,
+  the mouse does not use any serial ports. This port can also be used
+  for other input devices like light pens, tablets, keypads. Compaq,
+  AST and IBM all use this as their mouse port on currently shipping
+  machines. The trackballs of some laptops are PS/2 mice also. In
+  particular, the C&T 82C710 mouse on TI Travelmates is a PS/2 mouse.
+
+  Although PS/2 mice are not technically bus mice, they are explained
+  in detail in the Busmouse-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  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://gnu.systemy.it/pub/gpm/>) solves this problem, or you can get
+  the "mconv2" utility from <ftp://ibiblio.org/pub/Linux/system/mouse/>.
+
+CONFIG_WATCHDOG
+  If you say Y here (and to one of the following options) and create a
+  character special file /dev/watchdog with major number 10 and minor
+  number 130 using mknod ("man mknod"), you will get a watchdog, i.e.:
+  subsequently opening the file and then failing to write to it for
+  longer than 1 minute will result in rebooting the machine. This
+  could be useful for a networked machine that needs to come back
+  online as fast as possible after a lock-up. There's both a watchdog
+  implementation entirely in software (which can sometimes fail to
+  reboot the machine) and a driver for hardware watchdog boards, which
+  are more robust and can also keep track of the temperature inside
+  your computer. For details, read <file:Documentation/watchdog.txt>
+  in the kernel source.
+
+  The watchdog is usually used together with the watchdog daemon
+  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.
+
+CONFIG_WATCHDOG_NOWAYOUT
+  The default watchdog behaviour (which you get if you say N here) is
+  to stop the timer if the process managing it closes the file
+  /dev/watchdog. It's always remotely possible that this process might
+  get killed. If you say Y here, the watchdog cannot be stopped once
+  it has been started.
+
+CONFIG_SH_WDT
+  This driver adds watchdog support for the integrated watchdog in the
+  SuperH 3 and 4 processors. If you have one of these processors, say Y,
+  otherwise say N.
+
+  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 is called shwdt.o. If you want to compile it as a module,
+  say M here and read Documentation/modules.txt.
+
+CONFIG_RTC
+  If you say Y here and create a character special file /dev/rtc with
+  major number 10 and minor number 135 using mknod ("man mknod"), you
+  will get access to the real time clock (or hardware clock) built
+  into your computer.
+
+  Every PC has such a clock built in. It can be used to generate
+  signals from as low as 1Hz up to 8192Hz, and can also be used
+  as a 24 hour alarm. It reports status information via the file
+  /proc/driver/rtc and its behaviour is set by various ioctls on
+  /dev/rtc.
+
+  If you run Linux on a multiprocessor machine and said Y to
+  "Symmetric Multi Processing" above, you should say Y here to read
+  and set the RTC in an SMP compatible fashion.
+
+  If you think you have a use for such a device (such as periodic data
+  sampling), then say Y here, and read <file:Documentation/rtc.txt>
+  for details.
+
+  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 is called rtc.o. If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y.  Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. General information about
+  the modular sound system is contained in the files
+  <file:Documentation/sound/Introduction>.  The file
+  <file:Documentation/sound/README.OSS> contains some slightly
+  outdated but still useful information as well.
+
+  If you have a PnP sound card and you want to configure it at boot
+  time using the ISA PnP tools (read
+  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished.  To do
+  this, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/sound/README.modules>; the module will be
+  called soundcore.o.
+
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and supporting utilities to do that are in the pcsp
+  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_SH_RTC
+  Selecting this option will allow the Linux kernel to emulate
+  PC's RTC.
+
+  If unsure, say N.
+
+CONFIG_SH_DMA
+  Selecting this option will provide same API as PC's Direct Memory
+  Access Controller(8237A) for SuperH DMAC.
+
+  If unsure, say N.
+
+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".
+
+CONFIG_CF_ENABLER
+  Compact Flash is a small, removable mass storage device introduced
+  in 1994 originally as a PCMCIA device.  If you say `Y' here, you
+  compile in support for Compact Flash devices directly connected to
+  a SuperH processor.  A Compact Flash FAQ is available at
+  <http://www.compactflash.org/faqs/faq.htm>.
+
+  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, select 'N'.
+
+CONFIG_SH_GENERIC
+  Select Generic if configuring for a generic SuperH system.
+  The "generic" option compiles in *all* the possible hardware
+  support and relies on the sh_mv= kernel commandline option to choose
+  at runtime which routines to use.  "MV" stands for "machine vector";
+  each of the machines below is described by a machine vector.
+
+  Select SolutionEngine if configuring for a Hitachi SH7709
+  or SH7750/7750S evalutation board.
+
+  Select Overdrive if configuring for a ST407750 Overdrive board.
+  More information at
+  <http://linuxsh.sourceforge.net/docs/7750overdrive.php3>.
+
+  Select HP620 if configuring for a HP Jornada HP620.
+  More information (hardware only) at
+  <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/>.
+
+  Select HP690 if configuring for a HP Jornada HP690.
+  More information (hardware only) at
+  <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/>.
+
+  Select EC3104 if configuring for a system with an Eclipse
+  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
+  Dreamcast project is at <http://linuxdc.sourceforge.net/>.
+
+  Select BareCPU if you know what this means, and it applies
+  to your system.
+
+CONFIG_SH_SOLUTION_ENGINE
+  Select SolutionEngine if configuring for a Hitachi SH7709
+  or SH7750 evalutation board.
+
+CONFIG_SH_7751_SOLUTION_ENGINE
+  Select 7751 SolutionEngine if configuring for a Hitachi SH7751
+  evalutation board.
+
+CONFIG_SH_HP620
+  Select HP620 if configuring for a HP jornada HP620.
+  More information (hardware only) at
+  <http://www.hp.com/jornada/>.
+
+CONFIG_SH_HP680
+  Select HP680 if configuring for a HP Jornada HP680.
+  More information (hardware only) at
+  <http://www.hp.com/jornada/products/680/>.
+
+CONFIG_SH_HP690
+  Select HP690 if configuring for a HP Jornada HP690.
+  More information (hardware only)
+  at <http://www.hp.com/jornada/products/680/>.
+
+CONFIG_SH_CQREEK
+  Select CqREEK if configuring for a CqREEK SH7708 or SH7750.
+  More information at
+  <http://sources.redhat.com/ecos/hardware.html#SuperH>.
+
+CONFIG_SH_DMIDA
+  Select DMIDA if configuring for a DataMyte 4000 Industrial
+  Digital Assistant. More information at <http://www.dmida.com/>.
+
+CONFIG_SH_EC3104
+  Select EC3104 if configuring for a system with an Eclipse
+  International EC3104 chip, e.g. the Harris AD2000.
+
+CONFIG_SH_DREAMCAST
+  Select Dreamcast if configuring for a SEGA Dreamcast.
+  More information at
+  <http://www.m17n.org/linux-sh/dreamcast/>.  There is a
+  Dreamcast project is at <http://linuxdc.sourceforge.net/>.
+
+CONFIG_SH_UNKNOWN
+  "Bare CPU" aka "unknown" means an SH-based system which is not one
+  of the specific ones mentioned above, which means you need to enter
+  all sorts of stuff like CONFIG_MEMORY_START because the config
+  system doesn't already know what it is.  You get a machine vector
+  without any platform-specific code in it, so things like the RTC may
+  not work.
+
+  This option is for the early stages of porting to a new machine.
+
+CONFIG_CPU_SUBTYPE_SH7707
+  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.
+
+  Select SH7708 if you have a  60 Mhz SH-3 HD6417708S or
+                if you have a 100 Mhz SH-3 HD6417708R CPU.
+
+  Select SH7709 if you have a  80 Mhz SH-3 HD6417709 CPU.
+
+  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
+
+CONFIG_CPU_SUBTYPE_SH7708
+  Select SH7708 if you have a  60 Mhz SH-3 HD6417708S or
+                if you have a 100 Mhz SH-3 HD6417708R CPU.
+
+CONFIG_CPU_SUBTYPE_SH7709
+  Select SH7709 if you have a  80 Mhz SH-3 HD6417709 CPU.
+
+CONFIG_CPU_SUBTYPE_SH7750
+  Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
+
+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.  
+
+  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.
+
+  Tweak this only when porting to a new machine which is not already
+  known by the config system.  Changing it from the known correct
+  value on any of the known systems will only lead to disaster.
+
+CONFIG_HD64461
+  The Hitachi HD64461 provides an interface for
+  the SH7709 CPU, supporting a LCD controller,
+  CRT color controller, IrDA up to 4 Mbps, and a
+  PCMCIA controller supporting 2 slots.
+
+  More information is available at
+  <http://semiconductor.hitachi.com/windowsce/superh/sld013.htm>.
+
+  Say Y if you want support for the HD64461.
+  Otherwise, say N.
+
+CONFIG_HD64461_ENABLER
+  Say Y here if you want to enable PCMCIA support
+  via the HD64461 companion chip.
+  Otherwise, say N.
+
+CONFIG_HD64461_IRQ
+  The default setting of the HD64461 IRQ is 36.
+
+  Do not change this unless you know what you are doing.
+
+CONFIG_HD64465
+  The Hitachi HD64465 provides an interface for
+  the SH7750 CPU, supporting a LCD controller,
+  CRT color controller, IrDA, USB, PCMCIA,
+  keyboard controller, and a printer interface.
+
+  More information is available at
+  <http://global.hitachi.com/New/cnews/E/1998/981019B.html>.
+
+  Say Y if you want support for the HD64465.
+  Otherwise, say N.
+
+CONFIG_HD64465_IRQ
+  The default setting of the HD64465 IRQ is 5.
+
+  Do not change this unless you know what you are doing.
+
+CONFIG_HD64465_IOBASE
+  The default setting of the HD64465 IO base address is 0xb0000000.
+
+  Do not change this unless you know what you are doing.
+
+CONFIG_SH_EARLY_PRINTK
+  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. If unsure, say N.
+
+CONFIG_SH_SCI
+  Selecting this option will allow the Linux kernel to transfer data
+  over SCI (Serial Communication Interface) and/or SCIF (Serial
+  Communication Interface with FIFO) which are built into the Hitachi
+  SuperH processor.  The option provides 1 to 3 (depending
+  on the CPU model) standard Linux tty devices, /dev/ttySC[012]; one
+  of these is normally used as the system console.
+
+  If in doubt, press "y".
+
+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 (including calls to read and
+  write characters to a system console, get a MAC address from an
+  on-board Ethernet interface, and shut down the hardware).  Note this
+  does not work with machines with an existing operating system in
+  mask ROM and no flash (WindowsCE machines fall in this category).
+  If unsure, say N.
+
diff -u --recursive --new-file v2.5.2/linux/arch/sh/config.in linux/arch/sh/config.in
--- v2.5.2/linux/arch/sh/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/sh/config.in	Thu Jan 24 11:29:38 2002
@@ -10,19 +10,7 @@
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'Processor type and features'
@@ -143,8 +131,6 @@
 define_bool CONFIG_MCA n
 define_bool CONFIG_SBUS n
 
-bool 'Networking support' CONFIG_NET
-
 if [ "$CONFIG_SH_GENERIC" = "y" -o "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o \
      "$CONFIG_SH_UNKNOWN" = "y" -o "$CONFIG_SH_CAT68701" = "y" -o \
      "$CONFIG_SH_ADX" = "y" ]; then
@@ -202,9 +188,6 @@
    define_bool CONFIG_PCMCIA n
 fi
 
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
 if [ "$CONFIG_PROC_FS" = "y" ]; then
    choice 'Kernel core (/proc/kcore) format' \
 	"ELF		CONFIG_KCORE_ELF	\
diff -u --recursive --new-file v2.5.2/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S
--- v2.5.2/linux/arch/sh/kernel/entry.S	Mon Oct  8 10:39:18 2001
+++ linux/arch/sh/kernel/entry.S	Mon Jan 28 15:14:23 2002
@@ -61,12 +61,11 @@
  * These are offsets into the task-struct.
  */
 flags		=  4
-sigpending	=  8
-need_resched	= 20
-tsk_ptrace	= 24
+#error sigpending	=  8
+#error need_resched	= 20
+#error tsk_ptrace	= 24
 
-PT_TRACESYS  = 0x00000002
-PF_USEDFPU   = 0x00100000
+#error PT_TRACESYS  = 0x00000002
 
 ENOSYS = 38
 EINVAL = 22
@@ -301,8 +300,8 @@
 	! If we're being traced, return via syscall_ret_trace, otherwise
 	! return directly to ret_from_syscall
 	stc	k_current, r0
-	mov.l	@(tsk_ptrace,r0), r0	! Is current PTRACE_SYSCALL'd?
-	mov	#PT_TRACESYS, r1
+#error	mov.l	@(tsk_ptrace,r0), r0	! Is current PTRACE_SYSCALL'd?
+#error	mov	#PT_TRACESYS, r1
 	tst	r1, r0
 	bt	ret_from_syscall
 	bra	syscall_ret_trace
@@ -372,8 +371,8 @@
 	STI()
 	!
 	stc	k_current, r11
-	mov.l	@(tsk_ptrace,r11), r10	! Is current PTRACE_SYSCALL'd?
-	mov	#PT_TRACESYS, r11
+#error	mov.l	@(tsk_ptrace,r11), r10	! Is current PTRACE_SYSCALL'd?
+#error	mov	#PT_TRACESYS, r11
 	tst	r11, r10
 	bt	5f
 	!                     	Yes it is traced.
@@ -498,7 +497,7 @@
 	.align	2
 __TRA:	.long	TRA
 __syscall_trace:
-    	.long	SYMBOL_NAME(syscall_trace)
+#error    	.long	SYMBOL_NAME(syscall_trace)
 __n_sys:.long	NR_syscalls
 __sct:	.long	SYMBOL_NAME(sys_call_table)
 __syscall_ret_trace:
@@ -546,10 +545,10 @@
 	ldc	r0, sr
 	!
 	stc	k_current, r1
-	mov.l	@(need_resched,r1), r0
+#error	mov.l	@(need_resched,r1), r0
 	tst	r0, r0
 	bf	reschedule
-	mov.l	@(sigpending,r1), r0
+#error	mov.l	@(sigpending,r1), r0
 	tst	r0, r0
 	bt	restore_all
 signal_return:
@@ -561,18 +560,12 @@
 	 lds	r0, pr
 	.align	2
 __do_signal:
-	.long	SYMBOL_NAME(do_signal)
+#error	.long	SYMBOL_NAME(do_signal)
 __irq_stat:
 	.long	SYMBOL_NAME(irq_stat)
 
 	.align 2
 restore_all:
-#if defined(__SH4__)
-	mov.l	__fpu_prepare_fd, r0
-	jsr	@r0
-	 stc	sr, r4
-#endif
-	!
 	mov.l	@r15+, r0
 	mov.l	@r15+, r1
 	mov.l	@r15+, r2
@@ -585,7 +578,7 @@
 	stc	sr, r8
 	mov.l	__blrb_flags, r9	! BL =1, RB=1
 	or	r9, r8
-	ldc	r8, sr		! here, change the register bank
+	ldc	r8, sr			! here, change the register bank
 	!
 	mov.l	@r15+, r8
 	mov.l	@r15+, r9
@@ -594,25 +587,25 @@
 	mov.l	@r15+, r12
 	mov.l	@r15+, r13
 	mov.l	@r15+, r14
-	mov.l	@r15+, k4	! original stack pointer
+	mov.l	@r15+, k4		! original stack pointer
 	ldc.l	@r15+, spc
 	lds.l	@r15+, pr
-	mov.l	@r15+, k3	! original SR
+	mov.l	@r15+, k3		! original SR
 	ldc.l	@r15+, gbr
 	lds.l	@r15+, mach
 	lds.l	@r15+, macl
-	add	#4, r15	! Skip syscall number
+	add	#4, r15			! Skip syscall number
 	!
 	! Calculate new SR value
-	mov	k3, k2	! original SR value
+	mov	k3, k2			! original SR value
 	mov.l	1f, k1
 	stc	sr, k0
-	and	k1, k0	! Get current FD-bit
+	and	k1, k0			! Get current FD-bit
 	mov.l	2f, k1
-	and	k1, k2	! Mask orignal SR value
-	or	k0, k2	! Inherit current FD-bit
+	and	k1, k2			! Mask orignal SR value
+	or	k0, k2			! Inherit current FD-bit
 	!
-	mov	k3, k0	! Calculate IMASK-bits
+	mov	k3, k0			! Calculate IMASK-bits
 	shlr2	k0
 	and	#0x3c, k0
 	cmp/eq	#0x3c, k0
@@ -620,69 +613,15 @@
 	 shll2	k0
 	mov	g_imask, k0
 	!
-7:	or	k0, k2	! Set the IMASK-bits
+7:	or	k0, k2			! Set the IMASK-bits
 	ldc	k2, ssr
 	!
-#if defined(__SH4__)
-	shll	k2
-	shll	k2
-	bf	9f		! user mode
-	/* Kernel to kernel transition */
-	mov.l	1f, k1
-	tst	k1, k3
-	bf	9f		! it hadn't FPU
-	! Kernel to kernel and FPU was used
-	! There's the case we don't get FPU now
-	stc	sr, k2
-	tst	k1, k2
-	bt	8f
-	! We need to grab FPU here
-	xor	k1, k2
-	ldc	k2, sr		! Grab FPU
-	mov.l	__init_task_flags, k1
-	mov.l	@k1, k2
-	mov.l	__PF_USEDFPU, k0
-	or	k0, k2
-	mov.l	k2, @k1		! Set init_task.flags |= PF_USEDFPU
-	!
-	! Restoring FPU...
-	!
-8:	mov.l	3f, k1
-	lds	k1, fpscr
-	fmov.s	@r15+, fr0
-	fmov.s	@r15+, fr1
-	fmov.s	@r15+, fr2
-	fmov.s	@r15+, fr3
-	fmov.s	@r15+, fr4
-	fmov.s	@r15+, fr5
-	fmov.s	@r15+, fr6
-	fmov.s	@r15+, fr7
-	fmov.s	@r15+, fr8
-	fmov.s	@r15+, fr9
-	fmov.s	@r15+, fr10
-	fmov.s	@r15+, fr11
-	fmov.s	@r15+, fr12
-	fmov.s	@r15+, fr13
-	fmov.s	@r15+, fr14
-	fmov.s	@r15+, fr15
-	lds.l	@r15+, fpscr
-	lds.l	@r15+, fpul
-9:
-#endif
 	mov	k4, r15
 	rte
 	 nop
 
 	.align	2
 __blrb_flags:	.long	0x30000000
-#if defined(__SH4__)
-__fpu_prepare_fd:
-	.long	SYMBOL_NAME(fpu_prepare_fd)
-__init_task_flags:
-	.long	SYMBOL_NAME(init_task_union)+4
-__PF_USEDFPU:
-	.long	PF_USEDFPU
-#endif
 1:	.long	0x00008000	! FD
 2:	.long	0xffff7f0f	! ~(IMASK+FD)
 3:	.long	0x00080000	! SZ=0, PR=1
@@ -732,61 +671,21 @@
 	! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
 	! save all registers onto stack.
 	!
-	stc	ssr, k0	! from kernel space?
-	shll	k0		! Check MD bit (bit30) by shifting it into the T bit
-	shll	k0
-#if defined(__SH4__)
-	bf/s	8f		! it's from user to kernel transition
-	 mov	r15, k0	! save original stack to k0
-	/* It's a kernel to kernel transition. */
-	/* Is the FPU disabled? */
-	mov.l	2f, k1
-	stc	ssr, k0
-	tst	k1, k0
-	mov.l	4f, k1
-	bf/s	9f		! FPU is not enabled, no need to save it
-	 mov	r15, k0	! save original stack to k0
-	! FPU is enabled, save it
-	! /* XXX: Need to save another bank of FPU if all FPU feature is used */
-	! /* Currently it's not the case for GCC (only udivsi3_i4, divsi3_i4) */
-	sts.l	fpul,  @-r15
-	sts.l	fpscr, @-r15
-	mov.l	6f, k1
-	lds	k1, fpscr
-	mov.l	3f, k1
-	fmov.s	fr15, @-r15
-	fmov.s	fr14, @-r15
-	fmov.s	fr13, @-r15
-	fmov.s	fr12, @-r15
-	fmov.s	fr11, @-r15
-	fmov.s	fr10, @-r15
-	fmov.s	fr9, @-r15
-	fmov.s	fr8, @-r15
-	fmov.s	fr7, @-r15
-	fmov.s	fr6, @-r15
-	fmov.s	fr5, @-r15
-	fmov.s	fr4, @-r15
-	fmov.s	fr3, @-r15
-	fmov.s	fr2, @-r15
-	fmov.s	fr1, @-r15
-	bra 9f
-	 fmov.s	fr0, @-r15
-#else
-	mov.l	3f, k1
-	bt/s	9f		! it's a kernel to kernel transition, and skip the FPU save.
-	 mov	r15, k0	! save original stack to k0 anyway
-#endif
-8:	/* User space to kernel */
+	stc	ssr, k0		! Is it from kernel space?
+	shll	k0		! Check MD bit (bit30) by shifting it into...
+	shll	k0		!       ...the T bit
+	bt/s	9f		! It's a kernel to kernel transition.
+	 mov	r15, k0		! save original stack to k0
+	/* User space to kernel */
 	mov	#0x20, k1
-	shll8	k1			! k1 <= 8192 == THREAD_SIZE
+	shll8	k1		! k1 <= 8192 == THREAD_SIZE
 	add	current, k1
 	mov	k1, r15		! change to kernel stack
 	!
-	mov.l	4f, k1			! let kernel release FPU
-9:	! Save the user registers on the stack.
-	! At this point, k1 should have been set to the new SR value
-  	mov	#-1, k4
-	mov.l	k4, @-r15		! syscall_nr (default: -1)
+9:  	mov	#-1, k4
+	mov.l	3f, k1
+	! Save the user registers on the stack.
+	mov.l	k4, @-r15	! syscall_nr (default: -1)
 	!
 	sts.l	macl, @-r15
 	sts.l	mach, @-r15
@@ -806,11 +705,11 @@
 	mov.l	r9, @-r15
 	mov.l	r8, @-r15
 	!
-	stc	sr, r8	! Back to normal register bank, and
-	or	k1, r8	! Block all interrupts, may release FPU
+	stc	sr, r8		! Back to normal register bank, and
+	or	k1, r8		! Block all interrupts
 	mov.l	5f, k1
-	and	k1, r8	! ...
-	ldc	r8, sr	! ...changed here.
+	and	k1, r8		! ...
+	ldc	r8, sr		! ...changed here.
 	!
 	mov.l	r7, @-r15
 	mov.l	r6, @-r15
@@ -831,9 +730,7 @@
 	 nop
 	.align	2
 1:	.long	SYMBOL_NAME(exception_handling_table)
-2:	.long	0x00008000	! FD=1
 3:	.long	0x000000f0	! FD=0, IMASK=15
-4:	.long	0x000080f0	! FD=1, IMASK=15
 5:	.long	0xcfffffff	! RB=0, BL=0
 6:	.long	0x00080000	! SZ=0, PR=1
 
diff -u --recursive --new-file v2.5.2/linux/arch/sh/kernel/fpu.c linux/arch/sh/kernel/fpu.c
--- v2.5.2/linux/arch/sh/kernel/fpu.c	Sun Jan 28 18:56:00 2001
+++ linux/arch/sh/kernel/fpu.c	Thu Jan 24 12:08:14 2002
@@ -18,6 +18,10 @@
 #include <asm/processor.h>
 #include <asm/io.h>
 
+/*
+ * Save FPU registers onto task structure.
+ * Assume called with FPU enabled (SR.FD=0).
+ */
 void
 save_fpu(struct task_struct *tsk)
 {
@@ -118,7 +122,8 @@
  * double precission represents signaling NANS.  
  */
 
-void fpu_init(void)
+static void
+fpu_init(void)
 {
 	asm volatile("lds	%0, fpul\n\t"
 		     "lds	%1, fpscr\n\t"
@@ -160,15 +165,125 @@
 		     : "r" (0), "r" (FPSCR_INIT));
 }
 
+/**
+ *	denormal_to_double - Given denormalized float number,
+ *	                     store double float
+ *
+ *	@fpu: Pointer to sh_fpu_hard structure
+ *	@n: Index to FP register
+ */
+static void
+denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
+{
+	unsigned long du, dl;
+	unsigned long x = fpu->fpul;
+	int exp = 1023 - 126;
+
+	if (x != 0 && (x & 0x7f800000) == 0) {
+		du = (x & 0x80000000);
+		while ((x & 0x00800000) == 0) {
+			x <<= 1;
+			exp--;
+		}
+		x &= 0x007fffff;
+		du |= (exp << 20) | (x >> 3);
+		dl = x << 29;
+
+		fpu->fp_regs[n] = du;
+		fpu->fp_regs[n+1] = dl;
+	}
+}
+
+/**
+ *	ieee_fpe_handler - Handle denormalized number exception
+ *
+ *	@regs: Pointer to register structure
+ *
+ *	Returns 1 when it's handled (should not cause exception).
+ */
+static int
+ieee_fpe_handler (struct pt_regs *regs)
+{
+	unsigned short insn = *(unsigned short *) regs->pc;
+	unsigned short finsn;
+	unsigned long nextpc;
+	int nib[4] = {
+		(insn >> 12) & 0xf,
+		(insn >> 8) & 0xf,
+		(insn >> 4) & 0xf,
+		insn & 0xf};
+
+	if (nib[0] == 0xb ||
+	    (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */
+		regs->pr = regs->pc + 4;
+  
+	if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */
+		nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3);
+		finsn = *(unsigned short *) (regs->pc + 2);
+	} else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */
+		if (regs->sr & 1)
+			nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
+		else
+			nextpc = regs->pc + 4;
+		finsn = *(unsigned short *) (regs->pc + 2);
+	} else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */
+		if (regs->sr & 1)
+			nextpc = regs->pc + 4;
+		else
+			nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
+		finsn = *(unsigned short *) (regs->pc + 2);
+	} else if (nib[0] == 0x4 && nib[3] == 0xb &&
+		 (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */
+		nextpc = regs->regs[nib[1]];
+		finsn = *(unsigned short *) (regs->pc + 2);
+	} else if (nib[0] == 0x0 && nib[3] == 0x3 &&
+		 (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */
+		nextpc = regs->pc + 4 + regs->regs[nib[1]];
+		finsn = *(unsigned short *) (regs->pc + 2);
+	} else if (insn == 0x000b) { /* rts */
+		nextpc = regs->pr;
+		finsn = *(unsigned short *) (regs->pc + 2);
+	} else {
+		nextpc = regs->pc + 2;
+		finsn = insn;
+	}
+
+	if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
+		struct task_struct *tsk = current;
+
+		save_fpu(tsk);
+		if ((tsk->thread.fpu.hard.fpscr & (1 << 17))) {
+			/* FPU error */
+			denormal_to_double (&tsk->thread.fpu.hard,
+					    (finsn >> 8) & 0xf);
+			tsk->thread.fpu.hard.fpscr &=
+				~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
+			grab_fpu();
+			restore_fpu(tsk);
+			tsk->flags |= PF_USEDFPU;
+		} else {
+			tsk->thread.trap_no = 11;
+			tsk->thread.error_code = 0;
+			force_sig(SIGFPE, tsk);
+		}
+
+		regs->pc = nextpc;
+		return 1;
+	}
+
+	return 0;
+}
+
 asmlinkage void
 do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7,
 	     struct pt_regs regs)
 {
 	struct task_struct *tsk = current;
 
-	regs.pc += 2;
+	if (ieee_fpe_handler (&regs))
+		return;
 
-	grab_fpu();
+	regs.pc += 2;
 	save_fpu(tsk);
 	tsk->thread.trap_no = 11;
 	tsk->thread.error_code = 0;
@@ -181,102 +296,12 @@
 {
 	struct task_struct *tsk = current;
 
-	if (!user_mode(&regs)) {
-		if (tsk != &init_task) {
-			unlazy_fpu(tsk);
-		}
-		tsk = &init_task;
-		if (tsk->flags & PF_USEDFPU) {
-			/*
-			 * This weird situation can be occurred.
-			 *
-			 * There's race condition in __cli:
-			 *
-			 *   (1) SR --> register
-			 *   (2) Set IMASK of register
-			 *   (3) SR <-- register
-			 *
-			 * Between (1) and (2), or (2) and (3) getting
-			 * interrupt, and interrupt handler (or
-			 * softirq) may use FPU.
-			 *
-			 * Then, SR.FD is overwritten by (3).
-			 *
-			 * This results init_task.PF_USEDFPU is on,
-			 * with SR.FD == 1.
-			 *
-			 */
-			release_fpu();
-			return;
-		}
-	}
-
 	grab_fpu();
-	if (tsk->used_math) {
-		/* Using the FPU again.  */
-		restore_fpu(tsk);
-	} else	{
-		/* First time FPU user.  */
-		fpu_init();
-		tsk->used_math = 1;
-	}
-	tsk->flags |= PF_USEDFPU;
-	release_fpu();
-}
-
-/*
- * Change current FD flag to set FD flag back to exception
- */
-asmlinkage void
-fpu_prepare_fd(unsigned long sr, unsigned long r5, unsigned long r6,
-	       unsigned long r7, struct pt_regs regs)
-{
-	__cli();
 	if (!user_mode(&regs)) {
-		if (init_task.flags & PF_USEDFPU)
-			grab_fpu();
-		else {
-			if (!(sr & SR_FD)) {
-				BUG();
-				release_fpu();
-			}
-		}
+		printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
 		return;
 	}
 
-	if (sr & SR_FD) { /* Kernel doesn't grab FPU */
-		if (current->flags & PF_USEDFPU)
-			grab_fpu();
-		else {
-			if (init_task.flags & PF_USEDFPU) {
-				/*
-				 * This weird situation can be occurred.
-				 * See the comment in do_fpu_state_restore.
-				 */
-				grab_fpu();
-				save_fpu(&init_task);
-			}
-		}
-	} else {
-		if (init_task.flags & PF_USEDFPU)
-			save_fpu(&init_task);
-		else {
-			BUG();
-			release_fpu();
-		}
-	}
-}
-
-/* Short cut for the FPU exception */
-asmlinkage void
-enable_fpu_in_danger(void)
-{
-	struct task_struct *tsk = current;
-
-	if (tsk != &init_task)
-		unlazy_fpu(tsk);
-
-	tsk = &init_task;
 	if (tsk->used_math) {
 		/* Using the FPU again.  */
 		restore_fpu(tsk);
diff -u --recursive --new-file v2.5.2/linux/arch/sh/kernel/head.S linux/arch/sh/kernel/head.S
--- v2.5.2/linux/arch/sh/kernel/head.S	Sun Jan 28 18:56:00 2001
+++ linux/arch/sh/kernel/head.S	Thu Jan 24 12:08:14 2002
@@ -50,12 +50,6 @@
 	sub	r1, r0		!
 	ldc	r0, r7_bank	! ... and init_task
 	!
-#if defined(__SH4__)
-	!                       Initialize fpu
-	mov.l   7f, r0
-	jsr     @r0
-	 nop
-#endif
 	!			Enable cache
 	mov.l	6f, r0
 	jsr	@r0
@@ -74,12 +68,9 @@
 	 nop
 
 	.balign 4
-1:	.long	0x400000F0		! MD=1, RB=0, BL=0, FD=0, IMASK=0xF
+1:	.long	0x400080F0		! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
 2:	.long	SYMBOL_NAME(stack)
 3:	.long	SYMBOL_NAME(__bss_start)
 4:	.long	SYMBOL_NAME(_end)
 5:	.long	SYMBOL_NAME(start_kernel)
 6:	.long	SYMBOL_NAME(cache_init)
-#if defined(__SH4__)
-7:	.long   SYMBOL_NAME(fpu_init)
-#endif
diff -u --recursive --new-file v2.5.2/linux/arch/sh/kernel/init_task.c linux/arch/sh/kernel/init_task.c
--- v2.5.2/linux/arch/sh/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/sh/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,6 +1,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/sh/kernel/irq.c linux/arch/sh/kernel/irq.c
--- v2.5.2/linux/arch/sh/kernel/irq.c	Tue Dec 18 14:56:35 2001
+++ linux/arch/sh/kernel/irq.c	Thu Jan 24 12:08:14 2002
@@ -22,6 +22,7 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
+#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/smp.h>
diff -u --recursive --new-file v2.5.2/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c
--- v2.5.2/linux/arch/sh/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sh/kernel/process.c	Thu Jan 24 12:08:14 2002
@@ -12,7 +12,9 @@
  */
 
 #include <linux/unistd.h>
+#include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/a.out.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -39,16 +41,13 @@
 void cpu_idle(void *unused)
 {
 	/* endless idle loop with no priority at all */
-	init_idle();
-	current->nice = 20;
-
 	while (1) {
 		if (hlt_counter) {
-			if (current->need_resched)
+			if (need_resched())
 				break;
 		} else {
 			__cli();
-			while (!current->need_resched) {
+			while (!need_resched()) {
 				__sti();
 				asm volatile("sleep" : : : "memory");
 				__cli();
diff -u --recursive --new-file v2.5.2/linux/arch/sh/kernel/rtc.c linux/arch/sh/kernel/rtc.c
--- v2.5.2/linux/arch/sh/kernel/rtc.c	Wed Jun 27 13:55:29 2001
+++ linux/arch/sh/kernel/rtc.c	Thu Jan 24 12:08:14 2002
@@ -46,7 +46,7 @@
 	} while ((ctrl_inb(RCR1) & RCR1_CF) != 0);
 
 #if RTC_BIT_INVERTED != 0
-	/* Work around to avoid reading correct value. */
+	/* Work around to avoid reading incorrect value. */
 	if (sec128 == RTC_BIT_INVERTED) {
 		schedule_timeout(1);
 		goto again;
@@ -81,12 +81,18 @@
 		goto again;
 	}
 
+#if RTC_BIT_INVERTED != 0
+	if ((sec128 & RTC_BIT_INVERTED))
+		sec--;
+#endif
+
 	tv->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
-	tv->tv_usec = ((sec128 ^ RTC_BIT_INVERTED) * 1000000) / 128;
+	tv->tv_usec = (sec128 * 1000000) / 128;
 }
 
-static int set_rtc_time(unsigned long nowtime)
+int sh_rtc_settimeofday(const struct timeval *tv)
 {
+	unsigned long nowtime = tv->tv_sec;
 	int retval = 0;
 	int real_seconds, real_minutes, cmos_minutes;
 
@@ -122,13 +128,4 @@
 	ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2);  /* Start RTC */
 
 	return retval;
-}
-
-int sh_rtc_settimeofday(const struct timeval *tv)
-{
-#if RTC_BIT_INVERTED != 0
-	/* This is not accurate, but better than nothing. */
-	schedule_timeout(HZ/2);
-#endif
-	return set_rtc_time(tv->tv_sec);
 }
diff -u --recursive --new-file v2.5.2/linux/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c
--- v2.5.2/linux/arch/sh/kernel/setup.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sh/kernel/setup.c	Thu Jan 24 12:08:14 2002
@@ -142,9 +142,8 @@
 
 static kdev_t sh_console_device(struct console *c)
 {
-    	/* TODO: this is totally bogus */
-	/* return MKDEV(SCI_MAJOR, SCI_MINOR_START + c->index); */
-	return 0;
+	/* /dev/null */
+	return mk_kdev(MEM_MAJOR, 3);
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c
--- v2.5.2/linux/arch/sh/kernel/signal.c	Mon Oct 15 13:36:48 2001
+++ linux/arch/sh/kernel/signal.c	Thu Jan 24 12:08:15 2002
@@ -22,6 +22,8 @@
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <linux/personality.h>
+#include <linux/tty.h>
+
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c
--- v2.5.2/linux/arch/sh/kernel/traps.c	Tue Dec 18 14:56:35 2001
+++ linux/arch/sh/kernel/traps.c	Thu Jan 24 12:08:15 2002
@@ -300,10 +300,19 @@
 /*
  * handle an instruction that does an unaligned memory access
  * - have to be careful of branch delay-slot instructions that fault
+ *  SH3:
  *   - if the branch would be taken PC points to the branch
  *   - if the branch would not be taken, PC points to delay-slot
+ *  SH4:
+ *   - PC always points to delayed branch
  * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
  */
+
+/* Macros to determine offset from current PC for branch instructions */
+/* Explicit type coercion is used to force sign extension where needed */
+#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4)
+#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
+
 static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
 {
 	u_int rm;
@@ -392,15 +401,27 @@
 			break;
 		case 0x0F00: /* bf/s lab */
 			ret = handle_unaligned_delayslot(regs);
-			if (ret==0)
-				regs->pc += (instruction&0x00FF)*2 + 4;
+			if (ret==0) {
+#if defined(__SH4__)
+				if ((regs->sr & 0x00000001) != 0)
+					regs->pc += 4; /* next after slot */
+				else
+#endif
+					regs->pc += SH_PC_8BIT_OFFSET(instruction);
+			}
 			break;
 		case 0x0900: /* bt   lab - no delayslot */
 			break;
 		case 0x0D00: /* bt/s lab */
 			ret = handle_unaligned_delayslot(regs);
-			if (ret==0)
-				regs->pc += (instruction&0x00FF)*2 + 4;
+			if (ret==0) {
+#if defined(__SH4__)
+				if ((regs->sr & 0x00000001) == 0)
+					regs->pc += 4; /* next after slot */
+				else
+#endif
+					regs->pc += SH_PC_8BIT_OFFSET(instruction);
+			}
 			break;
 		}
 		break;
@@ -408,14 +429,14 @@
 	case 0xA000: /* bra label */
 		ret = handle_unaligned_delayslot(regs);
 		if (ret==0)
-			regs->pc += (instruction&0x0FFF)*2 + 4;
+			regs->pc += SH_PC_12BIT_OFFSET(instruction);
 		break;
 
 	case 0xB000: /* bsr label */
 		ret = handle_unaligned_delayslot(regs);
 		if (ret==0) {
 			regs->pr = regs->pc + 4;
-			regs->pc += (instruction&0x0FFF)*2 + 4;
+			regs->pc += SH_PC_12BIT_OFFSET(instruction);
 		}
 		break;
 	}
diff -u --recursive --new-file v2.5.2/linux/arch/sh/mm/cache-sh4.c linux/arch/sh/mm/cache-sh4.c
--- v2.5.2/linux/arch/sh/mm/cache-sh4.c	Mon Oct 15 13:36:48 2001
+++ linux/arch/sh/mm/cache-sh4.c	Tue Jan 15 10:56:35 2002
@@ -295,7 +295,7 @@
  * Flushing the cache lines for U0 only isn't enough.
  * We need to flush for P1 too, which may contain aliases.
  */
-void flush_cache_range(struct mm_struct *mm, unsigned long start,
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 		       unsigned long end)
 {
 	/*
diff -u --recursive --new-file v2.5.2/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c
--- v2.5.2/linux/arch/sh/mm/fault.c	Mon Oct 15 13:36:48 2001
+++ linux/arch/sh/mm/fault.c	Thu Jan 24 12:08:15 2002
@@ -207,8 +207,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
 	}
@@ -249,6 +248,8 @@
 		dir = pgd_offset_k(address);
 	else if (address >= TASK_SIZE)
 		return 1;
+	else if (!current->mm)
+		return 1;
 	else
 		dir = pgd_offset(current->mm, address);
 
@@ -374,9 +375,11 @@
 	}
 }
 
-void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 		     unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (mm->context != NO_CONTEXT) {
 		unsigned long flags;
 		int size;
diff -u --recursive --new-file v2.5.2/linux/arch/sh/vmlinux.lds.S linux/arch/sh/vmlinux.lds.S
--- v2.5.2/linux/arch/sh/vmlinux.lds.S	Sat Sep  8 12:29:09 2001
+++ linux/arch/sh/vmlinux.lds.S	Wed Jan 23 10:54:42 2002
@@ -63,7 +63,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   __machvec_start = .;
   .machvec.init : { *(.machvec.init) }
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/Config.help linux/arch/sparc/Config.help
--- v2.5.2/linux/arch/sparc/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc/Config.help	Fri Jan 25 16:04:13 2002
@@ -0,0 +1,1136 @@
+CONFIG_SMP
+  This enables support for systems with more than one CPU. If you have
+  a system with only one CPU, like most personal computers, say N. If
+  you have a system with more than one CPU, say Y.
+
+  If you say N here, the kernel will run on single and multiprocessor
+  machines, but will use only one CPU of a multiprocessor machine. If
+  you say Y here, the kernel will run on many, but not all,
+  singleprocessor machines. On a singleprocessor machine, the kernel
+  will run faster if you say N here.
+
+  Note that if you say Y here and choose architecture "586" or
+  "Pentium" under "Processor family", the kernel will not work on 486
+  architectures. Similarly, multiprocessor kernels for the "PPro"
+  architecture may not work on all Pentium based boards.
+
+  People using multiprocessor machines who say Y here should also say
+  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+  Management" code will be disabled if you say Y here.
+
+  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-HOWTO available at
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you don't know what to do here, say N.
+
+CONFIG_SPARC32
+  SPARC is a family of RISC microprocessors designed and marketed by
+  Sun Microsystems, incorporated.  They are very widely found in Sun
+  workstations and clones. This port covers the original 32-bit SPARC;
+  it is old and stable and usually considered one of the "big three"
+  along with the Intel and Alpha ports.  The UltraLinux project
+  maintains both the SPARC32 and SPARC64 ports; its web page is
+  available at <http://www.ultralinux.org/>.
+
+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
+  Thinkpad users, is contained in <file:Documentation/floppy.txt>.
+  That file also contains the location of the Floppy driver FAQ as
+  well as location of the fdutils package used to configure additional
+  parameters of the driver at run time.
+
+  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 floppy.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_BLK_DEV_RAM
+  Saying Y here will allow you to use a portion of your RAM memory as
+  a block device, so that you can make file systems on it, read and
+  write to it and do all the other things that you can do with normal
+  block devices (such as hard drives). It is usually used to load and
+  store a copy of a minimal root file system off of a floppy into RAM
+  during the initial install of Linux.
+
+  Note that the kernel command line option "ramdisk=XX" is now
+  obsolete. For details, read <file:Documentation/ramdisk.txt>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M and read <file:Documentation/modules.txt>. The module will be
+  called rd.o.
+
+  Most normal users won't need the RAM disk functionality, and can
+  thus say N here.
+
+CONFIG_BLK_DEV_RAM_SIZE
+  The default value is 4096. Only change this if you know what are
+  you doing. If you are using IBM S/390, then set this to 8192.
+
+CONFIG_BLK_DEV_INITRD
+  The initial RAM disk is a RAM disk that is loaded by the boot loader
+  (loadlin or lilo) and that is mounted as root before the normal boot
+  procedure. It is typically used to load modules needed to mount the
+  "real" root file system, etc. See <file:Documentation/initrd.txt>
+  for details.
+
+CONFIG_BLK_DEV_LOOP
+  Saying Y here will allow you to use a regular file as a block
+  device; you can then create a file system on that block device and
+  mount it just as you would mount other block devices such as hard
+  drive partitions, CD-ROM drives or floppy drives. The loop devices
+  are block special device files with major number 7 and typically
+  called /dev/loop0, /dev/loop1 etc.
+
+  This is useful if you want to check an ISO 9660 file system before
+  burning the CD, or if you want to use floppy images without first
+  writing them to floppy. Furthermore, some Linux distributions avoid
+  the need for a dedicated Linux partition by keeping their complete
+  root file system inside a DOS FAT file using this loop device
+  driver.
+
+  The loop device driver can also be used to "hide" a file system in a
+  disk partition, floppy, or regular file, either using encryption
+  (scrambling the data) or steganography (hiding the data in the low
+  bits of, say, a sound file). This is also safe if the file resides
+  on a remote file server. If you want to do this, you will first have
+  to acquire and install a kernel patch from
+  <ftp://ftp.kerneli.org/pub/kerneli/>, and then you need to
+  say Y to this option.
+
+  Note that alternative ways to use encrypted file systems are
+  provided by the cfs package, which can be gotten from
+  <ftp://ftp.kerneli.org/pub/kerneli/net-source/>, and the newer tcfs
+  package, available at <http://tcfs.dia.unisa.it/>. You do not need
+  to say Y here if you want to use one of these. However, using cfs
+  requires saying Y to "NFS file system support" below while using
+  tcfs requires applying a kernel patch. An alternative steganography
+  solution is provided by StegFS, also available from
+  <ftp://ftp.kerneli.org/pub/kerneli/net-source/>.
+
+  To use the loop device, you need the losetup utility and a recent
+  version of the mount program, both contained in the util-linux
+  package. The location and current version number of util-linux is
+  contained in the file <file:Documentation/Changes>.
+
+  Note that this loop device has nothing to do with the loopback
+  device used for network connections from the machine to itself.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called loop.o.
+
+  Most users will answer N here.
+
+CONFIG_BLK_DEV_NBD
+  Saying Y here will allow your computer to be a client for network
+  block devices, i.e. it will be able to use block devices exported by
+  servers (mount file systems on them etc.). Communication between
+  client and server works over TCP/IP networking, but to the client
+  program this is hidden: it looks like a regular local file access to
+  a block device special file such as /dev/nd0.
+
+  Network block devices also allows you to run a block-device in
+  userland (making server and client physically the same computer,
+  communicating using the loopback network device).
+
+  Read <file:Documentation/nbd.txt> for more information, especially
+  about where to find the server code, which runs in user space and
+  does not need special kernel support.
+
+  Note that this has nothing to do with the network file systems NFS
+  or Coda; you can say N here even if you intend to use NFS or Coda.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called nbd.o.
+
+  If unsure, say N.
+
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+CONFIG_BLK_DEV_LVM
+  This driver lets you combine several hard disks, hard disk
+  partitions, multiple devices or even loop devices (for evaluation
+  purposes) into a volume group.  Imagine a volume group as a kind of
+  virtual disk. Logical volumes, which can be thought of as virtual
+  partitions, can be created in the volume group.  You can resize
+  volume groups and logical volumes after creation time, corresponding
+  to new capacity needs.  Logical volumes are accessed as block
+  devices named /dev/VolumeGroupName/LogicalVolumeName.
+
+  For details see <file:Documentation/LVM-HOWTO>.  You will need
+  supporting user space software; location is in
+  <file:Documentation/Changes>.
+
+  If you want to compile this 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 lvm-mod.o.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_PCI
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+  computer.  These are credit-card size devices such as network cards,
+  modems or hard drives often used with laptops computers.  There are
+  actually two varieties of these cards: the older 16 bit PCMCIA cards
+  and the newer 32 bit CardBus cards.  If you want to use CardBus
+  cards, you need to say Y here and also to "CardBus support" below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  Please also read the PCMCIA-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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_AOUT
+  A.out (Assembler.OUTput) is a set of formats for libraries and
+  executables used in the earliest versions of UNIX. Linux used the
+  a.out formats QMAGIC and ZMAGIC until they were replaced with the
+  ELF format.
+
+  As more and more programs are converted to ELF, the use for a.out
+  will gradually diminish. If you disable this option it will reduce
+  your kernel by one page. This is not much and by itself does not
+  warrant removing support. However its removal is a good idea if you
+  wish to ensure that absolutely none of your programs will use this
+  older executable format. If you don't know what to answer at this
+  point then answer Y. If someone told you "You need a kernel with
+  QMAGIC support" then you'll have to say Y here. You may answer M to
+  compile a.out support as a module and later load the module when you
+  want to use a program or library in a.out format. The module will be
+  called binfmt_aout.o. Saying M or N here is dangerous though,
+  because some crucial programs on your system might still be in A.OUT
+  format.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_BLK_DEV_SD
+  If you want to use a SCSI hard disk or the SCSI or parallel port
+  version of the IOMEGA ZIP drive under Linux, say Y and read the
+  SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. This is NOT for SCSI
+  CD-ROMs.
+
+  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 sd_mod.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  Do not compile this driver as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI disk. In this case, do not compile the driver
+  for your SCSI host adapter (below) as a module either.
+
+CONFIG_SD_EXTRA_DEVS
+  This controls the amount of additional space allocated in tables for
+  drivers that are loaded as modules after the kernel is booted.  In
+  the event that the SCSI core itself was loaded as a module, this
+  value is the number of additional disks that can be loaded after the
+  first host driver is loaded.
+
+  Admittedly this isn't pretty, but there are tons of race conditions
+  involved with resizing the internal arrays on the fly.  Someday this
+  flag will go away, and everything will work automatically.
+
+  If you don't understand what's going on, go with the default.
+
+CONFIG_CHR_DEV_ST
+  If you want to use a SCSI tape drive under Linux, say Y and read the
+  SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, and
+  <file:drivers/scsi/README.st> in the kernel source.  This is NOT for
+  SCSI CD-ROMs.
+
+  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 st.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_CHR_DEV_OSST
+  The OnStream SC-x0 SCSI tape drives can not be driven by the
+  standard st driver, but instead need this special osst driver and
+  use the  /dev/osstX char device nodes (major 206).  Via usb-storage
+  and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives
+  as well.  Note that there is also a second generation of OnStream
+  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
+  <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/>
+  Please also have a look at the standard st docu, as most of it
+  applies to osst as well.
+
+  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 osst.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_BLK_DEV_SR
+  If you want to use a SCSI CD-ROM under Linux, say Y and read the
+  SCSI-HOWTO and the CD-ROM-HOWTO at
+  <http://www.linuxdoc.org/docs.html#howto>. Also make sure to say Y
+  or M to "ISO 9660 CD-ROM file system support" later.
+
+  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 sr_mod.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_SR_EXTRA_DEVS
+  This controls the amount of additional space allocated in tables for
+  drivers that are loaded as modules after the kernel is booted. In
+  the event that the SCSI core itself was loaded as a module, this
+  value is the number of additional CD-ROMs that can be loaded after
+  the first host driver is loaded.
+
+  Admittedly this isn't pretty, but there are tons of race conditions
+  involved with resizing the internal arrays on the fly.  Someday this
+  flag will go away, and everything will work automatically.
+
+  If you don't understand what's going on, go with the default.
+
+CONFIG_BLK_DEV_SR_VENDOR
+  This enables the usage of vendor specific SCSI commands. This is
+  required to support multisession CDs with old NEC/TOSHIBA cdrom
+  drives (and HP Writers). If you have such a drive and get the first
+  session only, try saying Y here; everybody else says N.
+
+CONFIG_CHR_DEV_SG
+  If you want to use SCSI scanners, synthesizers or CD-writers or just
+  about anything having "SCSI" in its name other than hard disks,
+  CD-ROMs or tapes, say Y here. These won't be supported by the kernel
+  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 Cdrtools
+  (<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html>)
+  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.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>. The module will be called sg.o. If unsure,
+  say N.
+
+CONFIG_SCSI_MULTI_LUN
+  If you have a SCSI device that supports more than one LUN (Logical
+  Unit Number), e.g. a CD jukebox, and only one LUN is detected, you
+  can say Y here to force the SCSI driver to probe for multiple LUNs.
+  A SCSI device with multiple LUNs acts logically like multiple SCSI
+  devices. The vast majority of SCSI devices have only one LUN, and
+  so most people can say N here and should in fact do so, because it
+  is safer.
+
+CONFIG_SCSI_CONSTANTS
+  The error messages regarding your SCSI hardware will be easier to
+  understand if you say Y here; it will enlarge your kernel by about
+  12 KB. If in doubt, say Y.
+
+CONFIG_SCSI_LOGGING
+  This turns on a logging facility that can be used to debug a number
+  of SCSI related problems.
+
+  If you say Y here, no logging output will appear by default, but you
+  can enable logging by saying Y to "/proc file system support" and
+  "Sysctl support" below and executing the command
+
+     echo "scsi log token [level]" > /proc/scsi/scsi
+
+  at boot time after the /proc file system has been mounted.
+
+  There are a number of things that can be used for 'token' (you can
+  find them in the source: <file:drivers/scsi/scsi.c>), and this
+  allows you to select the types of information you want, and the
+  level allows you to select the level of verbosity.
+
+  If you say N here, it may be harder to track down some types of SCSI
+  problems. If you say Y here your kernel will be somewhat larger, but
+  there should be no noticeable performance impact as long as you have
+  logging turned off.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_DUMMY
+  This is essentially a bit-bucket device (i.e. traffic you send to
+  this device is consigned into oblivion) with a configurable IP
+  address. It is most commonly used in order to make your currently
+  inactive SLIP address seem like a real address for local programs.
+  If you use SLIP or PPP, you might want to say Y here. Since this
+  thing often comes in handy, the default is Y. It won't enlarge your
+  kernel either. What a deal. Read about it in the Network
+  Administrator's Guide, available from
+  <http://www.linuxdoc.org/docs.html#guide>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called dummy.o.  If you want to use more than one dummy
+  device at a time, you need to compile this driver as a module.
+  Instead of 'dummy', the devices will then be called 'dummy0',
+  'dummy1' etc.
+
+CONFIG_BONDING
+  Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet
+  Channels together. This is called 'Etherchannel' by Cisco,
+  'Trunking' by Sun, and 'Bonding' in Linux.
+
+  If you have two Ethernet connections to some other computer, you can
+  make them behave like one double speed connection using this driver.
+  Naturally, this has to be supported at the other end as well, either
+  with a similar Bonding Linux driver, a Cisco 5500 switch or a
+  SunTrunking SunSoft driver.
+
+  This is similar to the EQL driver, but it merges Ethernet segments
+  instead of serial lines.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called bonding.o.
+
+CONFIG_SLIP
+  Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
+  connect to your Internet service provider or to connect to some
+  other local Unix box or if you want to configure your Linux box as a
+  Slip/CSlip server for other people to dial in. SLIP (Serial Line
+  Internet Protocol) is a protocol used to send Internet traffic over
+  serial connections such as telephone lines or null modem cables;
+  nowadays, the protocol PPP is more commonly used for this same
+  purpose.
+
+  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 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
+  <http://www.linuxdoc.org/docs.html#howto>, explains how to
+  configure SLIP. Note that you don't need this option if you just
+  want to run term (term is a program which gives you almost full
+  Internet connectivity if you have a regular dial up shell account on
+  some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). SLIP
+  support will enlarge your kernel by about 4 KB. If unsure, say N.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>. The module will be
+  called slip.o.
+
+CONFIG_SLIP_COMPRESSED
+  This protocol is faster than SLIP because it uses compression on the
+  TCP/IP headers (not on the data itself), but it has to be supported
+  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://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
+  CSLIP. This won't enlarge your kernel.
+
+CONFIG_SLIP_SMART
+  Adds additional capabilities to the SLIP driver to support the
+  RELCOM line fill and keepalive monitoring. Ideal on poor quality
+  analogue lines.
+
+CONFIG_SLIP_MODE_SLIP6
+  Just occasionally you may need to run IP over hostile serial
+  networks that don't pass all control characters or are only seven
+  bit. Saying Y here adds an extra mode you can use with SLIP:
+  "slip6". In this mode, SLIP will only send normal ASCII symbols over
+  the serial device. Naturally, this has to be supported at the other
+  end of the link as well. It's good enough, for example, to run IP
+  over the async ports of a Camtec JNT Pad. If unsure, say N.
+
+CONFIG_PPP
+  PPP (Point to Point Protocol) is a newer and better SLIP.  It serves
+  the same purpose: sending Internet traffic over telephone (and other
+  serial) lines.  Ask your access provider if they support it, because
+  otherwise you can't use it; most Internet access providers these
+  days support PPP rather than SLIP.
+
+  To use PPP, you need an additional program called pppd as described
+  in the PPP-HOWTO, available at
+  <http://www.linuxdoc.org/docs.html#howto>.  Make sure that you have
+  the version of pppd recommended in <file:Documentation/Changes>.
+  The PPP option enlarges your kernel by about 16 KB.
+
+  There are actually two versions of PPP: the traditional PPP for
+  asynchronous lines, such as regular analog phone lines, and
+  synchronous PPP which can be used over digital ISDN lines for
+  example.  If you want to use PPP over phone lines or other
+  asynchronous serial lines, you need to say Y (or M) here and also to
+  the next option, "PPP support for async serial ports".  For PPP over
+  synchronous lines, you should say Y (or M) here and to "Support
+  synchronous PPP", below.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you said Y to "Version information on all symbols" above, then
+  you cannot compile the PPP driver into the kernel; you can then only
+  compile it as a module.  The module will be called ppp_generic.o.
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_PPP_ASYNC
+  Say Y (or M) here if you want to be able to use PPP over standard
+  asynchronous serial ports, such as COM1 or COM2 on a PC.  If you use
+  a modem (not a synchronous or ISDN modem) to contact your ISP, you
+  need this option.
+
+  This code is also available as a module (code which can be inserted
+  into and removed from the running kernel).  If you want to compile
+  it as a module, say M here and read <file:Documentation/modules.txt>.
+
+  If unsure, say Y.
+
+CONFIG_PPP_SYNC_TTY
+  Say Y (or M) here if you want to be able to use PPP over synchronous
+  (HDLC) tty devices, such as the SyncLink adapter. These devices
+  are often used for high-speed leased lines like T1/E1.
+
+  This code is also available as a module (code which can be inserted
+  into and removed from the running kernel).  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+CONFIG_PPP_DEFLATE
+  Support for the Deflate compression method for PPP, which uses the
+  Deflate algorithm (the same algorithm that gzip uses) to compress
+  each PPP packet before it is sent over the wire.  The machine at the
+  other end of the PPP link (usually your ISP) has to support the
+  Deflate compression method as well for this to be useful.  Even if
+  they don't support it, it is safe to say Y here.
+
+  This code is also available as a module (code which can be inserted
+  into and removed from the running kernel).  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+CONFIG_PPP_BSDCOMP
+  Support for the BSD-Compress compression method for PPP, which uses
+  the LZW compression method to compress each PPP packet before it is
+  sent over the wire. The machine at the other end of the PPP link
+  (usually your ISP) has to support the BSD-Compress compression
+  method as well for this to be useful. Even if they don't support it,
+  it is safe to say Y here.
+
+  The PPP Deflate compression method ("PPP Deflate compression",
+  above) is preferable to BSD-Compress, because it compresses better
+  and is patent-free.
+
+  Note that the BSD compression code will always be compiled as a
+  module; it is called bsd_comp.o and will show up in the directory
+  modules once you have said "make modules". If unsure, say N.
+
+CONFIG_TUN
+  TUN/TAP provides packet reception and transmission for user space
+  programs.  It can be viewed as a simple Point-to-Point or Ethernet
+  device, which instead of receiving packets from a physical media,
+  receives them from user space program and instead of sending packets
+  via physical media writes them to the user space program.
+
+  When a program opens /dev/net/tun, driver creates and registers
+  corresponding net device tunX or tapX.  After a program closed above
+  devices, driver will automatically delete tunXX or tapXX device and
+  all routes corresponding to it.
+
+  Please read <file:Documentation/networking/tuntap.txt> for more
+  information.
+
+  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 tun.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+  If you don't know what to use this for, you don't need it.
+
+CONFIG_ETHERTAP
+  If you say Y here (and have said Y to "Kernel/User network link
+  driver", above) and create a character special file /dev/tap0 with
+  major number 36 and minor number 16 using mknod ("man mknod"), you
+  will be able to have a user space program read and write raw
+  Ethernet frames from/to that special file.  tap0 can be configured
+  with ifconfig and route like any other Ethernet device but it is not
+  connected to any physical LAN; everything written by the user to
+  /dev/tap0 is treated by the kernel as if it had come in from a LAN
+  to the device tap0; everything the kernel wants to send out over the
+  device tap0 can instead be read by the user from /dev/tap0: the user
+  mode program replaces the LAN that would be attached to an ordinary
+  Ethernet device. Please read the file
+  <file:Documentation/networking/ethertap.txt> for more information.
+
+  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 ethertap.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+  If you don't know what to use this for, you don't need it.
+
+CONFIG_MYRI_SBUS
+  This driver supports MyriCOM Sbus gigabit Ethernet cards.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called myri_sbus.o.
+
+CONFIG_VORTEX
+  This option enables driver support for a large number of 10mbps and
+  10/100mbps EISA, PCI and PCMCIA 3Com network cards:
+
+  "Vortex"    (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI
+  "Boomerang" (EtherLink XL 3c900 or 3c905)            PCI
+  "Cyclone"   (3c540/3c900/3c905/3c980/3c575/3c656)    PCI and Cardbus
+  "Tornado"   (3c905)                                  PCI
+  "Hurricane" (3c555/3cSOHO)                           PCI
+
+  If you have such a card, say Y and read the Ethernet-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>. More
+  specific information is in
+  <file:Documentation/networking/vortex.txt> and in the comments at
+  the beginning of <file:drivers/net/3c59x.c>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_HAPPYMEAL
+  This driver supports the "hme" interface present on most Ultra
+  systems and as an option on older Sbus systems. This driver supports
+  both PCI and Sbus devices. This driver also supports the "qfe" quad
+  100baseT device available in both PCI and Sbus configurations.
+
+  This support is also available as a module called sunhme.o ( = 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>.
+
+CONFIG_SUNLANCE
+  This driver supports the "le" interface present on all 32-bit Sparc
+  systems, on some older Ultra systems and as an Sbus option.  These
+  cards are based on the AMD Lance chipset, which is better known
+  via the NE2100 cards.
+
+  This support is also available as a module called sunlance.o ( =
+  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>.
+
+CONFIG_SUNBMAC
+  This driver supports the "be" interface available as an Sbus option.
+  This is Sun's older 100baseT Ethernet device.
+
+  This support is also available as a module called sunbmac.o ( = 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>.
+
+CONFIG_SUNQE
+  This driver supports the "qe" 10baseT Ethernet device, available as
+  an Sbus option. Note that this is not the same as Quad FastEthernet
+  "qfe" which is supported by the Happy Meal driver instead.
+
+  This support is also available as a module called sunqe.o ( = 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>.
+
+CONFIG_FDDI
+  Fiber Distributed Data Interface is a high speed local area network
+  design; essentially a replacement for high speed Ethernet. FDDI can
+  run over copper or fiber. If you are connected to such a network and
+  want a driver for the FDDI card in your computer, say Y here (and
+  then also Y to the driver for your FDDI card, below). Most people
+  will say N.
+
+CONFIG_VT
+  If you say Y here, you will get support for terminal devices with
+  display and keyboard devices. These are called "virtual" because you
+  can run several virtual terminals (also called virtual consoles) on
+  one physical terminal. This is rather useful, for example one
+  virtual terminal can collect system messages and warnings, another
+  one can be used for a text-mode user session, and a third could run
+  an X session, all in parallel. Switching between virtual terminals
+  is done with certain key combinations, usually Alt-<function key>.
+
+  The setterm command ("man setterm") can be used to change the
+  properties (such as colors or beeping) of a virtual terminal. The
+  man page console_codes(4) ("man console_codes") contains the special
+  character sequences that can be used to change those properties
+  directly. The fonts used on virtual terminals can be changed with
+  the setfont ("man setfont") command and the key bindings are defined
+  with the loadkeys ("man loadkeys") command.
+
+  You need at least one virtual terminal device in order to make use
+  of your keyboard and monitor. Therefore, only people configuring an
+  embedded system would want to say N here in order to save some
+  memory; the only way to log into such a system is then via a serial
+  or network connection.
+
+  If unsure, say Y, or else you won't be able to do much with your new
+  shiny Linux system :-)
+
+CONFIG_VT_CONSOLE
+  The system console is the device which receives all kernel messages
+  and warnings and which allows logins in single user mode. If you
+  answer Y here, a virtual terminal (the device used to interact with
+  a physical terminal) can be used as system console. This is the most
+  common mode of operations, so you should say Y here unless you want
+  the kernel messages be output only to a serial port (in which case
+  you should say Y to "Console on serial port", below).
+
+  If you do say Y here, by default the currently visible virtual
+  terminal (/dev/tty0) will be used as system console. You can change
+  that with a kernel command line option such as "console=tty3" which
+  would use the third virtual terminal as system console. (Try "man
+  bootparam" or see the documentation of your boot loader (lilo or
+  loadlin) about how to pass options to the kernel at boot time.)
+
+  If unsure, say Y.
+
+CONFIG_SERIAL
+  This selects whether you want to include the driver for the standard
+  serial ports.  The standard answer is Y.  People who might say N
+  here are those that are setting up dedicated Ethernet WWW/FTP
+  servers, or users that have one of the various bus mice instead of a
+  serial mouse and don't intend to use their machine's standard serial
+  port for anything.  (Note that the Cyclades and Stallion multi
+  serial port drivers do not need this driver built in for them to
+  work.)
+
+  If you want to compile this driver as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  serial.o.
+  [WARNING: Do not compile this driver as a module if you are using
+  non-standard serial ports, since the configuration information will
+  be lost when the driver is unloaded.  This limitation may be lifted
+  in the future.]
+
+  BTW1: If you have a mouseman serial mouse which is not recognized by
+  the X window system, try running gpm first.
+
+  BTW2: If you intend to use a software modem (also called Winmodem)
+  under Linux, forget it.  These modems are crippled and require
+  proprietary drivers which are only available under Windows.
+
+  Most people will say Y or M here, so that they can use serial mice,
+  modems and similar devices connecting to the standard serial ports.
+
+CONFIG_SERIAL_CONSOLE
+  If you say Y here, it will be possible to use a serial port as the
+  system console (the system console is the device which receives all
+  kernel messages and warnings and which allows logins in single user
+  mode). This could be useful if some terminal or printer is connected
+  to that serial port.
+
+  Even if you say Y here, the currently visible virtual console
+  (/dev/tty0) will still be used as the system console by default, but
+  you can alter that using a kernel command line option such as
+  "console=ttyS1". (Try "man bootparam" or see the documentation of
+  your boot loader (lilo or loadlin) about how to pass options to the
+  kernel at boot time.)
+
+  If you don't have a VGA card installed and you say Y here, the
+  kernel will automatically use the first serial line, /dev/ttyS0, as
+  system console.
+
+  If unsure, say N.
+
+CONFIG_UNIX98_PTYS
+  A pseudo terminal (PTY) is a software device consisting of two
+  halves: a master and a slave. The slave device behaves identical to
+  a physical terminal; the master device is used by a process to
+  read data from and write data to the slave, thereby emulating a
+  terminal. Typical programs for the master side are telnet servers
+  and xterms.
+
+  Linux has traditionally used the BSD-like names /dev/ptyxx for
+  masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
+  has a number of problems. The GNU C library glibc 2.1 and later,
+  however, supports the Unix98 naming standard: in order to acquire a
+  pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
+  terminal is then made available to the process and the pseudo
+  terminal slave can be accessed as /dev/pts/<number>. What was
+  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
+
+  The entries in /dev/pts/ are created on the fly by a virtual
+  file system; therefore, if you say Y here you should say Y to
+  "/dev/pts file system for Unix98 PTYs" as well.
+
+  If you want to say Y here, you need to have the C library glibc 2.1
+  or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
+  Read the instructions in <file:Documentation/Changes> pertaining to
+  pseudo terminals. It's safe to say N.
+
+CONFIG_UNIX98_PTY_COUNT
+  The maximum number of Unix98 PTYs that can be used at any one time.
+  The default is 256, and should be enough for desktop systems. Server
+  machines which support incoming telnet/rlogin/ssh connections and/or
+  serve several X terminals may want to increase this: every incoming
+  connection and every xterm uses up one PTY.
+
+  When not in use, each additional set of 256 PTYs occupy
+  approximately 8 KB of kernel memory on 32-bit architectures.
+
+CONFIG_PRINTER
+  If you intend to attach a printer to the parallel port of your Linux
+  box (as opposed to using a serial printer; if the connector at the
+  printer has 9 or 25 holes ["female"], then it's serial), say Y.
+  Also read the Printing-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  It is possible to share one parallel port among several devices
+  (e.g. printer and ZIP drive) and it is safe to compile the
+  corresponding drivers into the kernel.  If you want to compile this
+  driver as a module however ( = code which can be inserted in and
+  removed from the running kernel whenever you want), say M here and
+  read <file:Documentation/modules.txt> and
+  <file:Documentation/parport.txt>.  The module will be called lp.o.
+
+  If you have several parallel ports, you can specify which ports to
+  use with the "lp" kernel command line option.  (Try "man bootparam"
+  or see the documentation of your boot loader (lilo or loadlin) about
+  how to pass options to the kernel at boot time.)  The syntax of the
+  "lp" command line option can be found in <file:drivers/char/lp.c>.
+
+  If you have more than 8 printers, you need to increase the LP_NO
+  macro in lp.c and the PARPORT_MAX macro in parport.h.
+
+CONFIG_BUSMOUSE
+  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 a laptop, you either have to check the documentation or
+  experiment a bit to find out whether the trackball is a serial mouse
+  or not; it's best to say Y here for you.
+
+  This is the generic bus mouse driver code. If you have a bus mouse,
+  you will have to say Y here and also to the specific driver for your
+  mouse below.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called busmouse.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SOFT_WATCHDOG
+  A software monitoring watchdog. This will fail to reboot your system
+  from some situations that the hardware watchdog will recover
+  from. Equally it's a lot cheaper to install.
+
+  This driver is also available 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>. The module will be called
+   softdog.o.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_ISDN
+  ISDN ("Integrated Services Digital Networks", called RNIS in France)
+  is a special type of fully digital telephone service; it's mostly
+  used to connect to your Internet service provider (with SLIP or
+  PPP).  The main advantage is that the speed is higher than ordinary
+  modem/telephone connections, and that you can have voice
+  conversations while downloading stuff.  It only works if your
+  computer is equipped with an ISDN card and both you and your service
+  provider purchased an ISDN line from the phone company.  For
+  details, read <http://alumni.caltech.edu/~dank/isdn/> on the WWW.
+
+  This driver allows you to use an ISDN-card for networking
+  connections and as dialin/out device.  The isdn-tty's have a built
+  in AT-compatible modem emulator.  Network devices support autodial,
+  channel-bundling, callback and caller-authentication without having
+  a daemon running.  A reduced T.70 protocol is supported with tty's
+  suitable for German BTX.  On D-Channel, the protocols EDSS1
+  (Euro-ISDN) and 1TR6 (German style) are supported.  See
+  <file:Documentation/isdn/README> for more information.
+
+  If you want to compile the ISDN code 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 isdn.o. If unsure, say N.
+
+CONFIG_SUN4
+  Say Y here if, and only if, your machine is a Sun4. Note that
+  a kernel compiled with this option will run only on Sun4.
+  (And the current version will probably work only on sun4/330.)
+
+CONFIG_SCSI_SUNESP
+  This is the driver for the Sun ESP SCSI host adapter. The ESP
+  chipset is present in most SPARC SBUS-based computers.
+
+  This support is also available as a module called esp.o ( = 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>.
+
+CONFIG_SCSI_QLOGICPTI
+  This driver supports SBUS SCSI controllers from PTI or QLogic. These
+  controllers are known under Solaris as qpti and in the openprom as
+  PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are
+  driven by a different driver.
+
+  This support is also available as a module called qlogicpti.o ( =
+  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>.
+
+CONFIG_PROM_CONSOLE
+  Say Y to build a console driver for Sun machines that uses the
+  terminal emulation built into their console PROMS.
+
+CONFIG_SUN_OPENPROMFS
+  If you say Y, the OpenPROM device tree will be available as a
+  virtual file system, which you can mount to /proc/openprom by "mount
+  -t openpromfs none /proc/openprom".
+
+  If you want to compile the /proc/openprom 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 openpromfs.o.  If unsure, say M.
+
+CONFIG_SUNOS_EMUL
+  This allows you to run most SunOS binaries.  If you want to do this,
+  say Y here and place appropriate files in /usr/gnemul/sunos. See
+  <http://www.ultralinux.org/faq.html> for more information.  If you
+  want to run SunOS binaries on an Ultra you must also say Y to
+  "Kernel support for 32-bit a.out binaries" above.
+
+CONFIG_SUN_KEYBOARD
+  Say Y here to support the keyboard found on Sun 3 and 3x
+  workstations.  It can also be used support Sun Type-5 keyboards
+  through an adaptor.  See
+  <http://www.suse.cz/development/input/adapters.html> and
+  <http://sourceforge.net/projects/linuxconsole/> for details on the
+  latter.
+
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v2.5.2/linux/arch/sparc/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc/config.in	Thu Jan 24 22:04:21 2002
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.111 2001/06/01 08:12:10 davem Exp $
+# $Id: config.in,v 1.113 2002/01/24 22:14:44 davem Exp $
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
 #
@@ -7,19 +7,7 @@
 define_bool CONFIG_UID16 y
 define_bool CONFIG_HIGHMEM y
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all symbols for modules' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'General setup'
@@ -60,10 +48,6 @@
 fi
 
 tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS
-bool 'Networking support' CONFIG_NET
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
 if [ "$CONFIG_PROC_FS" = "y" ]; then
    define_bool CONFIG_KCORE_ELF y
 fi
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.5.2/linux/arch/sparc/defconfig	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc/defconfig	Thu Jan 24 22:04:21 2002
@@ -5,6 +5,14 @@
 CONFIG_HIGHMEM=y
 
 #
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
@@ -43,10 +51,6 @@
 # CONFIG_SUN4 is not set
 # CONFIG_PCI is not set
 CONFIG_SUN_OPENPROMFS=m
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
@@ -138,7 +142,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 +152,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
@@ -288,7 +293,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=m
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
@@ -402,3 +407,8 @@
 # Kernel hacking
 #
 # CONFIG_MAGIC_SYSRQ is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/kernel/init_task.c linux/arch/sparc/kernel/init_task.c
--- v2.5.2/linux/arch/sparc/kernel/init_task.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,5 +1,6 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c
--- v2.5.2/linux/arch/sparc/kernel/pcic.c	Sun Feb 18 19:49:44 2001
+++ linux/arch/sparc/kernel/pcic.c	Wed Jan 23 15:28:39 2002
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.22 2001/02/13 01:16:43 davem Exp $
+/* $Id: pcic.c,v 1.23 2002/01/23 14:33:55 davem Exp $
  * pcic.c: Sparc/PCI controller support
  *
  * Copyright (C) 1998 V. Roganov and G. Raiko
@@ -759,7 +759,6 @@
 	unsigned long v;
 	int timer_irq, irq;
 
-	do_get_fast_time = pci_do_gettimeofday;
 	/* A hack until do_gettimeofday prototype is moved to arch specific headers
 	   and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */
 	((unsigned int *)do_gettimeofday)[0] = 
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.5.2/linux/arch/sparc/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc/kernel/process.c	Wed Jan 23 15:28:39 2002
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.160 2002/01/11 08:45:38 davem Exp $
+/*  $Id: process.c,v 1.161 2002/01/23 11:27:32 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -106,7 +106,7 @@
 {
 	/* endless idle loop with no priority at all */
 	while(1) {
-		if(current->need_resched) {
+		if(need_resched()) {
 			schedule();
 			check_pgt_cache();
 		}
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S
--- v2.5.2/linux/arch/sparc/kernel/rtrap.S	Thu Jul 19 18:11:13 2001
+++ linux/arch/sparc/kernel/rtrap.S	Mon Jan 28 15:14:23 2002
@@ -58,15 +58,15 @@
 	 nop
 
 1:
-	ld	[%curptr + AOFF_task_need_resched], %g2
+#error	ld	[%curptr + AOFF_task_need_resched], %g2
 	orcc	%g2, %g0, %g0
 	be	signal_p
-	 ld	[%curptr + AOFF_task_sigpending], %g2
+#error	 ld	[%curptr + AOFF_task_sigpending], %g2
 
 	call	C_LABEL(schedule)
 	 nop
 
-	ld	[%curptr + AOFF_task_sigpending], %g2
+#error	ld	[%curptr + AOFF_task_sigpending], %g2
 signal_p:
 	cmp	%g2, 0
 	bz,a	ret_trap_continue
@@ -98,7 +98,7 @@
 	 add	%sp, REGWIN_SZ, %o0
 
 	b	signal_p
-	 ld	[%curptr + AOFF_task_sigpending], %g2
+#error	 ld	[%curptr + AOFF_task_sigpending], %g2
 
 ret_trap_nobufwins:
 	/* Load up the user's out registers so we can pull
@@ -168,7 +168,7 @@
 	 nop
 
 	b	signal_p
-	 ld	[%curptr + AOFF_task_sigpending], %g2
+#error	 ld	[%curptr + AOFF_task_sigpending], %g2
 
 ret_trap_kernel:
 		/* Will the rett land us in the invalid window? */
@@ -218,7 +218,7 @@
 	 add	%sp, REGWIN_SZ, %o0
 
 	b	signal_p
-	 ld	[%curptr + AOFF_task_sigpending], %g2
+#error	 ld	[%curptr + AOFF_task_sigpending], %g2
 
 	.globl	C_LABEL(sun4c_rett_stackchk)
 C_LABEL(sun4c_rett_stackchk):
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v2.5.2/linux/arch/sparc/kernel/smp.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc/kernel/smp.c	Mon Jan 28 15:14:23 2002
@@ -177,23 +177,27 @@
 	}
 }
 
-void smp_flush_cache_range(struct mm_struct *mm, unsigned long start,
+void smp_flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 			   unsigned long end)
 {
-	if(mm->context != NO_CONTEXT) {
+	struct mm_struct *mm = vma->vm_mm;
+
+	if (mm->context != NO_CONTEXT) {
 		if(mm->cpu_vm_mask != (1 << smp_processor_id()))
-			xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) mm, start, end);
-		local_flush_cache_range(mm, start, end);
+			xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) vma, start, end);
+		local_flush_cache_range(vma, start, end);
 	}
 }
 
-void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			 unsigned long end)
 {
-	if(mm->context != NO_CONTEXT) {
+	struct mm_struct *mm = vma->vm_mm;
+
+	if (mm->context != NO_CONTEXT) {
 		if(mm->cpu_vm_mask != (1 << smp_processor_id()))
-			xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) mm, start, end);
-		local_flush_tlb_range(mm, start, end);
+			xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) vma, start, end);
+		local_flush_tlb_range(vma, start, end);
 	}
 }
 
@@ -243,7 +247,7 @@
 /* Reschedule call back. */
 void smp_reschedule_irq(void)
 {
-	current->need_resched = 1;
+	current->work.need_resched = 1;
 }
 
 /* Stopping processors. */
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c
--- v2.5.2/linux/arch/sparc/kernel/time.c	Tue Oct 30 15:08:11 2001
+++ linux/arch/sparc/kernel/time.c	Wed Jan 23 15:28:39 2002
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.59 2001/10/30 04:54:21 davem Exp $
+/* $Id: time.c,v 1.60 2002/01/23 14:33:55 davem Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -371,7 +371,6 @@
 	struct intersil *iregs;
 #endif
 
-	do_get_fast_time = do_gettimeofday;
 	BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
 	btfixup();
 
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/generic.c linux/arch/sparc/mm/generic.c
--- v2.5.2/linux/arch/sparc/mm/generic.c	Thu Jul 19 18:11:13 2001
+++ linux/arch/sparc/mm/generic.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.13 2001/07/17 16:17:33 anton Exp $
+/* $Id: generic.c,v 1.14 2001/12/21 04:56:15 davem Exp $
  * generic.c: Generic Sparc mm routines that are not dependent upon
  *            MMU type but are Sparc specific.
  *
@@ -75,18 +75,18 @@
 	return 0;
 }
 
-int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
+int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
 {
 	int error = 0;
 	pgd_t * dir;
 	unsigned long beg = from;
 	unsigned long end = from + size;
-	struct mm_struct *mm = current->mm;
+	struct mm_struct *mm = vma->vm_mm;
 
 	prot = __pgprot(pg_iobits);
 	offset -= from;
 	dir = pgd_offset(mm, from);
-	flush_cache_range(mm, beg, end);
+	flush_cache_range(vma, beg, end);
 
 	spin_lock(&mm->page_table_lock);
 	while (from < end) {
@@ -102,6 +102,6 @@
 	}
 	spin_unlock(&mm->page_table_lock);
 
-	flush_tlb_range(current->mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return error;
 }
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/hypersparc.S linux/arch/sparc/mm/hypersparc.S
--- v2.5.2/linux/arch/sparc/mm/hypersparc.S	Tue Jul 18 12:29:47 2000
+++ linux/arch/sparc/mm/hypersparc.S	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: hypersparc.S,v 1.17 2000/07/16 21:48:52 anton Exp $
+/* $Id: hypersparc.S,v 1.18 2001/12/21 04:56:15 davem Exp $
  * hypersparc.S: High speed Hypersparc mmu/cache operations.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -74,6 +74,7 @@
 
 	/* The things we do for performance... */
 hypersparc_flush_cache_range:
+	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
 #ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g1
 	cmp	%g1, -1
@@ -283,6 +284,7 @@
 	 sta	%g5, [%g1] ASI_M_MMUREGS
 
 hypersparc_flush_tlb_range:
+	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	lda	[%g1] ASI_M_MMUREGS, %g5
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.5.2/linux/arch/sparc/mm/srmmu.c	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc/mm/srmmu.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.233 2001/11/13 00:49:27 davem Exp $
+/* $Id: srmmu.c,v 1.234 2001/12/21 04:56:15 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -536,14 +536,14 @@
 /* tsunami.S */
 extern void tsunami_flush_cache_all(void);
 extern void tsunami_flush_cache_mm(struct mm_struct *mm);
-extern void tsunami_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void tsunami_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
 extern void tsunami_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 extern void tsunami_flush_page_to_ram(unsigned long page);
 extern void tsunami_flush_page_for_dma(unsigned long page);
 extern void tsunami_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
 extern void tsunami_flush_tlb_all(void);
 extern void tsunami_flush_tlb_mm(struct mm_struct *mm);
-extern void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void tsunami_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
 extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 extern void tsunami_setup_blockops(void);
 
@@ -582,7 +582,7 @@
 /* swift.S */
 extern void swift_flush_cache_all(void);
 extern void swift_flush_cache_mm(struct mm_struct *mm);
-extern void swift_flush_cache_range(struct mm_struct *mm,
+extern void swift_flush_cache_range(struct vm_area_struct *vma,
 				    unsigned long start, unsigned long end);
 extern void swift_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 extern void swift_flush_page_to_ram(unsigned long page);
@@ -590,7 +590,7 @@
 extern void swift_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
 extern void swift_flush_tlb_all(void);
 extern void swift_flush_tlb_mm(struct mm_struct *mm);
-extern void swift_flush_tlb_range(struct mm_struct *mm,
+extern void swift_flush_tlb_range(struct vm_area_struct *vma,
 				  unsigned long start, unsigned long end);
 extern void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 
@@ -686,8 +686,9 @@
 	FLUSH_END
 }
 
-static void cypress_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void cypress_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	register unsigned long a, b, c, d, e, f, g;
 	unsigned long flags, faddr;
 	int octx;
@@ -827,8 +828,9 @@
 	FLUSH_END
 }
 
-static void cypress_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void cypress_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long size;
 
 	FLUSH_BEGIN(mm)
@@ -870,7 +872,7 @@
 /* viking.S */
 extern void viking_flush_cache_all(void);
 extern void viking_flush_cache_mm(struct mm_struct *mm);
-extern void viking_flush_cache_range(struct mm_struct *mm, unsigned long start,
+extern void viking_flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 				     unsigned long end);
 extern void viking_flush_cache_page(struct vm_area_struct *vma,
 				    unsigned long page);
@@ -881,13 +883,13 @@
 extern void viking_mxcc_flush_page(unsigned long page);
 extern void viking_flush_tlb_all(void);
 extern void viking_flush_tlb_mm(struct mm_struct *mm);
-extern void viking_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void viking_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				   unsigned long end);
 extern void viking_flush_tlb_page(struct vm_area_struct *vma,
 				  unsigned long page);
 extern void sun4dsmp_flush_tlb_all(void);
 extern void sun4dsmp_flush_tlb_mm(struct mm_struct *mm);
-extern void sun4dsmp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void sun4dsmp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				   unsigned long end);
 extern void sun4dsmp_flush_tlb_page(struct vm_area_struct *vma,
 				  unsigned long page);
@@ -895,14 +897,14 @@
 /* hypersparc.S */
 extern void hypersparc_flush_cache_all(void);
 extern void hypersparc_flush_cache_mm(struct mm_struct *mm);
-extern void hypersparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void hypersparc_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
 extern void hypersparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 extern void hypersparc_flush_page_to_ram(unsigned long page);
 extern void hypersparc_flush_page_for_dma(unsigned long page);
 extern void hypersparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
 extern void hypersparc_flush_tlb_all(void);
 extern void hypersparc_flush_tlb_mm(struct mm_struct *mm);
-extern void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void hypersparc_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
 extern void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 extern void hypersparc_setup_blockops(void);
 
@@ -1559,8 +1561,10 @@
 	FLUSH_END
 }
 
-static void turbosparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void turbosparc_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	FLUSH_BEGIN(mm)
 	flush_user_windows();
 	turbosparc_idflash_clear();
@@ -1610,8 +1614,10 @@
 	FLUSH_END
 }
 
-static void turbosparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void turbosparc_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	FLUSH_BEGIN(mm)
 	srmmu_flush_whole_tlb();
 	FLUSH_END
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.5.2/linux/arch/sparc/mm/sun4c.c	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc/mm/sun4c.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.210 2001/11/13 03:27:47 davem Exp $
+/* $Id: sun4c.c,v 1.212 2001/12/21 04:56:15 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -1337,7 +1337,7 @@
 static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
 {
 	while (sz >= 0) {
-		sg[sz].dvma_address = (__u32)sun4c_lockarea(sg[sz].address, sg[sz].length);
+		sg[sz].dvma_address = (__u32)sun4c_lockarea(page_address(sg[sz].page) + sg[sz].offset, sg[sz].length);
 		sg[sz].dvma_length = sg[sz].length;
 		sz--;
 	}
@@ -1484,8 +1484,9 @@
 	}
 }
 
-static void sun4c_flush_cache_range_hw(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void sun4c_flush_cache_range_hw(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
 	
 	if (new_ctx != NO_CONTEXT) {
@@ -1608,8 +1609,9 @@
 	}
 }
 
-static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void sun4c_flush_cache_range_sw(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
 
 	if (new_ctx != NO_CONTEXT) {
@@ -1765,8 +1767,9 @@
 	}
 }
 
-static void sun4c_flush_tlb_range_hw(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void sun4c_flush_tlb_range_hw(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
 
 	if (new_ctx != NO_CONTEXT) {
@@ -1848,8 +1851,9 @@
 	}
 }
 
-static void sun4c_flush_tlb_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void sun4c_flush_tlb_range_sw(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
 
 	if (new_ctx != NO_CONTEXT) {
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/swift.S linux/arch/sparc/mm/swift.S
--- v2.5.2/linux/arch/sparc/mm/swift.S	Tue Jul 18 12:29:47 2000
+++ linux/arch/sparc/mm/swift.S	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: swift.S,v 1.7 2000/07/16 21:48:52 anton Exp $
+/* $Id: swift.S,v 1.9 2002/01/08 11:11:59 davem Exp $
  * swift.S: MicroSparc-II mmu/cache operations.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -108,6 +108,7 @@
 
 	.globl	swift_flush_cache_range
 swift_flush_cache_range:
+	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
 	sub	%o2, %o1, %o2
 	sethi	%hi(4096), %o3
 	cmp	%o2, %o3
@@ -222,8 +223,9 @@
 	.globl	swift_flush_tlb_mm
 	.globl	swift_flush_tlb_range
 	.globl	swift_flush_tlb_all
-swift_flush_tlb_mm:
 swift_flush_tlb_range:
+	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
+swift_flush_tlb_mm:
 #ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/tsunami.S linux/arch/sparc/mm/tsunami.S
--- v2.5.2/linux/arch/sparc/mm/tsunami.S	Tue Jul 18 12:29:47 2000
+++ linux/arch/sparc/mm/tsunami.S	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: tsunami.S,v 1.6 2000/07/16 21:48:52 anton Exp $
+/* $Id: tsunami.S,v 1.7 2001/12/21 04:56:15 davem Exp $
  * tsunami.S: High speed MicroSparc-I mmu/cache operations.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -23,9 +23,9 @@
 
 	/* Sliiick... */
 tsunami_flush_cache_page:
+tsunami_flush_cache_range:
 	ld	[%o0 + 0x0], %o0	/* XXX vma->vm_mm, GROSS XXX */
 tsunami_flush_cache_mm:
-tsunami_flush_cache_range:
 	ld	[%o0 + AOFF_mm_context], %g2
 #ifndef CONFIG_SMP
 	cmp	%g2, -1
@@ -47,8 +47,9 @@
 	 flush	%o1 + 4
 
 	/* More slick stuff... */
-tsunami_flush_tlb_mm:
 tsunami_flush_tlb_range:
+	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
+tsunami_flush_tlb_mm:
 #ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/viking.S linux/arch/sparc/mm/viking.S
--- v2.5.2/linux/arch/sparc/mm/viking.S	Tue Jul 18 12:29:47 2000
+++ linux/arch/sparc/mm/viking.S	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: viking.S,v 1.18 2000/07/16 21:48:52 anton Exp $
+/* $Id: viking.S,v 1.19 2001/12/21 04:56:15 davem Exp $
  * viking.S: High speed Viking cache/mmu operations
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -108,11 +108,11 @@
 	 nop
 
 viking_flush_cache_page:
+viking_flush_cache_range:
 #ifndef CONFIG_SMP
 	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
 #endif
 viking_flush_cache_mm:
-viking_flush_cache_range:
 #ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g1
 	cmp	%g1, -1
@@ -150,6 +150,7 @@
 #endif
 
 viking_flush_tlb_range:
+	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	lda	[%g1] ASI_M_MMUREGS, %g5
@@ -240,6 +241,7 @@
 	tst	%g5
 	bne	3f
 	 mov	SRMMU_CTX_REG, %g1
+	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
 	ld	[%o0 + AOFF_mm_context], %o3
 	lda	[%g1] ASI_M_MMUREGS, %g5
 	sethi	%hi(~((1 << SRMMU_PGDIR_SHIFT) - 1)), %o4
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/vmlinux.lds linux/arch/sparc/vmlinux.lds
--- v2.5.2/linux/arch/sparc/vmlinux.lds	Mon Jul  2 14:40:58 2001
+++ linux/arch/sparc/vmlinux.lds	Wed Jan 23 10:54:42 2002
@@ -45,7 +45,15 @@
   .setup_init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/Config.help linux/arch/sparc64/Config.help
--- v2.5.2/linux/arch/sparc64/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/Config.help	Fri Jan 25 16:04:31 2002
@@ -0,0 +1,1316 @@
+CONFIG_SMP
+  This enables support for systems with more than one CPU. If you have
+  a system with only one CPU, like most personal computers, say N. If
+  you have a system with more than one CPU, say Y.
+
+  If you say N here, the kernel will run on single and multiprocessor
+  machines, but will use only one CPU of a multiprocessor machine. If
+  you say Y here, the kernel will run on many, but not all,
+  singleprocessor machines. On a singleprocessor machine, the kernel
+  will run faster if you say N here.
+
+  Note that if you say Y here and choose architecture "586" or
+  "Pentium" under "Processor family", the kernel will not work on 486
+  architectures. Similarly, multiprocessor kernels for the "PPro"
+  architecture may not work on all Pentium based boards.
+
+  People using multiprocessor machines who say Y here should also say
+  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+  Management" code will be disabled if you say Y here.
+
+  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-HOWTO available at
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you don't know what to do here, say N.
+
+CONFIG_SPARC64
+  SPARC is a family of RISC microprocessors designed and marketed by
+  Sun Microsystems, incorporated.  This port covers the newer 64-bit
+  UltraSPARC.  The UltraLinux project maintains both the SPARC32 and
+  SPARC64 ports; its web page is available at
+  <http://www.ultralinux.org/>.
+
+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
+  Thinkpad users, is contained in <file:Documentation/floppy.txt>.
+  That file also contains the location of the Floppy driver FAQ as
+  well as location of the fdutils package used to configure additional
+  parameters of the driver at run time.
+
+  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 floppy.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_BLK_DEV_RAM
+  Saying Y here will allow you to use a portion of your RAM memory as
+  a block device, so that you can make file systems on it, read and
+  write to it and do all the other things that you can do with normal
+  block devices (such as hard drives). It is usually used to load and
+  store a copy of a minimal root file system off of a floppy into RAM
+  during the initial install of Linux.
+
+  Note that the kernel command line option "ramdisk=XX" is now
+  obsolete. For details, read <file:Documentation/ramdisk.txt>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M and read <file:Documentation/modules.txt>. The module will be
+  called rd.o.
+
+  Most normal users won't need the RAM disk functionality, and can
+  thus say N here.
+
+CONFIG_BLK_DEV_RAM_SIZE
+  The default value is 4096. Only change this if you know what are
+  you doing. If you are using IBM S/390, then set this to 8192.
+
+CONFIG_BLK_DEV_INITRD
+  The initial RAM disk is a RAM disk that is loaded by the boot loader
+  (loadlin or lilo) and that is mounted as root before the normal boot
+  procedure. It is typically used to load modules needed to mount the
+  "real" root file system, etc. See <file:Documentation/initrd.txt>
+  for details.
+
+CONFIG_BLK_DEV_LOOP
+  Saying Y here will allow you to use a regular file as a block
+  device; you can then create a file system on that block device and
+  mount it just as you would mount other block devices such as hard
+  drive partitions, CD-ROM drives or floppy drives. The loop devices
+  are block special device files with major number 7 and typically
+  called /dev/loop0, /dev/loop1 etc.
+
+  This is useful if you want to check an ISO 9660 file system before
+  burning the CD, or if you want to use floppy images without first
+  writing them to floppy. Furthermore, some Linux distributions avoid
+  the need for a dedicated Linux partition by keeping their complete
+  root file system inside a DOS FAT file using this loop device
+  driver.
+
+  The loop device driver can also be used to "hide" a file system in a
+  disk partition, floppy, or regular file, either using encryption
+  (scrambling the data) or steganography (hiding the data in the low
+  bits of, say, a sound file). This is also safe if the file resides
+  on a remote file server. If you want to do this, you will first have
+  to acquire and install a kernel patch from
+  <ftp://ftp.kerneli.org/pub/kerneli/>, and then you need to
+  say Y to this option.
+
+  Note that alternative ways to use encrypted file systems are
+  provided by the cfs package, which can be gotten from
+  <ftp://ftp.kerneli.org/pub/kerneli/net-source/>, and the newer tcfs
+  package, available at <http://tcfs.dia.unisa.it/>. You do not need
+  to say Y here if you want to use one of these. However, using cfs
+  requires saying Y to "NFS file system support" below while using
+  tcfs requires applying a kernel patch. An alternative steganography
+  solution is provided by StegFS, also available from
+  <ftp://ftp.kerneli.org/pub/kerneli/net-source/>.
+
+  To use the loop device, you need the losetup utility and a recent
+  version of the mount program, both contained in the util-linux
+  package. The location and current version number of util-linux is
+  contained in the file <file:Documentation/Changes>.
+
+  Note that this loop device has nothing to do with the loopback
+  device used for network connections from the machine to itself.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called loop.o.
+
+  Most users will answer N here.
+
+CONFIG_BLK_DEV_NBD
+  Saying Y here will allow your computer to be a client for network
+  block devices, i.e. it will be able to use block devices exported by
+  servers (mount file systems on them etc.). Communication between
+  client and server works over TCP/IP networking, but to the client
+  program this is hidden: it looks like a regular local file access to
+  a block device special file such as /dev/nd0.
+
+  Network block devices also allows you to run a block-device in
+  userland (making server and client physically the same computer,
+  communicating using the loopback network device).
+
+  Read <file:Documentation/nbd.txt> for more information, especially
+  about where to find the server code, which runs in user space and
+  does not need special kernel support.
+
+  Note that this has nothing to do with the network file systems NFS
+  or Coda; you can say N here even if you intend to use NFS or Coda.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called nbd.o.
+
+  If unsure, say N.
+
+CONFIG_IDE
+  If you say Y here, your kernel will be able to manage low cost mass
+  storage units such as ATA/(E)IDE and ATAPI units. The most common
+  cases are IDE hard drives and ATAPI CD-ROM drives.
+
+  If your system is pure SCSI and doesn't use these interfaces, you
+  can say N here.
+
+  Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+  for mass storage units such as hard disks. It was designed by
+  Western Digital and Compaq Computer in 1984. It was then named
+  ST506. Quite a number of disks use the IDE interface.
+
+  AT Attachment (ATA) is the superset of the IDE specifications.
+  ST506 was also called ATA-1.
+
+  Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+  ATA-3. It provides support for larger disks (up to 8.4GB by means of
+  the LBA standard), more disks (4 instead of 2) and for other mass
+  storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+  ATA-4 and provides faster (and more CPU friendly) transfer modes
+  than previous PIO (Programmed processor Input/Output) from previous
+  ATA/IDE standards by means of fast DMA controllers.
+
+  ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+  CD-ROM drives, similar in many respects to the SCSI protocol.
+
+  SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+  designed in order to prevent data corruption and disk crash by
+  detecting pre hardware failure conditions (heat, access time, and
+  the like...). Disks built since June 1995 may follow this standard.
+  The kernel itself don't manage this; however there are quite a
+  number of user programs such as smart that can query the status of
+  SMART parameters disk.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called ide.o.
+
+  For further information, please read <file:Documentation/ide.txt>.
+
+  If unsure, say Y.
+
+CONFIG_ISA
+  Find out whether you have ISA slots on your motherboard.  ISA is the
+  name of a bus system, i.e. the way the CPU talks to the other stuff
+  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+CONFIG_PCI
+  Find out whether you have a PCI motherboard. PCI is the name of a
+  bus system, i.e. the way the CPU talks to the other stuff inside
+  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+  VESA. If you have PCI, say Y, otherwise N.
+
+  The PCI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
+
+CONFIG_MCA
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops.  It is a bus system similar to PCI or ISA. See
+  <file:Documentation/mca.txt> (and especially the web page given
+  there) before attempting to build an MCA bus kernel.
+
+CONFIG_EISA
+  The Extended Industry Standard Architecture (EISA) bus was
+  developed as an open alternative to the IBM MicroChannel bus.
+
+  The EISA bus provided some of the features of the IBM MicroChannel
+  bus while maintaining backward compatibility with cards made for
+  the older ISA bus.  The EISA bus saw limited use between 1988 and
+  1995 when it was made obsolete by the PCI bus.
+
+  Say Y here if you are building a kernel for an EISA-based machine.
+
+  Otherwise, say N.
+
+CONFIG_ISAPNP
+  Say Y here if you would like support for ISA Plug and Play devices.
+  Some information is in <file:Documentation/isapnp.txt>.
+
+  This support is also available as a module called isapnp.o ( =
+  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>.
+
+  If unsure, say Y.
+
+CONFIG_HOTPLUG
+  Say Y here if you want to plug devices into your computer while
+  the system is running, and be able to use them quickly.  In many
+  cases, the devices can likewise be unplugged at any time too.
+
+  One well known example of this is PCMCIA- or PC-cards, credit-card
+  size devices such as network cards, modems or hard drives which are
+  plugged into slots found on all modern laptop computers.  Another
+  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.
+  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.
+
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+  computer.  These are credit-card size devices such as network cards,
+  modems or hard drives often used with laptops computers.  There are
+  actually two varieties of these cards: the older 16 bit PCMCIA cards
+  and the newer 32 bit CardBus cards.  If you want to use CardBus
+  cards, you need to say Y here and also to "CardBus support" below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  Please also read the PCMCIA-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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.
+
+CONFIG_KCORE_ELF
+  If you enabled support for /proc file system then the file
+  /proc/kcore will contain the kernel core image. This can be used
+  in gdb:
+
+  $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+  You have two choices here: ELF and A.OUT. Selecting ELF will make
+  /proc/kcore appear in ELF core format as defined by the Executable
+  and Linking Format specification. Selecting A.OUT will choose the
+  old "a.out" format which may be necessary for some old versions
+  of binutils or on some architectures.
+
+  This is especially useful if you have compiled the kernel with the
+  "-g" option to preserve debugging information. It is mainly used
+  for examining kernel data structures on the live kernel so if you
+  don't understand what this means or are not a kernel hacker, just
+  leave it at its default value ELF.
+
+CONFIG_BINFMT_ELF
+  ELF (Executable and Linkable Format) is a format for libraries and
+  executables used across different architectures and operating
+  systems. Saying Y here will enable your kernel to run ELF binaries
+  and enlarge it by about 13 KB. ELF support under Linux has now all
+  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
+  because it is portable (this does *not* mean that you will be able
+  to run executables from different architectures or operating systems
+  however) and makes building run-time libraries very easy. Many new
+  executables are distributed solely in ELF format. You definitely
+  want to say Y here.
+
+  Information about ELF is contained in the ELF HOWTO available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you find that after upgrading from Linux kernel 1.2 and saying Y
+  here, you still can't run any ELF binaries (they just crash), then
+  you'll have to install the newest ELF runtime libraries, including
+  ld.so (check the file <file:Documentation/Changes> for location and
+  latest version).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called binfmt_elf.o. Saying M or N here is dangerous because
+  some crucial programs on your system might be in ELF format.
+
+CONFIG_BINFMT_MISC
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
+
+  You can do other nice things, too. Read the file
+  <file:Documentation/binfmt_misc.txt> to learn how to use this
+  feature, and <file:Documentation/java.txt> for information about how
+  to include Java support.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
+
+  You may say M here for module support and later load the module when
+  you have use for it; the module is called binfmt_misc.o. If you
+  don't know what to answer at this point, say Y.
+
+CONFIG_SOLARIS_EMUL
+  This is experimental code which will enable you to run (many)
+  Solaris binaries on your SPARC Linux machine.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called solaris.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_ENVCTRL
+  Kernel support for temperature and fan monitoring on Sun SME
+  machines.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called envctrl.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI
+  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+  any other SCSI device under Linux, say Y and make sure that you know
+  the name of your SCSI host adapter (the card inside your computer
+  that "speaks" the SCSI protocol, also called SCSI controller),
+  because you will be asked for it.
+
+  You also need to say Y here if you want support for the parallel
+  port version of the 100 MB IOMEGA ZIP drive.
+
+  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
+  a module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  However, do not compile this as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI device.
+
+CONFIG_BLK_DEV_SD
+  If you want to use a SCSI hard disk or the SCSI or parallel port
+  version of the IOMEGA ZIP drive under Linux, say Y and read the
+  SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. This is NOT for SCSI
+  CD-ROMs.
+
+  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 sd_mod.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  Do not compile this driver as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI disk. In this case, do not compile the driver
+  for your SCSI host adapter (below) as a module either.
+
+CONFIG_SD_EXTRA_DEVS
+  This controls the amount of additional space allocated in tables for
+  drivers that are loaded as modules after the kernel is booted.  In
+  the event that the SCSI core itself was loaded as a module, this
+  value is the number of additional disks that can be loaded after the
+  first host driver is loaded.
+
+  Admittedly this isn't pretty, but there are tons of race conditions
+  involved with resizing the internal arrays on the fly.  Someday this
+  flag will go away, and everything will work automatically.
+
+  If you don't understand what's going on, go with the default.
+
+CONFIG_CHR_DEV_ST
+  If you want to use a SCSI tape drive under Linux, say Y and read the
+  SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, and
+  <file:drivers/scsi/README.st> in the kernel source.  This is NOT for
+  SCSI CD-ROMs.
+
+  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 st.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_CHR_DEV_OSST
+  The OnStream SC-x0 SCSI tape drives can not be driven by the
+  standard st driver, but instead need this special osst driver and
+  use the  /dev/osstX char device nodes (major 206).  Via usb-storage
+  and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives
+  as well.  Note that there is also a second generation of OnStream
+  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
+  <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/>
+  Please also have a look at the standard st docu, as most of it
+  applies to osst as well.
+
+  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 osst.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_BLK_DEV_SR
+  If you want to use a SCSI CD-ROM under Linux, say Y and read the
+  SCSI-HOWTO and the CD-ROM-HOWTO at
+  <http://www.linuxdoc.org/docs.html#howto>. Also make sure to say Y
+  or M to "ISO 9660 CD-ROM file system support" later.
+
+  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 sr_mod.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_SR_EXTRA_DEVS
+  This controls the amount of additional space allocated in tables for
+  drivers that are loaded as modules after the kernel is booted. In
+  the event that the SCSI core itself was loaded as a module, this
+  value is the number of additional CD-ROMs that can be loaded after
+  the first host driver is loaded.
+
+  Admittedly this isn't pretty, but there are tons of race conditions
+  involved with resizing the internal arrays on the fly.  Someday this
+  flag will go away, and everything will work automatically.
+
+  If you don't understand what's going on, go with the default.
+
+CONFIG_BLK_DEV_SR_VENDOR
+  This enables the usage of vendor specific SCSI commands. This is
+  required to support multisession CDs with old NEC/TOSHIBA cdrom
+  drives (and HP Writers). If you have such a drive and get the first
+  session only, try saying Y here; everybody else says N.
+
+CONFIG_CHR_DEV_SG
+  If you want to use SCSI scanners, synthesizers or CD-writers or just
+  about anything having "SCSI" in its name other than hard disks,
+  CD-ROMs or tapes, say Y here. These won't be supported by the kernel
+  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 Cdrtools
+  (<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html>)
+  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.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>. The module will be called sg.o. If unsure,
+  say N.
+
+CONFIG_SCSI_MULTI_LUN
+  If you have a SCSI device that supports more than one LUN (Logical
+  Unit Number), e.g. a CD jukebox, and only one LUN is detected, you
+  can say Y here to force the SCSI driver to probe for multiple LUNs.
+  A SCSI device with multiple LUNs acts logically like multiple SCSI
+  devices. The vast majority of SCSI devices have only one LUN, and
+  so most people can say N here and should in fact do so, because it
+  is safer.
+
+CONFIG_SCSI_CONSTANTS
+  The error messages regarding your SCSI hardware will be easier to
+  understand if you say Y here; it will enlarge your kernel by about
+  12 KB. If in doubt, say Y.
+
+CONFIG_SCSI_LOGGING
+  This turns on a logging facility that can be used to debug a number
+  of SCSI related problems.
+
+  If you say Y here, no logging output will appear by default, but you
+  can enable logging by saying Y to "/proc file system support" and
+  "Sysctl support" below and executing the command
+
+     echo "scsi log token [level]" > /proc/scsi/scsi
+
+  at boot time after the /proc file system has been mounted.
+
+  There are a number of things that can be used for 'token' (you can
+  find them in the source: <file:drivers/scsi/scsi.c>), and this
+  allows you to select the types of information you want, and the
+  level allows you to select the level of verbosity.
+
+  If you say N here, it may be harder to track down some types of SCSI
+  problems. If you say Y here your kernel will be somewhat larger, but
+  there should be no noticeable performance impact as long as you have
+  logging turned off.
+
+CONFIG_SCSI_AIC7XXX_OLD
+  WARNING This driver is an older aic7xxx driver and is no longer
+  under active development.  Adaptec, Inc. is writing a new driver to
+  take the place of this one, and it is recommended that whenever
+  possible, people should use the new Adaptec written driver instead
+  of this one.  This driver will eventually be phased out entirely.
+
+  This is support for the various aic7xxx based Adaptec SCSI
+  controllers. These include the 274x EISA cards; 284x VLB cards;
+  2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and
+  motherboard based SCSI controllers from Adaptec. It does not support
+  the AAA-13x RAID controllers from Adaptec, nor will it likely ever
+  support them. It does not support the 2920 cards from Adaptec that
+  use the Future Domain SCSI controller chip. For those cards, you
+  need the "Future Domain 16xx SCSI support" driver.
+
+  In general, if the controller is based on an Adaptec SCSI controller
+  chip from the aic777x series or the aic78xx series, this driver
+  should work. The only exception is the 7810 which is specifically
+  not supported (that's the RAID controller chip on the AAA-13x
+  cards).
+
+  Note that the AHA2920 SCSI host adapter is *not* supported by this
+  driver; choose "Future Domain 16xx SCSI support" instead if you have
+  one of those.
+
+  Information on the configuration options for this controller can be
+  found by checking the help file for each of the available
+  configuration options. You should read
+  <file:drivers/scsi/aic7xxx_old/README.aic7xxx> at a minimum before
+  contacting the maintainer with any questions.  The SCSI-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>, can also
+  be of great help.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called aic7xxx_old.o.
+
+CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
+  This option causes the aic7xxx driver to attempt to use Tagged
+  Command Queueing (TCQ) on all devices that claim to support it.
+
+  TCQ is a feature of SCSI-2 which improves performance: the host
+  adapter can send several SCSI commands to a device's queue even if
+  previous commands haven't finished yet.  Because the device is
+  intelligent, it can optimize its operations (like head positioning)
+  based on its own request queue.  Not all devices implement this
+  correctly.
+
+  If you say Y here, you can still turn off TCQ on troublesome devices
+  with the use of the tag_info boot parameter.  See the file
+  <file:drivers/scsi/README.aic7xxx> for more information on that and
+  other aic7xxx setup commands.  If this option is turned off, you may
+  still enable TCQ on known good devices by use of the tag_info boot
+  parameter.
+
+  If you are unsure about your devices then it is safest to say N
+  here.
+
+  However, TCQ can increase performance on some hard drives by as much
+  as 50% or more, so it is recommended that if you say N here, you
+  should at least read the <file:drivers/scsi/README.aic7xxx> file so
+  you will know how to enable this option manually should your drives
+  prove to be safe in regards to TCQ.
+
+  Conversely, certain drives are known to lock up or cause bus resets
+  when TCQ is enabled on them.  If you have a Western Digital
+  Enterprise SCSI drive for instance, then don't even bother to enable
+  TCQ on it as the drive will become unreliable, and it will actually
+  reduce performance.
+
+CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
+  Specify the number of commands you would like to allocate per SCSI
+  device when Tagged Command Queueing (TCQ) is enabled on that device.
+
+  Reasonable figures are in the range of 8 to 24 commands per device,
+  but depending on hardware could be increased or decreased from that
+  figure. If the number is too high for any particular device, the
+  driver will automatically compensate usually after only 10 minutes
+  of uptime. It will not hinder performance if some of your devices
+  eventually have their command depth reduced, but is a waste of
+  memory if all of your devices end up reducing this number down to a
+  more reasonable figure.
+
+  NOTE: Certain very broken drives are known to lock up when given
+  more commands than they like to deal with. Quantum Fireball drives
+  are the most common in this category. For the Quantum Fireball
+  drives it is suggested to use no more than 8 commands per device.
+
+  Default: 8
+
+CONFIG_AIC7XXX_OLD_PROC_STATS
+  This option tells the driver to keep track of how many commands have
+  been sent to each particular device and report that information to
+  the user via the /proc/scsi/aic7xxx/n file, where n is the number of
+  the aic7xxx controller you want the information on. This adds a
+  small amount of overhead to each and every SCSI command the aic7xxx
+  driver handles, so if you aren't really interested in this
+  information, it is best to leave it disabled. This will only work if
+  you also say Y to "/proc file system support", below.
+
+  If unsure, say N.
+
+CONFIG_SCSI_SYM53C8XX_2
+  This driver supports the whole NCR53C8XX/SYM53C8XX family of 
+  PCI-SCSI controllers. It also supports the subset of LSI53C10XX 
+  Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS 
+  language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI 
+  controllers.
+
+  If your system has problems using this new major version of the
+  SYM53C8XX driver, you may switch back to driver version 1.
+
+  Please read <file:drivers/scsi/sym53c8xx_2/Documentation.txt> for more
+  information.
+
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE
+  This option only applies to PCI-SCSI chip that are PCI DAC capable 
+  (875A, 895A, 896, 1010-33, 1010-66, 1000).
+
+  When set to 0, only PCI 32 bit DMA addressing (SAC) will be performed.
+  When set to 1, 40 bit DMA addressing (with upper 24 bits of address 
+  set to zero) is supported. The addressable range is here 1 TB.
+  When set to 2, full 64 bits of address for DMA are supported, but only
+  16 segments of 4 GB can be addressed. The addressable range is so 
+  limited to 64 GB.
+
+  The safest value is 0 (32 bit DMA addressing) that is guessed to still 
+  fit most of real machines.
+
+  The preferred value 1 (40 bit DMA addressing) should make happy 
+  properly engineered PCI DAC capable host bridges. You may configure
+  this option for Intel platforms with more than 4 GB of memory.
+
+  The still experimental value 2 (64 bit DMA addressing with 16 x 4GB 
+  segments limitation) can be used on systems that require PCI address 
+  bits past bit 39 to be set for the addressing of memory using PCI 
+  DAC cycles.
+
+CONFIG_SCSI_SYM53C8XX_IOMAPPED
+  If you say Y here, the driver will preferently use normal IO rather than 
+  memory mapped IO.
+
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS
+  This option allows you to specify the maximum number of commands
+  that can be queued to any device, when tagged command queuing is
+  possible. The driver supports up to 256 queued commands per device.
+  This value is used as a compiled-in hard limit.
+
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS
+  This is the default value of the command queue depth the driver will 
+  announce to the generic SCSI layer for devices that support tagged 
+  command queueing. This value can be changed from the boot command line.
+  This is a soft limit that cannot exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS.
+
+CONFIG_SCSI_NCR53C8XX
+  This is the BSD ncr driver adapted to Linux for the NCR53C8XX family
+  of PCI-SCSI controllers.  This driver supports parity checking,
+  tagged command queuing and fast synchronous data transfers up to 80
+  MB/s with wide FAST-40 LVD devices and controllers.
+
+  Recent versions of the 53C8XX chips are better supported by the
+  option "SYM53C8XX SCSI support", below.
+
+  Note: there is yet another driver for the 53c8xx family of
+  controllers ("NCR53c7,8xx SCSI support" above).  If you want to use
+  them both, you need to say M to both and build them as modules, but
+  only one may be active at a time.  If you have a 53c8xx board, you
+  probably do not want to use the "NCR53c7,8xx SCSI support".
+
+  Please read <file:drivers/scsi/README.ncr53c8xx> for more
+  information.
+
+CONFIG_SCSI_SYM53C8XX
+  This driver supports all the features of recent 53C8XX chips (used
+  in PCI SCSI controllers), notably the hardware phase mismatch
+  feature of the SYM53C896.
+
+  Older versions of the 53C8XX chips are not supported by this
+  driver.  If your system uses either a 810 rev. < 16, a 815, or a 825
+  rev. < 16 PCI SCSI processor, you must use the generic NCR53C8XX
+  driver ("NCR53C8XX SCSI support" above) or configure both the
+  NCR53C8XX and this SYM53C8XX drivers either as module or linked to
+  the kernel image.
+
+  When both drivers are linked into the kernel, the SYM53C8XX driver
+  is called first at initialization and you can use the 'excl=ioaddr'
+  driver boot option to exclude attachment of adapters by the
+  SYM53C8XX driver.  For example, entering
+  'sym53c8xx=excl:0xb400,excl=0xc000' at the lilo prompt prevents
+  adapters at io address 0xb400 and 0xc000 from being attached by the
+  SYM53C8XX driver, thus allowing the NCR53C8XX driver to attach them.
+  The 'excl' option is also supported by the NCR53C8XX driver.
+
+  Please read <file:drivers/scsi/README.ncr53c8xx> for more
+  information.
+
+CONFIG_SCSI_NCR53C8XX_SYNC
+  The SCSI Parallel Interface-2 Standard defines 5 classes of transfer
+  rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80.  The numbers
+  are respectively the maximum data transfer rates in mega-transfers
+  per second for each class.  For example, a FAST-20 Wide 16 device is
+  able to transfer data at 20 million 16 bit packets per second for a
+  total rate of 40 MB/s.
+
+  You may specify 0 if you want to only use asynchronous data
+  transfers. This is the safest and slowest option. Otherwise, specify
+  a value between 5 and 80, depending on the capability of your SCSI
+  controller.  The higher the number, the faster the data transfer.
+  Note that 80 should normally be ok since the driver decreases the
+  value automatically according to the controller's capabilities.
+
+  Your answer to this question is ignored for controllers with NVRAM,
+  since the driver will get this information from the user set-up.  It
+  also can be overridden using a boot setup option, as follows
+  (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate
+  for FAST-20 synchronous data transfer (20 mega-transfers per
+  second).
+
+  The normal answer therefore is not to go with the default but to
+  select the maximum value 80 allowing the driver to use the maximum
+  value supported by each controller. If this causes problems with
+  your SCSI devices, you should come back and decrease the value.
+
+  There is no safe option other than using good cabling, right
+  terminations and SCSI conformant devices.
+
+CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
+  This option is only provided for safety if you suspect some SCSI
+  device of yours to not support properly the target-disconnect
+  feature. In that case, you would say Y here. In general however, to
+  not allow targets to disconnect is not reasonable if there is more
+  than 1 device on a SCSI bus. The normal answer therefore is N.
+
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS
+  "Tagged command queuing" is a feature of SCSI-2 which improves
+  performance: the host adapter can send several SCSI commands to a
+  device's queue even if previous commands haven't finished yet.
+  Because the device is intelligent, it can optimize its operations
+  (like head positioning) based on its own request queue. Some SCSI
+  devices don't implement this properly; if you want to disable this
+  feature, enter 0 or 1 here (it doesn't matter which).
+
+  The default value is 8 and should be supported by most hard disks.
+  This value can be overridden from the boot command line using the
+  'tags' option as follows (example):
+  'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to
+  4, set queue depth to 16 for target 2 and target 3 on controller 0
+  and set queue depth to 10 for target 0 / lun 2 on controller 1.
+
+  The normal answer therefore is to go with the default 8 and to use
+  a boot command line option for devices that need to use a different
+  command queue depth.
+
+  There is no safe option other than using good SCSI devices.
+
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS
+  This option allows you to specify the maximum number of commands
+  that can be queued to any device, when tagged command queuing is
+  possible. The default value is 32. Minimum is 2, maximum is 64.
+  Modern hard disks are able to support 64 tags and even more, but
+  do not seem to be faster when more than 32 tags are being used.
+
+  So, the normal answer here is to go with the default value 32 unless
+  you are using very large hard disks with large cache (>= 1 MB) that
+  are able to take advantage of more than 32 tagged commands.
+
+  There is no safe option and the default answer is recommended.
+
+CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
+  This option allows you to enable some features depending on GPIO
+  wiring. These General Purpose Input/Output pins can be used for
+  vendor specific features or implementation of the standard SYMBIOS
+  features. Genuine SYMBIOS controllers use GPIO0 in output for
+  controller LED and GPIO3 bit as a flag indicating
+  singled-ended/differential interface. The Tekram DC-390U/F boards
+  uses a different GPIO wiring.
+
+  Your answer to this question is ignored if all your controllers have
+  NVRAM, since the driver is able to detect the board type from the
+  NVRAM format.
+
+  If all the controllers in your system are genuine SYMBIOS boards or
+  use BIOS and drivers from SYMBIOS, you would want to say Y here,
+  otherwise N. N is the safe answer.
+
+CONFIG_SCSI_NCR53C8XX_PROFILE
+  This option allows you to enable profiling information gathering.
+  These statistics are not very accurate due to the low frequency
+  of the kernel clock (100 Hz on i386) and have performance impact
+  on systems that use very fast devices.
+
+  The normal answer therefore is N.
+
+CONFIG_SCSI_NCR53C8XX_PQS_PDS
+  Say Y here if you have a special SCSI adapter produced by NCR
+  corporation called a PCI Quad SCSI or PCI Dual SCSI. You do not need
+  this if you do not have one of these adapters. However, since this
+  device is detected as a specific PCI device, this option is quite
+  safe.
+
+  The common answer here is N, but answering Y is safe.
+
+CONFIG_SCSI_QLOGIC_ISP
+  This driver works for all QLogic PCI SCSI host adapters (IQ-PCI,
+  IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card.  (This latter
+  card is supported by the "AM53/79C974 PCI SCSI" driver.)
+
+  If you say Y here, make sure to choose "BIOS" at the question "PCI
+  access mode".
+
+  Please read the file <file:drivers/scsi/README.qlogicisp>.  You
+  should also read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called qlogicisp.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_QLOGIC_FC
+  This is a driver for the QLogic ISP2100 SCSI-FCP host adapter.
+
+  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 qlogicfc.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_VT
+  If you say Y here, you will get support for terminal devices with
+  display and keyboard devices. These are called "virtual" because you
+  can run several virtual terminals (also called virtual consoles) on
+  one physical terminal. This is rather useful, for example one
+  virtual terminal can collect system messages and warnings, another
+  one can be used for a text-mode user session, and a third could run
+  an X session, all in parallel. Switching between virtual terminals
+  is done with certain key combinations, usually Alt-<function key>.
+
+  The setterm command ("man setterm") can be used to change the
+  properties (such as colors or beeping) of a virtual terminal. The
+  man page console_codes(4) ("man console_codes") contains the special
+  character sequences that can be used to change those properties
+  directly. The fonts used on virtual terminals can be changed with
+  the setfont ("man setfont") command and the key bindings are defined
+  with the loadkeys ("man loadkeys") command.
+
+  You need at least one virtual terminal device in order to make use
+  of your keyboard and monitor. Therefore, only people configuring an
+  embedded system would want to say N here in order to save some
+  memory; the only way to log into such a system is then via a serial
+  or network connection.
+
+  If unsure, say Y, or else you won't be able to do much with your new
+  shiny Linux system :-)
+
+CONFIG_VT_CONSOLE
+  The system console is the device which receives all kernel messages
+  and warnings and which allows logins in single user mode. If you
+  answer Y here, a virtual terminal (the device used to interact with
+  a physical terminal) can be used as system console. This is the most
+  common mode of operations, so you should say Y here unless you want
+  the kernel messages be output only to a serial port (in which case
+  you should say Y to "Console on serial port", below).
+
+  If you do say Y here, by default the currently visible virtual
+  terminal (/dev/tty0) will be used as system console. You can change
+  that with a kernel command line option such as "console=tty3" which
+  would use the third virtual terminal as system console. (Try "man
+  bootparam" or see the documentation of your boot loader (lilo or
+  loadlin) about how to pass options to the kernel at boot time.)
+
+  If unsure, say Y.
+
+CONFIG_SERIAL
+  This selects whether you want to include the driver for the standard
+  serial ports.  The standard answer is Y.  People who might say N
+  here are those that are setting up dedicated Ethernet WWW/FTP
+  servers, or users that have one of the various bus mice instead of a
+  serial mouse and don't intend to use their machine's standard serial
+  port for anything.  (Note that the Cyclades and Stallion multi
+  serial port drivers do not need this driver built in for them to
+  work.)
+
+  If you want to compile this driver as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  serial.o.
+  [WARNING: Do not compile this driver as a module if you are using
+  non-standard serial ports, since the configuration information will
+  be lost when the driver is unloaded.  This limitation may be lifted
+  in the future.]
+
+  BTW1: If you have a mouseman serial mouse which is not recognized by
+  the X window system, try running gpm first.
+
+  BTW2: If you intend to use a software modem (also called Winmodem)
+  under Linux, forget it.  These modems are crippled and require
+  proprietary drivers which are only available under Windows.
+
+  Most people will say Y or M here, so that they can use serial mice,
+  modems and similar devices connecting to the standard serial ports.
+
+CONFIG_SERIAL_CONSOLE
+  If you say Y here, it will be possible to use a serial port as the
+  system console (the system console is the device which receives all
+  kernel messages and warnings and which allows logins in single user
+  mode). This could be useful if some terminal or printer is connected
+  to that serial port.
+
+  Even if you say Y here, the currently visible virtual console
+  (/dev/tty0) will still be used as the system console by default, but
+  you can alter that using a kernel command line option such as
+  "console=ttyS1". (Try "man bootparam" or see the documentation of
+  your boot loader (lilo or loadlin) about how to pass options to the
+  kernel at boot time.)
+
+  If you don't have a VGA card installed and you say Y here, the
+  kernel will automatically use the first serial line, /dev/ttyS0, as
+  system console.
+
+  If unsure, say N.
+
+CONFIG_UNIX98_PTYS
+  A pseudo terminal (PTY) is a software device consisting of two
+  halves: a master and a slave. The slave device behaves identical to
+  a physical terminal; the master device is used by a process to
+  read data from and write data to the slave, thereby emulating a
+  terminal. Typical programs for the master side are telnet servers
+  and xterms.
+
+  Linux has traditionally used the BSD-like names /dev/ptyxx for
+  masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
+  has a number of problems. The GNU C library glibc 2.1 and later,
+  however, supports the Unix98 naming standard: in order to acquire a
+  pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
+  terminal is then made available to the process and the pseudo
+  terminal slave can be accessed as /dev/pts/<number>. What was
+  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
+
+  The entries in /dev/pts/ are created on the fly by a virtual
+  file system; therefore, if you say Y here you should say Y to
+  "/dev/pts file system for Unix98 PTYs" as well.
+
+  If you want to say Y here, you need to have the C library glibc 2.1
+  or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
+  Read the instructions in <file:Documentation/Changes> pertaining to
+  pseudo terminals. It's safe to say N.
+
+CONFIG_UNIX98_PTY_COUNT
+  The maximum number of Unix98 PTYs that can be used at any one time.
+  The default is 256, and should be enough for desktop systems. Server
+  machines which support incoming telnet/rlogin/ssh connections and/or
+  serve several X terminals may want to increase this: every incoming
+  connection and every xterm uses up one PTY.
+
+  When not in use, each additional set of 256 PTYs occupy
+  approximately 8 KB of kernel memory on 32-bit architectures.
+
+CONFIG_PRINTER
+  If you intend to attach a printer to the parallel port of your Linux
+  box (as opposed to using a serial printer; if the connector at the
+  printer has 9 or 25 holes ["female"], then it's serial), say Y.
+  Also read the Printing-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  It is possible to share one parallel port among several devices
+  (e.g. printer and ZIP drive) and it is safe to compile the
+  corresponding drivers into the kernel.  If you want to compile this
+  driver as a module however ( = code which can be inserted in and
+  removed from the running kernel whenever you want), say M here and
+  read <file:Documentation/modules.txt> and
+  <file:Documentation/parport.txt>.  The module will be called lp.o.
+
+  If you have several parallel ports, you can specify which ports to
+  use with the "lp" kernel command line option.  (Try "man bootparam"
+  or see the documentation of your boot loader (lilo or loadlin) about
+  how to pass options to the kernel at boot time.)  The syntax of the
+  "lp" command line option can be found in <file:drivers/char/lp.c>.
+
+  If you have more than 8 printers, you need to increase the LP_NO
+  macro in lp.c and the PARPORT_MAX macro in parport.h.
+
+CONFIG_BBC_I2C
+  The BBC devices on the UltraSPARC III have two I2C controllers.  The
+  first I2C controller connects mainly to configuration PROMs (NVRAM,
+  CPU configuration, DIMM types, etc.).  The second I2C controller
+  connects to environmental control devices such as fans and
+  temperature sensors.  The second controller also connects to the
+  smartcard reader, if present.  Say Y to enable support for these.
+
+CONFIG_BUSMOUSE
+  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 a laptop, you either have to check the documentation or
+  experiment a bit to find out whether the trackball is a serial mouse
+  or not; it's best to say Y here for you.
+
+  This is the generic bus mouse driver code. If you have a bus mouse,
+  you will have to say Y here and also to the specific driver for your
+  mouse below.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called busmouse.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_DRM
+  Kernel-level support for the Direct Rendering Infrastructure (DRI)
+  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
+  details.  You should also select and configure AGP
+  (/dev/agpgart) support.
+
+CONFIG_DRM_TDFX
+  Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
+  graphics card.  If M is selected, the module will be called tdfx.o.
+
+CONFIG_DRM_R128
+  Choose this option if you have an ATI Rage 128 graphics card.  If M
+  is selected, the module will be called r128.o.  AGP support for
+  this card is strongly suggested (unless you have a PCI version).
+
+CONFIG_DRM_FFB
+  Choose this option if you have one of Sun's Creator3D-based graphics
+  and frame buffer cards.  Product page at
+  <http://www.sun.com/desktop/products/Graphics/creator3d.html>.
+
+CONFIG_SOFT_WATCHDOG
+  A software monitoring watchdog. This will fail to reboot your system
+  from some situations that the hardware watchdog will recover
+  from. Equally it's a lot cheaper to install.
+
+  This driver is also available 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>. The module will be called
+   softdog.o.
+
+CONFIG_RTC
+  If you say Y here and create a character special file /dev/rtc with
+  major number 10 and minor number 135 using mknod ("man mknod"), you
+  will get access to the real time clock (or hardware clock) built
+  into your computer.
+
+  Every PC has such a clock built in. It can be used to generate
+  signals from as low as 1Hz up to 8192Hz, and can also be used
+  as a 24 hour alarm. It reports status information via the file
+  /proc/driver/rtc and its behaviour is set by various ioctls on
+  /dev/rtc.
+
+  If you run Linux on a multiprocessor machine and said Y to
+  "Symmetric Multi Processing" above, you should say Y here to read
+  and set the RTC in an SMP compatible fashion.
+
+  If you think you have a use for such a device (such as periodic data
+  sampling), then say Y here, and read <file:Documentation/rtc.txt>
+  for details.
+
+  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 is called rtc.o. If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y.  Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. General information about
+  the modular sound system is contained in the files
+  <file:Documentation/sound/Introduction>.  The file
+  <file:Documentation/sound/README.OSS> contains some slightly
+  outdated but still useful information as well.
+
+  If you have a PnP sound card and you want to configure it at boot
+  time using the ISA PnP tools (read
+  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+  compile the sound card support as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  and load that module after the PnP configuration is finished.  To do
+  this, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/sound/README.modules>; the module will be
+  called soundcore.o.
+
+  I'm told that even without a sound card, you can make your computer
+  say more than an occasional beep, by programming the PC speaker.
+  Kernel patches and supporting utilities to do that are in the pcsp
+  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+CONFIG_MAGIC_SYSRQ
+  If you say Y here, you will have some control over the system even
+  if the system crashes for example during kernel debugging (e.g., you
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+  also works on a serial console (on PC hardware at least), if you
+  send a BREAK and then within 5 seconds a command keypress. The
+  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+  unless you really know what this hack does.
+
+CONFIG_SCSI_SUNESP
+  This is the driver for the Sun ESP SCSI host adapter. The ESP
+  chipset is present in most SPARC SBUS-based computers.
+
+  This support is also available as a module called esp.o ( = 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>.
+
+CONFIG_SCSI_QLOGICPTI
+  This driver supports SBUS SCSI controllers from PTI or QLogic. These
+  controllers are known under Solaris as qpti and in the openprom as
+  PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are
+  driven by a different driver.
+
+  This support is also available as a module called qlogicpti.o ( =
+  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>.
+
+CONFIG_PROM_CONSOLE
+  Say Y to build a console driver for Sun machines that uses the
+  terminal emulation built into their console PROMS.
+
+CONFIG_SUN_OPENPROMFS
+  If you say Y, the OpenPROM device tree will be available as a
+  virtual file system, which you can mount to /proc/openprom by "mount
+  -t openpromfs none /proc/openprom".
+
+  If you want to compile the /proc/openprom 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 openpromfs.o.  If unsure, say M.
+
+CONFIG_SPARC32_COMPAT
+  This allows you to run 32-bit binaries on your Ultra.
+  Everybody wants this; say Y.
+
+CONFIG_BINFMT_ELF32
+  This allows you to run 32-bit Linux/ELF binaries on your Ultra.
+  Everybody wants this; say Y.
+
+CONFIG_BINFMT_AOUT32
+  This allows you to run 32-bit a.out format binaries on your Ultra.
+  If you want to run SunOS binaries (see SunOS binary emulation below)
+  or other a.out binaries, say Y. If unsure, say N.
+
+CONFIG_SUNOS_EMUL
+  This allows you to run most SunOS binaries.  If you want to do this,
+  say Y here and place appropriate files in /usr/gnemul/sunos. See
+  <http://www.ultralinux.org/faq.html> for more information.  If you
+  want to run SunOS binaries on an Ultra you must also say Y to
+  "Kernel support for 32-bit a.out binaries" above.
+
+CONFIG_SUN_KEYBOARD
+  Say Y here to support the keyboard found on Sun 3 and 3x
+  workstations.  It can also be used support Sun Type-5 keyboards
+  through an adaptor.  See
+  <http://www.suse.cz/development/input/adapters.html> and
+  <http://sourceforge.net/projects/linuxconsole/> for details on the
+  latter.
+
+CONFIG_VIDEO_DEV
+  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/>.
+
+  If you are interested in writing a driver for such an audio/video
+  device or user software interacting with such a driver, please read
+  the file <file:Documentation/video4linux/API.html>.
+
+  This driver is also available as a module called videodev.o ( = 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>.
+
+CONFIG_VIDEO_BT848
+  Support for BT848 based frame grabber/overlay boards. This includes
+  the Miro, Hauppauge and STB boards. Please read the material in
+  <file:Documentation/video4linux/bttv> for more information.
+
+  If you say Y or M here, you need to say Y or M to "I2C support" and
+  "I2C bit-banging interfaces" in the character device section.
+
+  This driver is available as a module called bttv.o ( = 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>.
+
+CONFIG_DISPLAY7SEG
+  This is the driver for the 7-segment display and LED present on
+  Sun Microsystems CompactPCI models CP1400 and CP1500.
+
+  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 display7seg.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+  If you do not have a CompactPCI model CP1400 or CP1500, or
+  another UltraSPARC-IIi-cEngine boardset with a 7-segment display,
+  you should say N to this option.
+
+CONFIG_WATCHDOG_RIO
+  Say Y here to support the hardware watchdog capability on Sun RIO
+  machines.  The watchdog timeout period is normally one minute but
+  can be changed with a boot-time parameter.
+
+CONFIG_WATCHDOG_CP1XXX
+  This is the driver for the hardware watchdog timers present on
+  Sun Microsystems CompactPCI models CP1400 and CP1500.
+
+  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 cpwatchdog.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+  If you do not have a CompactPCI model CP1400 or CP1500, or
+  another UltraSPARC-IIi-cEngine boardset with hardware watchdog,
+  you should say N to this option.
+
+CONFIG_DEBUG_KERNEL
+  Say Y here if you are developing drivers or trying to debug and
+  identify kernel problems.
+
+CONFIG_DEBUG_SLAB
+  Say Y here to have the kernel do limited verification on memory
+  allocation as well as poisoning memory on free to catch use of freed
+  memory.
+
+CONFIG_DEBUG_SPINLOCK
+  Say Y here and build SMP to catch missing spinlock initialization
+  and certain other kinds of spinlock errors commonly made.  This is
+  best used in conjunction with the NMI watchdog so that spinlock
+  deadlocks are also debuggable.
+
+CONFIG_DEBUG_BUGVERBOSE
+  Say Y here to make BUG() panics output the file name and line number
+  of the BUG call as well as the EIP and oops trace.  This aids
+  debugging but costs about 70-100K of memory.
+
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.5.2/linux/arch/sparc64/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/config.in	Thu Jan 24 22:04:21 2002
@@ -1,22 +1,10 @@
-# $Id: config.in,v 1.156 2001/11/30 00:17:32 davem Exp $
+# $Id: config.in,v 1.158 2002/01/24 22:14:44 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
 mainmenu_name "Linux/UltraSPARC Kernel Configuration"
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all symbols for modules' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
-endmenu
+source init/Config.in
 
 mainmenu_option next_comment
 comment 'General setup'
@@ -60,10 +48,6 @@
 source drivers/pci/Config.in
 
 tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS
-bool 'Networking support' CONFIG_NET
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
 if [ "$CONFIG_PROC_FS" = "y" ]; then
    define_bool CONFIG_KCORE_ELF y
 fi
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.5.2/linux/arch/sparc64/defconfig	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/defconfig	Thu Jan 24 22:04:21 2002
@@ -3,6 +3,14 @@
 #
 
 #
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
@@ -46,10 +54,6 @@
 CONFIG_RTC=y
 # CONFIG_PCI_NAMES is not set
 CONFIG_SUN_OPENPROMFS=m
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 CONFIG_SPARC32_COMPAT=y
 CONFIG_BINFMT_ELF32=y
@@ -104,6 +108,7 @@
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 CONFIG_FB_SBUS=y
@@ -253,6 +258,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -267,6 +273,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -278,12 +285,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_IDEDMA_ONLYDISK=y
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 CONFIG_BLK_DEV_ALI15X3=y
@@ -298,6 +308,7 @@
 # CONFIG_BLK_DEV_HPT366 is not set
 CONFIG_BLK_DEV_NS87415=y
 # CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC_ADMA is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
 # CONFIG_PDC202XX_BURST is not set
 # CONFIG_PDC202XX_FORCE is not set
@@ -410,6 +421,7 @@
 #
 # CONFIG_IEEE1394_VIDEO1394 is not set
 CONFIG_IEEE1394_SBP2=m
+CONFIG_IEEE1394_DV1394=m
 CONFIG_IEEE1394_RAWIO=m
 # CONFIG_IEEE1394_VERBOSEDEBUG is not set
 
@@ -742,6 +754,7 @@
 # USB Host Controller Drivers
 #
 CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_OHCI_HCD is not set
 CONFIG_USB_UHCI=y
 # CONFIG_USB_UHCI_ALT is not set
 CONFIG_USB_OHCI=y
@@ -869,3 +882,8 @@
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_DCFLUSH is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- v2.5.2/linux/arch/sparc64/kernel/head.S	Sat Oct  6 08:50:28 2001
+++ linux/arch/sparc64/kernel/head.S	Tue Jan 15 10:52:11 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/init_task.c linux/arch/sparc64/kernel/init_task.c
--- v2.5.2/linux/arch/sparc64/kernel/init_task.c	Thu Sep 20 14:11:57 2001
+++ linux/arch/sparc64/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,5 +1,6 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.5.2/linux/arch/sparc64/kernel/ioctl32.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/ioctl32.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.135 2002/01/11 08:45:38 davem Exp $
+/* $Id: ioctl32.c,v 1.136 2002/01/14 09:49:52 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -1581,12 +1581,17 @@
 	}
 
 	err |= __get_user(sbp32, &sg_io32->sbp);
-	sg_io64.sbp = kmalloc(64, GFP_KERNEL);
+	sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
 	if (!sg_io64.sbp) {
 		err = -ENOMEM;
 		goto out;
 	}
-	memset(sg_io64.sbp, 0, 64);
+	if (copy_from_user(sg_io64.sbp,
+			   (void *) A(sbp32),
+			   sg_io64.mx_sb_len)) {
+		err = -EFAULT;
+		goto out;
+	}
 
 	err |= __get_user(dxferp32, &sg_io32->dxferp);
 	if (sg_io64.iovec_count) {
@@ -1634,7 +1639,7 @@
 	err |= __put_user(sg_io64.resid, &sg_io32->resid);
 	err |= __put_user(sg_io64.duration, &sg_io32->duration);
 	err |= __put_user(sg_io64.info, &sg_io32->info);
-	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, 64);
+	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
 	if (sg_io64.dxferp) {
 		if (sg_io64.iovec_count)
 			err |= copy_back_sg_iovec(&sg_io64, dxferp32);
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c
--- v2.5.2/linux/arch/sparc64/kernel/pci.c	Wed Oct 10 23:42:46 2001
+++ linux/arch/sparc64/kernel/pci.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.36 2001/10/06 00:38:25 davem Exp $
+/* $Id: pci.c,v 1.39 2002/01/05 01:13:43 davem Exp $
  * pci.c: UltraSparc PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -487,7 +487,7 @@
 	/* Our io_remap_page_range takes care of this, do nothing. */
 }
 
-extern int io_remap_page_range(unsigned long from, unsigned long offset,
+extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset,
 			       unsigned long size, pgprot_t prot, int space);
 
 /* Perform the actual remap of the pages for a PCI device mapping, as appropriate
@@ -511,7 +511,7 @@
 	__pci_mmap_set_flags(dev, vma, mmap_state);
 	__pci_mmap_set_pgprot(dev, vma, mmap_state);
 
-	ret = io_remap_page_range(vma->vm_start,
+	ret = io_remap_page_range(vma, vma->vm_start,
 				  (vma->vm_pgoff << PAGE_SHIFT |
 				   (write_combine ? 0x1UL : 0x0UL)),
 				  vma->vm_end - vma->vm_start, vma->vm_page_prot, 0);
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c
--- v2.5.2/linux/arch/sparc64/kernel/pci_common.c	Tue Aug 14 19:57:28 2001
+++ linux/arch/sparc64/kernel/pci_common.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.27 2001/08/12 13:18:22 davem Exp $
+/* $Id: pci_common.c,v 1.28 2002/01/14 05:47:02 davem Exp $
  * pci_common.c: PCI controller common support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -183,6 +183,17 @@
 		pcp->prom_name[err] = 0;
 	else
 		pcp->prom_name[0] = 0;
+
+	err = prom_getproperty(device_prom_node,
+			       "assigned-addresses",
+			       (char *)pcp->prom_assignments,
+			       sizeof(pcp->prom_assignments));
+	if (err == 0 || err == -1)
+		pcp->num_prom_assignments = 0;
+	else
+		pcp->num_prom_assignments =
+			(err / sizeof(pcp->prom_assignments[0]));
+
 	if (strcmp(pcp->prom_name, "ebus") == 0) {
 		struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX];
 		int iter;
@@ -208,16 +219,6 @@
 			ap->size_lo = ep->size;
 		}
 		pcp->num_prom_assignments = err;
-	} else {
-		err = prom_getproperty(device_prom_node,
-				       "assigned-addresses",
-				       (char *)pcp->prom_assignments,
-				       sizeof(pcp->prom_assignments));
-		if (err == 0 || err == -1)
-			pcp->num_prom_assignments = 0;
-		else
-			pcp->num_prom_assignments =
-				(err / sizeof(pcp->prom_assignments[0]));
 	}
 
 	fixup_obp_assignments(pdev, pcp);
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- v2.5.2/linux/arch/sparc64/kernel/pci_psycho.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/pci_psycho.c	Wed Jan 23 15:28:40 2002
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.31 2002/01/05 07:33:16 davem Exp $
+/* $Id: pci_psycho.c,v 1.32 2002/01/23 11:27:32 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -345,7 +345,7 @@
 /*0x2f*/15,		/* Correctable ECC		*/
 /*0x30*/15,		/* PCI Bus A Error		*/
 /*0x31*/15,		/* PCI Bus B Error		*/
-/*0x32*/1,		/* Power Management		*/
+/*0x32*/15,		/* Power Management		*/
 };
 
 static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
@@ -354,7 +354,7 @@
 
 	ret = psycho_pil_table[ino];
 	if (ret == 0 && pdev == NULL) {
-		ret = 1;
+		ret = 2;
 	} else if (ret == 0) {
 		switch ((pdev->class >> 16) & 0xff) {
 		case PCI_BASE_CLASS_STORAGE:
@@ -377,7 +377,7 @@
 			break;
 
 		default:
-			ret = 1;
+			ret = 2;
 			break;
 		};
 	}
@@ -410,6 +410,10 @@
 
 	/* Now build the IRQ bucket. */
 	pil = psycho_ino_to_pil(pdev, ino);
+
+	if (PIL_RESERVED(pil))
+		BUG();
+
 	imap = p->controller_regs + imap_off;
 	imap += 4;
 
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- v2.5.2/linux/arch/sparc64/kernel/pci_sabre.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/pci_sabre.c	Wed Jan 23 15:28:40 2002
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.41 2001/11/14 13:17:56 davem Exp $
+/* $Id: pci_sabre.c,v 1.42 2002/01/23 11:27:32 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -582,7 +582,7 @@
 /*0x2f*/15,		/* Correctable ECC		*/
 /*0x30*/15,		/* PCI Bus A Error		*/
 /*0x31*/15,		/* PCI Bus B Error		*/
-/*0x32*/1,		/* Power Management		*/
+/*0x32*/15,		/* Power Management		*/
 };
 
 static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
@@ -596,7 +596,7 @@
 
 	ret = sabre_pil_table[ino];
 	if (ret == 0 && pdev == NULL) {
-		ret = 1;
+		ret = 2;
 	} else if (ret == 0) {
 		switch ((pdev->class >> 16) & 0xff) {
 		case PCI_BASE_CLASS_STORAGE:
@@ -619,7 +619,7 @@
 			break;
 
 		default:
-			ret = 1;
+			ret = 2;
 			break;
 		};
 	}
@@ -651,6 +651,10 @@
 
 	/* Now build the IRQ bucket. */
 	pil = sabre_ino_to_pil(pdev, ino);
+
+	if (PIL_RESERVED(pil))
+		BUG();
+
 	imap = p->controller_regs + imap_off;
 	imap += 4;
 
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c
--- v2.5.2/linux/arch/sparc64/kernel/pci_schizo.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/pci_schizo.c	Wed Jan 23 15:28:40 2002
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.23 2001/11/14 13:17:56 davem Exp $
+/* $Id: pci_schizo.c,v 1.24 2002/01/23 11:27:32 davem Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -344,7 +344,7 @@
 
 	ret = schizo_pil_table[ino];
 	if (ret == 0 && pdev == NULL) {
-		ret = 1;
+		ret = 2;
 	} else if (ret == 0) {
 		switch ((pdev->class >> 16) & 0xff) {
 		case PCI_BASE_CLASS_STORAGE:
@@ -367,7 +367,7 @@
 			break;
 
 		default:
-			ret = 1;
+			ret = 2;
 			break;
 		};
 	}
@@ -395,6 +395,10 @@
 
 	/* Now build the IRQ bucket. */
 	pil = schizo_ino_to_pil(pdev, ino);
+
+	if (PIL_RESERVED(pil))
+		BUG();
+
 	imap = p->controller_regs + pbm_off + imap_off;
 	imap += 4;
 
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.5.2/linux/arch/sparc64/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/process.c	Mon Jan 28 15:14:23 2002
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.128 2002/01/11 08:45:38 davem Exp $
+/*  $Id: process.c,v 1.129 2002/01/23 11:27:32 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -54,14 +54,14 @@
 
 	/* endless idle loop with no priority at all */
 	for (;;) {
-		/* If current->need_resched is zero we should really
+		/* If current->work.need_resched is zero we should really
 		 * setup for a system wakup event and execute a shutdown
 		 * instruction.
 		 *
 		 * But this requires writing back the contents of the
 		 * L2 cache etc. so implement this later. -DaveM
 		 */
-		while (!current->need_resched)
+		while (!need_resched())
 			barrier();
 
 		schedule();
@@ -80,7 +80,7 @@
 int cpu_idle(void)
 {
 	while(1) {
-		if (current->need_resched != 0) {
+		if (need_resched()) {
 			unidle_me();
 			schedule();
 			check_pgt_cache();
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- v2.5.2/linux/arch/sparc64/kernel/rtrap.S	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/rtrap.S	Mon Jan 28 15:14:23 2002
@@ -42,14 +42,14 @@
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		/* Redo sched+sig checks */
-		ldx			[%g6 + AOFF_task_need_resched], %l0
+#error		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
+#error1:		lduw			[%g6 + AOFF_task_sigpending], %l0
 		brz,pt			%l0, __handle_user_windows_continue
 		 nop
 		clr			%o0
@@ -82,14 +82,14 @@
 		call			fault_in_user_windows
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-1:		ldx			[%g6 + AOFF_task_need_resched], %l0
+#error 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
+#error 1:		lduw			[%g6 + AOFF_task_sigpending], %l0
 		brz,pt			%l0, __handle_perfctrs_continue
 		 sethi			%hi(TSTATE_PEF), %o0
 		clr			%o0
@@ -173,9 +173,9 @@
 		 */
 to_user:	wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 __handle_preemption_continue:
-		ldx			[%g6 + AOFF_task_need_resched], %l0
+#error		ldx			[%g6 + AOFF_task_need_resched], %l0
 		brnz,pn			%l0, __handle_preemption
-		 lduw			[%g6 + AOFF_task_sigpending], %l0
+#error		 lduw			[%g6 + AOFF_task_sigpending], %l0
 		brnz,pn			%l0, __handle_signal
 		 nop
 __handle_signal_continue:
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c
--- v2.5.2/linux/arch/sparc64/kernel/sbus.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/sbus.c	Wed Jan 23 15:28:40 2002
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.18 2001/12/17 07:05:09 davem Exp $
+/* $Id: sbus.c,v 1.19 2002/01/23 11:27:32 davem Exp $
  * sbus.c: UltraSparc SBUS controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -628,10 +628,10 @@
 
 /* SBUS SYSIO INO number to Sparc PIL level. */
 static unsigned char sysio_ino_to_pil[] = {
-	0, 1, 2, 7, 5, 7, 8, 9,		/* SBUS slot 0 */
-	0, 1, 2, 7, 5, 7, 8, 9,		/* SBUS slot 1 */
-	0, 1, 2, 7, 5, 7, 8, 9,		/* SBUS slot 2 */
-	0, 1, 2, 7, 5, 7, 8, 9,		/* SBUS slot 3 */
+	0, 2, 2, 7, 5, 7, 8, 9,		/* SBUS slot 0 */
+	0, 2, 2, 7, 5, 7, 8, 9,		/* SBUS slot 1 */
+	0, 2, 2, 7, 5, 7, 8, 9,		/* SBUS slot 2 */
+	0, 2, 2, 7, 5, 7, 8, 9,		/* SBUS slot 3 */
 	3, /* Onboard SCSI */
 	5, /* Onboard Ethernet */
 /*XXX*/	8, /* Onboard BPP */
@@ -754,6 +754,10 @@
 		printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino);
 		panic("Bad SYSIO IRQ translations...");
 	}
+
+	if (PIL_RESERVED(pil))
+		BUG();
+
 	imap = sysio_irq_offsets[ino];
 	if (imap == ((unsigned long)-1)) {
 		prom_printf("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.5.2/linux/arch/sparc64/kernel/smp.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/smp.c	Wed Jan 23 15:28:40 2002
@@ -138,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);
 
@@ -209,10 +218,12 @@
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
 
+	init_idle();
+
 	while (!smp_threads_ready)
 		membar("#LoadLoad");
 
-	init_idle();
+	idle_startup_done();
 }
 
 void cpu_panic(void)
@@ -796,9 +807,11 @@
 	}
 }
 
-void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			 unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	{
 		u32 ctx = CTX_HWBITS(mm->context);
 		int cpu = smp_processor_id();
@@ -862,6 +875,48 @@
 	local_flush_and_out:
 		__flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
 	}
+}
+
+/* Process migration IPIs. */
+
+extern unsigned long xcall_migrate_task;
+
+static spinlock_t migration_lock = SPIN_LOCK_UNLOCKED;
+static task_t *new_task;
+
+void smp_migrate_task(int cpu, task_t *p)
+{
+	unsigned long mask = 1UL << cpu;
+
+	if (cpu == smp_processor_id())
+		return;
+
+	if (smp_processors_ready && (cpu_present_map & mask) != 0) {
+		u64 data0 = (((u64)&xcall_migrate_task) & 0xffffffff);
+
+		spin_lock(&migration_lock);
+		new_task = p;
+
+		if (tlb_type == spitfire)
+			spitfire_xcall_deliver(data0, 0, 0, mask);
+		else
+			cheetah_xcall_deliver(data0, 0, 0, mask);
+	}
+}
+
+/* Called at PIL level 1. */
+asmlinkage void smp_task_migration_interrupt(int irq, struct pt_regs *regs)
+{
+	task_t *p;
+
+	if (irq != PIL_MIGRATE)
+		BUG();
+
+	clear_softint(1 << irq);
+
+	p = new_task;
+	spin_unlock(&migration_lock);
+	sched_task_migrated(p);
 }
 
 /* CPU capture. */
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.5.2/linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Tue Jan 15 10:56:35 2002
@@ -88,7 +88,7 @@
 extern long sparc32_open(const char * filename, int flags, int mode);
 extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
 extern int unregister_ioctl32_conversion(unsigned int cmd);
-extern int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
+extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
                 
 extern int __ashrdi3(int, int);
 
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
--- v2.5.2/linux/arch/sparc64/kernel/time.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/time.c	Wed Jan 23 15:28:39 2002
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.41 2001/11/20 18:24:55 kanoj Exp $
+/* $Id: time.c,v 1.42 2002/01/23 14:33:55 davem Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -329,8 +329,6 @@
 	unsigned long dregs = 0UL;
 #endif
 	u8 tmp;
-
-	do_get_fast_time = do_gettimeofday;
 
 	if (!mregs && !dregs) {
 		prom_printf("Something wrong, clock regs not mapped yet.\n");
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S
--- v2.5.2/linux/arch/sparc64/kernel/ttable.S	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/ttable.S	Wed Jan 23 15:28:40 2002
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.36 2001/11/28 23:32:16 davem Exp $
+/* $Id: ttable.S,v 1.37 2002/01/23 11:27:32 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions.
  *
  * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu)
@@ -44,7 +44,12 @@
 tl0_privact:	TRAP_NOSAVE(__do_privact)
 tl0_resv038:	BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d)
 tl0_resv03e:	BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40)
-tl0_irq1:	TRAP_IRQ(handler_irq, 1)  TRAP_IRQ(handler_irq, 2)
+#ifdef CONFIG_SMP
+tl0_irq1:	TRAP_IRQ(smp_task_migration_interrupt, 1)
+#else
+tl0_irq1:	BTRAP(0x41)
+#endif
+tl0_irq2:	TRAP_IRQ(handler_irq, 2)
 tl0_irq3:	TRAP_IRQ(handler_irq, 3)  TRAP_IRQ(handler_irq, 4)
 tl0_irq5:	TRAP_IRQ(handler_irq, 5)  TRAP_IRQ(handler_irq, 6)
 tl0_irq7:	TRAP_IRQ(handler_irq, 7)  TRAP_IRQ(handler_irq, 8)
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/lib/U3copy_from_user.S linux/arch/sparc64/lib/U3copy_from_user.S
--- v2.5.2/linux/arch/sparc64/lib/U3copy_from_user.S	Thu Nov  9 15:57:41 2000
+++ linux/arch/sparc64/lib/U3copy_from_user.S	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: U3copy_from_user.S,v 1.3 2000/11/01 09:29:19 davem Exp $
+/* $Id: U3copy_from_user.S,v 1.4 2002/01/15 07:16:26 davem Exp $
  * U3memcpy.S: UltraSparc-III optimized copy from userspace.
  *
  * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
@@ -13,7 +13,7 @@
 	.section .fixup;		\
 	.align 4;			\
 99:	VISExitHalf;			\
-	ba,pt %xcc, U3cfu_fixup;	\
+	ba U3cfu_fixup;			\
 	 a, b, %o1;			\
 	.section __ex_table;		\
 	.align 4;			\
@@ -25,7 +25,7 @@
 	.section .fixup;		\
 	.align 4;			\
 99:	VISExitHalf;			\
-	ba,pt %xcc, U3cfu_fixup;	\
+	ba U3cfu_fixup;			\
 	 a, b, %o1;			\
 	.section __ex_table;		\
 	.align 4;			\
@@ -39,7 +39,7 @@
 99:	VISExitHalf;			\
 	and %o2, (0x40 - 1), %o1;	\
 	add %o1, %o4, %o1;		\
-	ba,pt %xcc, U3cfu_fixup;	\
+	ba U3cfu_fixup;			\
 	 add %o1, 0x1c0, %o1;		\
 	.section __ex_table;		\
 	.align 4;			\
@@ -54,7 +54,7 @@
 	and %o2, (0x40 - 1), %o1;	\
 	sll %g3, 6, %g3;		\
 	add %o1, 0x80, %o1;		\
-	ba,pt %xcc, U3cfu_fixup;	\
+	ba U3cfu_fixup;			\
 	 add %o1, %g3, %o1;		\
 	.section __ex_table;		\
 	.align 4;			\
@@ -68,7 +68,7 @@
 99:	VISExitHalf;			\
 	and %o2, (0x40 - 1), %o1;	\
 	add %o1, 0x40, %o1;		\
-	ba,pt %xcc, U3cfu_fixup;	\
+	ba U3cfu_fixup;			\
 	 add %o1, %g3, %o1;		\
 	.section __ex_table;		\
 	.align 4;			\
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/mm/generic.c linux/arch/sparc64/mm/generic.c
--- v2.5.2/linux/arch/sparc64/mm/generic.c	Thu Apr 12 12:10:25 2001
+++ linux/arch/sparc64/mm/generic.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.17 2001/04/09 04:08:06 davem Exp $
+/* $Id: generic.c,v 1.18 2001/12/21 04:56:15 davem Exp $
  * generic.c: Generic Sparc mm routines that are not dependent upon
  *            MMU type but are Sparc specific.
  *
@@ -111,18 +111,18 @@
 	return 0;
 }
 
-int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
+int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
 {
 	int error = 0;
 	pgd_t * dir;
 	unsigned long beg = from;
 	unsigned long end = from + size;
-	struct mm_struct *mm = current->mm;
+	struct mm_struct *mm = vma->vm_mm;
 
 	prot = __pgprot(pg_iobits);
 	offset -= from;
 	dir = pgd_offset(mm, from);
-	flush_cache_range(mm, beg, end);
+	flush_cache_range(vma, beg, end);
 
 	spin_lock(&mm->page_table_lock);
 	while (from < end) {
@@ -138,6 +138,6 @@
 	}
 	spin_unlock(&mm->page_table_lock);
 
-	flush_tlb_range(current->mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return error;
 }
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.5.2/linux/arch/sparc64/mm/init.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/mm/init.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.202 2001/11/13 00:49:28 davem Exp $
+/*  $Id: init.c,v 1.208 2001/12/21 04:56:15 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;
@@ -226,6 +228,82 @@
 	}
 }
 
+/* When shared+writable mmaps of files go away, we lose all dirty
+ * page state, so we have to deal with D-cache aliasing here.
+ *
+ * This code relies on the fact that flush_cache_range() is always
+ * called for an area composed by a single VMA.  It also assumes that
+ * the MM's page_table_lock is held.
+ */
+static inline void flush_cache_pte_range(struct mm_struct *mm, pmd_t *pmd, unsigned long address, unsigned long size)
+{
+	unsigned long offset;
+	pte_t *ptep;
+
+	if (pmd_none(*pmd))
+		return;
+	ptep = pte_offset(pmd, address);
+	offset = address & ~PMD_MASK;
+	if (offset + size > PMD_SIZE)
+		size = PMD_SIZE - offset;
+	size &= PAGE_MASK;
+	for (offset = 0; offset < size; ptep++, offset += PAGE_SIZE) {
+		pte_t pte = *ptep;
+
+		if (pte_none(pte))
+			continue;
+
+		if (pte_present(pte) && pte_dirty(pte)) {
+			struct page *page = pte_page(pte);
+			unsigned long pgaddr, uaddr;
+
+			if (!VALID_PAGE(page) || PageReserved(page) || !page->mapping)
+				continue;
+			pgaddr = (unsigned long) page_address(page);
+			uaddr = address + offset;
+			if ((pgaddr ^ uaddr) & (1 << 13))
+				flush_dcache_page_all(mm, page);
+		}
+	}
+}
+
+static inline void flush_cache_pmd_range(struct mm_struct *mm, pgd_t *dir, unsigned long address, unsigned long size)
+{
+	pmd_t *pmd;
+	unsigned long end;
+
+	if (pgd_none(*dir))
+		return;
+	pmd = pmd_offset(dir, address);
+	end = address + size;
+	if (end > ((address + PGDIR_SIZE) & PGDIR_MASK))
+		end = ((address + PGDIR_SIZE) & PGDIR_MASK);
+	do {
+		flush_cache_pte_range(mm, pmd, address, end - address);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address < end);
+}
+
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	pgd_t *dir = pgd_offset(mm, start);
+
+	if (mm == current->mm)
+		flushw_user();
+
+	if (vma->vm_file == NULL ||
+	    ((vma->vm_flags & (VM_SHARED|VM_WRITE)) != (VM_SHARED|VM_WRITE)))
+		return;
+
+	do {
+		flush_cache_pmd_range(mm, dir, start, end - start);
+		start = (start + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	} while (start && (start < end));
+}
+
 void flush_icache_range(unsigned long start, unsigned long end)
 {
 	/* Cheetah has coherent I-cache. */
@@ -505,6 +583,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 +594,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 +616,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 +804,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 +843,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 +881,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 +907,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 +1375,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 -u --recursive --new-file v2.5.2/linux/arch/sparc64/mm/modutil.c linux/arch/sparc64/mm/modutil.c
--- v2.5.2/linux/arch/sparc64/mm/modutil.c	Tue Aug 28 07:09:44 2001
+++ linux/arch/sparc64/mm/modutil.c	Tue Jan 15 10:52:11 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.5.2/linux/arch/sparc64/mm/ultra.S	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/mm/ultra.S	Wed Jan 23 15:28:40 2002
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.70 2001/11/29 16:42:10 kanoj Exp $
+/* $Id: ultra.S,v 1.71 2002/01/23 11:27:36 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
@@ -10,6 +10,7 @@
 #include <asm/page.h>
 #include <asm/spitfire.h>
 #include <asm/mmu_context.h>
+#include <asm/pil.h>
 
 	/* Basically, all this madness has to do with the
 	 * fact that Cheetah does not support IMMU flushes
@@ -690,5 +691,12 @@
 	 nop
 	b,pt		%xcc, rtrap
 	 clr		%l6
+
+	.globl		xcall_migrate_task
+xcall_migrate_task:
+	mov		1, %g2
+	sllx		%g2, (PIL_MIGRATE), %g2
+	wr		%g2, 0x0, %set_softint
+	retry
 
 #endif /* CONFIG_SMP */
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/vmlinux.lds linux/arch/sparc64/vmlinux.lds
--- v2.5.2/linux/arch/sparc64/vmlinux.lds	Fri Sep  7 11:01:20 2001
+++ linux/arch/sparc64/vmlinux.lds	Wed Jan 23 10:54:42 2002
@@ -46,7 +46,15 @@
   .setup_init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(8192);
   __init_end = .;
diff -u --recursive --new-file v2.5.2/linux/drivers/Makefile linux/drivers/Makefile
--- v2.5.2/linux/drivers/Makefile	Sun Nov 11 10:09:32 2001
+++ linux/drivers/Makefile	Thu Jan 24 14:07:46 2002
@@ -10,7 +10,7 @@
 		message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
 		fc4 net/hamradio i2c acpi bluetooth
 
-subdir-y :=	parport char block net sound misc media cdrom hotplug
+subdir-y :=	base parport char block net sound misc media cdrom hotplug
 subdir-m :=	$(subdir-y)
 
 
diff -u --recursive --new-file v2.5.2/linux/drivers/acorn/block/Config.help linux/drivers/acorn/block/Config.help
--- v2.5.2/linux/drivers/acorn/block/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/acorn/block/Config.help	Fri Jan 25 16:04:22 2002
@@ -0,0 +1,18 @@
+CONFIG_BLK_DEV_MFM
+  Support the MFM hard drives on the Acorn Archimedes both
+  on-board the A4x0 motherboards and via the Acorn MFM podules.
+  Drives up to 64MB are supported. If you haven't got one of these
+  machines or drives just say N.
+
+CONFIG_BLK_DEV_FD1772
+  Support the floppy drive on the Acorn Archimedes (A300, A4x0, A540,
+  R140 and R260) series of computers; it supports only 720K floppies
+  at the moment. If you don't have one of these machines just answer
+  N.
+
+CONFIG_BLK_DEV_MFM_AUTODETECT
+  If you answer Y, the MFM code will attempt to automatically detect
+  the cylinders/heads/sectors count on your hard drive. WARNING: This
+  sometimes doesn't work and it also does some dodgy stuff which
+  potentially might damage your drive.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/acorn/net/Config.help linux/drivers/acorn/net/Config.help
--- v2.5.2/linux/drivers/acorn/net/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/acorn/net/Config.help	Fri Jan 25 16:03:48 2002
@@ -0,0 +1,12 @@
+CONFIG_ARM_ETHER1
+  If you have an Acorn system with one of these (AKA25) network cards,
+  you should say Y to this option if you wish to use it with Linux.
+
+CONFIG_ARM_ETHER3
+  If you have an Acorn system with one of these network cards, you
+  should say Y to this option if you wish to use it with Linux.
+
+CONFIG_ARM_ETHERH
+  If you have an Acorn system with one of these network cards, you
+  should say Y to this option if you wish to use it with Linux.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/acorn/scsi/Config.help linux/drivers/acorn/scsi/Config.help
--- v2.5.2/linux/drivers/acorn/scsi/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/acorn/scsi/Config.help	Fri Jan 25 16:03:40 2002
@@ -0,0 +1,53 @@
+CONFIG_SCSI_ACORNSCSI_3
+  This enables support for the Acorn SCSI card (aka30). If you have an
+  Acorn system with one of these, say Y. If unsure, say N.
+
+CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+  Say Y here to enable tagged queuing support on the Acorn SCSI card.
+
+  This is a feature of SCSI-2 which improves performance: the host
+  adapter can send several SCSI commands to a device's queue even if
+  previous commands haven't finished yet. Some SCSI devices don't
+  implement this properly, so the safe answer is N.
+
+CONFIG_SCSI_ACORNSCSI_SYNC
+  Say Y here to enable synchronous transfer negotiation with all
+  targets on the Acorn SCSI card.
+
+  In general, this improves performance; however some SCSI devices
+  don't implement it properly, so the safe answer is N.
+
+CONFIG_SCSI_ARXESCSI
+  Around 1991, Arxe Systems Limited released a high density floppy
+  disc interface for the Acorn Archimedes range, to allow the use of
+  HD discs from the then new A5000 on earlier models. This interface
+  was either sold on its own or with an integral SCSI controller.
+  Technical details on this NCR53c94-based device are available at
+  <http://www.cryton.demon.co.uk/acornbits/scsi_arxe.html>
+  Say Y here to compile in support for the SCSI controller.
+
+CONFIG_SCSI_OAK1
+  This enables support for the Oak SCSI card. If you have an Acorn
+  system with one of these, say Y. If unsure, say N.
+
+CONFIG_SCSI_CUMANA_1
+  This enables support for the Cumana SCSI I card. If you have an
+  Acorn system with one of these, say Y. If unsure, say N.
+
+CONFIG_SCSI_CUMANA_2
+  This enables support for the Cumana SCSI II card. If you have an
+  Acorn system with one of these, say Y. If unsure, say N.
+
+CONFIG_SCSI_ECOSCSI
+  This enables support for the EcoSCSI card -- a small card that sits
+  in the Econet socket. If you have an Acorn system with one of these,
+  say Y. If unsure, say N.
+
+CONFIG_SCSI_EESOXSCSI
+  This enables support for the EESOX SCSI card. If you have an Acorn
+  system with one of these, say Y, otherwise say N.
+
+CONFIG_SCSI_POWERTECSCSI
+  This enables support for the Powertec SCSI card on Acorn systems. If
+  you have one of these, say Y. If unsure, say N.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/acpi/Config.help linux/drivers/acpi/Config.help
--- v2.5.2/linux/drivers/acpi/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/acpi/Config.help	Fri Jan 25 16:04:02 2002
@@ -0,0 +1,44 @@
+CONFIG_ACPI_DEBUG
+  The ACPI driver can optionally report errors with a great deal
+  of verbosity. Saying Y enables these statements. This will increase
+  your kernel size by around 50K.
+
+CONFIG_ACPI_BUSMGR
+  The ACPI Bus Manager enumerates devices in the ACPI namespace, and
+  handles PnP messages.  All ACPI devices use its services, so using
+  them requires saying Y here.
+
+CONFIG_ACPI_SYS
+  This driver will enable your system to shut down using ACPI, and
+  dump your ACPI DSDT table using /proc/acpi/dsdt.
+
+CONFIG_ACPI_CPU
+  This driver installs ACPI as the idle handler for Linux, and uses
+  ACPI C2 and C3 processor states to save power, on systems that
+  support it.
+
+CONFIG_ACPI_BUTTON
+  This driver registers for events based on buttons, such as the
+  power, sleep, and lid switch.  In the future, a daemon will read
+  /proc/acpi/event and perform user-defined actions such as shutting
+  down the system.  Until then, you can cat it, and see output when
+  a button is pressed.
+
+CONFIG_ACPI_AC
+  This driver adds support for the AC Adapter object, which indicates
+  whether a system is on AC, or not.  Typically, only laptops have
+  this object, since desktops are always on AC.
+
+CONFIG_ACPI_EC
+  This driver is required on some systems for the proper operation of
+  the battery and thermal drivers.  If you are compiling for a laptop,
+  say Y.
+
+CONFIG_ACPI_CMBATT
+  This driver adds support for battery information through
+  /proc/acpi/battery. If you have a laptop with a battery, say Y.
+
+CONFIG_ACPI_THERMAL
+  This driver handles overheating conditions on laptops. It is HIGHLY
+  recommended, as your laptop CPU may be damaged without it.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/atm/Config.help linux/drivers/atm/Config.help
--- v2.5.2/linux/drivers/atm/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/atm/Config.help	Fri Jan 25 16:03:36 2002
@@ -0,0 +1,296 @@
+CONFIG_ATM_TCP
+  ATM over TCP driver. Useful mainly for development and for
+  experiments. If unsure, say N.
+
+CONFIG_ATM_ENI
+  Driver for the Efficient Networks ENI155p series and SMC ATM
+  Power155 155 Mbps ATM adapters. Both, the versions with 512KB and
+  2MB on-board RAM (Efficient calls them "C" and "S", respectively),
+  and the FPGA and the ASIC Tonga versions of the board are supported.
+  The driver works with MMF (-MF or ...F) and UTP-5 (-U5 or ...D)
+  adapters.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called eni.o.
+
+CONFIG_ATM_ENI_DEBUG
+  Extended debugging records various events and displays that list
+  when an inconsistency is detected. This mechanism is faster than
+  generally using printks, but still has some impact on performance.
+  Note that extended debugging may create certain race conditions
+  itself. Enable this ONLY if you suspect problems with the driver.
+
+CONFIG_ATM_ENI_TUNE_BURST
+  In order to obtain good throughput, the ENI NIC can transfer
+  multiple words of data per PCI bus access cycle. Such a multi-word
+  transfer is called a burst.
+
+  The default settings for the burst sizes are suitable for most PCI
+  chipsets. However, in some cases, large bursts may overrun buffers
+  in the PCI chipset and cause data corruption. In such cases, large
+  bursts must be disabled and only (slower) small bursts can be used.
+  The burst sizes can be set independently in the send (TX) and
+  receive (RX) direction.
+
+  Note that enabling many different burst sizes in the same direction
+  may increase the cost of setting up a transfer such that the
+  resulting throughput is lower than when using only the largest
+  available burst size.
+
+  Also, sometimes larger bursts lead to lower throughput, e.g. on an
+  Intel 440FX board, a drop from 135 Mbps to 103 Mbps was observed
+  when going from 8W to 16W bursts.
+
+CONFIG_ATM_ENI_BURST_TX_16W
+  Burst sixteen words at once in the send direction. This may work
+  with recent PCI chipsets, but is known to fail with older chipsets.
+
+CONFIG_ATM_ENI_BURST_TX_8W
+  Burst eight words at once in the send direction. This is the default
+  setting.
+
+CONFIG_ATM_ENI_BURST_TX_4W
+  Burst four words at once in the send direction. You may want to try
+  this if you have disabled 8W bursts. Enabling 4W if 8W is also set
+  may or may not improve throughput.
+
+CONFIG_ATM_ENI_BURST_TX_2W
+  Burst two words at once in the send direction. You may want to try
+  this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or 8W
+  are also set may or may not improve throughput.
+
+CONFIG_ATM_ENI_BURST_RX_16W
+  Burst sixteen words at once in the receive direction. This may work
+  with recent PCI chipsets, but is known to fail with older chipsets.
+
+CONFIG_ATM_ENI_BURST_RX_8W
+  Burst eight words at once in the receive direction. This may work
+  with recent PCI chipsets, but is known to fail with older chipsets,
+  such as the Intel Neptune series.
+
+CONFIG_ATM_ENI_BURST_RX_4W
+  Burst four words at once in the receive direction. This is the
+  default setting. Enabling 4W if 8W is also set may or may not
+  improve throughput.
+
+CONFIG_ATM_ENI_BURST_RX_2W
+  Burst two words at once in the receive direction. You may want to
+  try this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or
+  8W are also set may or may not improve throughput.
+
+CONFIG_ATM_ZATM
+  Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM
+  adapters.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called zatm.o.
+
+CONFIG_ATM_ZATM_DEBUG
+  Extended debugging records various events and displays that list
+  when an inconsistency is detected. This mechanism is faster than
+  generally using printks, but still has some impact on performance.
+  Note that extended debugging may create certain race conditions
+  itself. Enable this ONLY if you suspect problems with the driver.
+
+CONFIG_ATM_FIRESTREAM
+  Driver for the Fujitsu FireStream 155 (MB86697) and
+  FireStream 50 (MB86695) ATM PCI chips.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  firestream.o.
+
+CONFIG_ATM_ZATM_EXACT_TS
+  The uPD98401 SAR chip supports a high-resolution timer (approx. 30
+  MHz) that is used for very accurate reception timestamps. Because
+  that timer overflows after 140 seconds, and also to avoid timer
+  drift, time measurements need to be periodically synchronized with
+  the normal system time. Enabling this feature will add some general
+  overhead for timer synchronization and also per-packet overhead for
+  time conversion.
+
+CONFIG_ATM_NICSTAR
+  The NICStAR chipset family is used in a large number of ATM NICs for
+  25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
+  series. Say Y if you have one of those.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  nicstar.o.
+
+CONFIG_ATM_NICSTAR_USE_SUNI
+  Support for the S-UNI and compatible PHYsical layer chips. These are
+  found in most 155Mbps NICStAR based ATM cards, namely in the
+  ForeRunner LE155 cards. This driver provides detection of cable~
+  removal and reinsertion and provides some statistics. This driver
+  doesn't have removal capability when compiled as a module, so if you
+  need that capability don't include S-UNI support (it's not needed to
+  make the card work).
+
+CONFIG_ATM_NICSTAR_USE_IDT77105
+  Support for the PHYsical layer chip in ForeRunner LE25 cards. In
+  addition to cable removal/reinsertion detection, this driver allows
+  you to control the loopback mode of the chip via a dedicated IOCTL.
+  This driver is required for proper handling of temporary carrier
+  loss, so if you have a 25Mbps NICStAR based ATM card you must say Y.
+
+CONFIG_ATM_IDT77252
+  Driver for the IDT 77252 ATM PCI chips.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called idt77252.o
+
+CONFIG_ATM_IDT77252_DEBUG
+  Somewhat useful debugging messages are available. The choice of
+  messages is controlled by a bitmap.  This may be specified as a
+  module argument.  See the file <file:drivers/atm/idt77252.h> for
+  the meanings of the bits in the mask.
+
+  When active, these messages can have a significant impact on the
+  speed of the driver, and the size of your syslog files! When
+  inactive, they will have only a modest impact on performance.
+
+CONFIG_ATM_IDT77252_RCV_ALL
+  Enable receiving of all cells on the ATM link, that do not match
+  an open connection in the raw cell queue of the driver.  Useful
+  for debugging or special applications only, so the safe answer is N.
+
+CONFIG_ATM_AMBASSADOR
+  This is a driver for ATMizer based ATM card produced by Madge
+  Networks Ltd. Say Y (or M to compile as a module named ambassador.o)
+  here if you have one of these cards.
+
+CONFIG_ATM_AMBASSADOR_DEBUG
+  Somewhat useful debugging messages are available. The choice of
+  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 (not yet) or changed by sending the
+  string "Dxxxx" to VCI 1023 (where x is a hex digit).  See the file
+  <file:drivers/atm/ambassador.h> for the meanings of the bits in the
+  mask.
+
+  When active, these messages can have a significant impact on the
+  speed of the driver, and the size of your syslog files! When
+  inactive, they will have only a modest impact on performance.
+
+CONFIG_ATM_HORIZON
+  This is a driver for the Horizon chipset ATM adapter cards once
+  produced by Madge Networks Ltd. Say Y (or M to compile as a module
+  named horizon.o) here if you have one of these cards.
+
+CONFIG_ATM_HORIZON_DEBUG
+  Somewhat useful debugging messages are available. The choice of
+  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 (not yet) or changed by sending the
+  string "Dxxxx" to VCI 1023 (where x is a hex digit).  See the file
+  <file:drivers/atm/horizon.h> for the meanings of the bits in the
+  mask.
+
+  When active, these messages can have a significant impact on the
+  speed of the driver, and the size of your syslog files! When
+  inactive, they will have only a modest impact on performance.
+
+CONFIG_ATM_IA
+  This is a driver for the Interphase (i)ChipSAR adapter cards
+  which include a variety of variants in term of the size of the
+  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:
+  	<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.
+
+  See the file <file:Documentation/networking/iphase.txt> for further
+  details.
+
+CONFIG_ATM_IA_DEBUG
+  Somewhat useful debugging messages are available. The choice of
+  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/>).
+
+  See the file <file:drivers/atm/iphase.h> for the meanings of the
+  bits in the mask.
+
+  When active, these messages can have a significant impact on the
+  speed of the driver, and the size of your syslog files! When
+  inactive, they will have only a modest impact on performance.
+
+CONFIG_ATM_FORE200E_MAYBE
+  This is a driver for the FORE Systems 200E-series ATM adapter
+  cards. It simultaneously supports PCA-200E and SBA-200E models
+  on PCI and SBUS hosts. Say Y (or M to compile as a module
+  named fore_200e.o) here if you have one of these ATM adapters.
+
+  Note that the driver will actually be compiled only if you
+  additionally enable the support for PCA-200E and/or SBA-200E
+  cards.
+
+  See the file <file:Documentation/networking/fore200e.txt> for
+  further details.
+
+CONFIG_ATM_FORE200E_PCA
+  Say Y here if you want your PCA-200E cards to be probed.
+
+CONFIG_ATM_FORE200E_PCA_DEFAULT_FW
+  Use the default PCA-200E firmware data shipped with the driver.
+
+  Normal users do not have to deal with the firmware stuff, so
+  they should say Y here.
+
+CONFIG_ATM_FORE200E_PCA_FW
+  This defines the pathname of an alternative PCA-200E binary
+  firmware image supplied by the user. This pathname may be
+  absolute or relative to the drivers/atm directory.
+
+  The driver comes with an adequate firmware image, so normal users do
+  not have to supply an alternative one. They just say Y to "Use
+  default PCA-200E firmware" instead.
+
+CONFIG_ATM_FORE200E_SBA
+  Say Y here if you want your SBA-200E cards to be probed.
+
+CONFIG_ATM_FORE200E_SBA_DEFAULT_FW
+  Use the default SBA-200E firmware data shipped with the driver.
+
+  Normal users do not have to deal with the firmware stuff, so
+  they should say Y here.
+
+CONFIG_ATM_FORE200E_SBA_FW
+  This defines the pathname of an alternative SBA-200E binary
+  firmware image supplied by the user. This pathname may be
+  absolute or relative to the drivers/atm directory.
+
+  The driver comes with an adequate firmware image, so normal users do
+  not have to supply an alternative one. They just say Y to "Use
+  default SBA-200E firmware", above.
+
+CONFIG_ATM_FORE200E_TX_RETRY
+  Specifies the number of times the driver attempts to transmit
+  a message before giving up, if the transmit queue of the ATM card
+  is transiently saturated.
+
+  Saturation of the transmit queue may occur only under extreme
+  conditions, e.g. when a fast host continuously submits very small
+  frames (<64 bytes) or raw AAL0 cells (48 bytes) to the ATM adapter.
+
+  Note that under common conditions, it is unlikely that you encounter
+  a saturation of the transmit queue, so the retry mechanism never
+  comes into play.
+
+CONFIG_ATM_FORE200E_DEBUG
+  Specifies the level of debugging messages issued by the driver.
+  The verbosity of the driver increases with the value of this
+  parameter.
+
+  When active, these messages can have a significant impact on
+  the performances of the driver, and the size of your syslog files!
+  Keep the debugging level to 0 during normal operations.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/base/Makefile linux/drivers/base/Makefile
--- v2.5.2/linux/drivers/base/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/base/Makefile	Thu Jan 24 14:07:46 2002
@@ -0,0 +1,7 @@
+O_TARGET	:= base.o
+
+obj-y		:= core.o interface.o fs.o
+
+export-objs	:= core.o interface.o fs.o 
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.5.2/linux/drivers/base/core.c linux/drivers/base/core.c
--- v2.5.2/linux/drivers/base/core.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/base/core.c	Mon Jan 28 16:57:27 2002
@@ -0,0 +1,214 @@
+/*
+ * drivers/base/core.c - core driver model code (device registration, etc)
+ * 
+ * Copyright (c) 2002 Patrick Mochel
+ *		 2002 Open Source Development Lab
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+# define DBG(x...) printk(x)
+#else
+# define DBG(x...)
+#endif
+
+static struct iobus device_root = {
+	bus_id: "root",
+	name:	"Logical System Root",
+};
+
+int (*platform_notify)(struct device * dev) = NULL;
+int (*platform_notify_remove)(struct device * dev) = NULL;
+
+extern int device_make_dir(struct device * dev);
+extern void device_remove_dir(struct device * dev);
+
+extern int iobus_make_dir(struct iobus * iobus);
+extern void iobus_remove_dir(struct iobus * iobus);
+
+static spinlock_t device_lock;
+
+/**
+ * device_register - register a device
+ * @dev:	pointer to the device structure
+ *
+ * First, make sure that the device has a parent, create
+ * a directory for it, then add it to the parent's list of
+ * children.
+ */
+int device_register(struct device *dev)
+{
+	int error;
+
+	if (!dev || !strlen(dev->bus_id))
+		return -EINVAL;
+	BUG_ON(!dev->parent);
+
+	spin_lock(&device_lock);
+	INIT_LIST_HEAD(&dev->node);
+	spin_lock_init(&dev->lock);
+	atomic_set(&dev->refcount,2);
+
+	get_iobus(dev->parent);
+	list_add_tail(&dev->node,&dev->parent->devices);
+	spin_unlock(&device_lock);
+
+	DBG("DEV: registering device: ID = '%s', name = %s, parent = %s\n",
+	    dev->bus_id, dev->name, parent->bus_id);
+
+	if ((error = device_make_dir(dev)))
+		goto register_done;
+
+	/* notify platform of device entry */
+	if (platform_notify)
+		platform_notify(dev);
+
+ register_done:
+	put_device(dev);
+	if (error)
+		put_iobus(dev->parent);
+	return error;
+}
+
+/**
+ * put_device - clean up device
+ * @dev:	device in question
+ *
+ * Decrement reference count for device.
+ * If it hits 0, we need to clean it up.
+ * However, we may be here in interrupt context, and it may
+ * take some time to do proper clean up (removing files, calling
+ * back down to device to clean up everything it has).
+ * So, we remove it from its parent's list and add it to the list of
+ * devices to be cleaned up.
+ */
+void put_device(struct device * dev)
+{
+	if (!atomic_dec_and_lock(&dev->refcount,&device_lock))
+		return;
+	list_del_init(&dev->node);
+	spin_unlock(&device_lock);
+
+	DBG("DEV: Unregistering device. ID = '%s', name = '%s'\n",
+	    dev->bus_id,dev->name);
+
+	/* remove the driverfs directory */
+	device_remove_dir(dev);
+
+	if (dev->subordinate)
+		iobus_remove_dir(dev->subordinate);
+
+	/* Notify the platform of the removal, in case they
+	 * need to do anything...
+	 */
+	if (platform_notify_remove)
+		platform_notify_remove(dev);
+
+	/* Tell the driver to clean up after itself.
+	 * Note that we likely didn't allocate the device,
+	 * so this is the driver's chance to free that up...
+	 */
+	if (dev->driver && dev->driver->remove)
+		dev->driver->remove(dev,REMOVE_FREE_RESOURCES);
+
+	put_iobus(dev->parent);
+}
+
+int iobus_register(struct iobus *bus)
+{
+	int error;
+
+	if (!bus || !strlen(bus->bus_id))
+		return -EINVAL;
+	
+	spin_lock(&device_lock);
+	atomic_set(&bus->refcount,2);
+	spin_lock_init(&bus->lock);
+	INIT_LIST_HEAD(&bus->node);
+	INIT_LIST_HEAD(&bus->devices);
+	INIT_LIST_HEAD(&bus->children);
+
+	if (bus != &device_root) {
+		if (!bus->parent)
+			bus->parent = &device_root;
+		get_iobus(bus->parent);
+		list_add_tail(&bus->node,&bus->parent->children);
+	}
+	spin_unlock(&device_lock);
+
+	DBG("DEV: registering bus. ID = '%s' name = '%s' parent = %p\n",
+	    bus->bus_id,bus->name,bus->parent);
+
+	error = iobus_make_dir(bus);
+
+	put_iobus(bus);
+	if (error && bus->parent)
+		put_iobus(bus->parent);
+	return error;
+}
+
+/**
+ * iobus_unregister - remove bus and children from device tree
+ * @bus:	pointer to bus structure
+ *
+ * Remove device from parent's list of children and decrement
+ * reference count on controlling device. That should take care of
+ * the rest of the cleanup.
+ */
+void put_iobus(struct iobus * iobus)
+{
+	if (!atomic_dec_and_lock(&iobus->refcount,&device_lock))
+		return;
+	list_del_init(&iobus->node);
+	spin_unlock(&device_lock);
+
+	if (!list_empty(&iobus->devices) ||
+	    !list_empty(&iobus->children))
+		BUG();
+
+	put_iobus(iobus->parent);
+	/* unregister itself */
+	put_device(iobus->self);
+}
+
+static int __init device_init_root(void)
+{
+	/* initialize parent bus lists */
+	return iobus_register(&device_root);
+}
+
+int __init device_driver_init(void)
+{
+	int error = 0;
+
+	DBG("DEV: Initialising Device Tree\n");
+
+	spin_lock_init(&device_lock);
+
+	error = init_driverfs_fs();
+
+	if (error) {
+		panic("DEV: could not initialise driverfs\n");
+		return error;
+	}
+
+	error = device_init_root();
+	if (error) {
+		printk(KERN_ERR "%s: device root init failed!\n", __FUNCTION__);
+		return error;
+	}
+
+	DBG("DEV: Done Initialising\n");
+	return error;
+}
+
+EXPORT_SYMBOL(device_register);
+EXPORT_SYMBOL(put_device);
+EXPORT_SYMBOL(iobus_register);
+EXPORT_SYMBOL(put_iobus);
+EXPORT_SYMBOL(device_driver_init);
diff -u --recursive --new-file v2.5.2/linux/drivers/base/fs.c linux/drivers/base/fs.c
--- v2.5.2/linux/drivers/base/fs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/base/fs.c	Thu Jan 24 14:07:46 2002
@@ -0,0 +1,131 @@
+/*
+ * drivers/base/fs.c - driver model interface to driverfs 
+ *
+ * Copyright (c) 2002 Patrick Mochel
+ *		 2002 Open Source Development Lab
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+
+extern struct driver_file_entry * device_default_files[];
+
+/**
+ * device_create_file - create a driverfs file for a device
+ * @dev:	device requesting file
+ * @entry:	entry describing file
+ *
+ * Allocate space for file entry, copy descriptor, and create.
+ */
+int device_create_file(struct device * dev, struct driver_file_entry * entry)
+{
+	struct driver_file_entry * new_entry;
+	int error = -ENOMEM;
+
+	if (!dev)
+		return -EINVAL;
+	get_device(dev);
+
+	new_entry = kmalloc(sizeof(*new_entry),GFP_KERNEL);
+	if (!new_entry)
+		goto done;
+
+	memcpy(new_entry,entry,sizeof(*entry));
+	error = driverfs_create_file(new_entry,&dev->dir);
+	if (error)
+		kfree(new_entry);
+ done:
+	put_device(dev);
+	return error;
+}
+
+/**
+ * device_remove_file - remove a device's file by name
+ * @dev:	device requesting removal
+ * @name:	name of the file
+ *
+ */
+void device_remove_file(struct device * dev, const char * name)
+{
+	if (dev) {
+		get_device(dev);
+		driverfs_remove_file(&dev->dir,name);
+		put_device(dev);
+	}
+}
+
+/**
+ * device_remove_dir - remove a device's directory
+ * @dev:	device in question
+ */
+void device_remove_dir(struct device * dev)
+{
+	if (dev)
+		driverfs_remove_dir(&dev->dir);
+}
+
+/**
+ * device_make_dir - create a driverfs directory
+ * @name:	name of directory
+ * @parent:	dentry for the parent directory
+ *
+ * Do the initial creation of the device's driverfs directory
+ * and populate it with the one default file.
+ *
+ * This is just a helper for device_register(), as we
+ * don't export this function. (Yes, that means we don't allow
+ * devices to create subdirectories).
+ */
+int device_make_dir(struct device * dev)
+{
+	struct driver_dir_entry * parent = NULL;
+	struct driver_file_entry * entry;
+	int error;
+	int i;
+
+	INIT_LIST_HEAD(&dev->dir.files);
+	dev->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
+	dev->dir.name = dev->bus_id;
+
+	if (dev->parent)
+		parent = &dev->parent->dir;
+
+	if ((error = driverfs_create_dir(&dev->dir,parent)))
+		return error;
+
+	for (i = 0; (entry = *(device_default_files + i)); i++) {
+		if ((error = device_create_file(dev,entry))) {
+			device_remove_dir(dev);
+			return error;
+		}
+	}
+	return 0;
+}
+
+void iobus_remove_dir(struct iobus * iobus)
+{
+	if (iobus)
+		driverfs_remove_dir(&iobus->dir);
+}
+
+int iobus_make_dir(struct iobus * iobus)
+{
+	struct driver_dir_entry * parent = NULL;
+	int error;
+
+	INIT_LIST_HEAD(&iobus->dir.files);
+	iobus->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
+	iobus->dir.name = iobus->bus_id;
+
+	if (iobus->parent)
+		parent = &iobus->parent->dir;
+
+	error = driverfs_create_dir(&iobus->dir,parent);
+	return error;
+}
+
+EXPORT_SYMBOL(device_create_file);
+EXPORT_SYMBOL(device_remove_file);
+
diff -u --recursive --new-file v2.5.2/linux/drivers/base/interface.c linux/drivers/base/interface.c
--- v2.5.2/linux/drivers/base/interface.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/base/interface.c	Mon Jan 28 16:57:27 2002
@@ -0,0 +1,174 @@
+/*
+ * drivers/base/interface.c - common driverfs interface that's exported to 
+ * 	the world for all devices.
+ * Copyright (c) 2002 Patrick Mochel
+ *		 2002 Open Source Development Lab
+ */
+
+#include <linux/device.h>
+
+/**
+ * device_read_status - report some device information
+ * @page:	page-sized buffer to write into
+ * @count:	number of bytes requested
+ * @off:	offset into buffer
+ * @data:	device-specific data
+ *
+ * Report some human-readable information about the device.
+ * This includes the name, the bus id, and the current power state.
+ */
+static ssize_t device_read_status(struct device * dev, char * page, size_t count, loff_t off)
+{
+	char *str = page;
+
+	if (off)
+		return 0;
+
+	str += sprintf(str,"Name:       %s\n",dev->name);
+	str += sprintf(str,"Bus ID:     %s\n",dev->bus_id);
+
+	return (str - page);
+}
+
+/**
+ * device_write_status - forward a command to a driver
+ * @buf:	encoded command
+ * @count:	number of bytes in buffer
+ * @off:	offset into buffer to start with
+ * @data:	device-specific data
+ *
+ * Send a comamnd to a device driver.
+ * The following actions are supported:
+ * probe - scan slot for device
+ * remove - detach driver from slot
+ * suspend <state> <stage> - perform <stage> for entering <state>
+ * resume <stage> - perform <stage> for waking device up.
+ * (See Documentation/driver-model.txt for the theory of an n-stage
+ * suspend sequence).
+ */
+static ssize_t device_write_status(struct device * dev, const char* buf, size_t count, loff_t off)
+{
+	char command[20];
+	int num;
+	int arg = 0;
+	int error = 0;
+
+	if (off)
+		return 0;
+
+	/* everything involves dealing with the driver. */
+	if (!dev->driver)
+		return 0;
+
+	num = sscanf(buf,"%10s %d",command,&arg);
+
+	if (!num)
+		return 0;
+
+	if (!strcmp(command,"probe")) {
+		if (dev->driver->probe)
+			error = dev->driver->probe(dev);
+
+	} else if (!strcmp(command,"remove")) {
+		if (dev->driver->remove)
+			error = dev->driver->remove(dev,REMOVE_NOTIFY);
+	} else
+		error = -EFAULT;
+	return error < 0 ? error : count;
+}
+
+static struct driver_file_entry device_status_entry = {
+	name:		"status",
+	mode:		S_IWUSR | S_IRUGO,
+	show:		device_read_status,
+	store:		device_write_status,
+};
+
+static ssize_t
+device_read_power(struct device * dev, char * page, size_t count, loff_t off)
+{
+	char	* str = page;
+
+	if (off)
+		return 0;
+
+	str += sprintf(str,"State:      %d\n",dev->current_state);
+
+	return (str - page);
+}
+
+static ssize_t
+device_write_power(struct device * dev, const char * buf, size_t count, loff_t off)
+{
+	char	str_command[20];
+	char	str_stage[20];
+	int	num_args;
+	u32	state;
+	u32	int_stage;
+	int	error = 0;
+
+	if (off)
+		return 0;
+
+	if (!dev->driver)
+		goto done;
+
+	num_args = sscanf(buf,"%10s %10s %u",str_command,str_stage,&state);
+
+	error = -EINVAL;
+
+	if (!num_args)
+		goto done;
+
+	if (!strnicmp(str_command,"suspend",7)) {
+		if (num_args != 3)
+			goto done;
+		if (!strnicmp(str_stage,"notify",6))
+			int_stage = SUSPEND_NOTIFY;
+		else if (!strnicmp(str_stage,"save",4))
+			int_stage = SUSPEND_SAVE_STATE;
+		else if (!strnicmp(str_stage,"disable",7))
+			int_stage = SUSPEND_DISABLE;
+		else if (!strnicmp(str_stage,"powerdown",8))
+			int_stage = SUSPEND_POWER_DOWN;
+		else
+			goto done;
+
+		if (dev->driver->suspend)
+			error = dev->driver->suspend(dev,state,int_stage);
+		else
+			error = 0;
+	} else if (!strnicmp(str_command,"resume",6)) {
+		if (num_args != 2)
+			goto done;
+
+		if (!strnicmp(str_stage,"poweron",7))
+			int_stage = RESUME_POWER_ON;
+		else if (!strnicmp(str_stage,"restore",7))
+			int_stage = RESUME_RESTORE_STATE;
+		else if (!strnicmp(str_stage,"enable",6))
+			int_stage = RESUME_ENABLE;
+		else
+			goto done;
+
+		if (dev->driver->resume)
+			error = dev->driver->resume(dev,int_stage);
+		else
+			error = 0;
+	}
+ done:
+	return error < 0 ? error : count;
+}
+
+static struct driver_file_entry device_power_entry = {
+	name:		"power",
+	mode:		S_IWUSR | S_IRUGO,
+	show:		device_read_power,
+	store:		device_write_power,
+};
+
+struct driver_file_entry * device_default_files[] = {
+	&device_status_entry,
+	&device_power_entry,
+	NULL,
+};
diff -u --recursive --new-file v2.5.2/linux/drivers/block/Config.help linux/drivers/block/Config.help
--- v2.5.2/linux/drivers/block/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/Config.help	Fri Jan 25 16:04:19 2002
@@ -0,0 +1,242 @@
+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
+  Thinkpad users, is contained in <file:Documentation/floppy.txt>.
+  That file also contains the location of the Floppy driver FAQ as
+  well as location of the fdutils package used to configure additional
+  parameters of the driver at run time.
+
+  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 floppy.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_BLK_DEV_RAM
+  Saying Y here will allow you to use a portion of your RAM memory as
+  a block device, so that you can make file systems on it, read and
+  write to it and do all the other things that you can do with normal
+  block devices (such as hard drives). It is usually used to load and
+  store a copy of a minimal root file system off of a floppy into RAM
+  during the initial install of Linux.
+
+  Note that the kernel command line option "ramdisk=XX" is now
+  obsolete. For details, read <file:Documentation/ramdisk.txt>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M and read <file:Documentation/modules.txt>. The module will be
+  called rd.o.
+
+  Most normal users won't need the RAM disk functionality, and can
+  thus say N here.
+
+CONFIG_BLK_DEV_RAM_SIZE
+  The default value is 4096. Only change this if you know what are
+  you doing. If you are using IBM S/390, then set this to 8192.
+
+CONFIG_BLK_DEV_INITRD
+  The initial RAM disk is a RAM disk that is loaded by the boot loader
+  (loadlin or lilo) and that is mounted as root before the normal boot
+  procedure. It is typically used to load modules needed to mount the
+  "real" root file system, etc. See <file:Documentation/initrd.txt>
+  for details.
+
+CONFIG_BLK_DEV_LOOP
+  Saying Y here will allow you to use a regular file as a block
+  device; you can then create a file system on that block device and
+  mount it just as you would mount other block devices such as hard
+  drive partitions, CD-ROM drives or floppy drives. The loop devices
+  are block special device files with major number 7 and typically
+  called /dev/loop0, /dev/loop1 etc.
+
+  This is useful if you want to check an ISO 9660 file system before
+  burning the CD, or if you want to use floppy images without first
+  writing them to floppy. Furthermore, some Linux distributions avoid
+  the need for a dedicated Linux partition by keeping their complete
+  root file system inside a DOS FAT file using this loop device
+  driver.
+
+  The loop device driver can also be used to "hide" a file system in a
+  disk partition, floppy, or regular file, either using encryption
+  (scrambling the data) or steganography (hiding the data in the low
+  bits of, say, a sound file). This is also safe if the file resides
+  on a remote file server. If you want to do this, you will first have
+  to acquire and install a kernel patch from
+  <ftp://ftp.kerneli.org/pub/kerneli/>, and then you need to
+  say Y to this option.
+
+  Note that alternative ways to use encrypted file systems are
+  provided by the cfs package, which can be gotten from
+  <ftp://ftp.kerneli.org/pub/kerneli/net-source/>, and the newer tcfs
+  package, available at <http://tcfs.dia.unisa.it/>. You do not need
+  to say Y here if you want to use one of these. However, using cfs
+  requires saying Y to "NFS file system support" below while using
+  tcfs requires applying a kernel patch. An alternative steganography
+  solution is provided by StegFS, also available from
+  <ftp://ftp.kerneli.org/pub/kerneli/net-source/>.
+
+  To use the loop device, you need the losetup utility and a recent
+  version of the mount program, both contained in the util-linux
+  package. The location and current version number of util-linux is
+  contained in the file <file:Documentation/Changes>.
+
+  Note that this loop device has nothing to do with the loopback
+  device used for network connections from the machine to itself.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called loop.o.
+
+  Most users will answer N here.
+
+CONFIG_BLK_DEV_NBD
+  Saying Y here will allow your computer to be a client for network
+  block devices, i.e. it will be able to use block devices exported by
+  servers (mount file systems on them etc.). Communication between
+  client and server works over TCP/IP networking, but to the client
+  program this is hidden: it looks like a regular local file access to
+  a block device special file such as /dev/nd0.
+
+  Network block devices also allows you to run a block-device in
+  userland (making server and client physically the same computer,
+  communicating using the loopback network device).
+
+  Read <file:Documentation/nbd.txt> for more information, especially
+  about where to find the server code, which runs in user space and
+  does not need special kernel support.
+
+  Note that this has nothing to do with the network file systems NFS
+  or Coda; you can say N here even if you intend to use NFS or Coda.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called nbd.o.
+
+  If unsure, say N.
+
+CONFIG_BLK_DEV_XD
+  Very old 8 bit hard disk controllers used in the IBM XT computer
+  will be supported if you say Y here.
+
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called xd.o.
+
+  It's pretty unlikely that you have one of these: say N.
+
+CONFIG_BLK_DEV_PS2
+  Say Y here if you have a PS/2 machine with a MCA bus and an ESDI
+  hard disk.
+
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ps2esdi.o.
+
+CONFIG_BLK_DEV_DAC960
+  This driver adds support for the Mylex DAC960, AcceleRAID, and
+  eXtremeRAID PCI RAID controllers.  See the file
+  <file:Documentation/README.DAC960> for further information about
+  this driver.
+
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called DAC960.o.
+
+CONFIG_PARIDE
+  There are many external CD-ROM and disk devices that connect through
+  your computer's parallel port. Most of them are actually IDE devices
+  using a parallel port IDE adapter. This option enables the PARIDE
+  subsystem which contains drivers for many of these external drives.
+  Read <file:Documentation/paride.txt> for more information.
+
+  If you have said Y to the "Parallel-port support" configuration
+  option, you may share a single port between your printer and other
+  parallel port devices. Answer Y to build PARIDE support into your
+  kernel, or M if you would like to build it as a loadable module. If
+  your parallel port support is in a loadable module, you must build
+  PARIDE as a module. If you built PARIDE support into your kernel,
+  you may still build the individual protocol modules and high-level
+  drivers as loadable modules. If you build this support as a module,
+  it will be called paride.o.
+
+  To use the PARIDE support, you must say Y or M here and also to at
+  least one high-level driver (e.g. "Parallel port IDE disks",
+  "Parallel port ATAPI CD-ROMs", "Parallel port ATAPI disks" etc.) and
+  to at least one protocol driver (e.g. "ATEN EH-100 protocol",
+  "MicroSolutions backpack protocol", "DataStor Commuter protocol"
+  etc.).
+
+CONFIG_BLK_CPQ_CISS_DA
+  This is the driver for Compaq Smart Array 5xxx controllers.
+  Everyone using these boards should say Y here.
+  See <file:Documentation/cciss.txt> for the current list of
+  boards supported by this driver, and for further information
+  on the use of this driver.
+
+CONFIG_CISS_SCSI_TAPE
+  When enabled (Y), this option allows SCSI tape drives and SCSI medium
+  changers (tape robots) to be accessed via a Compaq 5xxx array 
+  controller.  (See Documentation/cciss.txt for more details.)
+
+  "SCSI support" and "SCSI tape support" must also be enabled for this 
+  option to work.
+
+  When this option is disabled (N), the SCSI portion of the driver 
+  is not compiled.
+
+CONFIG_BLK_DEV_SWIM_IOP
+  Say Y here to support the SWIM (Super Woz Integrated Machine) IOP
+  floppy controller on the Macintosh IIfx and Quadra 900/950.
+
+CONFIG_AMIGA_Z2RAM
+  This enables support for using Chip RAM and Zorro II RAM as a
+  ramdisk or as a swap partition. Say Y if you want to include this
+  driver in the kernel. 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 is called z2ram.o. If you want
+  to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+CONFIG_ATARI_ACSI
+  This enables support for the Atari ACSI interface. The driver
+  supports hard disks and CD-ROMs, which have 512-byte sectors, or can
+  be switched to that mode. Due to the ACSI command format, only disks
+  up to 1 GB are supported. Special support for certain ACSI to SCSI
+  adapters, which could relax that, isn't included yet. The ACSI
+  driver is also the basis for certain other drivers for devices
+  attached to the ACSI bus: Atari SLM laser printer, BioNet-100
+  Ethernet, and PAMsNet Ethernet. If you want to use one of these
+  devices, you need ACSI support, too.
+
+  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 acsi.o.
+
+CONFIG_ACSI_MULTI_LUN
+  If you have a ACSI device that supports more than one LUN (Logical
+  Unit Number), e.g. a CD jukebox, you should say Y here so that all
+  will be found by the ACSI driver. An ACSI device with multiple LUNs
+  acts logically like multiple ACSI devices. The vast majority of ACSI
+  devices have only one LUN, and so most people can say N here and
+  should in fact do so, because it is safer.
+
+CONFIG_ATARI_SLM
+  If you have an Atari SLM laser printer, say Y to include support for
+  it in the kernel. Otherwise, say N. 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
+  acsi_slm.o. Be warned: the driver needs much ST-RAM and can cause
+  problems due to that fact!
+
+CONFIG_BLK_CPQ_DA
+  This is the driver for Compaq Smart Array controllers.  Everyone
+  using these boards should say Y here.  See the file
+  <file:Documentation/cpqarray.txt> for the current list of boards
+  supported by this driver, and for further information on the use of
+  this driver.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/block/cciss.c linux/drivers/block/cciss.c
--- v2.5.2/linux/drivers/block/cciss.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/cciss.c	Fri Jan 18 14:05:55 2002
@@ -64,6 +64,8 @@
                         0x0E11, 0x4080, 0, 0, 0},
 	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
                         0x0E11, 0x4082, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
+                        0x0E11, 0x4083, 0, 0, 0},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -78,6 +80,7 @@
 	{ 0x40700E11, "Smart Array 5300",	&SA5_access },
 	{ 0x40800E11, "Smart Array 5i", &SA5B_access},
 	{ 0x40820E11, "Smart Array 532", &SA5B_access},
+	{ 0x40830E11, "Smart Array 5312", &SA5B_access},
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
@@ -102,6 +105,8 @@
 static int revalidate_allvol(kdev_t dev);
 static int revalidate_logvol(kdev_t dev, int maxusage);
 static int frevalidate_logvol(kdev_t dev);
+static int deregister_disk(int ctlr, int logvol);
+static int register_new_disk(kdev_t dev, int cltr);
 
 static void cciss_getgeometry(int cntl_num);
 
@@ -148,6 +153,7 @@
                 "       Memory Address: 0x%08lx\n"
                 "       IRQ: %d\n"
                 "       Logical drives: %d\n"
+		"       Highest Logical Volume ID: %d\n"
                 "       Current Q depth: %d\n"
                 "       Max Q depth since init: %d\n"
 		"       Max # commands on controller since init: %d\n"
@@ -159,12 +165,15 @@
                 (unsigned long)h->vaddr,
                 (unsigned int)h->intr,
                 h->num_luns, 
+                h->highest_lun, 
                 h->Qdepth, h->maxQsinceinit, h->max_outstanding, h->maxSG);
 
         pos += size; len += size;
 	cciss_proc_tape_report(ctlr, buffer, &pos, &len);
-	for(i=0; i<h->num_luns; i++) {
+	for(i=0; i<h->highest_lun; i++) {
                 drv = &h->drv[i];
+		if (drv->block_size == 0)
+			continue;
                 size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n",
                                 ctlr, i, drv->block_size, drv->nr_blocks);
                 pos += size; len += size;
@@ -344,9 +353,10 @@
 		for(j=0; j<MAX_PART; j++)
 			hba[ctlr]->blocksizes[(i<<NWD_SHIFT) + j] = 1024; 
 
-		hba[ctlr]->gendisk.nr_real++;
+		//hba[ctlr]->gendisk.nr_real++;
 		(BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->block_size;
 	}
+	hba[ctlr]->gendisk.nr_real = hba[ctlr]->highest_lun+1;
 }
 /*
  * Open.  Make sure the device is really there.
@@ -416,24 +426,42 @@
 	switch(cmd) {
 	case HDIO_GETGEO:
 	{
-		struct hd_geometry *geo = (struct hd_geometry *)arg;
-		int diskinfo[4];
-
-		if (hba[ctlr]->drv[dsk].cylinders) {
-			diskinfo[0] = hba[ctlr]->drv[dsk].heads;
-			diskinfo[1] = hba[ctlr]->drv[dsk].sectors;
-			diskinfo[2] = hba[ctlr]->drv[dsk].cylinders;
-		} else {
-			diskinfo[0] = 0xff;
-			diskinfo[1] = 0x3f;
-			diskinfo[2] = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);
-		}
-		put_user(diskinfo[0], &geo->heads);
-		put_user(diskinfo[1], &geo->sectors);
-		put_user(diskinfo[2], &geo->cylinders);
-		put_user(get_start_sect(inode->i_rdev), &geo->start);
-		return 0;
+                struct hd_geometry driver_geo;
+                if (hba[ctlr]->drv[dsk].cylinders) {
+                        driver_geo.heads = hba[ctlr]->drv[dsk].heads;
+                        driver_geo.sectors = hba[ctlr]->drv[dsk].sectors;
+                        driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders;
+                } else {
+                        driver_geo.heads = 0xff;
+                        driver_geo.sectors = 0x3f;
+                        driver_geo.cylinders = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);
+                }
+                driver_geo.start=
+                        hba[ctlr]->hd[minor(inode->i_rdev)].start_sect;
+                if (copy_to_user((void *) arg, &driver_geo,
+                                sizeof( struct hd_geometry)))
+                        return  -EFAULT;
+                return(0);
 	}
+	case HDIO_GETGEO_BIG:
+        {
+		struct hd_big_geometry driver_geo;
+                if (hba[ctlr]->drv[dsk].cylinders) {
+                        driver_geo.heads = hba[ctlr]->drv[dsk].heads;
+                        driver_geo.sectors = hba[ctlr]->drv[dsk].sectors;
+                        driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders;
+                } else {
+                        driver_geo.heads = 0xff;
+                        driver_geo.sectors = 0x3f;
+                        driver_geo.cylinders = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);
+              	}
+	      	driver_geo.start= 
+			hba[ctlr]->hd[minor(inode->i_rdev)].start_sect;
+		if (copy_to_user((void *) arg, &driver_geo,  
+				sizeof( struct hd_big_geometry)))
+                        return  -EFAULT;
+                return(0);
+        }
 	case BLKRRPART:
 		return revalidate_logvol(inode->i_rdev, 1);
 	case BLKGETSIZE:
@@ -603,7 +631,14 @@
 
 	case CCISS_REVALIDVOLS:
                 return( revalidate_allvol(inode->i_rdev));
-	
+
+	case CCISS_DEREGDISK:
+		return( deregister_disk(ctlr,dsk));
+
+	case CCISS_REGNEWD:
+	{
+		return(register_new_disk(inode->i_rdev, ctlr));
+	}	
 	case CCISS_PASSTHRU:
 	{
 		IOCTL_Command_struct iocommand;
@@ -827,8 +862,503 @@
         return 0;
 }
 
+static int deregister_disk(int ctlr, int logvol)
+{
+	unsigned long flags;
+	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	ctlr_info_t  *h = hba[ctlr];
+	int start, max_p, i;	
+
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+	/* make sure logical volume is NOT is use */
+	if( h->drv[logvol].usage_count > 1)
+	{
+		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+                return -EBUSY;
+	}
+	h->drv[logvol].usage_count++;
+	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+
+	/* invalidate the devices and deregister the disk */ 
+	max_p = 1 << gdev->minor_shift;
+	start = logvol << gdev->minor_shift;
+	for (i=max_p-1; i>=0; i--)
+	{
+		int minor = start+i;
+		kdev_t kdev = mk_kdev(MAJOR_NR+ctlr, minor);
+		// printk("invalidating( %d %d)\n", ctlr, minor);
+		invalidate_device(kdev, 1);
+		/* so open will now fail */
+		h->sizes[minor] = 0;
+		/* so it will no longer appear in /proc/partitions */ 
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;	
+	}
+	/* check to see if it was the last disk */
+	if (logvol == h->highest_lun)
+	{
+		/* if so, find the new hightest lun */
+		int i, newhighest =-1;
+		for(i=0; i<h->highest_lun; i++)
+		{
+			/* if the disk has size > 0, it is available */
+			if (h->sizes[i << gdev->minor_shift] != 0)
+				newhighest = i;
+		}
+		h->highest_lun = newhighest;
+				
+	}
+	--h->num_luns;
+	gdev->nr_real = h->highest_lun+1; 
+	/* zero out the disk size info */ 
+	h->drv[logvol].nr_blocks = 0;
+	h->drv[logvol].block_size = 0;
+	h->drv[logvol].LunID = 0;
+	return(0);
+}
+static int sendcmd_withirq(__u8	cmd,
+	int	ctlr,
+	void	*buff,
+	size_t	size,
+	unsigned int use_unit_num,
+	unsigned int log_unit,
+	__u8	page_code )
+{
+	ctlr_info_t *h = hba[ctlr];
+	CommandList_struct *c;
+	u64bit	buff_dma_handle;
+	unsigned long flags;
+	int return_status = IO_OK;
+	
+	if ((c = cmd_alloc(h , 0)) == NULL)
+	{
+		return -ENOMEM;
+	}
+	// Fill in the command type 
+	c->cmd_type = CMD_IOCTL_PEND;
+	// Fill in Command Header 
+	c->Header.ReplyQueue = 0;  // unused in simple mode
+	if( buff != NULL) 	// buffer to fill 
+	{
+		c->Header.SGList = 1;
+		c->Header.SGTotal= 1;
+	} else	// no buffers to fill  
+	{
+		c->Header.SGList = 0;
+                c->Header.SGTotal= 0;
+	}
+	c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
+	// Fill in Request block 	
+	switch(cmd)
+	{
+		case  CISS_INQUIRY:
+			/* If the logical unit number is 0 then, this is going
+				to controller so It's a physical command
+				mode = 0 target = 0.
+				So we have nothing to write. 
+				Otherwise 
+				mode = 1  target = LUNID
+			*/
+			if(use_unit_num != 0)
+			{
+				c->Header.LUN.LogDev.VolId=
+                                	hba[ctlr]->drv[log_unit].LunID;
+                        	c->Header.LUN.LogDev.Mode = 1;
+			}
+			if(page_code != 0)
+			{
+				c->Request.CDB[1] = 0x01;
+				c->Request.CDB[2] = page_code;
+			}
+			c->Request.CDBLen = 6;
+			c->Request.Type.Type =  TYPE_CMD; // It is a command. 
+			c->Request.Type.Attribute = ATTR_SIMPLE;  
+			c->Request.Type.Direction = XFER_READ; // Read 
+			c->Request.Timeout = 0; // Don't time out 
+			c->Request.CDB[0] =  CISS_INQUIRY;
+			c->Request.CDB[4] = size  & 0xFF;  
+		break;
+	case CISS_REPORT_LOG:
+                        /* Talking to controller so It's a physical command
+                                mode = 00 target = 0.
+                                So we have nothing to write.
+                        */
+                        c->Request.CDBLen = 12;
+                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Attribute = ATTR_SIMPLE; 
+                        c->Request.Type.Direction = XFER_READ; // Read
+                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.CDB[0] = CISS_REPORT_LOG;
+                        c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
+                        c->Request.CDB[7] = (size >> 16) & 0xFF;
+                        c->Request.CDB[8] = (size >> 8) & 0xFF;
+                        c->Request.CDB[9] = size & 0xFF;
+                break;
+	case CCISS_READ_CAPACITY:
+			c->Header.LUN.LogDev.VolId= 
+				hba[ctlr]->drv[log_unit].LunID;
+			c->Header.LUN.LogDev.Mode = 1;
+			c->Request.CDBLen = 10;
+                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Attribute = ATTR_SIMPLE; 
+                        c->Request.Type.Direction = XFER_READ; // Read
+                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.CDB[0] = CCISS_READ_CAPACITY;
+		break;
+		default:
+			printk(KERN_WARNING
+				"cciss:  Unknown Command 0x%c sent attempted\n", cmd);
+			cmd_free(h, c, 1);
+			return(IO_ERROR);
+	};
+
+	// Fill in the scatter gather information
+	if (size > 0 ) 
+	{
+		buff_dma_handle.val = (__u64) pci_map_single( h->pdev, 
+			buff, size, PCI_DMA_BIDIRECTIONAL);
+		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
+		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
+		c->SG[0].Len = size;
+		c->SG[0].Ext = 0;  // we are not chaining
+	}
+	
+	/* Put the request on the tail of the queue and send it */
+	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+	
+	/* wait for completion */ 
+	while(c->cmd_type != CMD_IOCTL_DONE)
+		schedule_timeout(1);
+	/* unlock the buffers from DMA */
+        pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
+                	size, PCI_DMA_BIDIRECTIONAL);
+
+	if(c->err_info->CommandStatus != 0) 
+	{ /* an error has occurred */ 
+		switch(c->err_info->CommandStatus)
+		{
+			case CMD_TARGET_STATUS:
+				printk(KERN_WARNING "cciss: cmd %p has "
+					" completed with errors\n", c);
+				if( c->err_info->ScsiStatus)
+                		{
+                    			printk(KERN_WARNING "cciss: cmd %p "
+					"has SCSI Status = %x\n",
+                        			c,  
+						c->err_info->ScsiStatus);
+                		}
+
+			break;
+			case CMD_DATA_UNDERRUN:
+			case CMD_DATA_OVERRUN:
+			/* expected for inquire and report lun commands */
+			break;
+			case CMD_INVALID:
+				printk(KERN_WARNING "cciss: Cmd %p is "
+					"reported invalid\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_PROTOCOL_ERR:
+                                printk(KERN_WARNING "cciss: cmd %p has "
+					"protocol error \n", c);
+                                return_status = IO_ERROR;
+                        break;
+case CMD_HARDWARE_ERR:
+                                printk(KERN_WARNING "cciss: cmd %p had " 
+                                        " hardware error\n", c);
+                                return_status = IO_ERROR;
+                        break;
+			case CMD_CONNECTION_LOST:
+				printk(KERN_WARNING "cciss: cmd %p had "
+					"connection lost\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_ABORTED:
+				printk(KERN_WARNING "cciss: cmd %p was "
+					"aborted\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_ABORT_FAILED:
+				printk(KERN_WARNING "cciss: cmd %p reports "
+					"abort failed\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_UNSOLICITED_ABORT:
+				printk(KERN_WARNING "cciss: cmd %p aborted "
+					"do to an unsolicited abort\n", c);
+				return_status = IO_ERROR;
+
 
+			break;
+			default:
+				printk(KERN_WARNING "cciss: cmd %p returned "
+					"unknown status %x\n", c, 
+						c->err_info->CommandStatus); 
+				return_status = IO_ERROR;
+		}
+	}	
+	cmd_free(h, c, 0);
+        return(return_status);
 
+}
+static int register_new_disk(kdev_t dev, int ctlr)
+{
+        struct gendisk *gdev = &(hba[ctlr]->gendisk);
+        ctlr_info_t  *h = hba[ctlr];
+        int start, max_p, i;
+	int num_luns;
+	int logvol;
+	int new_lun_found = 0;
+	int new_lun_index = 0;
+	int free_index_found = 0;
+	int free_index = 0;
+	ReportLunData_struct *ld_buff;
+	ReadCapdata_struct *size_buff;
+	InquiryData_struct *inq_buff;
+	int return_code;
+	int listlength = 0;
+	__u32 lunid = 0;
+	unsigned int block_size;
+	unsigned int total_size;
+
+        if (!capable(CAP_SYS_RAWIO))
+                return -EPERM;
+	/* if we have no space in our disk array left to add anything */
+	if(  h->num_luns >= CISS_MAX_LUN)
+		return -EINVAL;
+	
+	ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+	if (ld_buff == NULL)
+	{
+		printk(KERN_ERR "cciss: out of memory\n");
+		return -1;
+	}
+	memset(ld_buff, 0, sizeof(ReportLunData_struct));
+	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+        if (size_buff == NULL)
+        {
+                printk(KERN_ERR "cciss: out of memory\n");
+		kfree(ld_buff);
+                return -1;
+        }
+	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+        if (inq_buff == NULL)
+        {
+                printk(KERN_ERR "cciss: out of memory\n");
+                kfree(ld_buff);
+		kfree(size_buff);
+                return -1;
+        }
+	
+	return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, 
+			sizeof(ReportLunData_struct), 0, 0, 0 );
+
+	if( return_code == IO_OK)
+	{
+		
+		// printk("LUN Data\n--------------------------\n");
+
+		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
+		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
+		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;	
+		listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
+	} else /* reading number of logical volumes failed */
+	{
+		printk(KERN_WARNING "cciss: report logical volume"
+			" command failed\n");
+		listlength = 0;
+		return -1;
+	}
+	num_luns = listlength / 8; // 8 bytes pre entry
+	if (num_luns > CISS_MAX_LUN)
+	{
+		num_luns = CISS_MAX_LUN;
+	}
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
+		ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
+		ld_buff->LUNListLength[3],  num_luns);
+#endif 
+	for(i=0; i<  num_luns; i++)
+	{
+		int j;
+		int lunID_found = 0;
+
+	  	lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
+        	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
+        	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
+        	lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+		
+ 		/* check to see if this is a new lun */ 
+		for(j=0; j <= h->highest_lun; j++)
+		{
+#ifdef CCISS_DEBUG
+			printk("Checking %d %x against %x\n", j,h->drv[j].LunID,
+						lunid);
+#endif /* CCISS_DEBUG */
+			if (h->drv[j].LunID == lunid)
+			{
+				lunID_found = 1;
+				break;
+			}
+			
+		}
+		if( lunID_found == 1)
+			continue;
+		else
+		{	/* It is the new lun we have been looking for */
+#ifdef CCISS_DEBUG
+			printk("new lun found at %d\n", i);
+#endif /* CCISS_DEBUG */
+			new_lun_index = i;
+			new_lun_found = 1;
+			break;	
+		}
+	 }
+	 if (!new_lun_found)
+	 {
+		printk(KERN_WARNING "cciss:  New Logical Volume not found\n");
+		return -1;
+	 }
+	 /* Now find the free index 	*/
+	for(i=0; i <CISS_MAX_LUN; i++)
+	{
+#ifdef CCISS_DEBUG
+		printk("Checking Index %d\n", i);
+#endif /* CCISS_DEBUG */
+		if(hba[ctlr]->drv[i].LunID == 0)
+		{
+#ifdef CCISS_DEBUG
+			printk("free index found at %d\n", i);
+#endif /* CCISS_DEBUG */
+			free_index_found = 1;
+			free_index = i;
+			break;
+		}
+	}
+	if (!free_index_found)
+	{
+		printk(KERN_WARNING "cciss: unable to find free slot for disk\n");
+                return -1;
+         }
+
+	logvol = free_index;
+	hba[ctlr]->drv[logvol].LunID = lunid;
+		/* there could be gaps in lun numbers, track hightest */
+	if(hba[ctlr]->highest_lun < lunid)
+		hba[ctlr]->highest_lun = logvol;
+		
+	memset(size_buff, 0, sizeof(ReadCapdata_struct));
+	return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, size_buff,
+		sizeof( ReadCapdata_struct), 1, logvol, 0 );
+	if (return_code == IO_OK)
+	{
+		total_size = (0xff & 
+			(unsigned int)(size_buff->total_size[0])) << 24;
+		total_size |= (0xff & 
+				(unsigned int)(size_buff->total_size[1])) << 16;
+		total_size |= (0xff & 
+				(unsigned int)(size_buff->total_size[2])) << 8;
+		total_size |= (0xff & (unsigned int)
+				(size_buff->total_size[3])); 
+		total_size++; // command returns highest block address
+
+		block_size = (0xff & 
+				(unsigned int)(size_buff->block_size[0])) << 24;
+               	block_size |= (0xff & 
+				(unsigned int)(size_buff->block_size[1])) << 16;
+               	block_size |= (0xff & 
+				(unsigned int)(size_buff->block_size[2])) << 8;
+               	block_size |= (0xff & 
+				(unsigned int)(size_buff->block_size[3]));
+	} else /* read capacity command failed */ 
+	{
+			printk(KERN_WARNING "cciss: read capacity failed\n");
+			total_size = 0;
+			block_size = BLOCK_SIZE;
+	}	
+	printk(KERN_INFO "      blocks= %d block_size= %d\n", 
+					total_size, block_size);
+	/* Execute the command to read the disk geometry */
+	memset(inq_buff, 0, sizeof(InquiryData_struct));
+	return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
+                	sizeof(InquiryData_struct), 1, logvol ,0xC1 );
+	if (return_code == IO_OK)
+		{
+			if(inq_buff->data_byte[8] == 0xFF)
+			{
+			   printk(KERN_WARNING "cciss: reading geometry failed, "
+				"volume does not support reading geometry\n");
+
+                           hba[ctlr]->drv[logvol].block_size = block_size;
+                           hba[ctlr]->drv[logvol].nr_blocks = total_size;
+                           hba[ctlr]->drv[logvol].heads = 255;
+                           hba[ctlr]->drv[logvol].sectors = 32; // Sectors per track
+                           hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32;
+                	} else
+			{
+
+		 	   hba[ctlr]->drv[logvol].block_size = block_size;
+                           hba[ctlr]->drv[logvol].nr_blocks = total_size;
+                           hba[ctlr]->drv[logvol].heads = 
+					inq_buff->data_byte[6]; 
+                           hba[ctlr]->drv[logvol].sectors = 
+					inq_buff->data_byte[7]; 
+			   hba[ctlr]->drv[logvol].cylinders = 
+					(inq_buff->data_byte[4] & 0xff) << 8;
+			   hba[ctlr]->drv[logvol].cylinders += 
+                                        inq_buff->data_byte[5];
+			}
+		}
+		else /* Get geometry failed */
+		{
+
+			printk(KERN_WARNING "cciss: reading geometry failed, "
+				"continuing with default geometry\n"); 
+
+			hba[ctlr]->drv[logvol].block_size = block_size;
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = 255;
+			hba[ctlr]->drv[logvol].sectors = 32; // Sectors per track 
+			hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32;
+		}
+		printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d\n\n",
+			hba[ctlr]->drv[logvol].heads, 
+			hba[ctlr]->drv[logvol].sectors,
+			hba[ctlr]->drv[logvol].cylinders);
+	hba[ctlr]->drv[logvol].usage_count = 0;
+	max_p = 1 << gdev->minor_shift;
+        start = logvol<< gdev->minor_shift;
+
+        for(i=max_p-1; i>=0; i--) {
+                int minor = start+i;
+		kdev_t kdev = mk_kdev(MAJOR_NR + ctlr, minor);
+                invalidate_device(kdev, 1);
+                gdev->part[minor].start_sect = 0;
+                gdev->part[minor].nr_sects = 0;
+
+                /* reset the blocksize so we can read the partition table */
+                blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+        }
+
+	++hba[ctlr]->num_luns;
+	gdev->nr_real = hba[ctlr]->highest_lun + 1;
+	/* setup partitions per disk */
+	grok_partitions(dev, hba[ctlr]->drv[logvol].nr_blocks);
+	
+	kfree(ld_buff);
+	kfree(size_buff);
+	kfree(inq_buff);
+	return (logvol);
+}
 /*
  *   Wait polling for a command to complete.
  *   The memory mapped FIFO is polled for the completion.
@@ -959,6 +1489,15 @@
                         c->Request.Timeout = 0; // Don't time out
                         c->Request.CDB[0] = CCISS_READ_CAPACITY;
 		break;
+		case CCISS_CACHE_FLUSH:
+			c->Request.CDBLen = 12;
+                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Attribute = ATTR_SIMPLE;
+                        c->Request.Type.Direction = XFER_WRITE; // No data
+                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.CDB[0] = BMIC_WRITE;  // BMIC Passthru
+                        c->Request.CDB[6] = BMIC_CACHE_FLUSH;
+		break;
 		default:
 			printk(KERN_WARNING
 				"cciss:  Unknown Command 0x%c sent attempted\n",
@@ -1169,17 +1708,32 @@
 	{ /* an error has occurred */ 
 		switch(cmd->err_info->CommandStatus)
 		{
+			unsigned char sense_key;
 			case CMD_TARGET_STATUS:
-				printk(KERN_WARNING "cciss: cmd %p has "
-					" completed with errors\n", cmd);
-				if( cmd->err_info->ScsiStatus)
-                		{
-                    			printk(KERN_WARNING "cciss: cmd %p "
-					"has SCSI Status = %x\n",
-                        			cmd,  
-						cmd->err_info->ScsiStatus);
-                		}
-
+				status = 0;
+			
+				if( cmd->err_info->ScsiStatus == 0x02)
+				{
+					printk(KERN_WARNING "cciss: cmd %p "
+                                        	"has CHECK CONDITION "
+						" byte 2 = 0x%x\n", cmd,
+						cmd->err_info->SenseInfo[2]
+					);
+					/* check the sense key */
+					sense_key = 0xf & 
+						cmd->err_info->SenseInfo[2];
+					/* no status or recovered error */
+					if((sense_key == 0x0) ||
+					    (sense_key == 0x1))
+					{
+							status = 1;
+					}
+				} else
+				{
+					printk(KERN_WARNING "cciss: cmd %p "
+                                                "has SCSI Status 0x%x\n",
+						cmd, cmd->err_info->ScsiStatus);
+				}
 			break;
 			case CMD_DATA_UNDERRUN:
 				printk(KERN_WARNING "cciss: cmd %p has"
@@ -1460,6 +2014,15 @@
 }
 #endif /* CCISS_DEBUG */ 
 
+static void release_io_mem(ctlr_info_t *c)
+{
+	/* if IO mem was not protected do nothing */
+	if( c->io_mem_addr == 0)
+		return;
+	release_region(c->io_mem_addr, c->io_mem_length);
+	c->io_mem_addr = 0;
+	c->io_mem_length = 0;
+}
 static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 {
 	ushort vendor_id, device_id, command;
@@ -1489,17 +2052,49 @@
 		printk(KERN_ERR "cciss:  Unable to set DMA mask\n");
 		return(-1);
 	}
-	
+
 	(void) pci_read_config_word(pdev, PCI_COMMAND,&command);
 	(void) pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
 	(void) pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE,
 						&cache_line_size);
 	(void) pci_read_config_byte(pdev, PCI_LATENCY_TIMER,
 						&latency_timer);
-
 	(void) pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID, 
 						&board_id);
 
+	/* check to see if controller has been disabled */
+	if(!(command & 0x02))
+	{
+		printk(KERN_WARNING "cciss: controller appears to be disabled\n");
+		return(-1);
+	}
+
+	/* search for our IO range so we can protect it */
+	for(i=0; i<6; i++)
+	{
+		/* is this an IO range */ 
+		if( pdev->resource[i].flags & 0x01 )
+		{
+			c->io_mem_addr = pdev->resource[i].start;
+			c->io_mem_length = pdev->resource[i].end -
+				pdev->resource[i].start +1; 
+#ifdef CCISS_DEBUG
+			printk("IO value found base_addr[%d] %lx %lx\n", i,
+				c->io_mem_addr, c->io_mem_length);
+#endif /* CCISS_DEBUG */
+			/* register the IO range */ 
+			if(!request_region( c->io_mem_addr,
+                                        c->io_mem_length, "cciss"))
+			{
+				printk(KERN_WARNING "cciss I/O memory range already in use addr=%lx length=%ld\n",
+				c->io_mem_addr, c->io_mem_length);
+				c->io_mem_addr= 0;
+				c->io_mem_length = 0;
+			} 
+			break;
+		}
+	}
+
 #ifdef CCISS_DEBUG
 	printk("vendor_id = %x\n", vendor_id);
 	printk("device_id = %x\n", device_id);
@@ -1520,7 +2115,7 @@
          *   table
 	 */
 
-	c->paddr = addr[0] & 0xfffffff0; /* remove the addressing mode bits */
+	c->paddr = addr[0] ; /* addressing mode bits already removed */
 #ifdef CCISS_DEBUG
 	printk("address 0 = %x\n", c->paddr);
 #endif /* CCISS_DEBUG */ 
@@ -1617,7 +2212,7 @@
 	int return_code;
 	int i;
 	int listlength = 0;
-	int lunid = 0;
+	__u32 lunid = 0;
 	int block_size;
 	int total_size; 
 
@@ -1689,14 +2284,19 @@
 		ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
 		ld_buff->LUNListLength[3],  hba[cntl_num]->num_luns);
 #endif /* CCISS_DEBUG */
-	for(i=0; i<  hba[cntl_num]->num_luns ; i++)
+
+	hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
+	for(i=0; i<  hba[cntl_num]->num_luns; i++)
 	{
+
 	  	lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
         	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
         	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
         	lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+		
 		hba[cntl_num]->drv[i].LunID = lunid;
 
+
 #ifdef CCISS_DEBUG
 	  	printk(KERN_DEBUG "LUN[%d]:  %x %x %x %x = %x\n", i, 
 		ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], 
@@ -1729,7 +2329,8 @@
 		} else /* read capacity command failed */ 
 		{
 			printk(KERN_WARNING "cciss: read capacity failed\n");
-			total_size = block_size = 0; 
+			total_size = 0;
+			block_size = BLOCK_SIZE;
 		}	
 		printk(KERN_INFO "      blocks= %d block_size= %d\n", 
 					total_size, block_size);
@@ -1781,6 +2382,7 @@
 	}
 	kfree(ld_buff);
 	kfree(size_buff);
+	kfree(inq_buff);
 }	
 
 /* Function to find the first free pointer into our hba[] array */
@@ -1834,6 +2436,7 @@
 	memset(hba[i], 0, sizeof(ctlr_info_t));
 	if (cciss_pci_init(hba[i], pdev) != 0)
 	{
+		release_io_mem(hba[i]);
 		free_hba(i);
 		return (-1);
 	}
@@ -1856,6 +2459,7 @@
 	{
 		printk(KERN_ERR "cciss:  Unable to get major number "
 			"%d for %s\n", MAJOR_NR+i, hba[i]->devname);
+		release_io_mem(hba[i]);
 		free_hba(i);
 		return(-1);
 	}
@@ -1867,6 +2471,7 @@
 		printk(KERN_ERR "ciss: Unable to get irq %d for %s\n",
 			hba[i]->intr, hba[i]->devname);
 		unregister_blkdev( MAJOR_NR+i, hba[i]->devname);
+		release_io_mem(hba[i]);
 		free_hba(i);
 		return(-1);
 	}
@@ -1895,6 +2500,7 @@
 				hba[i]->errinfo_pool_dhandle);
                 free_irq(hba[i]->intr, hba[i]);
                 unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+		release_io_mem(hba[i]);
 		free_hba(i);
                 printk( KERN_ERR "cciss: out of memory");
 		return(-1);
@@ -1944,7 +2550,7 @@
 	hba[i]->gendisk.minor_shift = NWD_SHIFT;
 	hba[i]->gendisk.part = hba[i]->hd;
 	hba[i]->gendisk.sizes = hba[i]->sizes;
-	hba[i]->gendisk.nr_real = hba[i]->num_luns;
+	hba[i]->gendisk.nr_real = hba[i]->highest_lun+1;  
 
 	/* Get on the disk list */ 
 	add_gendisk(&(hba[i]->gendisk));
@@ -1965,6 +2571,8 @@
 {
 	ctlr_info_t *tmp_ptr;
 	int i;
+	char flush_buf[4];
+	int return_code; 
 
 	if (pci_get_drvdata(pdev) == NULL)
 	{
@@ -1979,8 +2587,16 @@
 			"already be removed \n");
 		return;
 	}
-	/* Turn board interrupts off */
-	hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
+	/* Turn board interrupts off  and send the flush cache command */
+	/* sendcmd will turn off interrupt, and send the flush...
+	* To write all data in the battery backed cache to disks */
+	memset(flush_buf, 0, 4);
+	return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL);
+	if(return_code != IO_OK)
+	{
+		printk(KERN_WARNING "Error Flushing cache on controller %d\n", 
+			i);
+	}
 	free_irq(hba[i]->intr, hba[i]);
 	pci_set_drvdata(pdev, NULL);
 	iounmap((void*)hba[i]->vaddr);
@@ -1996,6 +2612,7 @@
 	pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
 		hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
 	kfree(hba[i]->cmd_pool_bits);
+ 	release_io_mem(hba[i]);
 	free_hba(i);
 }	
 
diff -u --recursive --new-file v2.5.2/linux/drivers/block/cciss.h linux/drivers/block/cciss.h
--- v2.5.2/linux/drivers/block/cciss.h	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/cciss.h	Fri Jan 18 14:05:55 2002
@@ -46,6 +46,8 @@
 	__u32	board_id;
 	ulong   vaddr;
 	__u32	paddr;	
+	unsigned long io_mem_addr;
+	unsigned long io_mem_length;
 	CfgTable_struct *cfgtable;
 	int	intr;
 
@@ -53,6 +55,7 @@
 	int	commands_outstanding;
 	int 	max_outstanding; /* Debug */ 
 	int	num_luns;
+	int 	highest_lun;
 	int	usage_count;  /* number of opens all all minor devices */
 
 	// information about each logical volume
diff -u --recursive --new-file v2.5.2/linux/drivers/block/cciss_cmd.h linux/drivers/block/cciss_cmd.h
--- v2.5.2/linux/drivers/block/cciss_cmd.h	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/cciss_cmd.h	Fri Jan 18 14:05:55 2002
@@ -124,6 +124,12 @@
  #define CCISS_READ   0x28    // Read(10)
  #define CCISS_WRITE  0x2a    // Write(10)
 
+// BMIC commands 
+#define BMIC_READ 0x26
+#define BMIC_WRITE 0x27
+#define BMIC_CACHE_FLUSH 0xc2
+#define CCISS_CACHE_FLUSH 0x01	//C2 was already being used by CCISS
+
 //Command List Structure
 typedef union _SCSI3Addr_struct {
    struct {
diff -u --recursive --new-file v2.5.2/linux/drivers/block/cciss_scsi.c linux/drivers/block/cciss_scsi.c
--- v2.5.2/linux/drivers/block/cciss_scsi.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/cciss_scsi.c	Tue Jan 15 10:52:11 2002
@@ -209,13 +209,11 @@
 	stk = &sa->cmd_stack; 
 	size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
 
-	// We use NULL as first arg to pci_alloc_consistent so we can be
-	// sure that we get addresses that will fit through the 32 bit
-	// command register, (our DMA mask says we can do 64 bit DMA, which
-	// we, can, just not for commands.)
+	// pci_alloc_consistent guarentees 32-bit DMA address will
+	// be used
 
 	stk->pool = (struct cciss_scsi_cmd_stack_elem_t *)
-		pci_alloc_consistent(NULL, size, &stk->cmd_pool_handle);
+		pci_alloc_consistent(hba[ctlr]->pdev, size, &stk->cmd_pool_handle);
 
 	if (stk->pool == NULL) {
 		printk("stk->pool is null\n");
@@ -249,8 +247,7 @@
 	}
 	size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
 
-	// About NULL, see note above near pci_alloc_consistent	
-	pci_free_consistent(NULL, size, stk->pool, stk->cmd_pool_handle);
+	pci_free_consistent(hba[ctlr]->pdev, size, stk->pool, stk->cmd_pool_handle);
 	stk->pool = NULL;
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.5.2/linux/drivers/block/ll_rw_blk.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/ll_rw_blk.c	Sat Jan 19 16:49:38 2002
@@ -186,7 +186,8 @@
 	 * full 4GB zone, so we have to resort to low memory for any bounces.
 	 * ISA has its own < 16MB zone.
 	 */
-	if (dma_addr == BLK_BOUNCE_ISA) {
+	if (bounce_pfn < blk_max_low_pfn) {
+		BUG_ON(dma_addr < BLK_BOUNCE_ISA);
 		init_emergency_isa_pool();
 		q->bounce_gfp = GFP_NOIO | GFP_DMA;
 	} else
@@ -302,8 +303,8 @@
 static char *rq_flags[] = { "REQ_RW", "REQ_RW_AHEAD", "REQ_BARRIER",
 			   "REQ_CMD", "REQ_NOMERGE", "REQ_STARTED",
 			   "REQ_DONTPREP", "REQ_DRIVE_CMD", "REQ_DRIVE_TASK",
-			   "REQ_PC", "REQ_BLOCK_PC", "REQ_SENSE",
-			   "REQ_SPECIAL" };
+			   "REQ_DRIVE_ACB", "REQ_PC", "REQ_BLOCK_PC",
+			   "REQ_SENSE", "REQ_SPECIAL" };
 
 void blk_dump_rq_flags(struct request *rq, char *msg)
 {
diff -u --recursive --new-file v2.5.2/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.5.2/linux/drivers/block/loop.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/loop.c	Thu Jan 24 08:31:39 2002
@@ -488,15 +488,15 @@
 			      struct bio *rbh)
 {
 	unsigned long IV = loop_get_iv(lo, rbh->bi_sector);
-	struct bio_vec *to;
+	struct bio_vec *from;
 	char *vto, *vfrom;
 	int ret = 0, i;
 
-	bio_for_each_segment(to, bio, i) {
-		vfrom = page_address(rbh->bi_io_vec[i].bv_page) + rbh->bi_io_vec[i].bv_offset;
-		vto = page_address(to->bv_page) + to->bv_offset;
+	bio_for_each_segment(from, rbh, i) {
+		vfrom = page_address(from->bv_page) + from->bv_offset;
+		vto = page_address(bio->bi_io_vec[i].bv_page) + bio->bi_io_vec[i].bv_offset;
 		ret |= lo_do_transfer(lo, bio_data_dir(bio), vto, vfrom,
-					to->bv_len, IV);
+					from->bv_len, IV);
 	}
 
 	return ret;
@@ -534,7 +534,6 @@
 	struct bio *bio;
 
 	daemonize();
-	exit_files(current);
 
 	sprintf(current->comm, "loop%d", lo->lo_number);
 
diff -u --recursive --new-file v2.5.2/linux/drivers/block/paride/Config.help linux/drivers/block/paride/Config.help
--- v2.5.2/linux/drivers/block/paride/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/paride/Config.help	Fri Jan 25 16:03:19 2002
@@ -0,0 +1,223 @@
+CONFIG_PARIDE_PD
+  This option enables the high-level driver for IDE-type disk devices
+  connected through a parallel port. If you chose to build PARIDE
+  support into your kernel, you may answer Y here to build in the
+  parallel port IDE driver, otherwise you should answer M to build
+  it as a loadable module. The module will be called pd.o. You
+  must also have at least one parallel port protocol driver in your
+  system. Among the devices supported by this driver are the SyQuest
+  EZ-135, EZ-230 and SparQ drives, the Avatar Shark and the backpack
+  hard drives from MicroSolutions.
+
+CONFIG_PARIDE_PCD
+  This option enables the high-level driver for ATAPI CD-ROM devices
+  connected through a parallel port. If you chose to build PARIDE
+  support into your kernel, you may answer Y here to build in the
+  parallel port ATAPI CD-ROM driver, otherwise you should answer M to
+  build it as a loadable module. The module will be called pcd.o. You
+  must also have at least one parallel port protocol driver in your
+  system. Among the devices supported by this driver are the
+  MicroSolutions backpack CD-ROM drives and the Freecom Power CD. If
+  you have such a CD-ROM drive, you should also say Y or M to "ISO
+  9660 CD-ROM file system support" below, because that's the file
+  system used on CD-ROMs.
+
+CONFIG_PARIDE_PF
+  This option enables the high-level driver for ATAPI disk devices
+  connected through a parallel port. If you chose to build PARIDE
+  support into your kernel, you may answer Y here to build in the
+  parallel port ATAPI disk driver, otherwise you should answer M
+  to build it as a loadable module. The module will be called pf.o.
+  You must also have at least one parallel port protocol driver in
+  your system. Among the devices supported by this driver are the
+  MicroSolutions backpack PD/CD drive and the Imation Superdisk
+  LS-120 drive.
+
+CONFIG_PARIDE_PT
+  This option enables the high-level driver for ATAPI tape devices
+  connected through a parallel port. If you chose to build PARIDE
+  support into your kernel, you may answer Y here to build in the
+  parallel port ATAPI disk driver, otherwise you should answer M
+  to build it as a loadable module. The module will be called pt.o.
+  You must also have at least one parallel port protocol driver in
+  your system. Among the devices supported by this driver is the
+  parallel port version of the HP 5GB drive.
+
+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 cdrtools, to send ATAPI commands directly to a
+  device.
+
+  If you chose to build PARIDE support into your kernel, you may
+  answer Y here to build in the parallel port generic ATAPI driver,
+  otherwise you should answer M to build it as a loadable module. The
+  module will be called pg.o.
+
+  You must also have at least one parallel port protocol driver in
+  your system.
+
+  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 cdrtools from
+  <ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/>. Versions 1.6.1a3 and
+  later fully support this driver.
+
+CONFIG_PARIDE_ATEN
+  This option enables support for the ATEN EH-100 parallel port IDE
+  protocol. This protocol is used in some inexpensive low performance
+  parallel port kits made in Hong Kong. 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 aten.o. You must also
+  have a high-level driver for the type of device that you want to
+  support.
+
+CONFIG_PARIDE_BPCK
+  This option enables support for the Micro Solutions BACKPACK
+  parallel port Series 5 IDE protocol.  (Most BACKPACK drives made
+  before 1999 were Series 5) Series 5 drives will NOT always have the
+  Series noted on the bottom of the drive. Series 6 drivers will.
+
+  In other words, if your BACKPACK drive dosen't say "Series 6" on the
+  bottom, enable this option.
+
+  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 bpck.o.  You must also have a high-level driver for the type
+  of device that you want to support.
+
+CONFIG_PARIDE_BPCK6
+  This option enables support for the Micro Solutions BACKPACK
+  parallel port Series 6 IDE protocol.  (Most BACKPACK drives made
+  after 1999 were Series 6) Series 6 drives will have the Series noted
+  on the bottom of the drive.  Series 5 drivers don't always have it
+  noted.
+
+  In other words, if your BACKPACK drive says "Series 6" on the
+  bottom, enable this option.
+
+  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 bpck6.o.  You must also have a high-level driver for the type
+  of device that you want to support.
+
+CONFIG_PARIDE_COMM
+  This option enables support for the Commuter parallel port IDE
+  protocol from DataStor. 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 comm.o. You must also have
+  a high-level driver for the type of device that you want to support.
+
+CONFIG_PARIDE_DSTR
+  This option enables support for the EP-2000 parallel port IDE
+  protocol from DataStor. 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 dstr.o. You must also have
+  a high-level driver for the type of device that you want to support.
+
+CONFIG_PARIDE_EPAT
+  This option enables support for the EPAT parallel port IDE protocol.
+  EPAT is a parallel port IDE adapter manufactured by Shuttle
+  Technology and widely used in devices from major vendors such as
+  Hewlett-Packard, SyQuest, Imation and Avatar. 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 epat.o. You must also
+  have a high-level driver for the type of device that you want to
+  support.
+
+CONFIG_PARIDE_EPATC8
+  This option enables support for the newer Shuttle EP1284 (aka c7 and
+  c8) chip. You need this if you are using any recent Imation SuperDisk
+  (LS-120) drive.
+
+CONFIG_PARIDE_EPIA
+  This option enables support for the (obsolete) EPIA parallel port
+  IDE protocol from Shuttle Technology. This adapter can still be
+  found in some no-name kits. 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 epia.o. You must also have a
+  high-level driver for the type of device that you want to support.
+
+CONFIG_PARIDE_FIT2
+  This option enables support for the TD-2000 parallel port IDE
+  protocol from Fidelity International Technology. This is a simple
+  (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.
+  You must also have a high-level driver for the type of device that
+  you want to support.
+
+CONFIG_PARIDE_FIT3
+  This option enables support for the TD-3000 parallel port IDE
+  protocol from Fidelity International Technology. This protocol is
+  used in newer models of their portable disk, CD-ROM and PD/CD
+  devices. 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 fit3.o. You must also have a high-level driver for the type
+  of device that you want to support.
+
+CONFIG_PARIDE_FRIQ
+  This option enables support for version 2 of the Freecom IQ parallel
+  port IDE adapter.  This adapter is used by the Maxell Superdisk
+  drive.  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 friq.o. You must also have a high-level driver for the type
+  of device that you want to support.
+
+CONFIG_PARIDE_FRPW
+  This option enables support for the Freecom power parallel port IDE
+  protocol. 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 frpw.o. You must also have a high-level driver for the type
+  of device that you want to support.
+
+CONFIG_PARIDE_KBIC
+  This option enables support for the KBIC-951A and KBIC-971A parallel
+  port IDE protocols from KingByte Information Corp. KingByte's
+  adapters appear in many no-name portable disk and CD-ROM products,
+  especially in Europe. 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 kbic.o. You must also have a high-level driver
+  for the type of device that you want to support.
+
+CONFIG_PARIDE_KTTI
+  This option enables support for the "PHd" parallel port IDE protocol
+  from KT Technology. This is a simple (low speed) adapter that is
+  used in some 2.5" 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. You must also
+  have a high-level driver for the type of device that you want to
+  support.
+
+CONFIG_PARIDE_ON20
+  This option enables support for the (obsolete) 90c20 parallel port
+  IDE protocol from OnSpec (often marketed under the ValuStore brand
+  name). 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 on20.o. You must also have a high-level driver for the
+  type of device that you want to support.
+
+CONFIG_PARIDE_ON26
+  This option enables support for the 90c26 parallel port IDE protocol
+  from OnSpec Electronics (often marketed under the ValuStore brand
+  name). 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 on26.o. You must also have a high-level driver for the type
+  of device that you want to support.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/block/paride/pf.c linux/drivers/block/paride/pf.c
--- v2.5.2/linux/drivers/block/paride/pf.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/paride/pf.c	Tue Jan 15 10:58:04 2002
@@ -684,7 +684,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 -u --recursive --new-file v2.5.2/linux/drivers/block/paride/pg.c linux/drivers/block/paride/pg.c
--- v2.5.2/linux/drivers/block/paride/pg.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/paride/pg.c	Tue Jan 15 10:58:04 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/drivers/block/paride/pseudo.h linux/drivers/block/paride/pseudo.h
--- v2.5.2/linux/drivers/block/paride/pseudo.h	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/pseudo.h	Tue Jan 15 10:58:04 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/drivers/block/paride/pt.c linux/drivers/block/paride/pt.c
--- v2.5.2/linux/drivers/block/paride/pt.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/paride/pt.c	Tue Jan 15 10:58:04 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.5.2/linux/drivers/block/ps2esdi.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/ps2esdi.c	Mon Jan 21 16:03:19 2002
@@ -422,7 +422,7 @@
 	blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 128);
 
 	for (i = 0; i < ps2esdi_drives; i++) {
-		register_disk(&ps2esdi_gendisk,MKDEV(MAJOR_NR,i<<6),1<<6,
+		register_disk(&ps2esdi_gendisk,mk_kdev(MAJOR_NR,i<<6),1<<6,
 				&ps2esdi_fops,
 				ps2esdi_info[i].head * ps2esdi_info[i].sect *
 				ps2esdi_info[i].cyl);
@@ -466,7 +466,7 @@
 #if 0
 	printk("%s:got request. device : %d minor : %d command : %d  sector : %ld count : %ld, buffer: %p\n",
 	       DEVICE_NAME,
-	       CURRENT_DEV, MINOR(CURRENT->rq_dev),
+	       CURRENT_DEV, minor(CURRENT->rq_dev),
 	       CURRENT->cmd, CURRENT->sector,
 	       CURRENT->current_nr_sectors, CURRENT->buffer);
 #endif
@@ -481,12 +481,12 @@
 	}			/* check for above 16Mb dmas */
 	else if ((CURRENT_DEV < ps2esdi_drives) &&
 	    (CURRENT->sector + CURRENT->current_nr_sectors <=
-	     ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects) &&
+	     ps2esdi[minor(CURRENT->rq_dev)].nr_sects) &&
 	    	CURRENT->flags & REQ_CMD) {
 #if 0
 		printk("%s:got request. device : %d minor : %d command : %d  sector : %ld count : %ld\n",
 		       DEVICE_NAME,
-		       CURRENT_DEV, MINOR(CURRENT->rq_dev),
+		       CURRENT_DEV, minor(CURRENT->rq_dev),
 		       CURRENT->cmd, CURRENT->sector,
 		       CURRENT->current_nr_sectors);
 #endif
@@ -510,7 +510,7 @@
 	/* is request is valid */ 
 	else {
 		printk("Grrr. error. ps2esdi_drives: %d, %lu %lu\n", ps2esdi_drives,
-		       CURRENT->sector, ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects);
+		       CURRENT->sector, ps2esdi[minor(CURRENT->rq_dev)].nr_sects);
 		end_request(FAIL);
 	}
 
@@ -849,7 +849,7 @@
 	switch (int_ret_code & 0x0f) {
 	case INT_TRANSFER_REQ:
 		ps2esdi_prep_dma(CURRENT->buffer, CURRENT->current_nr_sectors,
-		    (CURRENT->cmd == READ)
+		    (rq_data_dir(CURRENT) == READ)
 		    ? MCA_DMA_MODE_16 | MCA_DMA_MODE_WRITE | MCA_DMA_MODE_XFER
 		    : MCA_DMA_MODE_16 | MCA_DMA_MODE_READ);
 		outb(CTRL_ENABLE_DMA | CTRL_ENABLE_INTR, ESDI_CONTROL);
diff -u --recursive --new-file v2.5.2/linux/drivers/bluetooth/Config.help linux/drivers/bluetooth/Config.help
--- v2.5.2/linux/drivers/bluetooth/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/bluetooth/Config.help	Fri Jan 25 16:04:13 2002
@@ -0,0 +1,23 @@
+CONFIG_BLUEZ_HCIUART
+  Bluetooth HCI UART driver.
+  This driver is required if you want to use Bluetooth devices with
+  serial port interface.
+
+  Say Y here to compile support for Bluetooth UART devices into the
+  kernel or say M to compile it as module (hci_uart.o).
+
+CONFIG_BLUEZ_HCIUSB
+  Bluetooth HCI USB driver.
+  This driver is required if you want to use Bluetooth devices with
+  USB interface.
+
+  Say Y here to compile support for Bluetooth USB devices into the
+  kernel or say M to compile it as module (hci_usb.o).
+
+CONFIG_BLUEZ_HCIVHCI
+  Bluetooth Virtual HCI device driver.
+  This driver is required if you want to use HCI Emulation software.
+
+  Say Y here to compile support for virtual HCI devices into the
+  kernel or say M to compile it as module (hci_vhci.o).
+
diff -u --recursive --new-file v2.5.2/linux/drivers/cdrom/Config.help linux/drivers/cdrom/Config.help
--- v2.5.2/linux/drivers/cdrom/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/cdrom/Config.help	Fri Jan 25 16:03:49 2002
@@ -0,0 +1,227 @@
+CONFIG_CDU31A
+  These CD-ROM drives have a spring-pop-out caddyless drawer, and a
+  rectangular green LED centered beneath it.  NOTE: these CD-ROM
+  drives will not be auto detected by the kernel at boot time; you
+  have to provide the interface address as an option to the kernel at
+  boot time as described in <file:Documentation/cdrom/cdu31a> or fill
+  in your parameters into <file:drivers/cdrom/cdu31a.c>.  Try "man
+  bootparam" or see the documentation of your boot loader (lilo or
+  loadlin) about how to pass options to the kernel.
+
+  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
+  file system support" below, because that's the file system used on
+  CD-ROMs.
+
+  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 cdu31a.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MCD
+  This is the older of the two drivers for the older Mitsumi models
+  LU-005, FX-001 and FX-001D. This is not the right driver for the
+  FX-001DE and the triple or quad speed models (all these are
+  IDE/ATAPI models). Please also the file
+  <file:Documentation/cdrom/mcd>.
+
+  With the old LU-005 model, the whole drive chassis slides out for cd
+  insertion. The FX-xxx models use a motorized tray type mechanism.
+  Note that this driver does not support XA or MultiSession CDs
+  (PhotoCDs). There is a new driver (next question) which can do
+  this. If you want that one, say N here.
+
+  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
+  file system support" below, because that's the file system used on
+  CD-ROMs.
+
+  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 mcd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MCD_IRQ
+  This allows you to specify the default value of the IRQ used by the
+  driver. This setting can be overridden by passing the "mcd="
+  parameter to the kernel at boot time (or at module load time if you
+  said M to "Standard Mitsumi CD-ROM support").
+
+CONFIG_MCD_BASE
+  This allows you to specify the default value of the I/O base address
+  used by the driver. This setting can be overridden by passing the
+  "mcd=" parameter to the kernel at boot time (or at module load time
+  if you said M to "Standard Mitsumi CD-ROM support").
+
+CONFIG_MCDX
+  Use this driver if you want to be able to read XA or MultiSession
+  CDs (PhotoCDs) as well as ordinary CDs with your Mitsumi LU-005,
+  FX-001 or FX-001D CD-ROM drive. In addition, this driver uses much
+  less kernel memory than the old one, if that is a concern. This
+  driver is able to support more than one drive, but each drive needs
+  a separate interface card. Please read the file
+  <file:Documentation/cdrom/mcdx>.
+
+  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
+  file system support" below, because that's the file system used on
+  CD-ROMs.
+
+  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 mcdx.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SBPCD
+  This driver supports most of the drives which use the Panasonic or
+  Sound Blaster interface.  Please read the file
+  <file:Documentation/cdrom/sbpcd>.
+
+  The Matsushita CR-521, CR-522, CR-523, CR-562, CR-563 drives
+  (sometimes labeled "Creative"), the Creative Labs CD200, the
+  Longshine LCS-7260, the "IBM External ISA CD-ROM" (in fact a CR-56x
+  model), the TEAC CD-55A fall under this category.  Some other
+  "electrically compatible" drives (Vertos, Genoa, some Funai models)
+  are currently not supported; for the Sanyo H94A drive currently a
+  separate driver (asked later) is responsible.  Most drives have a
+  uniquely shaped faceplate, with a caddyless motorized drawer, but
+  without external brand markings.  The older CR-52x drives have a
+  caddy and manual loading/eject, but still no external markings.  The
+  driver is able to do an extended auto-probing for interface
+  addresses and drive types; this can help to find facts in cases you
+  are not sure, but can consume some time during the boot process if
+  none of the supported drives gets found.  Once your drive got found,
+  you should enter the reported parameters into
+  <file:drivers/cdrom/sbpcd.h> and set "DISTRIBUTION 0" there.
+
+  This driver can support up to four CD-ROM controller cards, and each
+  card can support up to four CD-ROM drives; if you say Y here, you
+  will be asked how many controller cards you have.  If compiled as a
+  module, only one controller card (but with up to four drives) is
+  usable.
+
+  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
+  file system support" below, because that's the file system used on
+  CD-ROMs.
+
+  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 sbpcd.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SBPCD2
+  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:drivers/cdrom/sbpcd.h> before compiling the new kernel.  Read
+  the file <file:Documentation/cdrom/sbpcd>.
+
+CONFIG_SBPCD3
+  Say Y here only if you have three CD-ROM controller cards of this
+  type (usually only if you have more than six 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 the file <file:Documentation/cdrom/sbpcd>.
+
+CONFIG_SBPCD4
+  Say Y here only if you have four CD-ROM controller cards of this
+  type (usually only if you have more than eight 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 the file <file:Documentation/cdrom/sbpcd>.
+
+CONFIG_AZTCD
+  This is your driver if you have an Aztech CDA268-01A, Orchid
+  CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCD-ROM CR520 or
+  CR540 CD-ROM drive.  This driver -- just like all these CD-ROM
+  drivers -- is NOT for CD-ROM drives with IDE/ATAPI interfaces, such
+  as Aztech CDA269-031SE. Please read the file
+  <file:Documentation/cdrom/aztcd>.
+
+  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
+  file system support" below, because that's the file system used on
+  CD-ROMs.
+
+  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 aztcd.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_CDU535
+  This is the driver for the older Sony CDU-535 and CDU-531 CD-ROM
+  drives. Please read the file <file:Documentation/cdrom/sonycd535>.
+
+  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
+  file system support" below, because that's the file system used on
+  CD-ROMs.
+
+  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 sonycd535.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GSCD
+  If this is your CD-ROM drive, say Y here.  As described in the file
+  <file:Documentation/cdrom/gscd>, you might have to change a setting
+  in the file <file:drivers/cdrom/gscd.h> before compiling the
+  kernel.  Please read the file <file:Documentation/cdrom/gscd>.
+
+  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
+  file system support" below, because that's the file system used on
+  CD-ROMs.
+
+  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 gscd.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_CM206
+  If you have a Philips/LMS CD-ROM drive cm206 in combination with a
+  cm260 host adapter card, say Y here. Please also read the file
+  <file:Documentation/cdrom/cm206>.
+
+  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
+  file system support" below, because that's the file system used on
+  CD-ROMs.
+
+  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 cm206.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_OPTCD
+  This is the driver for the 'DOLPHIN' drive with a 34-pin Sony
+  compatible interface. It also works with the Lasermate CR328A. If
+  you have one of those, say Y. This driver does not work for the
+  Optics Storage 8001 drive; use the IDE-ATAPI CD-ROM driver for that
+  one. Please read the file <file:Documentation/cdrom/optcd>.
+
+  If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
+  file system support" below, because that's the file system used on
+  CD-ROMs.
+
+  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 optcd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SJCD
+  If this is your CD-ROM drive, say Y here and read the file
+  <file:Documentation/cdrom/sjcd>. You should then also say Y or M to
+  "ISO 9660 CD-ROM file system support" below, because that's the
+  file system used on CD-ROMs.
+
+  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 sjcd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_ISP16_CDI
+  These are sound cards with built-in cdrom interfaces using the OPTi
+  82C928 or 82C929 chips. Say Y here to have them detected and
+  possibly configured at boot time. In addition, You'll have to say Y
+  to a driver for the particular cdrom drive you have attached to the
+  card. Read <file:Documentation/cdrom/isp16> for details.
+
+  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 isp16.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/char/Config.help linux/drivers/char/Config.help
--- v2.5.2/linux/drivers/char/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/Config.help	Fri Jan 25 16:04:22 2002
@@ -0,0 +1,1155 @@
+CONFIG_QTRONIX_KEYBOARD
+  Images of Qtronix keyboards are at
+  <http://www.qtronix.com/keyboard.html>.
+
+CONFIG_SERIAL_NONSTANDARD
+  Say Y here if you have any non-standard serial boards -- boards
+  which aren't supported using the standard "dumb" serial driver.
+  This includes intelligent serial boards such as Cyclades,
+  Digiboards, etc. These are usually used for systems that need many
+  serial ports because they serve many terminals or dial-in
+  connections.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about non-standard serial boards.
+
+  Most people can say N here.
+
+CONFIG_SERIAL_EXTENDED
+  If you wish to use any non-standard features of the standard "dumb"
+  driver, say Y here. This includes HUB6 support, shared serial
+  interrupts, special multiport support, support for more than the
+  four COM 1/2/3/4 boards, etc.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about serial driver options. If unsure, say N.
+
+CONFIG_SERIAL_MANY_PORTS
+  Say Y here if you have dumb serial boards other than the four
+  standard COM 1/2/3/4 ports. This may happen if you have an AST
+  FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
+  from <http://www.linuxdoc.org/docs.html#howto>), or other custom
+  serial port hardware which acts similar to standard serial port
+  hardware. If you only use the standard COM 1/2/3/4 ports, you can
+  say N here to save some memory. You can also say Y if you have an
+  "intelligent" multiport card such as Cyclades, Digiboards, etc.
+
+CONFIG_SERIAL_ACPI
+  Legacy free machines may not have serial ports at the legacy COM1, 
+  COM2 etc addresses. Serial ports on such machines are described by
+  the ACPI tables SPCR (Serial Port Console Redirection) table and 
+  DBGP (Debug Port) table. Say Y here if you want to include support
+  for these serial ports.
+
+CONFIG_SERIAL_SHARE_IRQ
+  Some serial boards have hardware support which allows multiple dumb
+  serial ports on the same board to share a single IRQ. To enable
+  support for this in the serial driver, say Y here.
+
+CONFIG_SERIAL_DETECT_IRQ
+  Say Y here if you want the kernel to try to guess which IRQ
+  to use for your serial port.
+
+  This is considered unsafe; it is far better to configure the IRQ in
+  a boot script using the setserial command.
+
+  If unsure, say N.
+
+CONFIG_SERIAL_MULTIPORT
+  Some multiport serial ports have special ports which are used to
+  signal when there are any serial ports on the board which need
+  servicing. Say Y here to enable the serial driver to take advantage
+  of those special I/O ports.
+
+CONFIG_HUB6
+  Say Y here to enable support in the dumb serial driver to support
+  the HUB6 card.
+
+CONFIG_MWAVE
+  The ACP modem (Mwave) for Linux is a WinModem. It is composed of a
+  kernel driver and a user level application. Together these components
+  support direct attachment to public switched telephone networks (PSTNs)
+  and support selected world wide countries.
+
+  This version of the ACP Modem driver supports the IBM Thinkpad 600E,
+  600, and 770 that include on board ACP modem hardware.
+
+  The modem also supports the standard communications port interface
+  (ttySx) and is compatible with the Hayes AT Command Set.
+
+  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/>.
+
+  If you own one of the above IBM Thinkpads which has the Mwave chipset
+  in it, say Y.
+
+  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 mwave.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+
+CONFIG_AGP
+  AGP (Accelerated Graphics Port) is a bus system mainly used to
+  connect graphics cards to the rest of the system.
+
+  If you have an AGP system and you say Y here, it will be possible to
+  use the AGP features of your 3D rendering video card. This code acts
+  as a sort of "AGP driver" for the motherboard's chipset.
+
+  If you need more texture memory than you can get with the AGP GART
+  (theoretically up to 256 MB, but in practice usually 64 or 128 MB
+  due to kernel allocation issues), you could use PCI accesses
+  and have up to a couple gigs of texture space.
+
+  Note that this is the only means to have XFree4/GLX use
+  write-combining with MTRR support on the AGP bus. Without it, OpenGL
+  direct rendering will be a lot slower but still faster than PIO.
+
+  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+  use GLX or DRI.  If unsure, say N.
+
+  This driver is available as a module.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.  The
+  module will be called agpgart.o.
+
+CONFIG_AGP_INTEL
+  This option gives you AGP support for the GLX component of the
+  XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850 and 860 chipsets.
+
+  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+  use GLX or DRI.  If unsure, say N.
+
+CONFIG_AGP_I810
+  This option gives you AGP support for the Xserver on the Intel 810
+  815 and 830m chipset boards for their on-board integrated graphics. This
+  is required to do any useful video modes with these boards.
+
+CONFIG_AGP_VIA
+  This option gives you AGP support for the GLX component of the
+  XFree86 4.x on VIA MPV3/Apollo Pro chipsets.
+
+  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+  use GLX or DRI.  If unsure, say N.
+
+CONFIG_AGP_AMD
+  This option gives you AGP support for the GLX component of the
+  XFree86 4.x on AMD Irongate, 761, and 762 chipsets.
+
+  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+  use GLX or DRI.  If unsure, say N.
+
+CONFIG_AGP_SIS
+  This option gives you AGP support for the GLX component of the "soon
+  to be released" XFree86 4.x on Silicon Integrated Systems [SiS]
+  chipsets.
+
+  Note that 5591/5592 AGP chipsets are NOT supported.
+
+  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+  use GLX or DRI.  If unsure, say N.
+
+CONFIG_AGP_SWORKS
+  Say Y here to support the Serverworks AGP card.  See 
+  <http://www.serverworks.com/> for product descriptions and images.
+
+CONFIG_AGP_ALI
+  This option gives you AGP support for the GLX component of the
+  XFree86 4.x on the following ALi chipsets.  The supported chipsets
+  include M1541, M1621, M1631, M1632, M1641,M1647,and M1651.
+  For the ALi-chipset question, ALi suggests you refer to
+  <http://www.ali.com.tw/eng/support/index.shtml>.
+
+  The M1541 chipset can do AGP 1x and 2x, but note that there is an
+  acknowledged incompatibility with Matrox G200 cards. Due to
+  timing issues, this chipset cannot do AGP 2x with the G200.
+  This is a hardware limitation. AGP 1x seems to be fine, though.
+
+  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+  use GLX or DRI.  If unsure, say N.
+
+CONFIG_I810_TCO
+  Hardware driver for the TCO timer built into the Intel i810 and i815
+  chipset family.  The TCO (Total Cost of Ownership) timer is a
+  watchdog timer that will reboot the machine after its second
+  expiration. The expiration time can be configured by commandline
+  argument "i810_margin=<n>" where <n> is the counter initial value.
+  It is decremented every 0.6 secs, the default is 50 which gives a
+  timeout of 30 seconds and one minute until reset.
+
+  On some motherboards the driver may fail to reset the chipset's
+  NO_REBOOT flag which prevents the watchdog from rebooting the
+  machine. If this is the case you will get a kernel message like
+  "i810tco init: failed to reset NO_REBOOT flag".
+
+  If you want to compile this as a module, say M and read
+  <file:Documentation/modules.txt>.  The module will be called
+  i810-tco.o.
+
+CONFIG_VT
+  If you say Y here, you will get support for terminal devices with
+  display and keyboard devices. These are called "virtual" because you
+  can run several virtual terminals (also called virtual consoles) on
+  one physical terminal. This is rather useful, for example one
+  virtual terminal can collect system messages and warnings, another
+  one can be used for a text-mode user session, and a third could run
+  an X session, all in parallel. Switching between virtual terminals
+  is done with certain key combinations, usually Alt-<function key>.
+
+  The setterm command ("man setterm") can be used to change the
+  properties (such as colors or beeping) of a virtual terminal. The
+  man page console_codes(4) ("man console_codes") contains the special
+  character sequences that can be used to change those properties
+  directly. The fonts used on virtual terminals can be changed with
+  the setfont ("man setfont") command and the key bindings are defined
+  with the loadkeys ("man loadkeys") command.
+
+  You need at least one virtual terminal device in order to make use
+  of your keyboard and monitor. Therefore, only people configuring an
+  embedded system would want to say N here in order to save some
+  memory; the only way to log into such a system is then via a serial
+  or network connection.
+
+  If unsure, say Y, or else you won't be able to do much with your new
+  shiny Linux system :-)
+
+CONFIG_VT_CONSOLE
+  The system console is the device which receives all kernel messages
+  and warnings and which allows logins in single user mode. If you
+  answer Y here, a virtual terminal (the device used to interact with
+  a physical terminal) can be used as system console. This is the most
+  common mode of operations, so you should say Y here unless you want
+  the kernel messages be output only to a serial port (in which case
+  you should say Y to "Console on serial port", below).
+
+  If you do say Y here, by default the currently visible virtual
+  terminal (/dev/tty0) will be used as system console. You can change
+  that with a kernel command line option such as "console=tty3" which
+  would use the third virtual terminal as system console. (Try "man
+  bootparam" or see the documentation of your boot loader (lilo or
+  loadlin) about how to pass options to the kernel at boot time.)
+
+  If unsure, say Y.
+
+CONFIG_SERIAL
+  This selects whether you want to include the driver for the standard
+  serial ports.  The standard answer is Y.  People who might say N
+  here are those that are setting up dedicated Ethernet WWW/FTP
+  servers, or users that have one of the various bus mice instead of a
+  serial mouse and don't intend to use their machine's standard serial
+  port for anything.  (Note that the Cyclades and Stallion multi
+  serial port drivers do not need this driver built in for them to
+  work.)
+
+  If you want to compile this driver as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  serial.o.
+  [WARNING: Do not compile this driver as a module if you are using
+  non-standard serial ports, since the configuration information will
+  be lost when the driver is unloaded.  This limitation may be lifted
+  in the future.]
+
+  BTW1: If you have a mouseman serial mouse which is not recognized by
+  the X window system, try running gpm first.
+
+  BTW2: If you intend to use a software modem (also called Winmodem)
+  under Linux, forget it.  These modems are crippled and require
+  proprietary drivers which are only available under Windows.
+
+  Most people will say Y or M here, so that they can use serial mice,
+  modems and similar devices connecting to the standard serial ports.
+
+CONFIG_SERIAL_CONSOLE
+  If you say Y here, it will be possible to use a serial port as the
+  system console (the system console is the device which receives all
+  kernel messages and warnings and which allows logins in single user
+  mode). This could be useful if some terminal or printer is connected
+  to that serial port.
+
+  Even if you say Y here, the currently visible virtual console
+  (/dev/tty0) will still be used as the system console by default, but
+  you can alter that using a kernel command line option such as
+  "console=ttyS1". (Try "man bootparam" or see the documentation of
+  your boot loader (lilo or loadlin) about how to pass options to the
+  kernel at boot time.)
+
+  If you don't have a VGA card installed and you say Y here, the
+  kernel will automatically use the first serial line, /dev/ttyS0, as
+  system console.
+
+  If unsure, say N.
+
+CONFIG_ROCKETPORT
+  This is a driver for the Comtrol Rocketport cards which provide
+  multiple serial ports. You would need something like this to connect
+  more than two modems to your Linux box, for instance in order to
+  become a dial-in server.
+
+  If you want to compile this driver as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  rocket.o.
+
+CONFIG_DIGIEPCA
+  This is a driver for Digi International's Xx, Xeve, and Xem series
+  of cards which provide multiple serial ports. You would need
+  something like this to connect more than two modems to your Linux
+  box, for instance in order to become a dial-in server. This driver
+  supports the original PC (ISA) boards as well as PCI, and EISA. If
+  you have a card like this, say Y here and read the file
+  <file:Documentation/digiepca.txt>.
+
+  NOTE: There is another, separate driver for the Digiboard PC boards:
+  "Digiboard PC/Xx Support" below. You should (and can) only select
+  one of the two drivers.
+
+  If you want to compile this driver as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called epca.o.
+
+CONFIG_DIGI
+  This is a driver for the Digiboard PC/Xe, PC/Xi, and PC/Xeve cards
+  that give you many serial ports. You would need something like this
+  to connect more than two modems to your Linux box, for instance in
+  order to become a dial-in server. If you have a card like that, say
+  Y here and read the file <file:Documentation/digiboard.txt>.
+
+  If you want to compile this driver as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called pcxx.o.
+
+CONFIG_RISCOM8
+  This is a driver for the SDL Communications RISCom/8 multiport card,
+  which gives you many serial ports. You would need something like
+  this to connect more than two modems to your Linux box, for instance
+  in order to become a dial-in server. If you have a card like that,
+  say Y here and read the file <file:Documentation/riscom8.txt>.
+
+  Also it's possible to say M here and compile this driver as kernel
+  loadable module; the module will be called riscom8.o.
+
+CONFIG_COMPUTONE
+  This driver supports the entire family of Intelliport II/Plus
+  controllers with the exception of the MicroChannel controllers and
+  products previous to the Intelliport II. These are multiport cards,
+  which give you many serial ports. You would need something like this
+  to connect more than two modems to your Linux box, for instance in
+  order to become a dial-in server. If you have a card like that, say
+  Y here and read <file:Documentation/computone.txt>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. You will get
+  two modules called ip2.o and ip2main.o.
+
+CONFIG_SPECIALIX
+  This is a driver for the Specialix IO8+ multiport card (both the
+  ISA and the PCI version) which gives you many serial ports. You
+  would need something like this to connect more than two modems to
+  your Linux box, for instance in order to become a dial-in server.
+
+  If you have a card like that, say Y here and read the file
+  <file:Documentation/specialix.txt>. Also it's possible to say M here
+  and compile this driver as kernel loadable module which will be
+  called specialix.o.
+
+CONFIG_SPECIALIX_RTSCTS
+  The Specialix IO8+ card can only support either RTS or DTR. If you
+  say N here, the driver will use the pin as "DTR" when the tty is in
+  software handshake mode.  If you say Y here or hardware handshake is
+  on, it will always be RTS.  Read the file
+  <file:Documentation/specialix.txt> for more information.
+
+CONFIG_RIO
+  This is a driver for the Specialix RIO, a smart serial card which
+  drives an outboard box that can support up to 128 ports.  Product
+  information is at <http://www.sphinxcst.co.uk/perle/multi.htm>.
+  There are both ISA and PCI versions.
+
+CONFIG_RIO_OLDPCI
+  Older RIO PCI cards need some initialization-time configuration to
+  determine the IRQ and some control addresses.  If you have a RIO and
+  this doesn't seem to work, try setting this to Y.
+
+CONFIG_CYCLADES
+  This is a driver for a card that gives you many serial ports. You
+  would need something like this to connect more than two modems to
+  your Linux box, for instance in order to become a dial-in server.
+  For information about the Cyclades-Z card, read
+  <file:drivers/char/README.cycladesZ>.
+
+  As of 1.3.9x kernels, this driver's minor numbers start at 0 instead
+  of 32.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called cyclades.o.
+
+  If you haven't heard about it, it's safe to say N.
+
+CONFIG_CYZ_INTR
+  The Cyclades-Z family of multiport cards allows 2 (two) driver op
+  modes: polling and interrupt. In polling mode, the driver will check
+  the status of the Cyclades-Z ports every certain amount of time
+  (which is called polling cycle and is configurable). In interrupt
+  mode, it will use an interrupt line (IRQ) in order to check the
+  status of the Cyclades-Z ports. The default op mode is polling. If
+  unsure, say N.
+
+CONFIG_STALDRV
+  Stallion cards give you many serial ports.  You would need something
+  like this to connect more than two modems to your Linux box, for
+  instance in order to become a dial-in server.  If you say Y here,
+  you will be asked for your specific card model in the next
+  questions.  Make sure to read <file:Documentation/stallion.txt> in
+  this case.  If you have never heard about all this, it's safe to
+  say N.
+
+CONFIG_STALLION
+  If you have an EasyIO or EasyConnection 8/32 multiport Stallion
+  card, then this is for you; say Y.  Make sure to read
+  <file:Documentation/stallion.txt>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called stallion.o.
+
+CONFIG_ISTALLION
+  If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
+  serial multiport card, say Y here. Make sure to read
+  <file:Documentation/stallion.txt>.
+
+  To compile it 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
+  istallion.o.
+
+CONFIG_SYNCLINK
+  Provides support for the SyncLink ISA and PCI multiprotocol serial
+  adapters. These adapters support asynchronous and HDLC bit
+  synchronous communication up to 10Mbps (PCI adapter).
+
+  This driver can only be built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called synclink.o.  If you want to do that, say M
+  here.
+
+CONFIG_N_HDLC
+  Allows synchronous HDLC communications with tty device drivers that
+  support synchronous HDLC such as the Microgate SyncLink adapter.
+
+  This driver can only be built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called n_hdlc.o. If you want to do that, say M
+  here.
+
+CONFIG_SX
+  This is a driver for the SX and SI multiport serial cards.
+  Please read the file <file:Documentation/sx.txt> for details.
+
+  This driver can only be built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called sx.o. If you want to do that, say M here.
+
+CONFIG_ESPSERIAL
+  This is a driver which supports Hayes ESP serial ports.  Both single
+  port cards and multiport cards are supported.  Make sure to read
+  <file:Documentation/hayes-esp.txt>.
+
+  To compile this driver as a module ( = code which can be inserted in
+  and removed from the running kernel whenever you want), say M here
+  and read <file:Documentation/modules.txt>.  The module will be
+  called esp.o.  If unsure, say N.
+
+CONFIG_MOXA_INTELLIO
+  Say Y here if you have a Moxa Intellio multiport serial card.
+
+  This driver can also be built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called moxa.o. If you want to do that, say M
+  here.
+
+CONFIG_MOXA_SMARTIO
+  Say Y here if you have a Moxa SmartIO multiport serial card.
+
+  This driver can also be built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called mxser.o. If you want to do that, say M
+  here.
+
+CONFIG_ISI
+  This is a driver for the Multi-Tech cards which provide several
+  serial ports.  The driver is experimental and can currently only be
+  built as a module ( = code which can be inserted in and removed from
+  the running kernel whenever you want).  Please read
+  <file:Documentation/modules.txt>.  The module will be called
+  isicom.o.
+
+CONFIG_UNIX98_PTYS
+  A pseudo terminal (PTY) is a software device consisting of two
+  halves: a master and a slave. The slave device behaves identical to
+  a physical terminal; the master device is used by a process to
+  read data from and write data to the slave, thereby emulating a
+  terminal. Typical programs for the master side are telnet servers
+  and xterms.
+
+  Linux has traditionally used the BSD-like names /dev/ptyxx for
+  masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
+  has a number of problems. The GNU C library glibc 2.1 and later,
+  however, supports the Unix98 naming standard: in order to acquire a
+  pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
+  terminal is then made available to the process and the pseudo
+  terminal slave can be accessed as /dev/pts/<number>. What was
+  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
+
+  The entries in /dev/pts/ are created on the fly by a virtual
+  file system; therefore, if you say Y here you should say Y to
+  "/dev/pts file system for Unix98 PTYs" as well.
+
+  If you want to say Y here, you need to have the C library glibc 2.1
+  or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
+  Read the instructions in <file:Documentation/Changes> pertaining to
+  pseudo terminals. It's safe to say N.
+
+CONFIG_UNIX98_PTY_COUNT
+  The maximum number of Unix98 PTYs that can be used at any one time.
+  The default is 256, and should be enough for desktop systems. Server
+  machines which support incoming telnet/rlogin/ssh connections and/or
+  serve several X terminals may want to increase this: every incoming
+  connection and every xterm uses up one PTY.
+
+  When not in use, each additional set of 256 PTYs occupy
+  approximately 8 KB of kernel memory on 32-bit architectures.
+
+CONFIG_PRINTER
+  If you intend to attach a printer to the parallel port of your Linux
+  box (as opposed to using a serial printer; if the connector at the
+  printer has 9 or 25 holes ["female"], then it's serial), say Y.
+  Also read the Printing-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  It is possible to share one parallel port among several devices
+  (e.g. printer and ZIP drive) and it is safe to compile the
+  corresponding drivers into the kernel.  If you want to compile this
+  driver as a module however ( = code which can be inserted in and
+  removed from the running kernel whenever you want), say M here and
+  read <file:Documentation/modules.txt> and
+  <file:Documentation/parport.txt>.  The module will be called lp.o.
+
+  If you have several parallel ports, you can specify which ports to
+  use with the "lp" kernel command line option.  (Try "man bootparam"
+  or see the documentation of your boot loader (lilo or loadlin) about
+  how to pass options to the kernel at boot time.)  The syntax of the
+  "lp" command line option can be found in <file:drivers/char/lp.c>.
+
+  If you have more than 8 printers, you need to increase the LP_NO
+  macro in lp.c and the PARPORT_MAX macro in parport.h.
+
+CONFIG_LP_CONSOLE
+  If you want kernel messages to be printed out as they occur, you
+  can have a console on the printer. This option adds support for
+  doing that; to actually get it to happen you need to pass the
+  option "console=lp0" to the kernel at boot time.
+
+  If the printer is out of paper (or off, or unplugged, or too
+  busy..) the kernel will stall until the printer is ready again.
+  By defining CONSOLE_LP_STRICT to 0 (at your own risk) you
+  can make the kernel continue when this happens,
+  but it'll lose the kernel messages.
+
+  If unsure, say N.
+
+CONFIG_PPDEV
+  Saying Y to this adds support for /dev/parport device nodes.  This
+  is needed for programs that want portable access to the parallel
+  port, for instance deviceid (which displays Plug-and-Play device
+  IDs).
+
+  This is the parallel port equivalent of SCSI generic support (sg).
+  It is safe to say N to this -- it is not needed for normal printing
+  or parallel port CD-ROM/disk support.
+
+  This support is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  ppdev.o.
+
+  If unsure, say N.
+
+CONFIG_BUSMOUSE
+  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 a laptop, you either have to check the documentation or
+  experiment a bit to find out whether the trackball is a serial mouse
+  or not; it's best to say Y here for you.
+
+  This is the generic bus mouse driver code. If you have a bus mouse,
+  you will have to say Y here and also to the specific driver for your
+  mouse below.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called busmouse.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MOUSE
+  This is for machines with a mouse which is neither a serial nor a
+  bus mouse. Examples are PS/2 mice (such as the track balls on some
+  laptops) and some digitizer pads. 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>. This HOWTO contains
+  information about all non-serial mice, not just bus mice.
+
+  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
+  or not; it's best to say Y here for you.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about non-serial mice. If unsure, say Y.
+
+CONFIG_LOGIBUSMOUSE
+  Logitech mouse connected to a proprietary interface card.  It's
+  generally a round connector with 9 pins. Note that the newer mice
+  made by Logitech don't use the Logitech protocol anymore; for those,
+  you don't need this option.  You want to read the Busmouse-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called busmouse.o.  If you are unsure, say N and read the
+  HOWTO nevertheless: it will tell you what you have.
+
+CONFIG_PSMOUSE
+  The PS/2 mouse connects to a special mouse port that looks much like
+  the keyboard port (small circular connector with 6 pins). This way,
+  the mouse does not use any serial ports. This port can also be used
+  for other input devices like light pens, tablets, keypads. Compaq,
+  AST and IBM all use this as their mouse port on currently shipping
+  machines. The trackballs of some laptops are PS/2 mice also. In
+  particular, the C&T 82C710 mouse on TI Travelmates is a PS/2 mouse.
+
+  Although PS/2 mice are not technically bus mice, they are explained
+  in detail in the Busmouse-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  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://gnu.systemy.it/pub/gpm/>) solves this problem, or you can get
+  the "mconv2" utility from <ftp://ibiblio.org/pub/Linux/system/mouse/>.
+
+CONFIG_82C710_MOUSE
+  This is a certain kind of PS/2 mouse used on the TI Travelmate. If
+  you are unsure, try first to say N here and come back if the mouse
+  doesn't work. Read the Busmouse-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+CONFIG_PC110_PAD
+  This drives the digitizer pad on the IBM PC110 palmtop.  It can turn
+  the digitizer pad into a PS/2 mouse emulation with tap gestures or
+  into an absolute pad.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called pc110pad.o.
+
+CONFIG_MS_BUSMOUSE
+  These animals (also called Inport mice) are connected to an
+  expansion board using a round connector with 9 pins. If this is what
+  you have, say Y and read the Busmouse-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you are unsure, say N and read the HOWTO nevertheless: it will
+  tell you what you have. Also be aware that several vendors talk
+  about 'Microsoft busmouse' and actually mean PS/2 busmouse -- so
+  count the pins on the connector.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called msbusmouse.o.
+
+CONFIG_ADBMOUSE
+  Say Y here if you have this type of bus mouse (4 pin connector) as
+  is common on Macintoshes.  You may want to read the Busmouse-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called adbmouse.o.
+
+CONFIG_ATIXL_BUSMOUSE
+  This is a rare type of busmouse that is connected to the back of an
+  ATI video card.  Say Y if you have one of those. Note however that
+  most mice by ATI are actually Microsoft busmice; you should say Y to
+  "Microsoft busmouse support" above if you have one of those.  Read
+  the Busmouse-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called atixlmouse.o.
+
+  If you are unsure, say N and read the HOWTO nevertheless: it will
+  tell you what you have.
+
+CONFIG_QIC02_TAPE
+  If you have a non-SCSI tape drive like that, say Y. Or, if you want
+  to compile this driver as a module ( = code which can be inserted in
+  and removed from the running kernel whenever you want), say M here
+  and read <file:Documentation/modules.txt>. The module will be called
+  tpqic02.o.
+
+CONFIG_QIC02_DYNCONF
+  You can either configure this driver once and for all by editing a
+  header file (<file:include/linux/tpqic02.h>), in which case you
+  should say N, or you can fetch a program via anonymous FTP which is
+  able to configure this driver during runtime.  The program to do
+  this is called 'qic02conf' and it is part of the
+  tpqic02-support-X.Y.tar.gz support package.
+
+  If you want to use the qic02conf program, say Y.
+
+CONFIG_FTAPE
+  If you have a tape drive that is connected to your floppy
+  controller, say Y here.
+
+  Some tape drives (like the Seagate "Tape Store 3200" or the Iomega
+  "Ditto 3200" or the Exabyte "Eagle TR-3") come with a "high speed"
+  controller of their own. These drives (and their companion
+  controllers) are also supported if you say Y here.
+
+  If you have a special controller (such as the CMS FC-10, FC-20,
+  Mountain Mach-II, or any controller that is based on the Intel 82078
+  FDC like the high speed controllers by Seagate and Exabyte and
+  Iomega's "Ditto Dash") you must configure it by selecting the
+  appropriate entries from the "Floppy tape controllers" sub-menu
+  below and possibly modify the default values for the IRQ and DMA
+  channel and the IO base in ftape's configuration menu.
+
+  If you want to use your floppy tape drive on a PCI-bus based system,
+  please read the file <file:drivers/char/ftape/README.PCI>.
+
+  The ftape kernel driver is also available as a runtime loadable
+  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>. The
+  module will be called ftape.o.
+
+  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.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
+  changed quite a bit compared to previous versions of ftape.  Please
+  read <file:Documentation/ftape.txt>.
+
+CONFIG_DTLK
+  This driver is for the DoubleTalk PC, a speech synthesizer
+  manufactured by RC Systems (<http://www.rcsys.com/>).  It is also
+  called the `internal DoubleTalk'.  If you want to compile this as a
+  module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), say M here and read
+  <file:Documentation/modules.txt>. The module will be called dtlk.o.
+
+CONFIG_R3964
+  This driver allows synchronous communication with devices using the
+  Siemens R3964 packet protocol. Unless you are dealing with special
+  hardware like PLCs, you are unlikely to need this.
+
+  To compile this driver as a module ( = code which can be inserted in
+  and removed from the running kernel whenever you want), say M here
+  and read <file:Documentation/modules.txt>. The module will be called
+  n_r3964.o.
+
+  If unsure, say N.
+
+CONFIG_APPLICOM
+  This driver provides the kernel-side support for the intelligent
+  fieldbus cards made by Applicom International. More information
+  about these cards can be found on the WWW at the address
+  <http://www.applicom-int.com/>, or by email from David Woodhouse
+  <dwmw2@infradead.org>.
+
+  To compile this driver as a module ( = code which can be inserted in
+  and removed from the running kernel whenever you want), say M here
+  and read <file:Documentation/modules.txt>. The module will be called
+  applicom.o.
+
+  If unsure, say N.
+
+CONFIG_SONYPI
+  This driver enables access to the Sony Programmable I/O Control
+  Device which can be found in many (all ?) Sony Vaio laptops.
+
+  If you have one of those laptops, read
+  <file:Documentation/sonypi.txt>, and say Y or M here.
+
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called sonypi.o.
+
+CONFIG_INTEL_RNG
+  This driver provides kernel-side support for the Random Number
+  Generator hardware found on Intel i8xx-based motherboards.
+
+  Both a character driver, used to read() entropy data, and a timer
+  function which automatically adds entropy directly into the
+  kernel pool, are exported by this driver.
+
+  To compile this driver as a module ( = code which can be inserted in
+  and removed from the running kernel whenever you want), say M here
+  and read <file:Documentation/modules.txt>. The module will be called
+  i810_rng.o.
+
+  If unsure, say N.
+
+CONFIG_WATCHDOG
+  If you say Y here (and to one of the following options) and create a
+  character special file /dev/watchdog with major number 10 and minor
+  number 130 using mknod ("man mknod"), you will get a watchdog, i.e.:
+  subsequently opening the file and then failing to write to it for
+  longer than 1 minute will result in rebooting the machine. This
+  could be useful for a networked machine that needs to come back
+  online as fast as possible after a lock-up. There's both a watchdog
+  implementation entirely in software (which can sometimes fail to
+  reboot the machine) and a driver for hardware watchdog boards, which
+  are more robust and can also keep track of the temperature inside
+  your computer. For details, read <file:Documentation/watchdog.txt>
+  in the kernel source.
+
+  The watchdog is usually used together with the watchdog daemon
+  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.
+
+CONFIG_WATCHDOG_NOWAYOUT
+  The default watchdog behaviour (which you get if you say N here) is
+  to stop the timer if the process managing it closes the file
+  /dev/watchdog. It's always remotely possible that this process might
+  get killed. If you say Y here, the watchdog cannot be stopped once
+  it has been started.
+
+CONFIG_WDT
+  If you have a WDT500P or WDT501P watchdog board, say Y here,
+  otherwise N. It is not possible to probe for this board, which means
+  that you have to inform the kernel about the IO port and IRQ using
+  the "wdt=" kernel option (try "man bootparam" or see the
+  documentation of your boot loader (lilo or loadlin) about how to
+  pass options to the kernel at boot time).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called wdt.o.
+
+CONFIG_WDTPCI
+  If you have a PCI WDT500/501 watchdog board, say Y here, otherwise
+  N.  It is not possible to probe for this board, which means that you
+  have to inform the kernel about the IO port and IRQ using the "wdt="
+  kernel option (try "man bootparam" or see the documentation of your
+  boot loader (lilo or loadlin) about how to pass options to the
+  kernel at boot time).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called wdt_pci.o.
+
+CONFIG_WDT_501
+  Saying Y here and creating a character special file /dev/temperature
+  with major number 10 and minor number 131 ("man mknod") will give
+  you a thermometer inside your computer: reading from
+  /dev/temperature yields one byte, the temperature in degrees
+  Fahrenheit. This works only if you have a WDT501P watchdog board
+  installed.
+
+CONFIG_WDT_501_FAN
+  Enable the Fan Tachometer on the WDT501. Only do this if you have a
+  fan tachometer actually set up.
+
+CONFIG_SOFT_WATCHDOG
+  A software monitoring watchdog. This will fail to reboot your system
+  from some situations that the hardware watchdog will recover
+  from. Equally it's a lot cheaper to install.
+
+  This driver is also available 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>. The module will be called
+   softdog.o.
+
+CONFIG_PCWATCHDOG
+  This is the driver for the Berkshire Products PC Watchdog card.
+  This card simply watches your kernel to make sure it doesn't freeze,
+  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/>.
+
+  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 is called pcwd.o. If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.
+
+  Most people will say N.
+
+CONFIG_ACQUIRE_WDT
+  This is the driver for the hardware watchdog on the PSC-6x86 Single
+  Board Computer produced by Acquire Inc (and others).  This watchdog
+  simply watches your kernel to make sure it doesn't freeze, 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.
+  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 is called pscwdt.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.  Most
+  people will say N.
+
+CONFIG_ADVANTECH_WDT
+  If you are configuring a Linux kernel for the Advantech single-board
+  computer, say `Y' here to support its built-in watchdog timer
+  feature.  See the help for CONFIG_WATCHDOG for discussion.
+
+CONFIG_W83877F_WDT
+  This is the driver for the hardware watchdog on the W83877F chipset
+  as used in EMACS PC-104 motherboards (and likely others).  This
+  watchdog simply watches your kernel to make sure it doesn't freeze,
+  and if it does, it reboots your computer after a certain amount of
+  time.
+
+  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 is called mixcomwd.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.  Most
+  people will say N.
+
+CONFIG_IB700_WDT
+  This is the driver for the hardware watchdog on the IB700 Single
+  Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog
+  simply watches your kernel to make sure it doesn't freeze, and if
+  it does, it reboots your computer after a certain amount of time.
+
+  This driver is like the WDT501 driver but for slightly different hardware.
+
+  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 is called ib700wdt.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. Most people
+  will say N.
+
+CONFIG_MIXCOMWD
+  This is a driver for the Mixcom hardware watchdog cards.  This
+  watchdog simply watches your kernel to make sure it doesn't freeze,
+  and if it does, it reboots your computer after a certain amount of
+  time.
+
+  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 is called mixcomwd.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.  Most
+  people will say N.
+
+CONFIG_MACHZ_WDT
+  If you are using a ZF Micro MachZ processor, say Y here, otherwise
+  N.  This is the driver for the watchdog timer builtin on that
+  processor using ZF-Logic interface.  This watchdog simply watches
+  your kernel to make sure it doesn't freeze, and if it does, it
+  reboots your computer after a certain amount of time.
+
+  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 is called machzwd.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_60XX_WDT
+ This driver can be used with the watchdog timer found on some
+ single board computers, namely the 6010 PII based computer.
+ It may well work with other cards.  It reads port 0x443 to enable
+ and re-set the watchdog timer, and reads port 0x45 to disable
+ the watchdog.  If you have a card that behave in similar ways,
+ you can probably make this driver work with your card as well.
+
+ You can compile this driver directly into the kernel, or use
+ it as a module.  The module will be called sbc60xxwdt.o.
+
+CONFIG_RTC
+  If you say Y here and create a character special file /dev/rtc with
+  major number 10 and minor number 135 using mknod ("man mknod"), you
+  will get access to the real time clock (or hardware clock) built
+  into your computer.
+
+  Every PC has such a clock built in. It can be used to generate
+  signals from as low as 1Hz up to 8192Hz, and can also be used
+  as a 24 hour alarm. It reports status information via the file
+  /proc/driver/rtc and its behaviour is set by various ioctls on
+  /dev/rtc.
+
+  If you run Linux on a multiprocessor machine and said Y to
+  "Symmetric Multi Processing" above, you should say Y here to read
+  and set the RTC in an SMP compatible fashion.
+
+  If you think you have a use for such a device (such as periodic data
+  sampling), then say Y here, and read <file:Documentation/rtc.txt>
+  for details.
+
+  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 is called rtc.o. If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_H8
+  The Hitachi H8/337 is a microcontroller used to deal with the power
+  and thermal environment. If you say Y here, you will be able to
+  communicate with it via a character special device.
+
+  If unsure, say N.
+
+CONFIG_NVRAM
+  If you say Y here and create a character special file /dev/nvram
+  with major number 10 and minor number 144 using mknod ("man mknod"),
+  you get read and write access to the 50 bytes of non-volatile memory
+  in the real time clock (RTC), which is contained in every PC and
+  most Ataris.
+
+  This memory is conventionally called "CMOS RAM" on PCs and "NVRAM"
+  on Ataris. /dev/nvram may be used to view settings there, or to
+  change them (with some utility). It could also be used to frequently
+  save a few bits of very important data that may not be lost over
+  power-off and for which writing to disk is too insecure. Note
+  however that most NVRAM space in a PC belongs to the BIOS and you
+  should NEVER idly tamper with it. See Ralf Brown's interrupt list
+  for a guide to the use of CMOS bytes by your BIOS.
+
+  On Atari machines, /dev/nvram is always configured and does not need
+  to be selected.
+
+  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 nvram.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_ATOMWIDE_SERIAL
+  If you have an Atomwide Serial card for an Acorn system, say Y to
+  this option.  The driver can handle 1, 2, or 3 port cards.
+  If unsure, say N.
+
+CONFIG_DUALSP_SERIAL
+  If you have the Serial Port's dual serial card for an Acorn system,
+  say Y to this option.  If unsure, say N.
+
+CONFIG_NWBUTTON
+  If you say Y here and create a character device node /dev/nwbutton
+  with major and minor numbers 10 and 158 ("man mknod"), then every
+  time the orange button is pressed a number of times, the number of
+  times the button was pressed will be written to that device.
+
+  This is most useful for applications, as yet unwritten, which
+  perform actions based on how many times the button is pressed in a
+  row.
+
+  Do not hold the button down for too long, as the driver does not
+  alter the behaviour of the hardware reset circuitry attached to the
+  button; it will still execute a hard reset if the button is held
+  down for longer than approximately five seconds.
+
+  This driver is also available 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>.  The module will be called
+  nwbutton.o.
+
+  Most people will answer Y to this question and "Reboot Using Button"
+  below to be able to initiate a system shutdown from the button.
+
+CONFIG_NWBUTTON_REBOOT
+  If you say Y here, then you will be able to initiate a system
+  shutdown and reboot by pressing the orange button a number of times.
+  The number of presses to initiate the shutdown is two by default,
+  but this can be altered by modifying the value of NUM_PRESSES_REBOOT
+  in nwbutton.h and recompiling the driver or, if you compile the
+  driver as a module, you can specify the number of presses at load
+  time with "insmod button reboot_count=<something>".
+
+CONFIG_A2232
+  This option supports the 2232 7-port serial card shipped with the
+  Amiga 2000 and other Zorro-bus machines, dating from 1989.  At
+  a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip
+  each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The
+  ports were connected with 8 pin DIN connectors on the card bracket,
+  for which 8 pin to DB25 adapters were supplied. The card also had
+  jumpers internally to toggle various pinning configurations.
+
+  This driver can be built as a module; but then "generic_serial.o"
+  will also be built as a module. This has to be loaded before
+  "ser_a2232.o". If you want to do this, answer M here and read
+  "<file:Documentation/modules.txt>".
+
+CONFIG_DS1620
+  Say Y here to include support for the thermal management hardware
+  found in the NetWinder. This driver allows the user to control the
+  temperature set points and to read the current temperature.
+
+  It is also possible to say M here to build it as a module (ds1620.o)
+  It is recommended to be used on a NetWinder, but it is not a
+  necessity.
+
+CONFIG_SERIAL_21285
+  If you have a machine based on a 21285 (Footbridge) StrongARM(R)/
+  PCI bridge you can enable its onboard serial port by enabling this
+  option. The device has major ID 4, minor 64.
+
+CONFIG_SERIAL_21285_CONSOLE
+  If you have enabled the serial port on the 21285 footbridge you can
+  make it the console by answering Y to this option.
+
+CONFIG_NWFLASH
+  If you say Y here and create a character device /dev/flash with
+  major 10 and minor 160 you can manipulate the flash ROM containing
+  the NetWinder firmware. Be careful as accidentally overwriting the
+  flash contents can render your computer unbootable. On no account
+  allow random users access to this device. :-)
+
+  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 nwflash.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+  If you're not sure, say N.
+
+CONFIG_21285_WATCHDOG
+  The Intel Footbridge chip contains a builtin watchdog circuit. Say Y
+  here if you wish to use this. Alternatively say M to compile the
+  driver as a module, which will be called wdt285.o.
+
+  This driver does not work on all machines. In particular, early CATS
+  boards have hardware problems that will cause the machine to simply
+  lock up if the watchdog fires.
+
+  "If in doubt, leave it out" - say N.
+
+CONFIG_977_WATCHDOG
+  Say Y here to include support for the WB977 watchdog included in
+  NetWinder machines. Alternatively say M to compile the driver as
+  a module, which will be called wdt977.o.
+
+  Not sure? It's safe to say N.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c
--- v2.5.2/linux/drivers/char/agp/agpgart_fe.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/agp/agpgart_fe.c	Tue Jan 15 10:56:35 2002
@@ -638,7 +638,7 @@
 			AGP_UNLOCK();
 			return -EINVAL;
 		}
-		if (remap_page_range(vma->vm_start,
+		if (remap_page_range(vma, vma->vm_start,
 				     (kerninfo.aper_base + offset),
 				     size, vma->vm_page_prot)) {
 			AGP_UNLOCK();
@@ -652,7 +652,7 @@
 			AGP_UNLOCK();
 			return -EINVAL;
 		}
-		if (remap_page_range(vma->vm_start, kerninfo.aper_base,
+		if (remap_page_range(vma, vma->vm_start, kerninfo.aper_base,
 				     size, vma->vm_page_prot)) {
 			AGP_UNLOCK();
 			return -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.5.2/linux/drivers/char/console.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/console.c	Fri Jan 25 16:06:48 2002
@@ -2349,14 +2349,18 @@
 
 static void con_flush_chars(struct tty_struct *tty)
 {
-	struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
+	struct vt_struct *vt;
 
 	if (in_interrupt())	/* from flush_to_ldisc */
 		return;
 
 	pm_access(pm_con);
+	
+	/* if we race with con_close(), vt may be null */
 	acquire_console_sem();
-	set_cursor(vt->vc_num);
+	vt = (struct vt_struct *)tty->driver_data;
+	if (vt)
+		set_cursor(vt->vc_num);
 	release_console_sem();
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/char/drm/Config.help linux/drivers/char/drm/Config.help
--- v2.5.2/linux/drivers/char/drm/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/Config.help	Fri Jan 25 16:04:01 2002
@@ -0,0 +1,39 @@
+CONFIG_DRM
+  Kernel-level support for the Direct Rendering Infrastructure (DRI)
+  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
+  details.  You should also select and configure AGP
+  (/dev/agpgart) support.
+
+CONFIG_DRM_TDFX
+  Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
+  graphics card.  If M is selected, the module will be called tdfx.o.
+
+CONFIG_DRM_GAMMA
+  Choose this option if you have a 3dlabs GMX 2000 graphics card.
+  If M is selected, the module will be called gamma.o.
+
+CONFIG_DRM_R128
+  Choose this option if you have an ATI Rage 128 graphics card.  If M
+  is selected, the module will be called r128.o.  AGP support for
+  this card is strongly suggested (unless you have a PCI version).
+
+CONFIG_DRM_RADEON
+  Choose this option if you have an ATI Radeon graphics card.  There
+  are both PCI and AGP versions.  You don't need to choose this to
+  run the Radeon in plain VGA mode.  There is a product page at
+  <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
+  If M is selected, the module will be called radeon.o.
+
+CONFIG_DRM_I810
+  Choose this option if you have an Intel I810 graphics card.  If M is
+  selected, the module will be called i810.o.  AGP support is required
+  for this driver to work.
+
+CONFIG_DRM_MGA
+  Choose this option if you have a Matrox G200, G400 or G450 graphics
+  card.  If M is selected, the module will be called mga.o.  AGP
+  support is required for this driver to work.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/char/drm/drm_vm.h linux/drivers/char/drm/drm_vm.h
--- v2.5.2/linux/drivers/char/drm/drm_vm.h	Thu Nov 22 11:46:37 2001
+++ linux/drivers/char/drm/drm_vm.h	Tue Jan 29 21:41:57 2002
@@ -532,12 +532,12 @@
 		}
 		offset = DRIVER_GET_REG_OFS();
 #ifdef __sparc__
-		if (io_remap_page_range(vma->vm_start,
+		if (io_remap_page_range(vma, vma->vm_start,
 					VM_OFFSET(vma) + offset,
 					vma->vm_end - vma->vm_start,
 					vma->vm_page_prot, 0))
 #else
-		if (remap_page_range(vma->vm_start,
+		if (remap_page_range(vma, vma->vm_start,
 				     VM_OFFSET(vma) + offset,
 				     vma->vm_end - vma->vm_start,
 				     vma->vm_page_prot))
diff -u --recursive --new-file v2.5.2/linux/drivers/char/drm/i810_dma.c linux/drivers/char/drm/i810_dma.c
--- v2.5.2/linux/drivers/char/drm/i810_dma.c	Wed Aug  8 09:42:15 2001
+++ linux/drivers/char/drm/i810_dma.c	Tue Jan 15 10:56:35 2002
@@ -163,7 +163,7 @@
    	buf_priv->currently_mapped = I810_BUF_MAPPED;
 	unlock_kernel();
 
-	if (remap_page_range(vma->vm_start,
+	if (remap_page_range(vma, vma->vm_start,
 			     VM_OFFSET(vma),
 			     vma->vm_end - vma->vm_start,
 			     vma->vm_page_prot)) return -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/drivers/char/ftape/Config.help linux/drivers/char/ftape/Config.help
--- v2.5.2/linux/drivers/char/ftape/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/ftape/Config.help	Fri Jan 25 16:04:01 2002
@@ -0,0 +1,255 @@
+CONFIG_ZFTAPE
+  Normally, you want to say Y or M. DON'T say N here or you
+  WON'T BE ABLE TO USE YOUR FLOPPY TAPE DRIVE.
+
+  The ftape module itself no longer contains the routines necessary
+  to interface with the kernel VFS layer (i.e. to actually write data
+  to and read data from the tape drive).  Instead the file system
+  interface (i.e. the hardware independent part of the driver) has
+  been moved to a separate module.
+
+  If you say M zftape will be compiled as a runtime loadable
+  module ( = code which can be inserted in and removed from the
+  running kernel whenever you want).  In this case you should read
+  <file:Documentation/modules.txt>.  The module will be called
+  zftape.o.
+
+  Regardless of whether you say Y or M here, an additional runtime
+  loadable module called `zft-compressor.o' which contains code to
+  support user transparent on-the-fly compression based on Ross
+  William's lzrw3 algorithm will be produced.  If you have enabled the
+  kernel module loader (i.e. have said Y to "Kernel module loader
+  support", above) then `zft-compressor.o' will be loaded
+  automatically by zftape when needed.
+
+  Despite its name, zftape does NOT use compression by default.  The
+  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.instmath.rwth-aachen.de/~heine/ftape/> contains
+  further information.
+
+  IMPORTANT NOTE: zftape can read archives created by previous
+  versions of ftape and provide file mark support (i.e. fast skipping
+  between tape archives) but previous version of ftape will lack file
+  mark support when reading archives produced by zftape.
+
+CONFIG_ZFT_DFLT_BLK_SZ
+  If unsure leave this at its default value, i.e. 10240. Note that
+  you specify only the default block size here. The block size can be
+  changed at run time using the MTSETBLK tape operation with the
+  MTIOCTOP ioctl (i.e. with "mt -f /dev/qft0 setblk #BLKSZ" from the
+  shell command line).
+
+  The probably most striking difference between zftape and previous
+  versions of ftape is the fact that all data must be written or read
+  in multiples of a fixed block size. The block size defaults to
+  10240 which is what GNU tar uses. The values for the block size
+  should be either 1 or multiples of 1024 up to a maximum value of
+  63488 (i.e. 62 K). If you specify `1' then zftape's builtin
+  compression will be disabled.
+
+  Reasonable values are `10240' (GNU tar's default block size),
+  `5120' (afio's default block size), `32768' (default block size some
+  backup programs assume for SCSI tape drives) or `1' (no restriction
+  on block size, but disables builtin compression).
+
+CONFIG_FT_NR_BUFFERS
+  Please leave this at `3' unless you REALLY know what you are doing.
+  It is not necessary to change this value. Values below 3 make the
+  proper use of ftape impossible, values greater than 3 are a waste of
+  memory. You can change the amount of DMA memory used by ftape at
+  runtime with "mt -f /dev/qft0 setdrvbuffer #NUMBUFFERS". Each buffer
+  wastes 32 KB of memory. Please note that this memory cannot be
+  swapped out.
+
+CONFIG_FT_PROC_FS
+  Optional. Saying Y will result in creation of a directory
+  `/proc/ftape' under the /proc file system. The files can be viewed
+  with your favorite pager (i.e. use "more /proc/ftape/history" or
+  "less /proc/ftape/history" or simply "cat /proc/ftape/history"). The
+  file will contain some status information about the inserted
+  cartridge, the kernel driver, your tape drive, the floppy disk
+  controller and the error history for the most recent use of the
+  kernel driver. Saying Y will enlarge the size of the ftape driver
+  by approximately 2 KB.
+
+  WARNING: When compiling ftape as a module (i.e. saying M to "Floppy
+  tape drive") it is dangerous to use ftape's /proc file system
+  interface. Accessing `/proc/ftape' while the module is unloaded will
+  result in a kernel Oops. This cannot be fixed from inside ftape.
+
+CONFIG_FT_NORMAL_DEBUG
+  This option controls the amount of debugging output the ftape driver
+  is ABLE to produce; it does not increase or diminish the debugging
+  level itself. If unsure, leave this at its default setting,
+  i.e. choose "Normal".
+
+  Ftape can print lots of debugging messages to the system console
+  resp. kernel log files. Reducing the amount of possible debugging
+  output reduces the size of the kernel module by some KB, so it might
+  be a good idea to use "None" for emergency boot floppies.
+
+  If you want to save memory then the following strategy is
+  recommended: leave this option at its default setting "Normal" until
+  you know that the driver works as expected, afterwards reconfigure
+  the kernel, this time specifying "Reduced" or "None" and recompile
+  and install the kernel as usual. Note that choosing "Excessive"
+  debugging output does not increase the amount of debugging output
+  printed to the console but only makes it possible to produce
+  "Excessive" debugging output.
+
+  Please read <file:Documentation/ftape.txt> for a short description
+  how to control the amount of debugging output.
+
+CONFIG_FT_FULL_DEBUG
+  Extremely verbose output for driver debugging purposes.
+
+CONFIG_FT_NO_TRACE
+  Reduced tape driver debugging output.
+
+CONFIG_FT_NO_TRACE_AT_ALL
+  Suppress all debugging output from the tape drive.
+
+CONFIG_FT_STD_FDC
+  Only change this setting if you have a special controller. If you
+  didn't plug any add-on card into your computer system but just
+  plugged the floppy tape cable into the already existing floppy drive
+  controller then you don't want to change the default setting,
+  i.e. choose "Standard".
+
+  Choose "MACH-2" if you have a Mountain Mach-2 controller.
+  Choose "FC-10/FC-20" if you have a Colorado FC-10 or FC-20
+  controller.
+  Choose "Alt/82078" if you have another controller that is located at
+  an IO base address different from the standard floppy drive
+  controller's base address of `0x3f0', or uses an IRQ (interrupt)
+  channel different from `6', or a DMA channel different from
+  `2'. This is necessary for any controller card that is based on
+  Intel's 82078 FDC such as Seagate's, Exabyte's and Iomega's "high
+  speed" controllers.
+
+  If you choose something other than "Standard" then please make
+  sure that the settings for the IO base address and the IRQ and DMA
+  channel in the configuration menus below are correct. Use the manual
+  of your tape drive to determine the correct settings!
+
+  If you are already successfully using your tape drive with another
+  operating system then you definitely should use the same settings
+  for the IO base, the IRQ and DMA channel that have proven to work
+  with that other OS.
+
+  Note that this menu lets you specify only the default setting for
+  the hardware setup. The hardware configuration can be changed at
+  boot time (when ftape is compiled into the kernel, i.e. if you
+  have said Y to "Floppy tape drive") or module load time (i.e. if you
+  have said M to "Floppy tape drive").
+
+  Please read also the file <file:Documentation/ftape.txt> which
+  contains a short description of the parameters that can be set at
+  boot or load time. If you want to use your floppy tape drive on a
+  PCI-bus based system, please read the file
+  <file:drivers/char/ftape/README.PCI>.
+
+CONFIG_FT_FDC_BASE
+  You don't need to specify a value if the following default
+  settings for the base IO address are correct:
+  <<< MACH-2     : 0x1E0 >>>
+  <<< FC-10/FC-20: 0x180 >>>
+  <<< Secondary  : 0x370 >>>
+  Secondary refers to a secondary FDC controller like the "high speed"
+  controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash.
+  Please make sure that the setting for the IO base address
+  specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR
+  CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already
+  successfully using the tape drive with another operating system then
+  you definitely should use the same settings for the IO base that has
+  proven to work with that other OS.
+
+  Note that this menu lets you specify only the default setting for
+  the IO base. The hardware configuration can be changed at boot time
+  (when ftape is compiled into the kernel, i.e. if you specified Y to
+  "Floppy tape drive") or module load time (i.e. if you have said M to
+  "Floppy tape drive").
+
+  Please read also the file <file:Documentation/ftape.txt> which
+  contains a short description of the parameters that can be set at
+  boot or load time.
+
+CONFIG_FT_FDC_IRQ
+  You don't need to specify a value if the following default
+  settings for the interrupt channel are correct:
+  <<< MACH-2     : 6 >>>
+  <<< FC-10/FC-20: 9 >>>
+  <<< Secondary  : 6 >>>
+  Secondary refers to secondary a FDC controller like the "high speed"
+  controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash.
+  Please make sure that the setting for the IO base address
+  specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR
+  CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already
+  successfully using the tape drive with another operating system then
+  you definitely should use the same settings for the IO base that has
+  proven to work with that other OS.
+
+  Note that this menu lets you specify only the default setting for
+  the IRQ channel. The hardware configuration can be changed at boot
+  time (when ftape is compiled into the kernel, i.e. if you said Y to
+  "Floppy tape drive") or module load time (i.e. if you said M to
+  "Floppy tape drive").
+
+  Please read also the file <file:Documentation/ftape.txt> which
+  contains a short description of the parameters that can be set at
+  boot or load time.
+
+CONFIG_FT_FDC_DMA
+  You don't need to specify a value if the following default
+  settings for the DMA channel are correct:
+  <<< MACH-2     : 2 >>>
+  <<< FC-10/FC-20: 3 >>>
+  <<< Secondary  : 2 >>>
+  Secondary refers to a secondary FDC controller like the "high speed"
+  controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash.
+  Please make sure that the setting for the IO base address
+  specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR
+  CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already
+  successfully using the tape drive with another operating system then
+  you definitely should use the same settings for the IO base that has
+  proven to work with that other OS.
+
+  Note that this menu lets you specify only the default setting for
+  the DMA channel. The hardware configuration can be changed at boot
+  time (when ftape is compiled into the kernel, i.e. if you said Y to
+  "Floppy tape drive") or module load time (i.e. if you said M to
+  "Floppy tape drive").
+
+  Please read also the file <file:Documentation/ftape.txt> which
+  contains a short description of the parameters that can be set at
+  boot or load time.
+
+CONFIG_FT_FDC_THR
+  Set the FIFO threshold of the FDC. If this is higher the DMA
+  controller may serve the FDC after a higher latency time. If this is
+  lower, fewer DMA transfers occur leading to less bus contention.
+  You may try to tune this if ftape annoys you with "reduced data
+  rate because of excessive overrun errors" messages. However, this
+  doesn't seem to have too much effect.
+
+  If unsure, don't touch the initial value, i.e. leave it at "8".
+
+CONFIG_FT_FDC_MAX_RATE
+  With some motherboard/FDC combinations ftape will not be able to
+  run your FDC/tape drive combination at the highest available
+  speed. If this is the case you'll encounter "reduced data rate
+  because of excessive overrun errors" messages and lots of retries
+  before ftape finally decides to reduce the data rate.
+
+  In this case it might be desirable to tell ftape beforehand that
+  it need not try to run the tape drive at the highest available
+  speed. If unsure, leave this disabled, i.e. leave it at 2000
+  bits/sec.
+
+CONFIG_FT_ALPHA_CLOCK
+  On some DEC Alpha machines the CPU clock frequency cannot be
+  determined automatically, so you need to specify it here ONLY if
+  running a DEC Alpha, otherwise this setting has no effect.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/char/ftape/lowlevel/ftape-ctl.c linux/drivers/char/ftape/lowlevel/ftape-ctl.c
--- v2.5.2/linux/drivers/char/ftape/lowlevel/ftape-ctl.c	Tue Nov  7 11:09:19 2000
+++ linux/drivers/char/ftape/lowlevel/ftape-ctl.c	Tue Jan 15 10:56:35 2002
@@ -731,7 +731,7 @@
 		ftape_reset_buffer();
 	}
 	for (i = 0; i < num_buffers; i++) {
-		TRACE_CATCH(remap_page_range(vma->vm_start +
+		TRACE_CATCH(remap_page_range(vma, vma->vm_start +
 					     i * FT_BUFF_SIZE,
 					     virt_to_phys(ft_buffer[i]->address),
 					     FT_BUFF_SIZE,
diff -u --recursive --new-file v2.5.2/linux/drivers/char/joystick/Config.help linux/drivers/char/joystick/Config.help
--- v2.5.2/linux/drivers/char/joystick/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/joystick/Config.help	Fri Jan 25 16:04:04 2002
@@ -0,0 +1,300 @@
+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/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.
+
+  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 gameport.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called ns558.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called lightning.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_CS461X
+  Say Y here if you have a Cirrus CS461x aka "Crystal SoundFusion"
+  PCI audio accelerator.  A product page for the CS4614 is at
+  <http://www.cirrus.com/design/products/overview/index.cfm?ProductID=40>.
+
+  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 cs461x.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called pcigame.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called emu10k1-gp.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_ANALOG
+  Say Y here if you have a controller that connects to the PC
+  gameport.  This supports many different types, including joysticks
+  with throttle control, with rudders, or with extensions like
+  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/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).
+  The module will be called analog.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called a3d.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called adi.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called cobra.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called gf2k.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called grip.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called interact.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_TMDC
+  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/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).
+  The module will be called tmdc.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called sidewinder.o.  If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_SERIO
+  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/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).
+  The module will be called sidewinder.o.  If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called serport.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called warrior.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called magellan.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_SPACEORB
+  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/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).
+  The module will be called spaceorb.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called spaceball.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called stinger.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called iforce.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called iforce.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_DB9
+  Say Y here if you have a Sega Master System gamepad, Sega Genesis
+  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/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).
+  The module will be called db9.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_GAMECON
+  Say Y here if you have a Nintendo Entertainment System gamepad,
+  Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
+  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/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).
+  The module will be called gamecon.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_TURBOGRAFX
+  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/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).
+  The module will be called turbografx.o.  If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+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/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).
+  The module will be called joy-amiga.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/char/joystick/iforce.c linux/drivers/char/joystick/iforce.c
--- v2.5.2/linux/drivers/char/joystick/iforce.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/joystick/iforce.c	Wed Jan 23 15:33:46 2002
@@ -133,7 +133,7 @@
 #endif
 #ifdef IFORCE_USB
 	struct usb_device *usbdev;	/* USB transfer */
-	struct urb irq, out, ctrl;
+	struct urb *irq, *out, *ctrl;
 	struct usb_ctrlrequest dr;
 #endif
 					/* Force Feedback */
@@ -196,28 +196,28 @@
 			DECLARE_WAITQUEUE(wait, current);
 			int timeout = HZ; /* 1 second */
 
-			memcpy(iforce->out.transfer_buffer + 1, data, LO(cmd));
-			((char*)iforce->out.transfer_buffer)[0] = HI(cmd);
-			iforce->out.transfer_buffer_length = LO(cmd) + 2;
-			iforce->out.dev = iforce->usbdev;
+			memcpy(iforce->out->transfer_buffer + 1, data, LO(cmd));
+			((char*)iforce->out->transfer_buffer)[0] = HI(cmd);
+			iforce->out->transfer_buffer_length = LO(cmd) + 2;
+			iforce->out->dev = iforce->usbdev;
 
 			set_current_state(TASK_INTERRUPTIBLE);
 			add_wait_queue(&iforce->wait, &wait);
 
-			if (usb_submit_urb(&iforce->out)) {
+			if (usb_submit_urb(iforce->out)) {
 				set_current_state(TASK_RUNNING);
 				remove_wait_queue(&iforce->wait, &wait);
 				return;
 			}
 
-			while (timeout && iforce->out.status == -EINPROGRESS)
+			while (timeout && iforce->out->status == -EINPROGRESS)
 				timeout = schedule_timeout(timeout);
 
 			set_current_state(TASK_RUNNING);
 			remove_wait_queue(&iforce->wait, &wait);
 
 			if (!timeout)
-				usb_unlink_urb(&iforce->out);
+				usb_unlink_urb(iforce->out);
 
 			return;
 		}
@@ -284,25 +284,25 @@
 		case IFORCE_USB:
 
 			iforce->dr.bRequest = packet[0];
-			iforce->ctrl.dev = iforce->usbdev;
+			iforce->ctrl->dev = iforce->usbdev;
 
 			set_current_state(TASK_INTERRUPTIBLE);
 			add_wait_queue(&iforce->wait, &wait);
 
-			if (usb_submit_urb(&iforce->ctrl)) {
+			if (usb_submit_urb(iforce->ctrl)) {
 				set_current_state(TASK_RUNNING);
 				remove_wait_queue(&iforce->wait, &wait);
 				return -1;
 			}
 
-			while (timeout && iforce->ctrl.status == -EINPROGRESS)
+			while (timeout && iforce->ctrl->status == -EINPROGRESS)
 				timeout = schedule_timeout(timeout);
 
 			set_current_state(TASK_RUNNING);
 			remove_wait_queue(&iforce->wait, &wait);
 
 			if (!timeout) {
-				usb_unlink_urb(&iforce->ctrl);
+				usb_unlink_urb(iforce->ctrl);
 				return -1;
 			}
 
@@ -344,8 +344,8 @@
 		case IFORCE_USB:
 			if (iforce->open++)
 				break;
-			iforce->irq.dev = iforce->usbdev;
-			if (usb_submit_urb(&iforce->irq))
+			iforce->irq->dev = iforce->usbdev;
+			if (usb_submit_urb(iforce->irq))
 					return -EIO;
 			break;
 #endif
@@ -361,7 +361,7 @@
 #ifdef IFORCE_USB
 		case IFORCE_USB:
 			if (!--iforce->open)
-				usb_unlink_urb(&iforce->irq);
+				usb_unlink_urb(iforce->irq);
 			break;
 #endif
 	}
@@ -1024,6 +1024,25 @@
 	if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL;
 	memset(iforce, 0, sizeof(struct iforce));
 
+	iforce->irq = usb_alloc_urb(0);
+	if (!iforce->irq) {
+		kfree(iforce);
+		return NULL;
+	}
+	iforce->out = usb_alloc_urb(0);
+	if (!iforce->out) {
+		usb_free_urb(iforce->irq);
+		kfree(iforce);
+		return NULL;
+	}
+	iforce->ctrl = usb_alloc_urb(0);
+	if (!iforce->ctrl) {
+		usb_free_urb(iforce->out);
+		usb_free_urb(iforce->irq);
+		kfree(iforce);
+		return NULL;
+	}
+
 	iforce->bus = IFORCE_USB;
 	iforce->usbdev = dev;
 
@@ -1031,16 +1050,19 @@
 	iforce->dr.wIndex = 0;
 	iforce->dr.wLength = 16;
 
-	FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
+	FILL_INT_URB(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
 			iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
 
-	FILL_BULK_URB(&iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
+	FILL_BULK_URB(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
 			iforce + 1, 32, iforce_usb_out, iforce);
 
-	FILL_CONTROL_URB(&iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
+	FILL_CONTROL_URB(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
 			(void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce);
 
 	if (iforce_init_device(iforce)) {
+		usb_free_urb(iforce->ctrl);
+		usb_free_urb(iforce->out);
+		usb_free_urb(iforce->irq);
 		kfree(iforce);
 		return NULL;
 	}
@@ -1055,8 +1077,11 @@
 static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct iforce *iforce = ptr;
-	usb_unlink_urb(&iforce->irq);
+	usb_unlink_urb(iforce->irq);
 	input_unregister_device(&iforce->dev);
+	usb_free_urb(iforce->ctrl);
+	usb_free_urb(iforce->out);
+	usb_free_urb(iforce->irq);
 	kfree(iforce);
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.5.2/linux/drivers/char/lp.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/lp.c	Tue Jan 15 13:53:51 2002
@@ -367,7 +367,7 @@
 			  = lp_negotiate (port, 
 					  lp_table[minor].best_mode);
 
-		} else if (current->need_resched)
+		} else if (need_resched())
 			schedule ();
 
 		if (count) {
diff -u --recursive --new-file v2.5.2/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.5.2/linux/drivers/char/mem.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/mem.c	Tue Jan 15 13:53:51 2002
@@ -203,7 +203,7 @@
 	if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC))
 		vma->vm_flags |= VM_IO;
 
-	if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
+	if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start,
 			     vma->vm_page_prot))
 		return -EAGAIN;
 	return 0;
@@ -364,8 +364,8 @@
 		if (count > size)
 			count = size;
 
-		zap_page_range(mm, addr, count);
-        	zeromap_page_range(addr, count, PAGE_COPY);
+		zap_page_range(vma, addr, count);
+        	zeromap_page_range(vma, addr, count, PAGE_COPY);
 
 		size -= count;
 		buf += count;
@@ -381,8 +381,7 @@
 		unsigned long unwritten = clear_user(buf, PAGE_SIZE);
 		if (unwritten)
 			return size + unwritten - PAGE_SIZE;
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 		buf += PAGE_SIZE;
 		size -= PAGE_SIZE;
 	} while (size);
@@ -435,7 +434,7 @@
 {
 	if (vma->vm_flags & VM_SHARED)
 		return shmem_zero_setup(vma);
-	if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
+	if (zeromap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	return 0;
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/char/mwave/3780i.c linux/drivers/char/mwave/3780i.c
--- v2.5.2/linux/drivers/char/mwave/3780i.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/char/mwave/3780i.c	Tue Jan 15 13:53:51 2002
@@ -68,11 +68,9 @@
 
 static void PaceMsaAccess(unsigned short usDspBaseIO)
 {
-	if(current->need_resched)
-		schedule();
+	cond_resched();
 	udelay(100);
-	if(current->need_resched)
-		schedule();
+	cond_resched();
 }
 
 unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
diff -u --recursive --new-file v2.5.2/linux/drivers/char/pcmcia/Config.help linux/drivers/char/pcmcia/Config.help
--- v2.5.2/linux/drivers/char/pcmcia/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/pcmcia/Config.help	Fri Jan 25 16:03:24 2002
@@ -0,0 +1,12 @@
+CONFIG_PCMCIA_SERIAL_CS
+  Say Y here to enable support for 16-bit PCMCIA serial devices,
+  including serial port cards, modems, and the modem functions of
+  multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are
+  credit-card size devices often used with laptops.)
+
+  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 serial_cs.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+  If unsure, say N.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- v2.5.2/linux/drivers/char/ppdev.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/ppdev.c	Tue Jan 15 13:53:51 2002
@@ -170,9 +170,7 @@
 			break;
 		}
 
-		if (current->need_resched) {
-			schedule ();
-		}
+		cond_resched();
 	}
 
 	kfree (kbuffer);
@@ -242,9 +240,7 @@
 			break;
 		}
 
-		if (current->need_resched) {
-			schedule ();
-		}
+		cond_resched();
 	}
 
 	kfree (kbuffer);
diff -u --recursive --new-file v2.5.2/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.5.2/linux/drivers/char/random.c	Fri Nov  9 14:01:21 2001
+++ linux/drivers/char/random.c	Tue Jan 15 13:53:51 2002
@@ -1313,7 +1313,7 @@
 		/*
 		 * Check if we need to break out or reschedule....
 		 */
-		if ((flags & EXTRACT_ENTROPY_USER) && current->need_resched) {
+		if ((flags & EXTRACT_ENTROPY_USER) && need_resched()) {
 			if (signal_pending(current)) {
 				if (ret == 0)
 					ret = -ERESTARTSYS;
diff -u --recursive --new-file v2.5.2/linux/drivers/char/shwdt.c linux/drivers/char/shwdt.c
--- v2.5.2/linux/drivers/char/shwdt.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/shwdt.c	Thu Jan 24 12:08:15 2002
@@ -19,7 +19,6 @@
 #include <linux/watchdog.h>
 #include <linux/reboot.h>
 #include <linux/notifier.h>
-#include <linux/smp_lock.h>
 #include <linux/ioport.h>
 
 #include <asm/io.h>
@@ -47,18 +46,47 @@
 #define WTCSR_CKS1	0x02
 #define WTCSR_CKS0	0x01
 
-#define WTCSR_CKS	0x07
-#define WTCSR_CKS_1	0x00
-#define WTCSR_CKS_4	0x01
-#define WTCSR_CKS_16	0x02
-#define WTCSR_CKS_32	0x03
-#define WTCSR_CKS_64	0x04
-#define WTCSR_CKS_256	0x05
-#define WTCSR_CKS_1024	0x06
+/*
+ * CKS0-2 supports a number of clock division ratios. At the time the watchdog
+ * is enabled, it defaults to a 41 usec overflow period .. we overload this to
+ * something a little more reasonable, and really can't deal with anything
+ * lower than WTCSR_CKS_1024, else we drop back into the usec range.
+ *
+ * Clock Division Ratio         Overflow Period
+ * --------------------------------------------
+ *     1/32 (initial value)       41 usecs
+ *     1/64                       82 usecs
+ *     1/128                     164 usecs
+ *     1/256                     328 usecs
+ *     1/512                     656 usecs
+ *     1/1024                   1.31 msecs
+ *     1/2048                   2.62 msecs
+ *     1/4096                   5.25 msecs
+ */
+#define WTCSR_CKS_32	0x00
+#define WTCSR_CKS_64	0x01
+#define WTCSR_CKS_128	0x02
+#define WTCSR_CKS_256	0x03
+#define WTCSR_CKS_512	0x04
+#define WTCSR_CKS_1024	0x05
+#define WTCSR_CKS_2048	0x06
 #define WTCSR_CKS_4096	0x07
 
-static int sh_is_open = 0;
+/*
+ * Default clock division ratio is 5.25 msecs. Overload this at module load
+ * time. Any value not in the msec range will default to a timeout of one
+ * jiffy, which exceeds the usec overflow periods.
+ */
+static int clock_division_ratio = WTCSR_CKS_4096;
+
+#define msecs_to_jiffies(msecs)	(jiffies + ((HZ * msecs + 999) / 1000))
+#define next_ping_period(cks)	msecs_to_jiffies(cks - 4)
+#define user_ping_period(cks)	(next_ping_period(cks) * 10)
+
+static unsigned long sh_is_open = 0;
 static struct watchdog_info sh_wdt_info;
+static struct timer_list timer;
+static unsigned long next_heartbeat;
 
 /**
  *	sh_wdt_write_cnt - Write to Counter
@@ -93,6 +121,10 @@
  */
 static void sh_wdt_start(void)
 {
+	timer.expires = next_ping_period(clock_division_ratio);
+	next_heartbeat = user_ping_period(clock_division_ratio);
+	add_timer(&timer);
+
 	sh_wdt_write_csr(WTCSR_WT | WTCSR_CKS_4096);
 	sh_wdt_write_cnt(0);
 	sh_wdt_write_csr((ctrl_inb(WTCSR) | WTCSR_TME));
@@ -105,6 +137,8 @@
  */
 static void sh_wdt_stop(void)
 {
+	del_timer(&timer);
+
 	sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_TME));
 }
 
@@ -117,8 +151,13 @@
  */
 static void sh_wdt_ping(unsigned long data)
 {
-	sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_IOVF));
-	sh_wdt_write_cnt(0);
+	if (time_before(jiffies, next_heartbeat)) {
+		sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_IOVF));
+		sh_wdt_write_cnt(0);
+
+		timer.expires = next_ping_period(clock_division_ratio);
+		add_timer(&timer);
+	}
 }
 
 /**
@@ -133,14 +172,12 @@
 {
 	switch (minor(inode->i_rdev)) {
 		case WATCHDOG_MINOR:
-			if (sh_is_open) {
+			if (test_and_set_bit(0, &sh_is_open))
 				return -EBUSY;
-			}
 
-			sh_is_open = 1;
 			sh_wdt_start();
 
-			return 0;
+			break;
 		default:
 			return -ENODEV;
 	}
@@ -158,17 +195,13 @@
  */
 static int sh_wdt_close(struct inode *inode, struct file *file)
 {
-	lock_kernel();
-	
 	if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
 #ifndef CONFIG_WATCHDOG_NOWAYOUT
 		sh_wdt_stop();
 #endif
-		sh_is_open = 0;
+		clear_bit(0, &sh_is_open);
 	}
 	
-	unlock_kernel();
-
 	return 0;
 }
 
@@ -206,7 +239,7 @@
 		return -ESPIPE;
 
 	if (count) {
-		sh_wdt_ping(0);
+		next_heartbeat = user_ping_period(clock_division_ratio);
 		return 1;
 	}
 
@@ -245,7 +278,7 @@
 
 			break;
 		case WDIOC_KEEPALIVE:
-			sh_wdt_ping(0);
+			next_heartbeat = user_ping_period(clock_division_ratio);
 			
 			break;
 		default:
@@ -336,6 +369,10 @@
 		return -EINVAL;
 	}
 
+	init_timer(&timer);
+	timer.function = sh_wdt_ping;
+	timer.data = 0;
+
 	return 0;
 }
 
@@ -358,6 +395,8 @@
 MODULE_AUTHOR("Paul Mundt <lethal@chaoticdreams.org>");
 MODULE_DESCRIPTION("SH 3/4 watchdog driver");
 MODULE_LICENSE("GPL");
+MODULE_PARM(clock_division_ratio, "i");
+MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7.");
 
 module_init(sh_wdt_init);
 module_exit(sh_wdt_exit);
diff -u --recursive --new-file v2.5.2/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.5.2/linux/drivers/char/tty_io.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/tty_io.c	Tue Jan 15 13:53:51 2002
@@ -712,8 +712,7 @@
 			ret = -ERESTARTSYS;
 			if (signal_pending(current))
 				break;
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 		}
 	}
 	if (written) {
diff -u --recursive --new-file v2.5.2/linux/drivers/dio/dio.c linux/drivers/dio/dio.c
--- v2.5.2/linux/drivers/dio/dio.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/dio/dio.c	Wed Jan 23 10:54:42 2002
@@ -208,6 +208,8 @@
         }
 }
 
+subsys_initcall(dio_init);
+
 /* Bear in mind that this is called in the very early stages of initialisation
  * in order to get the virtual address of the serial port for the console...
  */
diff -u --recursive --new-file v2.5.2/linux/drivers/fc4/Config.help linux/drivers/fc4/Config.help
--- v2.5.2/linux/drivers/fc4/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/fc4/Config.help	Fri Jan 25 16:03:40 2002
@@ -0,0 +1,57 @@
+CONFIG_FC4
+  Fibre Channel is a high speed serial protocol mainly used to
+  connect large storage devices to the computer; it is compatible with
+  and intended to replace SCSI.
+
+  This is an experimental support for storage arrays connected to your
+  computer using optical fibre cables and the "X3.269-199X Fibre
+  Channel Protocol for SCSI" specification. If you want to use this,
+  you need to say Y here and to "SCSI support" as well as to the
+  drivers for the storage array itself and for the interface adapter
+  such as SOC or SOC+. This subsystem could even serve for IP
+  networking, with some code extensions.
+
+  If unsure, say N.
+
+CONFIG_FC4_SOC
+  Serial Optical Channel is an interface card with one or two Fibre
+  Optic ports, each of which can be connected to a disk array. Note
+  that if you have older firmware in the card, you'll need the
+  microcode from the Solaris driver to make it work.
+
+  This support is also available as a module called soc.o ( = 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>.
+
+CONFIG_FC4_SOCAL
+  Serial Optical Channel Plus is an interface card with up to two
+  Fibre Optic ports. This card supports FC Arbitrated Loop (usually
+  A5000 or internal FC disks in E[3-6]000 machines through the
+  Interface Board). You'll probably need the microcode from the
+  Solaris driver to make it work.
+
+  This support is also available as a module called socal.o ( = 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>.
+
+CONFIG_SCSI_PLUTO
+  If you never bought a disk array made by Sun, go with N.
+
+  This support is also available as a module called pluto.o ( = 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>.
+
+CONFIG_SCSI_FCAL
+  This driver drives FC-AL disks connected through a Fibre Channel
+  card using the drivers/fc4 layer (currently only SOCAL). The most
+  common is either A5000 array or internal disks in E[3-6]000
+  machines.
+
+  This support is also available as a module called fcal.o ( = 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>. If unsure, say N.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/fc4/fc.c linux/drivers/fc4/fc.c
--- v2.5.2/linux/drivers/fc4/fc.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/fc4/fc.c	Tue Jan 15 10:52:11 2002
@@ -769,10 +769,10 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+	spin_lock_irqsave(SCpnt->host->host_lock, flags);
 	if (FCP_CMND(SCpnt)->done)
 		FCP_CMND(SCpnt)->done(SCpnt);
-	spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+	spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 }
 
 static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, int prepare)
@@ -920,9 +920,9 @@
 		unsigned long flags;
 
 		SCpnt->result = DID_ABORT;
-		spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+		spin_lock_irqsave(SCpnt->host->host_lock, flags);
 		fcmd->done(SCpnt);
-		spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+		spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 		printk("FC: soft abort\n");
 		return SUCCESS;
 	} else {
diff -u --recursive --new-file v2.5.2/linux/drivers/hotplug/Config.help linux/drivers/hotplug/Config.help
--- v2.5.2/linux/drivers/hotplug/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/hotplug/Config.help	Fri Jan 25 16:03:25 2002
@@ -0,0 +1,31 @@
+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
+  powered up and running.  The file system pcihpfs must be mounted
+  in order to interact with any PCI Hotplug controllers.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pci_hotplug.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+  When in doubt, say N.
+
+CONFIG_HOTPLUG_PCI_COMPAQ
+  Say Y here if you have a motherboard with a Compaq PCI Hotplug
+  controller.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cpqphp.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+  When in doubt, say N.
+
+CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM
+  Say Y here if you have a Compaq server that has a PCI Hotplug
+  controller.  This will allow the PCI Hotplug driver to store the PCI
+  system configuration options in NVRAM.
+
+  When in doubt, say N.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/hotplug/cpqphp_core.c linux/drivers/hotplug/cpqphp_core.c
--- v2.5.2/linux/drivers/hotplug/cpqphp_core.c	Fri Nov  9 14:01:21 2001
+++ linux/drivers/hotplug/cpqphp_core.c	Thu Jan 17 14:06:53 2002
@@ -404,6 +404,10 @@
 		result = pci_hp_register (new_slot->hotplug_slot);
 		if (result) {
 			err ("pci_hp_register failed with error %d\n", result);
+			kfree (new_slot->hotplug_slot->info);
+			kfree (new_slot->hotplug_slot->name);
+			kfree (new_slot->hotplug_slot);
+			kfree (new_slot);
 			return result;
 		}
 		
@@ -429,6 +433,8 @@
 	while (old_slot) {
 		next_slot = old_slot->next;
 		pci_hp_deregister (old_slot->hotplug_slot);
+		kfree(old_slot->hotplug_slot->info);
+		kfree(old_slot->hotplug_slot->name);
 		kfree(old_slot->hotplug_slot);
 		kfree(old_slot);
 		old_slot = next_slot;
diff -u --recursive --new-file v2.5.2/linux/drivers/hotplug/pcihp_skeleton.c linux/drivers/hotplug/pcihp_skeleton.c
--- v2.5.2/linux/drivers/hotplug/pcihp_skeleton.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/hotplug/pcihp_skeleton.c	Fri Jan 25 16:17:51 2002
@@ -0,0 +1,432 @@
+/*
+ * PCI Hot Plug Controller Skeleton Driver - 0.1
+ *
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is to be used as a skeleton driver to be show how to interface
+ * with the pci hotplug core easily.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci_hotplug.h"
+
+
+#define SLOT_MAGIC	0x67267322
+struct slot {
+	u32 magic;
+	u8 number;
+	struct hotplug_slot *hotplug_slot;
+	struct list_head slot_list;
+};
+
+static LIST_HEAD(slot_list);
+
+#if !defined(CONFIG_HOTPLUG_PCI_SKELETON_MODULE)
+	#define MY_NAME	"pcihp_skeleton"
+#else
+	#define MY_NAME	THIS_MODULE->name
+#endif
+
+#define dbg(format, arg...)					\
+	do {							\
+		if (debug)					\
+			printk (KERN_DEBUG "%s: " format "\n",	\
+				MY_NAME , ## arg); 		\
+	} while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+
+
+
+/* local variables */
+static int debug;
+static int num_slots;
+
+#define DRIVER_VERSION	"0.1"
+#define DRIVER_AUTHOR	"Greg Kroah-Hartman <greg@kroah.com>"
+#define DRIVER_DESC	"Hot Plug PCI Controller Skeleton Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+
+static int enable_slot		(struct hotplug_slot *slot);
+static int disable_slot		(struct hotplug_slot *slot);
+static int set_attention_status (struct hotplug_slot *slot, u8 value);
+static int hardware_test	(struct hotplug_slot *slot, u32 value);
+static int get_power_status	(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
+static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+
+static struct hotplug_slot_ops skel_hotplug_slot_ops = {
+	owner:			THIS_MODULE,
+	enable_slot:		enable_slot,
+	disable_slot:		disable_slot,
+	set_attention_status:	set_attention_status,
+	hardware_test:		hardware_test,
+	get_power_status:	get_power_status,
+	get_attention_status:	get_attention_status,
+	get_latch_status:	get_latch_status,
+	get_adapter_status:	get_adapter_status,
+};
+
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int slot_paranoia_check (struct slot *slot, const char *function)
+{
+	if (!slot) {
+		dbg("%s - slot == NULL", function);
+		return -1;
+	}
+	if (slot->magic != SLOT_MAGIC) {
+		dbg("%s - bad magic number for slot", function);
+		return -1;
+	}
+	if (!slot->hotplug_slot) {
+		dbg("%s - slot->hotplug_slot == NULL!", function);
+		return -1;
+	}
+	return 0;
+}
+
+static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
+{ 
+	struct slot *slot;
+
+	if (!hotplug_slot) {
+		dbg("%s - hotplug_slot == NULL\n", function);
+		return NULL;
+	}
+
+	slot = (struct slot *)hotplug_slot->private;
+	if (slot_paranoia_check (slot, function))
+                return NULL;
+	return slot;
+}               
+
+
+static int enable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	/*
+	 * Fill in code here to enable the specified slot
+	 */
+
+	return retval;
+}
+
+
+static int disable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	/*
+	 * Fill in code here to disable the specified slot
+	 */
+
+	return retval;
+}
+
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	switch (status) {
+		case 0:
+			/*
+			 * Fill in code here to turn light off
+			 */
+			break;
+
+		case 1:
+		default:
+			/*
+			 * Fill in code here to turn light on
+			 */
+			break;
+	}
+
+	return retval;
+}
+
+static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	err ("No hardware tests are defined for this driver");
+	retval = -ENODEV;
+
+	/* Or you can specify a test if you want to */
+	
+	return retval;
+}
+
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+
+	/*
+	 * Fill in logic to get the current power status of the specific
+	 * slot and store it in the *value location.
+	 */
+
+	return retval;
+}
+
+static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+
+	/*
+	 * Fill in logic to get the current attention status of the specific
+	 * slot and store it in the *value location.
+	 */
+
+	return retval;
+}
+
+static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+
+	/*
+	 * Fill in logic to get the current latch status of the specific
+	 * slot and store it in the *value location.
+	 */
+
+	return retval;
+}
+
+static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+
+	/*
+	 * Fill in logic to get the current adapter status of the specific
+	 * slot and store it in the *value location.
+	 */
+
+	return retval;
+}
+
+#define SLOT_NAME_SIZE	10
+static void make_slot_name (struct slot *slot)
+{
+	/*
+	 * Stupid way to make a filename out of the slot name.
+	 * replace this if your hardware provides a better way to name slots.
+	 */
+	snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", slot->number);
+}
+
+static int init_slots (void)
+{
+	struct slot *slot;
+	struct hotplug_slot *hotplug_slot;
+	struct hotplug_slot_info *info;
+	char *name;
+	int retval = 0;
+	int i;
+
+	/*
+	 * Create a structure for each slot, and register that slot
+	 * with the pci_hotplug subsystem.
+	 */
+	for (i = 0; i < num_slots; ++i) {
+		slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
+		if (!slot)
+			return -ENOMEM;
+		memset(slot, 0, sizeof(struct slot));
+
+		hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+		if (!hotplug_slot) {
+			kfree (slot);
+			return -ENOMEM;
+		}
+		memset(hotplug_slot, 0, sizeof (struct hotplug_slot));
+		slot->hotplug_slot = hotplug_slot;
+
+		info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		if (!info) {
+			kfree (hotplug_slot);
+			kfree (slot);
+			return -ENOMEM;
+		}
+		memset(info, 0, sizeof (struct hotplug_slot_info));
+		hotplug_slot->info = info;
+
+		name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+		if (!name) {
+			kfree (info);
+			kfree (hotplug_slot);
+			kfree (slot);
+			return -ENOMEM;
+		}
+		hotplug_slot->name = name;
+
+		slot->magic = SLOT_MAGIC;
+		slot->number = i;
+
+		hotplug_slot->private = slot;
+		make_slot_name (slot);
+		hotplug_slot->ops = &skel_hotplug_slot_ops;
+		
+		/*
+		 * Initilize the slot info structure with some known
+		 * good values.
+		 */
+		info->power_status = get_skel_power_status(slot);
+		info->attention_status = get_skel_attention_status(slot);
+		info->latch_status = get_skel_latch_status(slot);
+		info->adapter_status = get_skel_adapter_status(slot);
+		
+		dbg ("registering slot %d\n", i);
+		retval = pci_hp_register (slot->hotplug_slot);
+		if (retval) {
+			err ("pci_hp_register failed with error %d\n", retval);
+			kfree (info);
+			kfree (name);
+			kfree (hotplug_slot);
+			kfree (slot);
+			return retval;
+		}
+
+		/* add slot to our internal list */
+		list_add (&slot->slot_list, &slot_list);
+	}
+
+	return retval;
+}
+		
+static void cleanup_slots (void)
+{
+	struct list_head *tmp;
+	struct slot *slot;
+
+	/*
+	 * Unregister all of our slots with the pci_hotplug subsystem,
+	 * and free up all memory that we had allocated.
+	 */
+	list_for_each (tmp, &slot_list) {
+		slot = list_entry (tmp, struct slot, slot_list);
+		list_del (&slot->slot_list);
+		pci_hp_deregister (slot->hotplug_slot);
+		kfree (slot->hotplug_slot->info);
+		kfree (slot->hotplug_slot->name);
+		kfree (slot->hotplug_slot);
+		kfree (slot);
+	}
+
+	return;
+}
+		
+static int __init pcihp_skel_init(void)
+{
+	int retval;
+
+	/*
+	 * Do specific initialization stuff for your driver here
+	 * Like initilizing your controller hardware (if any) and
+	 * determining the number of slots you have in the system
+	 * right now.
+	 */
+	num_slots = 5;
+
+	retval = init_slots();
+	if (retval)
+		return retval;
+
+	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
+	return 0;
+}
+
+static void __exit pcihp_skel_exit(void)
+{
+	/*
+	 * Clean everything up.
+	 */
+	cleanup_slots();
+}
+
+module_init(pcihp_skel_init);
+module_exit(pcihp_skel_exit);
+
diff -u --recursive --new-file v2.5.2/linux/drivers/i2c/Config.help linux/drivers/i2c/Config.help
--- v2.5.2/linux/drivers/i2c/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2c/Config.help	Fri Jan 25 16:04:00 2002
@@ -0,0 +1,101 @@
+CONFIG_I2C
+  I2C (pronounce: I-square-C) is a slow serial bus protocol used in
+  many micro controller applications and developed by Philips.  SMBus,
+  or System Management Bus is a subset of the I2C protocol.  More
+  information is contained in the directory <file:Documentation/i2c/>,
+  especially in the file called "summary" there.
+
+  Both I2C and SMBus are supported here. You will need this for
+  hardware sensors support, and also for Video For Linux support.
+  Specifically, if you want to use a BT848 based frame grabber/overlay
+  boards under Linux, say Y here and also to "I2C bit-banging
+  interfaces", below.
+
+  If you want I2C support, you should say Y here and also to the
+  specific driver for your bus adapter(s) below.  If you say Y to
+  "/proc file system" below, you will then get a /proc interface which
+  is documented in <file:Documentation/i2c/proc-interface>.
+
+  This I2C support is also available as a module.  If you want to
+  compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-core.o.
+
+CONFIG_I2C_ALGOBIT
+  This allows you to use a range of I2C adapters called bit-banging
+  adapters.  Say Y if you own an I2C adapter belonging to this class
+  and then say Y to the specific driver for you adapter below.
+
+  This support is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-algo-bit.o.
+
+CONFIG_I2C_PHILIPSPAR
+  This supports parallel-port I2C adapters made by Philips.  Say Y if
+  you own such an adapter.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-philips-par.o.
+
+  Note that if you want support for different parallel port devices,
+  life will be much easier if you compile them all as modules.
+
+CONFIG_I2C_ELV
+  This supports parallel-port I2C adapters called ELV.  Say Y if you
+  own such an adapter.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-elv.o.
+
+CONFIG_I2C_VELLEMAN
+  This supports the Velleman K9000 parallel-port I2C adapter.  Say Y
+  if you own such an adapter.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-velleman.o.
+
+CONFIG_I2C_ALGOPCF
+  This allows you to use a range of I2C adapters called PCF adapters.
+  Say Y if you own an I2C adapter belonging to this class and then say
+  Y to the specific driver for you adapter below.
+
+  This support is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-algo-pcf.o.
+
+CONFIG_I2C_ELEKTOR
+  This supports the PCF8584 ISA bus I2C adapter.  Say Y if you own
+  such an adapter.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-elektor.o.
+
+CONFIG_I2C_CHARDEV
+  Say Y here to use i2c-* device files, usually found in the /dev
+  directory on your system.  They make it possible to have user-space
+  programs use the I2C bus.  Information on how to do this is
+  contained in the file <file:Documentation/i2c/dev-interface>.
+
+  This code is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-dev.o.
+
+CONFIG_I2C_PROC
+  This provides support for i2c device entries in the /proc filesystem.
+  The entries will be found in /proc/sys/dev/sensors.
+
+  This code is also available as a module. If you want to compile
+  it as a module, say M here and read <file:Documentation/modules.txt>.
+  The module will be called i2c-proc.o.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/i2c/i2c-algo-bit.c linux/drivers/i2c/i2c-algo-bit.c
--- v2.5.2/linux/drivers/i2c/i2c-algo-bit.c	Thu Oct 11 08:05:47 2001
+++ linux/drivers/i2c/i2c-algo-bit.c	Tue Jan 15 13:53:51 2002
@@ -50,7 +50,7 @@
 /* might not like this, as they have an internal timeout of some mils	*/
 /*
 #define SLO_IO      jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
-                        if (need_resched) schedule();
+                        cond_resched();
 */
 
 
@@ -120,8 +120,7 @@
 		if (start+adap->timeout <= jiffies) {
 			return -ETIMEDOUT;
 		}
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 	}
 	DEBSTAT(printk("needed %ld jiffies\n", jiffies-start));
 #ifdef SLO_IO
diff -u --recursive --new-file v2.5.2/linux/drivers/i2c/i2c-algo-ite.c linux/drivers/i2c/i2c-algo-ite.c
--- v2.5.2/linux/drivers/i2c/i2c-algo-ite.c	Thu Oct 11 08:05:47 2001
+++ linux/drivers/i2c/i2c-algo-ite.c	Tue Jan 15 13:53:51 2002
@@ -67,7 +67,7 @@
 /* might not like this, as they have an internal timeout of some mils	*/
 /*
 #define SLO_IO      jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
-                        if (need_resched) schedule();
+                        cond_resched();
 */
 
 
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/Config.help linux/drivers/ide/Config.help
--- v2.5.2/linux/drivers/ide/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/ide/Config.help	Fri Jan 25 16:04:31 2002
@@ -0,0 +1,798 @@
+CONFIG_BLK_DEV_IDE
+  If you say Y here, you will use the full-featured IDE driver to
+  control up to ten ATA/IDE interfaces, each being able to serve a
+  "master" and a "slave" device, for a total of up to twenty ATA/IDE
+  disk/cdrom/tape/floppy drives.
+
+  Useful information about large (>540 MB) IDE disks, multiple
+  interfaces, what to do if ATA/IDE devices are not automatically
+  detected, sound card ATA/IDE ports, module support, and other
+  topics, is contained in <file:Documentation/ide.txt>. For detailed
+  information about hard drives, consult the Disk-HOWTO and the
+  Multi-Disk-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  To fine-tune ATA/IDE drive/interface parameters for improved
+  performance, look for the hdparm package at
+  <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),
+  say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/ide.txt>. The module will be called ide-mod.o.
+  Do not compile this driver as a module if your root file system (the
+  one containing the directory /) is located on an IDE device.
+
+  If you have one or more IDE drives, say Y or M here. If your system
+  has no IDE drives, or if memory requirements are really tight, you
+  could say N here, and select the "Old hard disk driver" below
+  instead to save about 13 KB of memory in the kernel.
+
+CONFIG_BLK_DEV_HD_ONLY
+  There are two drivers for MFM/RLL/IDE hard disks. Most people use
+  the newer enhanced driver, but this old one is still around for two
+  reasons. Some older systems have strange timing problems and seem to
+  work only with the old driver (which itself does not work with some
+  newer systems). The other reason is that the old driver is smaller,
+  since it lacks the enhanced functionality of the new one. This makes
+  it a good choice for systems with very tight memory restrictions, or
+  for systems with only older MFM/RLL/ESDI drives. Choosing the old
+  driver can save 13 KB or so of kernel memory.
+
+  If you are unsure, then just choose the Enhanced IDE/MFM/RLL driver
+  instead of this one. For more detailed information, read the
+  Disk-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+CONFIG_BLK_DEV_HD_IDE
+  There are two drivers for MFM/RLL/IDE disks.  Most people use just
+  the new enhanced driver by itself.  This option however installs the
+  old hard disk driver to control the primary IDE/disk interface in
+  the system, leaving the new enhanced IDE driver to take care of only
+  the 2nd/3rd/4th IDE interfaces.  Doing this will prevent you from
+  having an IDE/ATAPI CD-ROM or tape drive connected to the primary
+  IDE interface.  Choosing this option may be useful for older systems
+  which have MFM/RLL/ESDI controller+drives at the primary port
+  address (0x1f0), along with IDE drives at the secondary/3rd/4th port
+  addresses.
+
+  Normally, just say N here; you will then use the new driver for all
+  4 interfaces.
+
+CONFIG_BLK_DEV_IDEDISK
+  This will include enhanced support for MFM/RLL/IDE hard disks.  If
+  you have a MFM/RLL/IDE disk, and there is no special reason to use
+  the old hard disk driver instead, say Y.  If you have an SCSI-only
+  system, you can say N here.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ide-disk.o.  Do not compile this driver as a module
+  if your root file system (the one containing the directory /) is
+  located on the IDE disk. If unsure, say Y.
+
+CONFIG_IDEDISK_MULTI_MODE
+  If you get this error, try to say Y here:
+
+  hda: set_multmode: status=0x51 { DriveReady SeekComplete Error }
+  hda: set_multmode: error=0x04 { DriveStatusError }
+
+  If in doubt, say N.
+
+CONFIG_BLK_DEV_IDECS
+  Support for outboard IDE disks, tape drives, and CD-ROM drives
+  connected through a  PCMCIA card.
+
+CONFIG_BLK_DEV_IDECD
+  If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is
+  a newer protocol used by IDE CD-ROM and TAPE drives, similar to the
+  SCSI protocol. Most new CD-ROM drives use ATAPI, including the
+  NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI
+  double(2X) or better speed drives.
+
+  If you say Y here, the CD-ROM drive will be identified at boot time
+  along with other IDE devices, as "hdb" or "hdc", or something
+  similar (check the boot messages with dmesg). If this is your only
+  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".
+
+  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),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ide-cd.o.
+
+CONFIG_BLK_DEV_IDETAPE
+  If you have an IDE tape drive using the ATAPI protocol, say Y.
+  ATAPI is a newer protocol used by IDE tape and CD-ROM drives,
+  similar to the SCSI protocol.  If you have an SCSI tape drive
+  however, you can say N here.
+
+  You should also say Y if you have an OnStream DI-30 tape drive; this
+  will not work with the SCSI protocol, until there is support for the
+  SC-30 and SC-50 versions.
+
+  If you say Y here, the tape drive will be identified at boot time
+  along with other IDE devices, as "hdb" or "hdc", or something
+  similar, and will be mapped to a character device such as "ht0"
+  (check the boot messages with dmesg).  Be sure to consult the
+  <file:drivers/ide/ide-tape.c> and <file:Documentation/ide.txt> files
+  for usage information.
+
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ide-tape.o.
+
+CONFIG_BLK_DEV_IDEFLOPPY
+  If you have an IDE floppy drive which uses the ATAPI protocol,
+  answer Y.  ATAPI is a newer protocol used by IDE CD-ROM/tape/floppy
+  drives, similar to the SCSI protocol.
+
+  The LS-120 and the IDE/ATAPI Iomega ZIP drive are also supported by
+  this driver. For information about jumper settings and the question
+  of when a ZIP drive uses a partition table, see
+  <http://www.win.tue.nl/~aeb/linux/zip/zip-1.html>.
+  (ATAPI PD-CD/CDR drives are not supported by this driver; support
+  for PD-CD/CDR drives is available if you answer Y to
+  "SCSI emulation support", below).
+
+  If you say Y here, the FLOPPY drive will be identified along with
+  other IDE devices, as "hdb" or "hdc", or something similar (check
+  the boot messages with dmesg).
+
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ide-floppy.o.
+
+CONFIG_BLK_DEV_IDESCSI
+  This will provide SCSI host adapter emulation for IDE ATAPI devices,
+  and will allow you to use a SCSI device driver instead of a native
+  ATAPI driver.
+
+  This is useful if you have an ATAPI device for which no native
+  driver has been written (for example, an ATAPI PD-CD or CDR drive);
+  you can then use this emulation together with an appropriate SCSI
+  device driver. In order to do this, say Y here and to "SCSI support"
+  and "SCSI generic support", below. You must then provide the kernel
+  command line "hdx=scsi" (try "man bootparam" or see the
+  documentation of your boot loader (lilo or loadlin) about how to
+  pass options to the kernel at boot time) for devices if you want the
+  native EIDE sub-drivers to skip over the native support, so that
+  this SCSI emulation can be used instead. This is required for use of
+  CD-RW's.
+
+  Note that this option does NOT allow you to attach SCSI devices to a
+  box that doesn't have a SCSI host adapter installed.
+
+  If both this SCSI emulation and native ATAPI support are compiled
+  into the kernel, the native support will be used.
+
+CONFIG_BLK_DEV_ISAPNP
+  If you have an ISA EIDE card that is PnP (Plug and Play) and
+  requires setup first before scanning for devices, say Y here.
+
+  If unsure, say N.
+
+CONFIG_BLK_DEV_CMD640
+  The CMD-Technologies CMD640 IDE chip is used on many common 486 and
+  Pentium motherboards, usually in combination with a "Neptune" or
+  "SiS" chipset. Unfortunately, it has a number of rather nasty
+  design flaws that can cause severe data corruption under many common
+  conditions. Say Y here to include code which tries to automatically
+  detect and correct the problems under Linux. This option also
+  enables access to the secondary IDE ports in some CMD640 based
+  systems.
+
+  This driver will work automatically in PCI based systems (most new
+  systems have PCI slots). But if your system uses VESA local bus
+  (VLB) instead of PCI, you must also supply a kernel boot parameter
+  to enable the CMD640 bugfix/support: "ide0=cmd640_vlb". (Try "man
+  bootparam" or see the documentation of your boot loader about how to
+  pass options to the kernel.)
+
+  The CMD640 chip is also used on add-in cards by Acculogic, and on
+  the "CSA-6400E PCI to IDE controller" that some people have. For
+  details, read <file:Documentation/ide.txt>.
+
+CONFIG_BLK_DEV_CMD640_ENHANCED
+  This option includes support for setting/autotuning PIO modes and
+  prefetch on CMD640 IDE interfaces.  For details, read
+  <file:Documentation/ide.txt>. If you have a CMD640 IDE interface
+  and your BIOS does not already do this for you, then say Y here.
+  Otherwise say N.
+
+CONFIG_BLK_DEV_RZ1000
+  The PC-Technologies RZ1000 IDE chip is used on many common 486 and
+  Pentium motherboards, usually along with the "Neptune" chipset.
+  Unfortunately, it has a rather nasty design flaw that can cause
+  severe data corruption under many conditions. Say Y here to include
+  code which automatically detects and corrects the problem under
+  Linux. This may slow disk throughput by a few percent, but at least
+  things will operate 100% reliably.
+
+CONFIG_BLK_DEV_IDEPCI
+  Say Y here for PCI systems which use IDE drive(s).
+  This option helps the IDE driver to automatically detect and
+  configure all PCI-based IDE interfaces in your system.
+
+CONFIG_IDEPCI_SHARE_IRQ
+  Some ATA/IDE chipsets have hardware support which allows for
+  sharing a single IRQ with other cards. To enable support for
+  this in the ATA/IDE driver, say Y here.
+
+  It is safe to say Y to this question, in most cases.
+  If unsure, say N.
+
+CONFIG_BLK_DEV_IDEDMA_PCI
+  If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and
+  is capable of bus-master DMA operation (most Pentium PCI systems),
+  you will want to say Y here to reduce CPU overhead. You can then use
+  the "hdparm" utility to enable DMA for drives for which it was not
+  enabled automatically. By default, DMA is not enabled automatically
+  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://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.
+
+  It is safe to say Y to this question.
+
+CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+  If you say Y here, the model and firmware revision of your drive
+  will be compared against a blacklist of buggy drives that claim to
+  be (U)DMA capable but aren't. This is a blanket on/off test with no
+  speed limit options.
+
+  Straight GNU GCC 2.7.3/2.8.X compilers are known to be safe;
+  whereas, many versions of EGCS have a problem and miscompile if you
+  say Y here.
+
+  If in doubt, say N.
+
+CONFIG_BLK_DEV_IDEDMA_TIMEOUT
+  If you say Y here, this is a NASTY UGLY HACK!
+
+  We have to issue an abort and requeue the request DMA engine got
+  turned off by a goofy ASIC, and we have to clean up the mess, and
+  here is as good as any.  Do it globally for all chipsets.
+
+  If in doubt, say N.
+
+CONFIG_BLK_DEV_OFFBOARD
+  Normally, IDE controllers built into the motherboard (on-board
+  controllers) are assigned to ide0 and ide1 while those on add-in PCI
+  cards (off-board controllers) are relegated to ide2 and ide3.
+  Answering Y here will allow you to reverse the situation, with
+  off-board controllers on ide0/1 and on-board controllers on ide2/3.
+  This can improve the usability of some boot managers such as lilo
+  when booting from a drive on an off-board controller.
+
+  If you say Y here, and you actually want to reverse the device scan
+  order as explained above, you also need to issue the kernel command
+  line option "ide=reverse". (Try "man bootparam" or see the
+  documentation of your boot loader (lilo or loadlin) about how to
+  pass options to the kernel at boot time.)
+
+  Note that, if you do this, the order of the hd* devices will be
+  rearranged which may require modification of fstab and other files.
+
+  If in doubt, say N.
+
+CONFIG_IDEDMA_PCI_AUTO
+  Prior to kernel version 2.1.112, Linux used to automatically use
+  DMA for IDE drives and chipsets which support it. Due to concerns
+  about a couple of cases where buggy hardware may have caused damage,
+  the default is now to NOT use DMA automatically. To revert to the
+  previous behaviour, say Y to this question.
+
+  If you suspect your hardware is at all flakey, say N here.
+  Do NOT email the IDE kernel people regarding this issue!
+
+  It is normally safe to answer Y to this question unless your
+  motherboard uses a VIA VP2 chipset, in which case you should say N.
+
+CONFIG_IDEDMA_IVB
+  There are unclear terms is ATA-4 and ATA-5 standards how certain
+  hardware (an 80c ribbon) should be detected. Different interpretations
+  of the standards have been released in hardware. This causes problems:
+  for example, a host with Ultra Mode 4 (or higher) will not run
+  in that mode with an 80c ribbon.
+
+  If you are experiencing compatibility or performance problems, you
+  MAY try to answering Y here. However, it does not necessarily solve
+  any of your problems, it could even cause more of them.
+
+  It is normally safe to answer Y; however, the default is N.
+
+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
+  simply skip those options.
+
+  It is SAFEST to say N to this question.
+
+CONFIG_BLK_DEV_ADMA
+  Please read the comments at the top of
+  <file:drivers/ide/ide-adma.c>.
+
+CONFIG_BLK_DEV_PDC_ADMA
+  Please read the comments at the top of <file:drivers/ide/ide-pci.c>.
+
+CONFIG_BLK_DEV_AEC62XX
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. This add-on card is a bootable PCI UDMA controller. In
+  order to get this card to initialize correctly in some cases, you
+  should say Y here, and preferably also to "Use DMA by default when
+  available".
+
+  The ATP850U/UF is an UltraDMA 33 chipset base.
+  The ATP860 is an UltraDMA 66 chipset base.
+  The ATP860M(acintosh) version is an UltraDMA 66 chipset base.
+
+  Please read the comments at the top of <file:drivers/ide/aec62xx.c>.
+  If you say Y here, then say Y to "Use DMA by default when available"
+  as well.
+
+CONFIG_AEC62XX_TUNING
+  Please read the comments at the top of <file:drivers/ide/aec62xx.c>.
+  If unsure, say N.
+
+CONFIG_BLK_DEV_ALI15X3
+  This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
+  onboard chipsets.  It also tests for Simplex mode and enables
+  normal dual channel support.
+
+  If you say Y here, you also need to say Y to "Use DMA by default
+  when available", above.  Please read the comments at the top of
+  <file:drivers/ide/alim15x3.c>.
+
+  If unsure, say N.
+
+CONFIG_WDC_ALI15X3
+  This allows for UltraDMA support for WDC drives that ignore CRC
+  checking. You are a fool for enabling this option, but there have
+  been requests. DO NOT COMPLAIN IF YOUR DRIVE HAS FS CORRUPTION, IF
+  YOU ENABLE THIS! No one will listen, just laugh for ignoring this
+  SERIOUS WARNING.
+
+  Using this option can allow WDC drives to run at ATA-4/5 transfer
+  rates with only an ATA-2 support structure.
+
+  SAY N!
+
+CONFIG_BLK_DEV_AMD74XX
+  This driver ensures (U)DMA support for the AMD756/760 Viper
+  chipsets.
+
+  If you say Y here, you also need to say Y to "Use DMA by default
+  when available", above.
+  Please read the comments at the top of <file:drivers/ide/amd74xx.c>.
+
+  If unsure, say N.
+
+CONFIG_AMD74XX_OVERRIDE
+  This option auto-forces the ata66 flag.
+  This effect can be also invoked by calling "idex=ata66"
+  If unsure, say N.
+
+CONFIG_BLK_DEV_CMD64X
+  Say Y here if you have an IDE controller which uses any of these
+  chipsets: CMD643, CMD646, or CMD648.
+
+CONFIG_BLK_DEV_CY82C693
+  This driver adds detection and support for the CY82C693 chipset
+  used on Digital's PC-Alpha 164SX boards.
+
+  If you say Y here, you need to say Y to "Use DMA by default
+  when available" as well.
+
+CONFIG_BLK_DEV_CS5530
+  Include support for UDMA on the Cyrix MediaGX 5530 chipset. This
+  will automatically be detected and configured if found.
+
+  It is safe to say Y to this question.
+
+  People with SCSI-only systems should say N here. If unsure, say Y.
+
+CONFIG_BLK_DEV_HPT34X
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. The HPT343 chipset in its current form is a non-bootable
+  controller; the HPT345/HPT363 chipset is a bootable (needs BIOS FIX)
+  PCI UDMA controllers. This driver requires dynamic tuning of the
+  chipset during the ide-probe at boot time. It is reported to support
+  DVD II drives, by the manufacturer.
+
+CONFIG_HPT34X_AUTODMA
+  This is a dangerous thing to attempt currently! Please read the
+  comments at the top of <file:drivers/ide/hpt34x.c>.  If you say Y
+  here, then say Y to "Use DMA by default when available" as well.
+
+  If unsure, say N.
+
+CONFIG_BLK_DEV_HPT366
+  HPT366 is an Ultra DMA chipset for ATA-66.
+  HPT368 is an Ultra DMA chipset for ATA-66 RAID Based.
+  HPT370 is an Ultra DMA chipset for ATA-100.
+
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt.
+
+  The HPT366 chipset in its current form is bootable. One solution
+  for this problem are special LILO commands for redirecting the
+  reference to device 0x80. The other solution is to say Y to "Boot
+  off-board chipsets first support" (CONFIG_BLK_DEV_OFFBOARD) unless
+  your mother board has the chipset natively mounted. Regardless one
+  should use the fore mentioned option and call at LILO or include
+  "ide=reverse" in LILO's append-line.
+
+  This driver requires dynamic tuning of the chipset during the
+  ide-probe at boot. It is reported to support DVD II drives, by the
+  manufacturer.
+
+CONFIG_BLK_DEV_NS87415
+  This driver adds detection and support for the NS87415 chip
+  (used in SPARC64, among others).
+
+  Please read the comments at the top of <file:drivers/ide/ns87415.c>.
+
+CONFIG_BLK_DEV_OPTI621
+  This is a driver for the OPTi 82C621 EIDE controller.
+  Please read the comments at the top of <file:drivers/ide/opti621.c>.
+
+CONFIG_BLK_DEV_SVWKS
+  This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
+  chipsets.
+
+CONFIG_BLK_DEV_PIIX
+  This driver adds PIO mode setting and tuning for all PIIX IDE
+  controllers by Intel.  Since the BIOS can sometimes improperly tune
+  PIO 0-4 mode settings, this allows dynamic tuning of the chipset
+  via the standard end-user tool 'hdparm'.
+
+  Please read the comments at the top of <file:drivers/ide/piix.c>.
+
+  If you say Y here, you should also say Y to "PIIXn Tuning support",
+  below.
+
+  If unsure, say N.
+
+CONFIG_PIIX_TUNING
+  This driver extension adds DMA mode setting and tuning for all PIIX
+  IDE controllers by Intel. Since the BIOS can sometimes improperly
+  set up the device/adapter combination and speed limits, it has
+  become a necessity to back/forward speed devices as needed.
+
+  Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode
+  2 if the BIOS can not perform this task at initialization.
+
+  If unsure, say N.
+
+CONFIG_BLK_DEV_PDC202XX
+  Promise Ultra33 or PDC20246
+  Promise Ultra66 or PDC20262
+  Promise Ultra100 or PDC20265/PDC20267/PDC20268
+
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. This add-on card is a bootable PCI UDMA controller. Since
+  multiple cards can be installed and there are BIOS ROM problems that
+  happen if the BIOS revisions of all installed cards (three-max) do
+  not match, the driver attempts to do dynamic tuning of the chipset
+  at boot-time for max-speed.  Ultra33 BIOS 1.25 or newer is required
+  for more than one card. This card may require that you say Y to
+  "Special UDMA Feature".
+
+  If you say Y here, you need to say Y to "Use DMA by default when
+  available" as well.
+
+  Please read the comments at the top of
+  <file:drivers/ide/pdc202xx.c>.
+
+  If unsure, say N.
+
+CONFIG_PDC202XX_BURST
+  This option causes the pdc202xx driver to enable UDMA modes on the
+  PDC202xx even when the PDC202xx BIOS has not done so.
+
+  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>.
+
+  If unsure, say N.
+
+CONFIG_PDC202XX_FORCE
+  For FastTrak enable overriding BIOS.
+
+CONFIG_BLK_DEV_SIS5513
+  This driver ensures (U)DMA support for SIS5513 chipset based
+  mainboards. SiS620/530 UDMA mode 4, SiS5600/5597 UDMA mode 2, all
+  other DMA mode 2 limited chipsets are unsupported to date.
+
+  If you say Y here, you need to say Y to "Use DMA by default when
+  available" as well.
+
+  Please read the comments at the top of <file:drivers/ide/sis5513.c>.
+
+CONFIG_BLK_DEV_SLC90E66
+  This driver ensures (U)DMA support for Victroy66 SouthBridges for
+  SMsC with Intel NorthBridges.  This is an Ultra66 based chipset.
+  The nice thing about it is that you can mix Ultra/DMA/PIO devices
+  and it will handle timing cycles.  Since this is an improved
+  look-a-like to the PIIX4 it should be a nice addition.
+
+  If you say Y here, you need to say Y to "Use DMA by default when
+  available" as well.
+
+  Please read the comments at the top of
+  <file:drivers/ide/slc90e66.c>.
+
+CONFIG_BLK_DEV_SL82C105
+  If you have a Winbond SL82c105 IDE controller, say Y here to enable
+  special configuration for this chip. This is common on various CHRP
+  motherboards, but could be used elsewhere. If in doubt, say Y.
+
+CONFIG_BLK_DEV_TRM290
+  This driver adds support for bus master DMA transfers
+  using the Tekram TRM290 PCI IDE chip. Volunteers are
+  needed for further tweaking and development.
+  Please read the comments at the top of <file:drivers/ide/trm290.c>.
+
+CONFIG_BLK_DEV_VIA82CXXX
+  This allows you to configure your chipset for a better use while
+  running PIO/(U)DMA, it will allow you to enable efficiently the
+  second channel dma usage, as it may not be set by BIOS.  It will try
+  to set fifo configuration at its best.  It will allow you to get
+  information from /proc/ide/via provided you enabled "/proc file
+  system" support.
+
+  Please read the comments at the top of
+  <file:drivers/ide/via82cxxx.c>.
+
+  If you say Y here, then say Y to "Use DMA by default when available"
+  as well.
+
+  If unsure, say N.
+
+CONFIG_BLK_DEV_IDE_RAPIDE
+  Say Y here if you want to support the Yellowstone RapIDE controller
+  manufactured for use with Acorn computers.
+
+CONFIG_IDE_CHIPSETS
+  Say Y here if you want to include enhanced support for various IDE
+  interface chipsets used on motherboards and add-on cards. You can
+  then pick your particular IDE chip from among the following options.
+  This enhanced support may be necessary for Linux to be able to
+  access the 3rd/4th drives in some systems. It may also enable
+  setting of higher speed I/O rates to improve system performance with
+  these chipsets. Most of these also require special kernel boot
+  parameters to actually turn on the support at runtime; you can find
+  a list of these in the file <file:Documentation/ide.txt>.
+
+  People with SCSI-only systems can say N here.
+
+CONFIG_BLK_DEV_4DRIVES
+  Certain older chipsets, including the Tekram 690CD, use a single set
+  of I/O ports at 0x1f0 to control up to four drives, instead of the
+  customary two drives per port. Support for this can be enabled at
+  runtime using the "ide0=four" kernel boot parameter if you say Y
+  here.
+
+CONFIG_BLK_DEV_ALI14XX
+  This driver is enabled at runtime using the "ide0=ali14xx" kernel
+  boot parameter.  It enables support for the secondary IDE interface
+  of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
+  I/O speeds to be set as well.  See the files
+  <file:Documentation/ide.txt> and <file:drivers/ide/ali14xx.c> for
+  more info.
+
+CONFIG_BLK_DEV_DTC2278
+  This driver is enabled at runtime using the "ide0=dtc2278" kernel
+  boot parameter. It enables support for the secondary IDE interface
+  of the DTC-2278 card, and permits faster I/O speeds to be set as
+  well. See the <file:Documentation/ide.txt> and
+  <file:drivers/ide/dtc2278.c> files for more info.
+
+CONFIG_BLK_DEV_HT6560B
+  This driver is enabled at runtime using the "ide0=ht6560b" kernel
+  boot parameter. It enables support for the secondary IDE interface
+  of the Holtek card, and permits faster I/O speeds to be set as well.
+  See the <file:Documentation/ide.txt> and
+  <file:drivers/ide/ht6560b.c> files for more info.
+
+CONFIG_BLK_DEV_PDC4030
+  This driver provides support for the secondary IDE interface and
+  cache of Promise IDE chipsets, e.g. DC4030 and DC5030.  This driver
+  is known to incur timeouts/retries during heavy I/O to drives
+  attached to the secondary interface.  CD-ROM and TAPE devices are
+  not supported yet.  This driver is enabled at runtime using the
+  "ide0=dc4030" kernel boot parameter.  See the
+  <file:Documentation/ide.txt> and <file:drivers/ide/pdc4030.c> files
+  for more info.
+
+CONFIG_BLK_DEV_QD65XX
+  This driver is enabled at runtime using the "ide0=qd65xx" kernel
+  boot parameter.  It permits faster I/O speeds to be set.  See the
+  <file:Documentation/ide.txt> and <file:drivers/ide/qd65xx.c> for
+  more info.
+
+CONFIG_BLK_DEV_UMC8672
+  This driver is enabled at runtime using the "ide0=umc8672" kernel
+  boot parameter. It enables support for the secondary IDE interface
+  of the UMC-8672, and permits faster I/O speeds to be set as well.
+  See the files <file:Documentation/ide.txt> and
+  <file:drivers/ide/umc8672.c> for more info.
+
+CONFIG_BLK_DEV_GAYLE
+  This is the IDE driver for the builtin IDE interface on some Amiga
+  models. It supports both the `A1200 style' (used in A600 and A1200)
+  and `A4000 style' (used in A4000 and A4000T) of the Gayle IDE
+  interface. Say Y if you have such an Amiga model and want to use IDE
+  devices (hard disks, CD-ROM drives, etc.) that are connected to the
+  builtin IDE interface.
+
+CONFIG_BLK_DEV_FALCON_IDE
+  This is the IDE driver for the builtin IDE interface on the Atari
+  Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
+  disks, CD-ROM drives, etc.) that are connected to the builtin IDE
+  interface.
+
+CONFIG_BLK_DEV_BUDDHA
+  This is the IDE driver for the IDE interfaces on the Buddha, 
+  Catweasel and X-Surf expansion boards.  It supports up to two interfaces 
+  on the Buddha, three on the Catweasel and two on the X-Surf.
+
+  Say Y if you have a Buddha or Catweasel expansion board and want to
+  use IDE devices (hard disks, CD-ROM drives, etc.) that are connected
+  to one of its IDE interfaces.
+
+CONFIG_BLK_DEV_IDEDOUBLER
+  This driver provides support for the so-called `IDE doublers' (made
+  by various manufacturers, e.g. Eyetech) that can be connected to the
+  builtin IDE interface of some Amiga models. Using such an IDE
+  doubler, you can connect up to four instead of two IDE devices on
+  the Amiga's builtin IDE interface.
+
+  Note that the normal Amiga Gayle IDE driver may not work correctly
+  if you have an IDE doubler and don't enable this driver!
+
+  Say Y if you have an IDE doubler.  The driver is enabled at kernel
+  runtime using the "ide=doubler" kernel boot parameter.
+
+CONFIG_BLK_DEV_IDE_PMAC
+  This driver provides support for the built-in IDE controller on
+  most of the recent Apple Power Macintoshes and PowerBooks.
+  If unsure, say Y.
+
+CONFIG_BLK_DEV_IDEDMA_PMAC
+  This option allows the driver for the built-in IDE controller on
+  Power Macintoshes and PowerBooks to use DMA (direct memory access)
+  to transfer data to and from memory.  Saying Y is safe and improves
+  performance.
+
+CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
+  This option allows the driver for the built-in IDE controller on
+  Power Macintoshes and PowerBooks to use DMA automatically, without
+  it having to be explicitly enabled.  This option is provided because
+  of concerns about a couple of cases where using DMA on buggy PC
+  hardware may have caused damage.  Saying Y should be safe on all
+  Apple machines.
+
+CONFIG_BLK_DEV_MAC_IDE
+  This is the IDE driver for the builtin IDE interface on some m68k
+  Macintosh models. It supports both the `Quadra style' (used in
+  Quadra/ Centris 630 and Performa 588 models) and `Powerbook style'
+  (used in the Powerbook 150 and 190 models) IDE interface.
+
+  Say Y if you have such an Macintosh model and want to use IDE
+  devices (hard disks, CD-ROM drives, etc.) that are connected to the
+  builtin IDE interface.
+
+CONFIG_BLK_DEV_IDE_ICSIDE
+  On Acorn systems, say Y here if you wish to use the ICS IDE
+  interface card.  This is not required for ICS partition support.
+  If you are unsure, say N to this.
+
+CONFIG_BLK_DEV_IDEDMA_ICS
+  Say Y here if you want to add DMA (Direct Memory Access) support to
+  the ICS IDE driver.
+
+CONFIG_IDEDMA_ICS_AUTO
+  Prior to kernel version 2.1.112, Linux used to automatically use
+  DMA for IDE drives and chipsets which support it. Due to concerns
+  about a couple of cases where buggy hardware may have caused damage,
+  the default is now to NOT use DMA automatically. To revert to the
+  previous behaviour, say Y to this question.
+
+  If you suspect your hardware is at all flakey, say N here.
+  Do NOT email the IDE kernel people regarding this issue!
+
+CONFIG_BLK_DEV_ATARAID
+  Say Y or M if you have an IDE Raid controller and want linux
+  to use its softwareraid feature.  You must also select an
+  appropriate for your board low-level driver below.
+
+  Note, that Linux does not use the Raid implemetation in BIOS, and
+  the main purpose for this feature is to retain compatibility and
+  data integrity with other OS-es, using the same disk array. Linux
+  has its own Raid drivers, which you should use if you need better
+  performance.
+
+CONFIG_BLK_DEV_ATARAID_PDC
+  Say Y or M if you have a Promise Fasttrak (tm) Raid controller
+  and want linux to use the softwareraid feature of this card.
+  This driver uses /dev/ataraid/dXpY (X and Y numbers) as device
+  names.
+
+  If you choose to compile this as a module, the module will be called
+  pdcraid.o.
+
+CONFIG_BLK_DEV_ATARAID_HPT
+  Say Y or M if you have a Highpoint HPT 370 Raid controller
+  and want linux to use the softwareraid feature of this card.
+  This driver uses /dev/ataraid/dXpY (X and Y numbers) as device
+  names.
+
+  If you choose to compile this as a module, the module will be called
+  hptraid.o.
+
+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.
+
+CONFIG_IDE_8xx_PCCARD
+  Select how the IDE devices are connected to the MPC8xx system:
+
+  8xx_PCCARD uses the 8xx internal PCMCIA interface in combination
+             with a PC Card (e.g. ARGOSY portable Hard Disk Adapter),
+             ATA PC Card HDDs or ATA PC Flash Cards (example: TQM8xxL
+             systems)
+
+  8xx_DIRECT is used for directly connected IDE devices using the 8xx
+             internal PCMCIA interface (example: IVMS8 systems)
+
+  EXT_DIRECT is used for IDE devices directly connected to the 8xx
+             bus using some glue logic, but _not_ the 8xx internal
+             PCMCIA interface (example: IDIF860 systems)
+
+CONFIG_BLK_DEV_IDEDISK_FUJITSU
+  Enable vendor-specific code for Fujitsu IDE disks.  Unless you are
+  the IDE maintainer, you probably do not want to mess with this.
+
+CONFIG_BLK_DEV_IDEDISK_IBM
+  Enable vendor-specific code for IBM IDE disks.  Unless you are the
+  IDE maintainer, you probably do not want to mess with this.
+
+CONFIG_BLK_DEV_IDEDISK_MAXTOR
+  Enable vendor-specific code for Maxtor IDE disks.  Unless you are
+  the IDE maintainer, you probably do not want to mess with this.
+
+CONFIG_BLK_DEV_IDEDISK_QUANTUM
+  Enable vendor-specific code for Quantum IDE disks.  Unless you are
+  the IDE maintainer, you probably do not want to mess with this.
+
+CONFIG_BLK_DEV_IDEDISK_SEAGATE
+  Enable vendor-specific code for Seagate IDE disks.  Unless you are
+  the IDE maintainer, you probably do not want to mess with this.
+
+CONFIG_BLK_DEV_IDEDISK_WD
+  Enable vendor-specific code for Western Digital IDE disks.  Unless
+  you are the IDE maintainer, you probably do not want to mess with
+  this.
+
+CONFIG_BLK_DEV_TIVO
+  Enable vendor-specific code for TiVo IDE disks.  Unless you are the
+  IDE maintainer, you probably do not want to mess with this.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/Config.in linux/drivers/ide/Config.in
--- v2.5.2/linux/drivers/ide/Config.in	Mon Oct  8 11:40:13 2001
+++ linux/drivers/ide/Config.in	Tue Jan 15 11:27:30 2002
@@ -14,6 +14,7 @@
 
    dep_tristate '  Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
    dep_mbool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
+   dep_mbool '    Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK
 
    define_bool CONFIG_BLK_DEV_IDEDISK_VENDOR n
    dep_mbool '    Fujitsu Vendor Specific' CONFIG_BLK_DEV_IDEDISK_FUJITSU $CONFIG_BLK_DEV_IDEDISK_VENDOR
@@ -32,6 +33,8 @@
    dep_tristate '  Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
    dep_tristate '  SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
 
+   bool '  IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL
+
    comment 'IDE chipset support/bugfixes'
    if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
       dep_bool '  CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86
@@ -43,14 +46,17 @@
 	 if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
 	    bool '    Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
 	    bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
-#	    bool '    Asynchronous DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
-	    define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
 	    bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
+	    dep_bool '      Force enable legacy 2.0.X HOSTS to use DMA' CONFIG_BLK_DEV_IDEDMA_FORCED $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI
+            dep_bool '    Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
 	    define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-#	    dep_bool '      Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
+	    dep_bool '      Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
 	    dep_bool '      Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
+#	    dep_bool '      Asynchronous DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP
+	    define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
+#	    dep_bool '      Tag Command Queue DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDMA_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP
 
 	    dep_bool '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
@@ -74,7 +80,8 @@
 	    fi
 	    dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
-	    dep_bool '    PROMISE PDC202{46|62|65|67|68} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP
+	    dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
 	    dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
 	    dep_bool '    ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
@@ -84,8 +91,6 @@
 	    dep_bool '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
          fi
 
-#	 dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP
-
 	 if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
 	    bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
 	 fi
@@ -173,6 +178,7 @@
 else
   define_bool CONFIG_DMA_NONPCI n
 fi
+
 if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
      "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
      "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/Makefile linux/drivers/ide/Makefile
--- v2.5.2/linux/drivers/ide/Makefile	Tue Oct  9 09:18:37 2001
+++ linux/drivers/ide/Makefile	Tue Jan 15 11:27:30 2002
@@ -10,7 +10,7 @@
 
 O_TARGET := idedriver.o
 
-export-objs		:= ide.o ide-features.o ataraid.o
+export-objs		:= ide-taskfile.o ide.o ide-features.o ide-probe.o ataraid.o
 list-multi		:= ide-mod.o ide-probe-mod.o
 
 obj-y		:=
@@ -24,6 +24,7 @@
 obj-$(CONFIG_BLK_DEV_IDECD)     += ide-cd.o
 obj-$(CONFIG_BLK_DEV_IDETAPE)   += ide-tape.o
 obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
+
 obj-$(CONFIG_BLK_DEV_IT8172)    += it8172.o
 
 ide-obj-$(CONFIG_BLK_DEV_AEC62XX)	+= aec62xx.o
@@ -69,13 +70,13 @@
 
 # The virtualised raid layers MUST come after the ide itself or bad stuff
 # will happen.
-obj-$(CONFIG_BLK_DEV_ATARAID)	+= ataraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID)		+= ataraid.o
 obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
 obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
 
 ide-obj-$(CONFIG_PROC_FS)		+= ide-proc.o
 
-ide-mod-objs		:= ide.o ide-features.o $(ide-obj-y)
+ide-mod-objs		:= ide-taskfile.o ide.o ide-features.o $(ide-obj-y)
 ide-probe-mod-objs	:= ide-probe.o ide-geometry.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/alim15x3.c linux/drivers/ide/alim15x3.c
--- v2.5.2/linux/drivers/ide/alim15x3.c	Sun Jul 15 16:22:23 2001
+++ linux/drivers/ide/alim15x3.c	Tue Jan 15 11:27:30 2002
@@ -453,7 +453,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x003F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive, can_ultra_dma);
 				if ((id->field_valid & 2) &&
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/cmd64x.c linux/drivers/ide/cmd64x.c
--- v2.5.2/linux/drivers/ide/cmd64x.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/cmd64x.c	Tue Jan 15 11:27:30 2002
@@ -86,6 +86,7 @@
 #include <linux/proc_fs.h>
 
 static int cmd64x_get_info(char *, char **, off_t, int);
+static int cmd680_get_info(char *, char **, off_t, int);
 extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
 extern char *ide_media_verbose(ide_drive_t *);
 static struct pci_dev *bmide_dev;
@@ -180,24 +181,21 @@
 	return p-buffer;	/* => must be less than 4k! */
 }
 
-#if 0
-static char * cmd64x_chipset_data (char *buf, struct pci_dev *dev)
-{
-	char *p = buf;
-	p += sprintf(p, "thingy stuff\n");
-	return (char *)p;
-}
-static int __init cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+static int cmd680_get_info (char *buffer, char **addr, off_t offset, int count)
 {
 	char *p = buffer;
-	p = cmd64x_chipset_data(buffer, bmide_dev);
-	return p-buffer;	/* hoping it is less than 4K... */
+	p += sprintf(p, "\n                                CMD680 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "PIO Mode:       %s                %s               %s                 %s\n",
+		"?", "?", "?", "?");
+	return p-buffer;	/* => must be less than 4k! */
 }
-#endif
 
 #endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
 
 byte cmd64x_proc = 0;
+byte cmd680_proc = 0;
 
 /*
  * Registers and masks for easy access by drive index:
@@ -345,10 +343,58 @@
 		setup_count, active_count, recovery_count);
 }
 
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
 {
-	byte speed= 0x00;
-	byte set_pio= ide_get_best_pio_mode(drive, 4, 5, NULL);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte addr_mask		= (hwif->channel) ? 0xB2 : 0xA2;
+	unsigned short		timing;
+
+	pci_read_config_word(dev, addr_mask, &timing);
+
+	switch (timing) {
+		case 0x10c1:	return 4;
+		case 0x10c3:	return 3;
+		case 0x1281:	return 2;
+		case 0x2283:	return 1;
+		case 0x328a:
+		default:	return 0;
+	}
+}
+
+static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte			drive_pci;
+	unsigned short		speedt;
+
+	switch (drive->dn) {
+		case 0: drive_pci = 0xA4; break;
+		case 1: drive_pci = 0xA6; break;
+		case 2: drive_pci = 0xB4; break;
+		case 3: drive_pci = 0xB6; break;
+		default: return;
+        }
+
+	pci_read_config_word(dev, drive_pci, &speedt);
+
+	/* cheat for now and use the docs */
+//	switch(cmd680_taskfile_timing(hwif)) {
+	switch(mode_wanted) {
+		case 4:		speedt = 0x10c1; break;
+		case 3:		speedt = 0x10C3; break;
+		case 2:		speedt = 0x1104; break;
+		case 1:		speedt = 0x2283; break;
+		case 0:
+		default:	speedt = 0x328A; break;
+	}
+	pci_write_config_word(dev, drive_pci, speedt);
+}
+
+static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	byte speed	= 0x00;
+	byte set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
 
 	cmd64x_tuneproc(drive, set_pio);
 	speed = XFER_PIO_0 + set_pio;
@@ -356,6 +402,41 @@
 		(void) ide_config_drive_speed(drive, speed);
 }
 
+static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
+	u8 speed		= 0x00;
+	u8 mode_pci		= 0x00;
+	u8 channel_timings	= cmd680_taskfile_timing(hwif);
+	u8 set_pio		= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+	pci_read_config_byte(dev, addr_mask, &mode_pci);
+	mode_pci &= ~((unit) ? 0x30 : 0x03);
+
+	/* WARNING PIO timing mess is going to happen b/w devices, argh */
+	if ((channel_timings != set_pio) && (set_pio > channel_timings))
+		set_pio = channel_timings;
+
+	cmd680_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed) {
+		(void) ide_config_drive_speed(drive, speed);
+		drive->current_speed = speed;
+	}
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+        if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
+		config_cmd680_chipset_for_pio(drive, set_speed);
+	} else {
+		config_cmd64x_chipset_for_pio(drive, set_speed);
+	}
+}
+
 static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -363,7 +444,7 @@
 	struct pci_dev *dev	= hwif->pci_dev;
 	int err			= 0;
 
-	byte unit		= (drive->select.b.unit & 0x01);
+	u8 unit			= (drive->select.b.unit & 0x01);
 	u8 pciU			= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
 	u8 pciD			= (hwif->channel) ? BMIDESR1 : BMIDESR0;
 	u8 regU			= 0;
@@ -424,8 +505,123 @@
 	return err;
 }
 
+static int cmd680_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 dma_pci		= 0;
+	u8 udma_pci		= 0;
+	u8 mode_pci		= 0;
+	u8 scsc			= 0;
+	u16 ultra		= 0;
+	u16 multi		= 0;
+	int err			= 0;
+
+        pci_read_config_byte(dev, addr_mask, &mode_pci);
+	pci_read_config_byte(dev, 0x8A, &scsc);
+
+        switch (drive->dn) {
+		case 0: dma_pci = 0xA8; udma_pci = 0xAC; break;
+		case 1: dma_pci = 0xAA; udma_pci = 0xAE; break;
+		case 2: dma_pci = 0xB8; udma_pci = 0xBC; break;
+		case 3: dma_pci = 0xBA; udma_pci = 0xBE; break;
+		default: return 1;
+	}
+
+	pci_read_config_byte(dev, addr_mask, &mode_pci);
+	mode_pci &= ~((unit) ? 0x30 : 0x03);
+	pci_read_config_word(dev, dma_pci, &multi);
+	pci_read_config_word(dev, udma_pci, &ultra);
+
+	if ((speed == XFER_UDMA_6) && (scsc & 0x30) == 0x00) {
+		pci_write_config_byte(dev, 0x8A, scsc|0x01);
+		pci_read_config_byte(dev, 0x8A, &scsc);
+	}
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_6:
+			if ((scsc & 0x30) == 0x00)
+				goto speed_break;
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= 0x01;
+			break;
+speed_break :
+			speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x01 : 0x02);
+			break;
+		case XFER_UDMA_4:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x02 : 0x03);
+			break;
+		case XFER_UDMA_3:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x04 : 0x05);
+			break;
+		case XFER_UDMA_2:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x05 : 0x07);
+			break;
+		case XFER_UDMA_1:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x07 : 0x0B);
+			break;
+		case XFER_UDMA_0:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x0C : 0x0F);
+			break;
+		case XFER_MW_DMA_2:
+			multi = 0x10C1;
+			break;
+		case XFER_MW_DMA_1:
+			multi = 0x10C2;
+			break;
+		case XFER_MW_DMA_0:
+			multi = 0x2208;
+			break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:	cmd680_tuneproc(drive, 4); break;
+		case XFER_PIO_3:	cmd680_tuneproc(drive, 3); break;
+		case XFER_PIO_2:	cmd680_tuneproc(drive, 2); break;
+		case XFER_PIO_1:	cmd680_tuneproc(drive, 1); break;
+		case XFER_PIO_0:	cmd680_tuneproc(drive, 0); break;
+		default:
+			return 1;
+	}
+
+	
+	if (speed >= XFER_MW_DMA_0) 
+		config_cmd680_chipset_for_pio(drive, 0);
+
+	if (speed >= XFER_UDMA_0)
+		mode_pci |= ((unit) ? 0x30 : 0x03);
+	else if (speed >= XFER_MW_DMA_0)
+		mode_pci |= ((unit) ? 0x20 : 0x02);
+	else
+		mode_pci |= ((unit) ? 0x10 : 0x01);
+
+	pci_write_config_byte(dev, addr_mask, mode_pci);
+	pci_write_config_word(dev, dma_pci, multi);
+	pci_write_config_word(dev, udma_pci, ultra);
+
+	err = ide_config_drive_speed(drive, speed);
+	drive->current_speed = speed;
+	return err;
+}
+
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
+static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
 {
 	struct hd_driveid *id	= drive->id;
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -510,6 +706,55 @@
 	return rval;
 }
 
+static int config_cmd680_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	byte udma_66		= eighty_ninty_three(drive);
+	byte speed		= 0x00;
+	byte set_pio		= 0x00;
+	int rval;
+
+	if ((id->dma_ultra & 0x0040) && (udma_66))	speed = XFER_UDMA_6;
+	else if ((id->dma_ultra & 0x0020) && (udma_66))	speed = XFER_UDMA_5;
+	else if ((id->dma_ultra & 0x0010) && (udma_66))	speed = XFER_UDMA_4;
+	else if ((id->dma_ultra & 0x0008) && (udma_66))	speed = XFER_UDMA_3;
+	else if (id->dma_ultra & 0x0004)		speed = XFER_UDMA_2;
+	else if (id->dma_ultra & 0x0002)		speed = XFER_UDMA_1;
+	else if (id->dma_ultra & 0x0001)		speed = XFER_UDMA_0;
+	else if (id->dma_mword & 0x0004)		speed = XFER_MW_DMA_2;
+	else if (id->dma_mword & 0x0002)		speed = XFER_MW_DMA_1;
+	else if (id->dma_mword & 0x0001)		speed = XFER_MW_DMA_0;
+	else {
+		set_pio = 1;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	config_chipset_for_pio(drive, set_pio);
+
+	if (set_pio)
+		return ((int) ide_dma_off_quietly);
+
+	if (cmd680_tune_chipset(drive, speed))
+		return ((int) ide_dma_off);
+
+	rval = (int)(	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
+	return rval;
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
+{
+	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680)
+		return (config_cmd680_chipset_for_dma(drive));
+	return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66));
+}
+
 static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
 {
 	struct hd_driveid *id	= drive->id;
@@ -519,12 +764,15 @@
 	byte can_ultra_33	= 0;
 	byte can_ultra_66	= 0;
 	byte can_ultra_100	= 0;
+	byte can_ultra_133	= 0;
 	ide_dma_action_t dma_func = ide_dma_on;
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;	
 
 	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_680:
+			can_ultra_133 = 1;
 		case PCI_DEVICE_ID_CMD_649:
 			can_ultra_100 = 1;
 		case PCI_DEVICE_ID_CMD_648:
@@ -550,7 +798,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if ((id->field_valid & 4) && (can_ultra_33)) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x007F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66);
 				if ((id->field_valid & 2) &&
@@ -586,6 +834,18 @@
 	return HWIF(drive)->dmaproc(dma_func, drive);
 }
 
+static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			return cmd64x_config_drive_for_dma(drive);
+		default:
+			break;
+	}
+	/* Other cases are done by generic IDE-DMA code. */
+        return ide_dmaproc(func, drive);
+}
+
 static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
 	byte dma_stat		= 0;
@@ -663,7 +923,78 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
+static int cmd680_busproc (ide_drive_t * drive, int state)
+{
+#if 0
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
+	u32 stat_config		= 0;
+
+        pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
+
+	if (!hwif)
+		return -EINVAL;
+
+	switch (state) {
+		case BUSSTATE_ON:
+			hwif->drives[0].failures = 0;
+			hwif->drives[1].failures = 0;
+			break;
+		case BUSSTATE_OFF:
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		case BUSSTATE_TRISTATE:
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		default:
+			return 0;
+	}
+	hwif->bus_state = state;
+#endif
+	return 0;
+}
+
+void cmd680_reset (ide_drive_t *drive)
+{
+#if 0
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
+	byte reset		= 0;
+
+	pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
+	pci_write_config_byte(hwif->pci_dev, addr_mask, reset|0x03);
+#endif
+}
+
+unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name)
+{
+	u8 tmpbyte	= 0;	
+	pci_write_config_byte(dev, 0x80, 0x00);
+	pci_write_config_byte(dev, 0x84, 0x00);
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	pci_write_config_byte(dev, 0x8A, tmpbyte|0x01);
+	pci_write_config_word(dev, 0xA2, 0x328A);
+	pci_write_config_dword(dev, 0xA4, 0x328A);
+	pci_write_config_dword(dev, 0xA8, 0x4392);
+	pci_write_config_dword(dev, 0xAC, 0x4009);
+	pci_write_config_word(dev, 0xB2, 0x328A);
+	pci_write_config_dword(dev, 0xB4, 0x328A);
+	pci_write_config_dword(dev, 0xB8, 0x4392);
+	pci_write_config_dword(dev, 0xBC, 0x4009);
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!cmd64x_proc) {
+		cmd64x_proc = 1;
+		bmide_dev = dev;
+		cmd64x_display_info = &cmd680_get_info;
+	}
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name)
 {
 	unsigned char mrdmode;
 	unsigned int class_rev;
@@ -752,7 +1083,23 @@
 	return 0;
 }
 
-unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
+{
+	if (dev->device == PCI_DEVICE_ID_CMD_680)
+		return cmd680_pci_init (dev, name);
+	return cmd64x_pci_init (dev, name);
+}
+
+unsigned int cmd680_ata66 (ide_hwif_t *hwif)
+{
+	byte ata66	= 0;
+	byte addr_mask	= (hwif->channel) ? 0xB0 : 0xA0;
+
+	pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
+	return (ata66 & 0x01) ? 1 : 0;
+}
+
+unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
 {
 	byte ata66 = 0;
 	byte mask = (hwif->channel) ? 0x02 : 0x01;
@@ -761,6 +1108,14 @@
 	return (ata66 & mask) ? 1 : 0;
 }
 
+unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	if (dev->device == PCI_DEVICE_ID_CMD_680)
+		return cmd680_ata66(hwif);
+	return cmd64x_ata66(hwif);
+}
+
 void __init ide_init_cmd64x (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
@@ -769,8 +1124,6 @@
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
 
-	hwif->tuneproc	= &cmd64x_tuneproc;
-	hwif->speedproc	= &cmd64x_tune_chipset;
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
 
@@ -779,10 +1132,19 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_680:
+			hwif->busproc	= &cmd680_busproc;
+			hwif->dmaproc	= &cmd680_dmaproc;
+			hwif->resetproc = &cmd680_reset;
+			hwif->speedproc	= &cmd680_tune_chipset;
+			hwif->tuneproc	= &cmd680_tuneproc;
+			break;
 		case PCI_DEVICE_ID_CMD_649:
 		case PCI_DEVICE_ID_CMD_648:
 		case PCI_DEVICE_ID_CMD_643:
-			hwif->dmaproc = &cmd64x_dmaproc;
+			hwif->dmaproc	= &cmd64x_dmaproc;
+			hwif->tuneproc	= &cmd64x_tuneproc;
+			hwif->speedproc = &cmd64x_tune_chipset;
 			break;
 		case PCI_DEVICE_ID_CMD_646:
 			hwif->chipset = ide_cmd646;
@@ -791,6 +1153,8 @@
 			} else {
 				hwif->dmaproc = &cmd64x_dmaproc;
 			}
+			hwif->tuneproc	= &cmd64x_tuneproc;
+			hwif->speedproc	= &cmd64x_tune_chipset;
 			break;
 		default:
 			break;
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/hpt366.c linux/drivers/ide/hpt366.c
--- v2.5.2/linux/drivers/ide/hpt366.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/hpt366.c	Tue Jan 15 11:27:30 2002
@@ -1,7 +1,8 @@
 /*
- * linux/drivers/ide/hpt366.c		Version 0.18	June. 9, 2000
+ * linux/drivers/ide/hpt366.c		Version 0.22	20 Sep 2001
  *
  * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
  * May be copied or modified under the terms of the GNU General Public License
  *
  * Thanks to HighPoint Technologies for their assistance, and hardware.
@@ -11,6 +12,34 @@
  *
  * Note that final HPT370 support was done by force extraction of GPL.
  *
+ * - add function for getting/setting power status of drive
+ * - the HPT370's state machine can get confused. reset it before each dma 
+ *   xfer to prevent that from happening.
+ * - reset state engine whenever we get an error.
+ * - check for busmaster state at end of dma. 
+ * - use new highpoint timings.
+ * - detect bus speed using highpoint register.
+ * - use pll if we don't have a clock table. added a 66MHz table that's
+ *   just 2x the 33MHz table.
+ * - removed turnaround. NOTE: we never want to switch between pll and
+ *   pci clocks as the chip can glitch in those cases. the highpoint
+ *   approved workaround slows everything down too much to be useful. in
+ *   addition, we would have to serialize access to each chip.
+ * 	Adrian Sun <a.sun@sun.com>
+ *
+ * add drive timings for 66MHz PCI bus,
+ * fix ATA Cable signal detection, fix incorrect /proc info
+ * add /proc display for per-drive PIO/DMA/UDMA mode and
+ * per-channel ATA-33/66 Cable detect.
+ * 	Duncan Laurie <void@sun.com>
+ *
+ * fixup /proc output for multiple controllers
+ *	Tim Hockin <thockin@sun.com>
+ *
+ * On hpt366: 
+ * Reset the hpt366 on error, reset on dma
+ * Fix disabling Fast Interrupt hpt366.
+ * 	Mike Waychison <crlf@sun.com>
  */
 
 #include <linux/config.h>
@@ -28,6 +57,7 @@
 #include <linux/init.h>
 #include <linux/ide.h>
 
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
@@ -35,6 +65,11 @@
 
 #define DISPLAY_HPT366_TIMINGS
 
+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+/*#define HPT_DELAY_INTERRUPT*/
+/*#define HPT_SERIALIZE_IO*/
+
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
@@ -106,146 +141,302 @@
 
 struct chipset_bus_clock_list_entry {
 	byte		xfer_speed;
-	unsigned int	chipset_settings_write;
-	unsigned int	chipset_settings_read;
+	unsigned int	chipset_settings;
 };
 
+/* key for bus clock timings
+ * bit
+ * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ *        during task file register access.
+ * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ *        xfer.
+ * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ *        register access.
+ * 28     UDMA enable
+ * 29     DMA enable
+ * 30     PIO_MST enable. if set, the chip is in bus master mode during
+ *        PIO.
+ * 31     FIFO enable.
+ */
 struct chipset_bus_clock_list_entry forty_base [] = {
 
-	{	XFER_UDMA_4,	0x900fd943,	0x900fd943	},
-	{	XFER_UDMA_3,	0x900ad943,	0x900ad943	},
-	{	XFER_UDMA_2,	0x900bd943,	0x900bd943	},
-	{	XFER_UDMA_1,	0x9008d943,	0x9008d943	},
-	{	XFER_UDMA_0,	0x9008d943,	0x9008d943	},
-
-	{	XFER_MW_DMA_2,	0xa008d943,	0xa008d943	},
-	{	XFER_MW_DMA_1,	0xa010d955,	0xa010d955	},
-	{	XFER_MW_DMA_0,	0xa010d9fc,	0xa010d9fc	},
-
-	{	XFER_PIO_4,	0xc008d963,	0xc008d963	},
-	{	XFER_PIO_3,	0xc010d974,	0xc010d974	},
-	{	XFER_PIO_2,	0xc010d997,	0xc010d997	},
-	{	XFER_PIO_1,	0xc010d9c7,	0xc010d9c7	},
-	{	XFER_PIO_0,	0xc018d9d9,	0xc018d9d9	},
-	{	0,		0x0120d9d9,	0x0120d9d9	}
+	{	XFER_UDMA_4,    0x900fd943	},
+	{	XFER_UDMA_3,	0x900ad943	},
+	{	XFER_UDMA_2,	0x900bd943	},
+	{	XFER_UDMA_1,	0x9008d943	},
+	{	XFER_UDMA_0,	0x9008d943	},
+
+	{	XFER_MW_DMA_2,	0xa008d943	},
+	{	XFER_MW_DMA_1,	0xa010d955	},
+	{	XFER_MW_DMA_0,	0xa010d9fc	},
+
+	{	XFER_PIO_4,	0xc008d963	},
+	{	XFER_PIO_3,	0xc010d974	},
+	{	XFER_PIO_2,	0xc010d997	},
+	{	XFER_PIO_1,	0xc010d9c7	},
+	{	XFER_PIO_0,	0xc018d9d9	},
+	{	0,		0x0120d9d9	}
 };
 
 struct chipset_bus_clock_list_entry thirty_three_base [] = {
 
-	{	XFER_UDMA_4,	0x90c9a731,	0x90c9a731	},
-	{	XFER_UDMA_3,	0x90cfa731,	0x90cfa731	},
-	{	XFER_UDMA_2,	0x90caa731,	0x90caa731	},
-	{	XFER_UDMA_1,	0x90cba731,	0x90cba731	},
-	{	XFER_UDMA_0,	0x90c8a731,	0x90c8a731	},
-
-	{	XFER_MW_DMA_2,	0xa0c8a731,	0xa0c8a731	},
-	{	XFER_MW_DMA_1,	0xa0c8a732,	0xa0c8a732	},	/* 0xa0c8a733 */
-	{	XFER_MW_DMA_0,	0xa0c8a797,	0xa0c8a797	},
-
-	{	XFER_PIO_4,	0xc0c8a731,	0xc0c8a731	},
-	{	XFER_PIO_3,	0xc0c8a742,	0xc0c8a742	},
-	{	XFER_PIO_2,	0xc0d0a753,	0xc0d0a753	},
-	{	XFER_PIO_1,	0xc0d0a7a3,	0xc0d0a7a3	},	/* 0xc0d0a793 */
-	{	XFER_PIO_0,	0xc0d0a7aa,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
-	{	0,		0x0120a7a7,	0x0120a7a7	}
+	{	XFER_UDMA_4,	0x90c9a731	},
+	{	XFER_UDMA_3,	0x90cfa731	},
+	{	XFER_UDMA_2,	0x90caa731	},
+	{	XFER_UDMA_1,	0x90cba731	},
+	{	XFER_UDMA_0,	0x90c8a731	},
+
+	{	XFER_MW_DMA_2,	0xa0c8a731	},
+	{	XFER_MW_DMA_1,	0xa0c8a732	},	/* 0xa0c8a733 */
+	{	XFER_MW_DMA_0,	0xa0c8a797	},
+
+	{	XFER_PIO_4,	0xc0c8a731	},
+	{	XFER_PIO_3,	0xc0c8a742	},
+	{	XFER_PIO_2,	0xc0d0a753	},
+	{	XFER_PIO_1,	0xc0d0a7a3	},	/* 0xc0d0a793 */
+	{	XFER_PIO_0,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
+	{	0,		0x0120a7a7	}
 };
 
 struct chipset_bus_clock_list_entry twenty_five_base [] = {
 
-	{	XFER_UDMA_4,	0x90c98521,	0x90c98521	},
-	{	XFER_UDMA_3,	0x90cf8521,	0x90cf8521	},
-	{	XFER_UDMA_2,	0x90cf8521,	0x90cf8521	},
-	{	XFER_UDMA_1,	0x90cb8521,	0x90cb8521	},
-	{	XFER_UDMA_0,	0x90cb8521,	0x90cb8521	},
-
-	{	XFER_MW_DMA_2,	0xa0ca8521,	0xa0ca8521	},
-	{	XFER_MW_DMA_1,	0xa0ca8532,	0xa0ca8532	},
-	{	XFER_MW_DMA_0,	0xa0ca8575,	0xa0ca8575	},
-
-	{	XFER_PIO_4,	0xc0ca8521,	0xc0ca8521	},
-	{	XFER_PIO_3,	0xc0ca8532,	0xc0ca8532	},
-	{	XFER_PIO_2,	0xc0ca8542,	0xc0ca8542	},
-	{	XFER_PIO_1,	0xc0d08572,	0xc0d08572	},
-	{	XFER_PIO_0,	0xc0d08585,	0xc0d08585	},
-	{	0,		0x01208585,	0x01208585	}
+	{	XFER_UDMA_4,	0x90c98521	},
+	{	XFER_UDMA_3,	0x90cf8521	},
+	{	XFER_UDMA_2,	0x90cf8521	},
+	{	XFER_UDMA_1,	0x90cb8521	},
+	{	XFER_UDMA_0,	0x90cb8521	},
+
+	{	XFER_MW_DMA_2,	0xa0ca8521	},
+	{	XFER_MW_DMA_1,	0xa0ca8532	},
+	{	XFER_MW_DMA_0,	0xa0ca8575	},
+
+	{	XFER_PIO_4,	0xc0ca8521	},
+	{	XFER_PIO_3,	0xc0ca8532	},
+	{	XFER_PIO_2,	0xc0ca8542	},
+	{	XFER_PIO_1,	0xc0d08572	},
+	{	XFER_PIO_0,	0xc0d08585	},
+	{	0,		0x01208585	}
+};
+
+#if 1
+/* these are the current (4 sep 2001) timings from highpoint */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+        {       XFER_UDMA_5,    0x12446231      },
+        {       XFER_UDMA_4,    0x12446231      },
+        {       XFER_UDMA_3,    0x126c6231      },
+        {       XFER_UDMA_2,    0x12486231      },
+        {       XFER_UDMA_1,    0x124c6233      },
+        {       XFER_UDMA_0,    0x12506297      },
+
+        {       XFER_MW_DMA_2,  0x22406c31      },
+        {       XFER_MW_DMA_1,  0x22406c33      },
+        {       XFER_MW_DMA_0,  0x22406c97      },
+
+        {       XFER_PIO_4,     0x06414e31      },
+        {       XFER_PIO_3,     0x06414e42      },
+        {       XFER_PIO_2,     0x06414e53      },
+        {       XFER_PIO_1,     0x06814e93      },
+        {       XFER_PIO_0,     0x06814ea7      },
+        {       0,              0x06814ea7      }
 };
 
+/* 2x 33MHz timings */
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x1488e673       },
+	{       XFER_UDMA_4,    0x1488e673       },
+	{       XFER_UDMA_3,    0x1498e673       },
+	{       XFER_UDMA_2,    0x1490e673       },
+	{       XFER_UDMA_1,    0x1498e677       },
+	{       XFER_UDMA_0,    0x14a0e73f       },
+
+	{       XFER_MW_DMA_2,  0x2480fa73       },
+	{       XFER_MW_DMA_1,  0x2480fa77       }, 
+	{       XFER_MW_DMA_0,  0x2480fb3f       },
+
+	{       XFER_PIO_4,     0x0c82be73       },
+	{       XFER_PIO_3,     0x0c82be95       },
+	{       XFER_PIO_2,     0x0c82beb7       },
+	{       XFER_PIO_1,     0x0d02bf37       },
+	{       XFER_PIO_0,     0x0d02bf5f       },
+	{       0,              0x0d02bf5f       }
+};
+#else
+/* from highpoint documentation. these are old values */
 struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-	{	XFER_UDMA_5,	0x1A85F442,	0x16454e31	},
-	{	XFER_UDMA_4,	0x16454e31,	0x16454e31	},
-	{	XFER_UDMA_3,	0x166d4e31,	0x166d4e31	},
-	{	XFER_UDMA_2,	0x16494e31,	0x16494e31	},
-	{	XFER_UDMA_1,	0x164d4e31,	0x164d4e31	},
-	{	XFER_UDMA_0,	0x16514e31,	0x16514e31	},
-
-	{	XFER_MW_DMA_2,	0x26514e21,	0x26514e21	},
-	{	XFER_MW_DMA_1,	0x26514e33,	0x26514e33	},
-	{	XFER_MW_DMA_0,	0x26514e97,	0x26514e97	},
-
-	{	XFER_PIO_4,	0x06514e21,	0x06514e21	},
-	{	XFER_PIO_3,	0x06514e22,	0x06514e22	},
-	{	XFER_PIO_2,	0x06514e33,	0x06514e33	},
-	{	XFER_PIO_1,	0x06914e43,	0x06914e43	},
-	{	XFER_PIO_0,	0x06914e57,	0x06914e57	},
-	{	0,		0x06514e57,	0x06514e57	}
+	{	XFER_UDMA_5,	0x16454e31	},
+	{	XFER_UDMA_4,	0x16454e31	},
+	{	XFER_UDMA_3,	0x166d4e31	},
+	{	XFER_UDMA_2,	0x16494e31	},
+	{	XFER_UDMA_1,	0x164d4e31	},
+	{	XFER_UDMA_0,	0x16514e31	},
+
+	{	XFER_MW_DMA_2,	0x26514e21	},
+	{	XFER_MW_DMA_1,	0x26514e33	},
+	{	XFER_MW_DMA_0,	0x26514e97	},
+
+	{	XFER_PIO_4,	0x06514e21	},
+	{	XFER_PIO_3,	0x06514e22	},
+	{	XFER_PIO_2,	0x06514e33	},
+	{	XFER_PIO_1,	0x06914e43	},
+	{	XFER_PIO_0,	0x06914e57	},
+	{	0,		0x06514e57	}
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x14846231      },
+	{       XFER_UDMA_4,    0x14886231      },
+	{       XFER_UDMA_3,    0x148c6231      },
+	{       XFER_UDMA_2,    0x148c6231      },
+	{       XFER_UDMA_1,    0x14906231      },
+	{       XFER_UDMA_0,    0x14986231      },
+	
+	{       XFER_MW_DMA_2,  0x26514e21      },
+	{       XFER_MW_DMA_1,  0x26514e33      },
+	{       XFER_MW_DMA_0,  0x26514e97      },
+	
+	{       XFER_PIO_4,     0x06514e21      },
+	{       XFER_PIO_3,     0x06514e22      },
+	{       XFER_PIO_2,     0x06514e33      },
+	{       XFER_PIO_1,     0x06914e43      },
+	{       XFER_PIO_0,     0x06914e57      },
+	{       0,              0x06514e57      }
+};
+#endif
+
+struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x12848242      },
+	{       XFER_UDMA_4,    0x12ac8242      },
+	{       XFER_UDMA_3,    0x128c8242      },
+	{       XFER_UDMA_2,    0x120c8242      },
+	{       XFER_UDMA_1,    0x12148254      },
+	{       XFER_UDMA_0,    0x121882ea      },
+
+	{       XFER_MW_DMA_2,  0x22808242      },
+	{       XFER_MW_DMA_1,  0x22808254      },
+	{       XFER_MW_DMA_0,  0x228082ea      },
+
+	{       XFER_PIO_4,     0x0a81f442      },
+	{       XFER_PIO_3,     0x0a81f443      },
+	{       XFER_PIO_2,     0x0a81f454      },
+	{       XFER_PIO_1,     0x0ac1f465      },
+	{       XFER_PIO_0,     0x0ac1f48a      },
+	{       0,              0x0ac1f48a      }
 };
 
 #define HPT366_DEBUG_DRIVE_INFO		0
 #define HPT370_ALLOW_ATA100_5		1
 #define HPT366_ALLOW_ATA66_4		1
 #define HPT366_ALLOW_ATA66_3		1
+#define HPT366_MAX_DEVS			8
+
+#define F_LOW_PCI_33      0x23
+#define F_LOW_PCI_40      0x29
+#define F_LOW_PCI_50      0x2d
+#define F_LOW_PCI_66      0x42
+
+static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
+static int n_hpt_devs;
+
+static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev);
+static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev);
+byte hpt366_proc = 0;
+byte hpt363_shared_irq;
+byte hpt363_shared_pin;
+extern char *ide_xfer_verbose (byte xfer_rate);
 
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 static int hpt366_get_info(char *, char **, off_t, int);
 extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
 extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-static struct pci_dev *bmide2_dev;
 
 static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
 {
-	char *p		= buffer;
-	u32 bibma	= bmide_dev->resource[4].start;
-	u32 bibma2 	= bmide2_dev->resource[4].start;
-	char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"};
-	u8  c0 = 0, c1 = 0;
-	u32 class_rev;
-
-	pci_read_config_dword(bmide_dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	if (bmide2_dev)
-		c1 = inb_p((unsigned short)bibma2 + 0x02);
-
-	p += sprintf(p, "\n                                %s Chipset.\n", chipset_names[class_rev]);
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
+	char *p	= buffer;
+	char *chipset_nums[] = {"366", "366", "368", "370", "370A"};
+	int i;
+
+	p += sprintf(p, "\n                             "
+		"HighPoint HPT366/368/370\n");
+	for (i = 0; i < n_hpt_devs; i++) {
+		struct pci_dev *dev = hpt_devs[i];
+		unsigned short iobase = dev->resource[4].start;
+		u32 class_rev;
+		u8 c0, c1;
+
+		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+		class_rev &= 0xff;
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+		p += sprintf(p, "--------------- Primary Channel "
+				"--------------- Secondary Channel "
+				"--------------\n");
+
+		/* get the bus master status registers */
+		c0 = inb_p(iobase + 0x2);
+		c1 = inb_p(iobase + 0xa);
+		p += sprintf(p, "Enabled:        %s"
+				"                             %s\n",
+			(c0 & 0x80) ? "no" : "yes",
+			(c1 & 0x80) ? "no" : "yes");
+
+		if (pci_rev_check_hpt3xx(dev)) {
+			u8 cbl;
+			cbl = inb_p(iobase + 0x7b);
+			outb_p(cbl | 1, iobase + 0x7b);
+			outb_p(cbl & ~1, iobase + 0x7b);
+			cbl = inb_p(iobase + 0x7a);
+			p += sprintf(p, "Cable:          ATA-%d"
+					"                          ATA-%d\n",
+				(cbl & 0x02) ? 33 : 66,
+				(cbl & 0x01) ? 33 : 66);
+			p += sprintf(p, "\n");
+		}
 
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"------- drive0 ---------- drive1 -------\n");
+		p += sprintf(p, "DMA capable:    %s              %s" 
+				"            %s               %s\n",
+			(c0 & 0x20) ? "yes" : "no ", 
+			(c0 & 0x40) ? "yes" : "no ",
+			(c1 & 0x20) ? "yes" : "no ", 
+			(c1 & 0x40) ? "yes" : "no ");
+
+		{
+			u8 c2, c3;
+			/* older revs don't have these registers mapped 
+			 * into io space */
+			pci_read_config_byte(dev, 0x43, &c0);
+			pci_read_config_byte(dev, 0x47, &c1);
+			pci_read_config_byte(dev, 0x4b, &c2);
+			pci_read_config_byte(dev, 0x4f, &c3);
+
+			p += sprintf(p, "Mode:           %s             %s"
+					"           %s              %s\n",
+				(c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
+					(c0 & 0x80) ? "PIO " : "off ",
+				(c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
+					(c1 & 0x80) ? "PIO " : "off ",
+				(c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
+					(c2 & 0x80) ? "PIO " : "off ",
+				(c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
+					(c3 & 0x80) ? "PIO " : "off ");
+		}
+	}
+	p += sprintf(p, "\n");
+	
 	return p-buffer;/* => must be less than 4k! */
 }
 #endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-byte hpt366_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-byte hpt363_shared_irq;
-byte hpt363_shared_pin;
-
 static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
 {
 	unsigned int class_rev;
@@ -282,16 +473,16 @@
 	return 0;
 }
 
-static unsigned int pci_bus_clock_list (byte speed, int direction, struct chipset_bus_clock_list_entry * chipset_table)
+static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
 {
 	for ( ; chipset_table->xfer_speed ; chipset_table++)
 		if (chipset_table->xfer_speed == speed) {
-			return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
+			return chipset_table->chipset_settings;
 		}
-	return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
+	return chipset_table->chipset_settings;
 }
 
-static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
 {
 	byte regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
 	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
@@ -304,7 +495,7 @@
 	byte drive_fast		= 0;
 
 	/*
-	 * Disable the "fast interrupt" prediction.
+	 * Disable the "fast interrupt" prediction. 
 	 */
 	pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
 	if (drive_fast & 0x02)
@@ -314,16 +505,22 @@
 	/* detect bus speed by looking at control reg timing: */
 	switch((reg1 >> 8) & 7) {
 		case 5:
-			reg2 = pci_bus_clock_list(speed, direction, forty_base);
+			reg2 = pci_bus_clock_list(speed, forty_base);
 			break;
 		case 9:
-			reg2 = pci_bus_clock_list(speed, direction, twenty_five_base);
+			reg2 = pci_bus_clock_list(speed, twenty_five_base);
 			break;
 		default:
 		case 7:
-			reg2 = pci_bus_clock_list(speed, direction, thirty_three_base);
+			reg2 = pci_bus_clock_list(speed, thirty_three_base);
 			break;
 	}
+#if 0
+	/* this is a nice idea ... */
+	list_conf = pci_bus_clock_list(speed,
+				       (struct chipset_bus_clock_list_entry *)
+				       dev->sysdata);
+#endif
 	/*
 	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
 	 */
@@ -337,40 +534,47 @@
 	pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
 }
 
-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
 {
 	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
-	byte reg5bh		= (speed != XFER_UDMA_5) ? 0x22 : (direction) ? 0x20 : 0x22;
-	unsigned int list_conf	= pci_bus_clock_list(speed, direction, thirty_three_base_hpt370);
+	unsigned int list_conf	= 0;
 	unsigned int drive_conf = 0;
 	unsigned int conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-	byte drive_pci		= 0;
-	byte drive_fast		= 0;
+	byte drive_pci		= 0x40 + (drive->dn * 4);
+	byte new_fast, drive_fast		= 0;
+	struct pci_dev *dev 	= HWIF(drive)->pci_dev;
 
-	switch (drive->dn) {
-		case 0: drive_pci = 0x40; break;
-		case 1: drive_pci = 0x44; break;
-		case 2: drive_pci = 0x48; break;
-		case 3: drive_pci = 0x4c; break;
-		default: return;
-	}
 	/*
 	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
 	 */
-	pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
-	if (drive_fast & 0x80)
-		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x80);
+	pci_read_config_byte(dev, regfast, &drive_fast);
+	new_fast = drive_fast;
+	if (new_fast & 0x02)
+		new_fast &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+	if (new_fast & 0x01)
+		new_fast &= ~0x01;
+#else
+	if ((new_fast & 0x01) == 0)
+		new_fast |= 0x01;
+#endif
+	if (new_fast != drive_fast)
+		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast);
 
-	pci_read_config_dword(HWIF(drive)->pci_dev, drive_pci, &drive_conf);
-	pci_write_config_byte(HWIF(drive)->pci_dev, 0x5b, reg5bh);
+	list_conf = pci_bus_clock_list(speed, 
+				       (struct chipset_bus_clock_list_entry *)
+				       dev->sysdata);
 
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-	/*
-	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
-	 */
-	list_conf &= ~0x80000000;
+	
+	if (speed < XFER_MW_DMA_0) {
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	}
 
-	pci_write_config_dword(HWIF(drive)->pci_dev, drive_pci, list_conf);
+	pci_write_config_dword(dev, drive_pci, list_conf);
 }
 
 static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
@@ -382,9 +586,9 @@
 		drive->init_speed = speed;
 
 	if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-		hpt370_tune_chipset(drive, speed, 0);
+		hpt370_tune_chipset(drive, speed);
         } else {
-                hpt366_tune_chipset(drive, speed, 0);
+                hpt366_tune_chipset(drive, speed);
         }
 	drive->current_speed = speed;
 	return ((int) ide_config_drive_speed(drive, speed));
@@ -541,13 +745,6 @@
 	}
 }
 
-void hpt370_rw_proc (ide_drive_t *drive, ide_dma_action_t func)
-{
-	if ((func != ide_dma_write) || (func != ide_dma_read))
-		return;
-	hpt370_tune_chipset(drive, drive->current_speed, (func == ide_dma_write));
-}
-
 static int config_drive_xfer_rate (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
@@ -624,6 +821,13 @@
 				reg50h, reg52h, reg5ah);
 			if (reg5ah & 0x10)
 				pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
+			/* fall through to a reset */
+#if 0
+		case ide_dma_begin:
+		case ide_dma_end:
+			/* reset the chips state over and over.. */
+			pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
+#endif
 			break;
 		case ide_dma_timeout:
 		default:
@@ -634,9 +838,52 @@
 
 int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long dma_base = hwif->dma_base;
+	byte regstate = hwif->channel ? 0x54 : 0x50;
+	byte reginfo = hwif->channel ? 0x56 : 0x52;
+	byte dma_stat;
+
 	switch (func) {
 		case ide_dma_check:
 			return config_drive_xfer_rate(drive);
+		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
+			dma_stat = inb(dma_base+2);
+			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
+
+		case ide_dma_end:
+			dma_stat = inb(dma_base + 2);
+			if (dma_stat & 0x01) {
+				udelay(20); /* wait a little */
+				dma_stat = inb(dma_base + 2);
+			}
+			if ((dma_stat & 0x01) == 0) 
+				break;
+
+			func = ide_dma_timeout;
+			/* fallthrough */
+
+		case ide_dma_timeout:
+		case ide_dma_lostirq:
+			pci_read_config_byte(hwif->pci_dev, reginfo, 
+					     &dma_stat); 
+			printk("%s: %d bytes in FIFO\n", drive->name, 
+			       dma_stat);
+			pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+			udelay(10);
+			dma_stat = inb(dma_base);
+			outb(dma_stat & ~0x1, dma_base); /* stop dma */
+			dma_stat = inb(dma_base + 2); 
+			outb(dma_stat | 0x6, dma_base+2); /* clear errors */
+			/* fallthrough */
+
+#ifdef HPT_RESET_STATE_ENGINE
+	        case ide_dma_begin:
+#endif
+			pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+			udelay(10);
+			break;
+
 		default:
 			break;
 	}
@@ -644,6 +891,212 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+void hpt3xx_reset (ide_drive_t *drive)
+{
+#if 0
+	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
+	byte reset		= (HWIF(drive)->channel) ? 0x80 : 0x40;
+	byte reg59h		= 0;
+
+	pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
+#endif
+}
+
+#if 0
+static int hpt3xx_tristate (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte reset		= (hwif->channel) ? 0x80 : 0x40;
+	byte state_reg		= (hwif->channel) ? 0x57 : 0x53;
+	byte reg59h		= 0;
+	byte regXXh		= 0;
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	pci_read_config_byte(dev, 0x59, &reg59h);
+	pci_read_config_byte(dev, state_reg, &regXXh);
+
+	if (state) {
+		(void) ide_do_reset(drive);
+		pci_write_config_byte(dev, state_reg, regXXh|0x80);
+		pci_write_config_byte(dev, 0x59, reg59h|reset);
+	} else {
+		pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
+		pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
+		(void) ide_do_reset(drive);
+	}
+	return 0;
+}
+#endif
+
+/* 
+ * set/get power state for a drive.
+ * turning the power off does the following things:
+ *   1) soft-reset the drive
+ *   2) tri-states the ide bus
+ *
+ * when we turn things back on, we need to re-initialize things.
+ */
+#define TRISTATE_BIT  0x8000
+static int hpt370_busproc(ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	byte tristate, resetmask, bus_reg;
+	u16 tri_reg;
+
+	if (!hwif)
+		return -EINVAL;
+
+	hwif->bus_state = state;
+
+	if (hwif->channel) { 
+		/* secondary channel */
+		tristate = 0x56;
+		resetmask = 0x80; 
+	} else { 
+		/* primary channel */
+		tristate = 0x52;
+		resetmask = 0x40;
+	}
+
+	/* grab status */
+	pci_read_config_word(hwif->pci_dev, tristate, &tri_reg);
+	pci_read_config_byte(hwif->pci_dev, 0x59, &bus_reg);
+
+	/* set the state. we don't set it if we don't need to do so.
+	 * make sure that the drive knows that it has failed if it's off */
+	switch (state) {
+	case BUSSTATE_ON:
+		hwif->drives[0].failures = 0;
+		hwif->drives[1].failures = 0;
+		if ((bus_reg & resetmask) == 0)
+			return 0;
+		tri_reg &= ~TRISTATE_BIT;
+		bus_reg &= ~resetmask;
+		break;
+	case BUSSTATE_OFF:
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
+			return 0;
+		tri_reg &= ~TRISTATE_BIT;
+		bus_reg |= resetmask;
+		break;
+	case BUSSTATE_TRISTATE:
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
+			return 0;
+		tri_reg |= TRISTATE_BIT;
+		bus_reg |= resetmask;
+		break;
+	}
+	pci_write_config_byte(hwif->pci_dev, 0x59, bus_reg);
+	pci_write_config_word(hwif->pci_dev, tristate, tri_reg);
+
+	return 0;
+}
+
+static void __init init_hpt370(struct pci_dev *dev)
+{
+	int adjust, i;
+	u16 freq;
+	u32 pll;
+	byte reg5bh;
+
+	/*
+	 * default to pci clock. make sure MA15/16 are set to output
+	 * to prevent drives having problems with 40-pin cables.
+	 */
+	pci_write_config_byte(dev, 0x5b, 0x23);
+
+	/*
+	 * set up the PLL. we need to adjust it so that it's stable. 
+	 * freq = Tpll * 192 / Tpci
+	 */
+	pci_read_config_word(dev, 0x78, &freq);
+	freq &= 0x1FF;
+	if (freq < 0x9c) {
+		pll = F_LOW_PCI_33;
+		dev->sysdata = (void *) thirty_three_base_hpt370;
+		printk("HPT370: using 33MHz PCI clock\n");
+	} else if (freq < 0xb0) {
+		pll = F_LOW_PCI_40;
+	} else if (freq < 0xc8) {
+		pll = F_LOW_PCI_50;
+		dev->sysdata = (void *) fifty_base_hpt370;
+		printk("HPT370: using 50MHz PCI clock\n");
+	} else {
+		pll = F_LOW_PCI_66;
+		dev->sysdata = (void *) sixty_six_base_hpt370;
+		printk("HPT370: using 66MHz PCI clock\n");
+	}
+	
+	/*
+	 * only try the pll if we don't have a table for the clock
+	 * speed that we're running at. NOTE: the internal PLL will
+	 * result in slow reads when using a 33MHz PCI clock. we also
+	 * don't like to use the PLL because it will cause glitches
+	 * on PRST/SRST when the HPT state engine gets reset.
+	 */
+	if (dev->sysdata) 
+		goto init_hpt370_done;
+	
+	/*
+	 * adjust PLL based upon PCI clock, enable it, and wait for
+	 * stabilization.
+	 */
+	adjust = 0;
+	freq = (pll < F_LOW_PCI_50) ? 2 : 4;
+	while (adjust++ < 6) {
+		pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
+				       pll | 0x100);
+
+		/* wait for clock stabilization */
+		for (i = 0; i < 0x50000; i++) {
+			pci_read_config_byte(dev, 0x5b, &reg5bh);
+			if (reg5bh & 0x80) {
+				/* spin looking for the clock to destabilize */
+				for (i = 0; i < 0x1000; ++i) {
+					pci_read_config_byte(dev, 0x5b, 
+							     &reg5bh);
+					if ((reg5bh & 0x80) == 0)
+						goto pll_recal;
+				}
+				pci_read_config_dword(dev, 0x5c, &pll);
+				pci_write_config_dword(dev, 0x5c, 
+						       pll & ~0x100);
+				pci_write_config_byte(dev, 0x5b, 0x21);
+				dev->sysdata = (void *) fifty_base_hpt370;
+				printk("HPT370: using 50MHz internal PLL\n");
+				goto init_hpt370_done;
+			}
+		}
+pll_recal:
+		if (adjust & 1)
+			pll -= (adjust >> 1);
+		else
+			pll += (adjust >> 1);
+	} 
+
+init_hpt370_done:
+	/* reset state engine */
+	pci_write_config_byte(dev, 0x50, 0x37); 
+	pci_write_config_byte(dev, 0x54, 0x37); 
+	udelay(100);
+}
+
 unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
 {
 	byte test = 0;
@@ -652,14 +1105,8 @@
 		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
 
 	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
-
-#if 0
-	if (test != 0x08)
-		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x08);
-#else
 	if (test != (L1_CACHE_BYTES / 4))
 		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-#endif
 
 	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
 	if (test != 0x78)
@@ -673,17 +1120,18 @@
 	if (test != 0x08)
 		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
+	if (pci_rev_check_hpt3xx(dev)) {
+		init_hpt370(dev);
+		hpt_devs[n_hpt_devs++] = dev;
+	} else {
+		hpt_devs[n_hpt_devs++] = dev;
+	}
+	
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!hpt366_proc) {
 		hpt366_proc = 1;
-		bmide_dev = dev;
-		if (pci_rev_check_hpt3xx(dev))
-			bmide2_dev = dev;
 		hpt366_display_info = &hpt366_get_info;
 	}
-	if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) {
-		bmide2_dev = dev;
-	}
 #endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
 
 	return dev->irq;
@@ -691,38 +1139,58 @@
 
 unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
 {
-	byte ata66 = 0;
+	byte ata66	= 0;
+	byte regmask	= (hwif->channel) ? 0x01 : 0x02;
 
 	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
 #ifdef DEBUG
 	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
-		ata66, (ata66 & 0x02) ? "33" : "66",
+		ata66, (ata66 & regmask) ? "33" : "66",
 		PCI_FUNC(hwif->pci_dev->devfn));
 #endif /* DEBUG */
-	return ((ata66 & 0x02) ? 0 : 1);
+	return ((ata66 & regmask) ? 0 : 1);
 }
 
 void __init ide_init_hpt366 (ide_hwif_t *hwif)
 {
+	int hpt_rev;
+
 	hwif->tuneproc	= &hpt3xx_tune_drive;
 	hwif->speedproc	= &hpt3xx_tune_chipset;
 	hwif->quirkproc	= &hpt3xx_quirkproc;
 	hwif->intrproc	= &hpt3xx_intrproc;
 	hwif->maskproc	= &hpt3xx_maskproc;
 
+#ifdef HPT_SERIALIZE_IO
+	/* serialize access to this device */
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+#endif
+
+	hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev);
+	if (hpt_rev) {
+		/* set up ioctl for power status. note: power affects both
+		 * drives on each channel */
+		hwif->busproc   = &hpt370_busproc;
+	}
+
 	if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
 		/* do nothing now but will split device types */
+		hwif->resetproc = &hpt3xx_reset;
+/*
+ * don't do until we can parse out the cobalt box argh ...
+ *		hwif->busproc   = &hpt3xx_tristate;
+ */
 	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
-		if (pci_rev_check_hpt3xx(hwif->pci_dev)) {
+		if (hpt_rev) {
 			byte reg5ah = 0;
 			pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
 			if (reg5ah & 0x10)	/* interrupt force enable */
 				pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
 			hwif->dmaproc = &hpt370_dmaproc;
-			hwif->rwproc = &hpt370_rw_proc;
 		} else {
 			hwif->dmaproc = &hpt366_dmaproc;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- v2.5.2/linux/drivers/ide/ide-cd.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ide/ide-cd.c	Tue Jan 15 11:27:30 2002
@@ -2911,11 +2911,7 @@
 	return 0;
 }
 
-static
-int ide_cdrom_reinit (ide_drive_t *drive)
-{
-	return 0;
-}
+int ide_cdrom_reinit (ide_drive_t *drive);
 
 static ide_driver_t ide_cdrom_driver = {
 	name:			"ide-cdrom",
@@ -2925,6 +2921,8 @@
 	supports_dma:		1,
 	supports_dsc_overlap:	1,
 	cleanup:		ide_cdrom_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
 	do_request:		ide_do_rw_cdrom,
 	end_request:		NULL,
 	ioctl:			ide_cdrom_ioctl,
@@ -2952,6 +2950,39 @@
 
 MODULE_PARM(ignore, "s");
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
+
+int ide_cdrom_reinit (ide_drive_t *drive)
+{
+	struct cdrom_info *info;
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+	info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
+	if (info == NULL) {
+		printk ("%s: Can't allocate a cdrom structure\n", drive->name);
+		return 1;
+	}
+	if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+		printk ("%s: Failed to register the driver with ide.c\n", drive->name);
+		kfree (info);
+		return 1;
+	}
+	memset (info, 0, sizeof (struct cdrom_info));
+	drive->driver_data = info;
+	DRIVER(drive)->busy++;
+	if (ide_cdrom_setup (drive)) {
+		DRIVER(drive)->busy--;
+		if (ide_cdrom_cleanup (drive))
+			printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+		return 1;
+	}
+	DRIVER(drive)->busy--;
+	failed--;
+
+	ide_register_module(&ide_cdrom_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
 
 static void __exit ide_cdrom_exit(void)
 {
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-cd.h linux/drivers/ide/ide-cd.h
--- v2.5.2/linux/drivers/ide/ide-cd.h	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-cd.h	Tue Jan 29 21:43:41 2002
@@ -38,7 +38,9 @@
 /************************************************************************/
 
 #define SECTOR_BITS 		9
+#ifndef SECTOR_SIZE
 #define SECTOR_SIZE		(1 << SECTOR_BITS)
+#endif
 #define SECTORS_PER_FRAME	(CD_FRAMESIZE >> SECTOR_BITS)
 #define SECTOR_BUFFER_SIZE	(CD_FRAMESIZE * 32)
 #define SECTORS_BUFFER		(SECTOR_BUFFER_SIZE >> SECTOR_BITS)
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-cs.c linux/drivers/ide/ide-cs.c
--- v2.5.2/linux/drivers/ide/ide-cs.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-cs.c	Tue Jan 15 11:27:30 2002
@@ -227,16 +227,15 @@
 #define CFG_CHECK(fn, args...) \
 if (CardServices(fn, args) != 0) goto next_entry
 
-int idecs_register (int io_base, int ctl_base, int irq)
+int idecs_register (int arg1, int arg2, int irq)
 {
         hw_regs_t hw;
-        ide_init_hwif_ports(&hw, (ide_ioreg_t) io_base, (ide_ioreg_t) ctl_base, NULL);
+        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
         hw.irq = irq;
-        hw.chipset = ide_pci; // this enables IRQ sharing w/ PCI irqs
+        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
         return ide_register_hw(&hw, NULL);
 }
 
-
 void ide_config(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
@@ -338,15 +337,15 @@
     if (link->io.NumPorts2)
 	release_region(link->io.BasePort2, link->io.NumPorts2);
 
-    /* disable drive interrupts during IDE probe */
-    if(ctl_base)
-    	outb(0x02, ctl_base);
-
     /* retry registration in case device is still spinning up */
     for (i = 0; i < 10; i++) {
+	if (ctl_base)
+	    outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
 	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
 	if (hd >= 0) break;
 	if (link->io.NumPorts1 == 0x20) {
+	    if (ctl_base)
+		outb(0x02, ctl_base+0x10);
 	    hd = idecs_register(io_base+0x10, ctl_base+0x10,
 			      link->irq.AssignedIRQ);
 	    if (hd >= 0) {
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- v2.5.2/linux/drivers/ide/ide-disk.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ide/ide-disk.c	Thu Jan 17 13:58:35 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/ide-disk.c	Version 1.10	June 9, 2000
+ *  linux/drivers/ide/ide-disk.c	Version 1.13	Nov 28, 2001
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -28,9 +28,11 @@
  *			added UDMA 3/4 reporting
  * Version 1.10		request queue changes, Ultra DMA 100
  * Version 1.11		Highmem I/O support, Jens Axboe <axboe@suse.de>
+ * Version 1.12		added 48-bit lba
+ * Version 1.13		adding taskfile io access method
  */
 
-#define IDEDISK_VERSION	"1.11"
+#define IDEDISK_VERSION	"1.13"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -60,33 +62,6 @@
 #define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
 #endif
 
-static void idedisk_bswap_data (void *buffer, int wcount)
-{
-	u16 *p = buffer;
-
-	while (wcount--) {
-		*p = *p << 8 | *p >> 8; p++;
-		*p = *p << 8 | *p >> 8; p++;
-	}
-}
-
-inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	ide_input_data(drive, buffer, wcount);
-	if (drive->bswap)
-		idedisk_bswap_data(buffer, wcount);
-}
-
-static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	if (drive->bswap) {
-		idedisk_bswap_data(buffer, wcount);
-		ide_output_data(drive, buffer, wcount);
-		idedisk_bswap_data(buffer, wcount);
-	} else
-		ide_output_data(drive, buffer, wcount);
-}
-
 /*
  * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
  * value for this drive (from its reported identification information).
@@ -100,6 +75,11 @@
 {
 	unsigned long lba_sects, chs_sects, head, tail;
 
+	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+		printk("48-bit Drive: %llu \n", id->lba_capacity_2);
+		return 1;
+	}
+
 	/*
 	 * The ATA spec tells large drives to return
 	 * C/H/S = 16383/16/63 independent of their size.
@@ -132,367 +112,285 @@
 	return 0;	/* lba_capacity value may be bad */
 }
 
-/*
- * read_intr() is the handler for disk read/multread interrupts
- */
-static ide_startstop_t read_intr (ide_drive_t *drive)
-{
-	byte stat;
-	int i;
-	unsigned int msect, nsect;
-	unsigned long flags;
-	struct request *rq;
-	char *to;
-
-	/* new way for dealing with premature shared PCI interrupts */
-	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
-		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "read_intr", stat);
-		}
-		/* no data yet, so wait for another interrupt */
-		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
-		return ide_started;
-	}
-
-	msect = drive->mult_count;
-read_next:
-	rq = HWGROUP(drive)->rq;
-	if (msect) {
-		if ((nsect = rq->current_nr_sectors) > msect)
-			nsect = msect;
-		msect -= nsect;
-	} else
-		nsect = 1;
-	to = ide_map_buffer(rq, &flags);
-	idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
-#ifdef DEBUG
-	printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
-		drive->name, rq->sector, rq->sector+nsect-1,
-		(unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
-#endif
-	ide_unmap_buffer(to, &flags);
-	rq->sector += nsect;
-	rq->errors = 0;
-	i = (rq->nr_sectors -= nsect);
-	if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
-		ide_end_request(1, HWGROUP(drive));
-	if (i > 0) {
-		if (msect)
-			goto read_next;
-		ide_set_handler (drive, &read_intr, WAIT_CMD, NULL);
-                return ide_started;
-	}
-        return ide_stopped;
-}
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block);
 
 /*
- * write_intr() is the handler for disk write interrupts
+ * do_rw_disk() issues READ and WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.
+ * It also takes care of issuing special DRIVE_CMDs.
  */
-static ide_startstop_t write_intr (ide_drive_t *drive)
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	byte stat;
-	int i;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = hwgroup->rq;
+	if (rq->flags & REQ_CMD)
+		goto good_command;
 
-	if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
-		printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
-        } else {
-#ifdef DEBUG
-		printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
-			drive->name, rq->sector, (unsigned long) rq->buffer,
-			rq->nr_sectors-1);
-#endif
-		if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) {
-			rq->sector++;
-			rq->errors = 0;
-			i = --rq->nr_sectors;
-			--rq->current_nr_sectors;
-			if (((long)rq->current_nr_sectors) <= 0)
-				ide_end_request(1, hwgroup);
-			if (i > 0) {
-				unsigned long flags;
-				char *to = ide_map_buffer(rq, &flags);
-				idedisk_output_data (drive, to, SECTOR_WORDS);
-				ide_unmap_buffer(to, &flags);
-				ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
-                                return ide_started;
-			}
-                        return ide_stopped;
-		}
-		return ide_stopped;	/* the original code did this here (?) */
-	}
-	return ide_error(drive, "write_intr", stat);
-}
+	blk_dump_rq_flags(rq, "do_rw_disk, bad command");
+	ide_end_request(0, HWGROUP(drive));
+	return ide_stopped;
 
-/*
- * ide_multwrite() transfers a block of up to mcount sectors of data
- * to a drive as part of a disk multiple-sector write operation.
- *
- * Returns 0 on success.
- *
- * Note that we may be called from two contexts - the do_rw_disk context
- * and IRQ context. The IRQ can happen any time after we've output the
- * full "mcount" number of sectors, so we must make sure we update the
- * state _before_ we output the final part of the data!
- */
-int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
-{
- 	ide_hwgroup_t	*hwgroup= HWGROUP(drive);
- 	struct request	*rq = &hwgroup->wrq;
- 
-  	do {
-  		char *buffer;
-  		int nsect = rq->current_nr_sectors;
-		unsigned long flags;
-
-		if (nsect > mcount)
-			nsect = mcount;
-		mcount -= nsect;
-
-		buffer = ide_map_buffer(rq, &flags);
-		rq->sector += nsect;
-		rq->nr_sectors -= nsect;
-		rq->current_nr_sectors -= nsect;
-
-		/* Do we move to the next bh after this? */
-		if (!rq->current_nr_sectors) {
-			struct bio *bio = rq->bio->bi_next;
-
-			/* end early early we ran out of requests */
-			if (!bio) {
-				mcount = 0;
-			} else {
-				rq->bio = bio;
-				rq->current_nr_sectors = bio_sectors(bio);
-				rq->hard_cur_sectors = rq->current_nr_sectors;
-			}
-		}
+good_command:
 
-		/*
-		 * Ok, we're all setup for the interrupt
-		 * re-entering us on the last transfer.
-		 */
-		idedisk_output_data(drive, buffer, nsect<<7);
-		ide_unmap_buffer(buffer, &flags);
-	} while (mcount);
+#ifdef CONFIG_BLK_DEV_PDC4030
+	if (IS_PDC4030_DRIVE) {
+		extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+		return promise_rw_disk(drive, rq, block);
+	}
+#endif /* CONFIG_BLK_DEV_PDC4030 */
 
-        return 0;
-}
+	if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))	/* 48-bit LBA */
+		return lba_48_rw_disk(drive, rq, (unsigned long long) block);
+	if (drive->select.b.lba)		/* 28-bit LBA */
+		return lba_28_rw_disk(drive, rq, (unsigned long) block);
 
-/*
- * multwrite_intr() is the handler for disk multwrite interrupts
- */
-static ide_startstop_t multwrite_intr (ide_drive_t *drive)
-{
-	byte stat;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = &hwgroup->wrq;
-
-	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
-		if (stat & DRQ_STAT) {
-			/*
-			 *	The drive wants data. Remember rq is the copy
-			 *	of the request
-			 */
-			if (rq->nr_sectors) {
-				if (ide_multwrite(drive, drive->mult_count))
-					return ide_stopped;
-				ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
-				return ide_started;
-			}
-		} else {
-			/*
-			 *	If the copy has all the blocks completed then
-			 *	we can end the original request.
-			 */
-			if (!rq->nr_sectors) {	/* all done? */
-				rq = hwgroup->rq;
-
-				__ide_end_request(hwgroup, 1, rq->nr_sectors);
-				return ide_stopped;
-			}
-		}
-		return ide_stopped;	/* the original code did this here (?) */
-	}
-	return ide_error(drive, "multwrite_intr", stat);
+	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
+	return chs_rw_disk(drive, rq, (unsigned long) block);
 }
 
-/*
- * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
- */
-static ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
 {
-	byte stat;
+	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
-		drive->mult_count = drive->mult_req;
-	} else {
-		drive->mult_req = drive->mult_count = 0;
-		drive->special.b.recalibrate = 1;
-		(void) ide_dump_status(drive, "set_multmode", stat);
-	}
-	return ide_stopped;
+#if 1
+	lba48bit = drive->addressing;
+#endif
+
+	if ((cmd == READ) && (drive->using_dma))
+		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
+	else if ((cmd == READ) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+	else if (cmd == READ)
+		return (lba48bit) ? WIN_READ_EXT : WIN_READ;
+	else if ((cmd == WRITE) && (drive->using_dma))
+		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	else if ((cmd == WRITE) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+	else if (cmd == WRITE)
+		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+	else
+		return WIN_NOP;
 }
 
-/*
- * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
- */
-static ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	byte stat;
+	struct hd_drive_task_hdr	taskfile;
+	struct hd_drive_hob_hdr		hobfile;
+	ide_task_t			args;
+	int				sectors;
+
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
+	unsigned int track	= (block / drive->sect);
+	unsigned int sect	= (block % drive->sect) + 1;
+	unsigned int head	= (track % drive->head);
+	unsigned int cyl	= (track / drive->head);
+
+	memset(&taskfile, 0, sizeof(task_struct_t));
+	memset(&hobfile, 0, sizeof(hob_struct_t));
+
+	sectors = rq->nr_sectors;
+	if (sectors == 256)
+		sectors = 0;
+	if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+		sectors = drive->mult_count;
+		if (sectors > rq->current_nr_sectors)
+			sectors = rq->current_nr_sectors;
+	}
+
+	taskfile.sector_count	= sectors;
+	taskfile.sector_number	= sect;
+	taskfile.low_cylinder	= cyl;
+	taskfile.high_cylinder	= (cyl>>8);
+	taskfile.device_head	= head;
+	taskfile.device_head	|= drive->select.all;
+	taskfile.command	= command;
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
-		return ide_stopped;
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name,
+		(rq_data_dir(rq)==READ) ? "read" : "writ");
+	if (lba)	printk("LBAsect=%lld, ", block);
+	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
 
-	if (stat & (ERR_STAT|DRQ_STAT))
-		return ide_error(drive, "set_geometry_intr", stat);
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+	args.command_type	= ide_cmd_type_parser(&args);
+	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
+	args.handler		= ide_handler_parser(&taskfile, &hobfile);
+	args.posthandler	= NULL;
+	args.rq			= (struct request *) rq;
+	args.block		= block;
+	rq->special		= NULL;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_rw_taskfile(drive, &args);
+}
+
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	struct hd_drive_task_hdr	taskfile;
+	struct hd_drive_hob_hdr		hobfile;
+	ide_task_t			args;
+	int				sectors;
+
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
+	sectors = rq->nr_sectors;
+	if (sectors == 256)
+		sectors = 0;
+	if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+		sectors = drive->mult_count;
+		if (sectors > rq->current_nr_sectors)
+			sectors = rq->current_nr_sectors;
+	}
+
+	memset(&taskfile, 0, sizeof(task_struct_t));
+	memset(&hobfile, 0, sizeof(hob_struct_t));
+
+	taskfile.sector_count	= sectors;
+	taskfile.sector_number	= block;
+	taskfile.low_cylinder	= (block>>=8);
+	taskfile.high_cylinder	= (block>>=8);
+	taskfile.device_head	= ((block>>8)&0x0f);
+	taskfile.device_head	|= drive->select.all;
+	taskfile.command	= command;
 
-	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
-	return ide_started;	
-}
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name,
+		(rq_data_dir(rq)==READ) ? "read" : "writ");
+	if (lba)	printk("LBAsect=%lld, ", block);
+	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
 
-/*
- * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
- */
-static ide_startstop_t recal_intr (ide_drive_t *drive)
-{
-	byte stat = GET_STAT();
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+	args.command_type	= ide_cmd_type_parser(&args);
+	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
+	args.handler		= ide_handler_parser(&taskfile, &hobfile);
+	args.posthandler	= NULL;
+	args.rq			= (struct request *) rq;
+	args.block		= block;
+	rq->special		= NULL;
+	rq->special		= (ide_task_t *)&args;
 
-	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		return ide_error(drive, "recal_intr", stat);
-	return ide_stopped;
+	return do_rw_taskfile(drive, &args);
 }
 
 /*
- * do_rw_disk() issues READ and WRITE commands to a disk,
- * using LBA if supported, or CHS otherwise, to address sectors.
- * It also takes care of issuing special DRIVE_CMDs.
+ * 268435455  == 137439 MB or 28bit limit
+ * 320173056  == 163929 MB or 48bit addressing
+ * 1073741822 == 549756 MB or 48bit addressing fake drive
  */
-static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
 {
-	unsigned long flags;
+	struct hd_drive_task_hdr	taskfile;
+	struct hd_drive_hob_hdr		hobfile;
+	ide_task_t			args;
+	int				sectors;
+
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
+	memset(&taskfile, 0, sizeof(task_struct_t));
+	memset(&hobfile, 0, sizeof(hob_struct_t));
+
+	sectors = rq->nr_sectors;
+	if (sectors == 256)
+		sectors = 0;
+	if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+		sectors = drive->mult_count;
+		if (sectors > rq->current_nr_sectors)
+			sectors = rq->current_nr_sectors;
+	}
+
+	taskfile.sector_count	= sectors;
+	hobfile.sector_count	= sectors >> 8;
+
+	if (rq->nr_sectors == 65536) {
+		taskfile.sector_count	= 0x00;
+		hobfile.sector_count	= 0x00;
+	}
+
+	taskfile.sector_number	= block;	/* low lba */
+	taskfile.low_cylinder	= (block>>=8);	/* mid lba */
+	taskfile.high_cylinder	= (block>>=8);	/* hi  lba */
+	hobfile.sector_number	= (block>>=8);	/* low lba */
+	hobfile.low_cylinder	= (block>>=8);	/* mid lba */
+	hobfile.high_cylinder	= (block>>=8);	/* hi  lba */
+	taskfile.device_head	= drive->select.all;
+	hobfile.device_head	= taskfile.device_head;
+	hobfile.control		= (drive->ctl|0x80);
+	taskfile.command	= command;
 
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE(0x00, IDE_FEATURE_REG);
-	OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (drive->select.b.lba || IS_PDC4030_DRIVE) {
-#else /* !CONFIG_BLK_DEV_PDC4030 */
-	if (drive->select.b.lba) {
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-#ifdef DEBUG
-		printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
-			drive->name, (rq_data_dir(rq)==READ)?"read":"writ",
-			block, rq->nr_sectors, (unsigned long) rq->buffer);
-#endif
-		OUT_BYTE(block,IDE_SECTOR_REG);
-		OUT_BYTE(block>>=8,IDE_LCYL_REG);
-		OUT_BYTE(block>>=8,IDE_HCYL_REG);
-		OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
-	} else {
-		unsigned int sect,head,cyl,track;
-		track = block / drive->sect;
-		sect  = block % drive->sect + 1;
-		OUT_BYTE(sect,IDE_SECTOR_REG);
-		head  = track % drive->head;
-		cyl   = track / drive->head;
-		OUT_BYTE(cyl,IDE_LCYL_REG);
-		OUT_BYTE(cyl>>8,IDE_HCYL_REG);
-		OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
 #ifdef DEBUG
-		printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
-			drive->name, (rq_data_dir(rq)==READ)?"read":"writ", cyl,
-			head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
+	printk("%s: %sing: ", drive->name,
+		(rq_data_dir(rq)==READ) ? "read" : "writ");
+	if (lba)	printk("LBAsect=%lld, ", block);
+	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
 #endif
-	}
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (IS_PDC4030_DRIVE) {
-		extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *);
-		return do_pdc4030_io (drive, rq);
-	}
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-	if (rq_data_dir(rq) == READ) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
-			return ide_started;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
-		OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
-		return ide_started;
-	}
-	if (rq_data_dir(rq) == WRITE) {
-		ide_startstop_t startstop;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
-			return ide_started;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
-		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-			printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
-				drive->mult_count ? "MULTWRITE" : "WRITE");
-			return startstop;
-		}
-		if (!drive->unmask)
-			__cli();	/* local CPU only */
-		if (drive->mult_count) {
-			ide_hwgroup_t *hwgroup = HWGROUP(drive);
-			/*
-			 * Ugh.. this part looks ugly because we MUST set up
-			 * the interrupt handler before outputting the first block
-			 * of data to be written.  If we hit an error (corrupted buffer list)
-			 * in ide_multwrite(), then we need to remove the handler/timer
-			 * before returning.  Fortunately, this NEVER happens (right?).
-			 *
-			 * Except when you get an error it seems...
-			 */
-			hwgroup->wrq = *rq; /* scratchpad */
-			ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
-			if (ide_multwrite(drive, drive->mult_count)) {
-				spin_lock_irqsave(&ide_lock, flags);
-				hwgroup->handler = NULL;
-				del_timer(&hwgroup->timer);
-				spin_unlock_irqrestore(&ide_lock, flags);
-				return ide_stopped;
-			}
-		} else {
-			char *buffer = ide_map_buffer(rq, &flags);
-			ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
-			idedisk_output_data(drive, buffer, SECTOR_WORDS);
-			ide_unmap_buffer(buffer, &flags);
-		}
-		return ide_started;
-	}
-	printk(KERN_ERR "%s: bad command: %lx\n", drive->name, rq->flags);
-	ide_end_request(0, HWGROUP(drive));
-	return ide_stopped;
+
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+	args.command_type	= ide_cmd_type_parser(&args);
+	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
+	args.handler		= ide_handler_parser(&taskfile, &hobfile);
+	args.posthandler	= NULL;
+	args.rq			= (struct request *) rq;
+	args.block		= block;
+	rq->special		= NULL;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_rw_taskfile(drive, &args);
 }
 
 static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 	if (drive->removable && drive->usage == 1) {
+		struct hd_drive_task_hdr taskfile;
+		struct hd_drive_hob_hdr hobfile;
+		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
 		check_disk_change(inode->i_rdev);
+		taskfile.command = WIN_DOORLOCK;
 		/*
 		 * Ignore the return code from door_lock,
 		 * since the open() has already succeeded,
 		 * and the door_lock is irrelevant at this point.
 		 */
-		if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL))
+		if (drive->doorlocking &&
+		    ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
 			drive->doorlocking = 0;
 	}
 	return 0;
 }
 
+static int do_idedisk_flushcache(ide_drive_t *drive);
+
 static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	if (drive->removable && !drive->usage) {
+		struct hd_drive_task_hdr taskfile;
+		struct hd_drive_hob_hdr hobfile;
+		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
 		invalidate_bdev(inode->i_bdev, 0);
+		taskfile.command = WIN_DOORUNLOCK;
 		if (drive->doorlocking &&
-		    ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL))
+		    ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
 			drive->doorlocking = 0;
 	}
+	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+		if (do_idedisk_flushcache(drive))
+			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+				drive->name);
 	MOD_DEC_USE_COUNT;
 }
 
@@ -507,27 +405,234 @@
 }
 
 /*
+ * Queries for true maximum capacity of the drive.
+ * Returns maximum LBA address (> 0) of the drive, 0 if failed.
+ */
+static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
+{
+	ide_task_t args;
+	unsigned long addr = 0;
+
+	if (!(drive->id->command_set_1 & 0x0400) &&
+	    !(drive->id->cfs_enable_2 & 0x0100))
+		return addr;
+
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
+	args.handler				= task_no_data_intr;
+
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+		     | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+		     | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+		     | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+	}
+	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+	return addr;
+}
+
+static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
+{
+	ide_task_t args;
+	unsigned long long addr = 0;
+
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+
+	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
+	args.handler				= task_no_data_intr;
+
+        /* submit command request */
+        ide_raw_taskfile(drive, &args, NULL);
+
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+  			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); 
+		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+		addr = ((__u64)high << 24) | low;
+	}
+	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+	return addr;
+}
+
+#ifdef CONFIG_IDEDISK_STROKE
+/*
+ * Sets maximum virtual LBA address of the drive.
+ * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+ */
+static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
+{
+	ide_task_t args;
+	unsigned long addr_set = 0;
+	
+	addr_req--;
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
+	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>  8) & 0xff);
+	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
+	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
+	args.handler				= task_no_data_intr;
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+	/* if OK, read new maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+			 | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+			 | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+			 | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+	}
+	addr_set++;
+	return addr_set;
+}
+
+static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
+{
+	ide_task_t args;
+	unsigned long long addr_set = 0;
+
+	addr_req--;
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
+	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
+	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
+	args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX_EXT;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= 0x40;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+        args.handler				= task_no_data_intr;
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
+		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+		addr_set = ((__u64)high << 24) | low;
+	}
+	return addr_set;
+}
+
+/*
+ * Tests if the drive supports Host Protected Area feature.
+ * Returns true if supported, false otherwise.
+ */
+static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
+{
+	int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0;
+	printk("%s: host protected area => %d\n", drive->name, flag);
+	return flag;
+}
+
+#endif /* CONFIG_IDEDISK_STROKE */
+
+/*
  * Compute drive->capacity, the full capacity of the drive
  * Called with drive->id != NULL.
+ *
+ * To compute capacity, this uses either of
+ *
+ *    1. CHS value set by user       (whatever user sets will be trusted)
+ *    2. LBA value from target drive (require new ATA feature)
+ *    3. LBA value from system BIOS  (new one is OK, old one may break)
+ *    4. CHS value from system BIOS  (traditional style)
+ *
+ * in above order (i.e., if value of higher priority is available,
+ * reset will be ignored).
  */
 static void init_idedisk_capacity (ide_drive_t  *drive)
 {
 	struct hd_driveid *id = drive->id;
 	unsigned long capacity = drive->cyl * drive->head * drive->sect;
+	unsigned long set_max = idedisk_read_native_max_address(drive);
+	unsigned long long capacity_2 = capacity;
+	unsigned long long set_max_ext;
 
+	drive->capacity48 = 0;
 	drive->select.b.lba = 0;
 
+	if (id->cfs_enable_2 & 0x0400) {
+		capacity_2 = id->lba_capacity_2;
+		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
+		drive->head		= drive->bios_head = 255;
+		drive->sect		= drive->bios_sect = 63;
+		drive->select.b.lba	= 1;
+		set_max_ext = idedisk_read_native_max_address_ext(drive);
+		if (set_max_ext > capacity_2) {
+#ifdef CONFIG_IDEDISK_STROKE
+			set_max_ext = idedisk_read_native_max_address_ext(drive);
+			set_max_ext = idedisk_set_max_address_ext(drive, set_max_ext);
+			if (set_max_ext) {
+				drive->capacity48 = capacity_2 = set_max_ext;
+				drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect);
+				drive->select.b.lba = 1;
+				drive->id->lba_capacity_2 = capacity_2;
+                        }
+#else /* !CONFIG_IDEDISK_STROKE */
+			printk("%s: setmax_ext LBA %llu, native  %llu\n",
+				drive->name, set_max_ext, capacity_2);
+#endif /* CONFIG_IDEDISK_STROKE */
+		}
+		drive->bios_cyl		= drive->cyl;
+		drive->capacity48	= capacity_2;
+		drive->capacity		= (unsigned long) capacity_2;
+		return;
 	/* Determine capacity, and use LBA if the drive properly supports it */
-	if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+	} else if ((id->capability & 2) && lba_capacity_is_ok(id)) {
 		capacity = id->lba_capacity;
 		drive->cyl = capacity / (drive->head * drive->sect);
 		drive->select.b.lba = 1;
 	}
+
+	if (set_max > capacity) {
+#ifdef CONFIG_IDEDISK_STROKE
+		set_max = idedisk_read_native_max_address(drive);
+		set_max = idedisk_set_max_address(drive, set_max);
+		if (set_max) {
+			drive->capacity = capacity = set_max;
+			drive->cyl = set_max / (drive->head * drive->sect);
+			drive->select.b.lba = 1;
+			drive->id->lba_capacity = capacity;
+		}
+#else /* !CONFIG_IDEDISK_STROKE */
+		printk("%s: setmax LBA %lu, native  %lu\n",
+			drive->name, set_max, capacity);
+#endif /* CONFIG_IDEDISK_STROKE */
+	}
+
 	drive->capacity = capacity;
+
+	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+                drive->capacity48 = id->lba_capacity_2;
+		drive->head = 255;
+		drive->sect = 63;
+		drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect);
+	}
 }
 
-static unsigned long idedisk_capacity (ide_drive_t  *drive)
+static unsigned long idedisk_capacity (ide_drive_t *drive)
 {
+	if (drive->id->cfs_enable_2 & 0x0400)
+		return (drive->capacity48 - drive->sect0);
 	return (drive->capacity - drive->sect0);
 }
 
@@ -536,23 +641,48 @@
 	special_t *s = &drive->special;
 
 	if (s->b.set_geometry) {
-		s->b.set_geometry = 0;
-		OUT_BYTE(drive->sect,IDE_SECTOR_REG);
-		OUT_BYTE(drive->cyl,IDE_LCYL_REG);
-		OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG);
-		OUT_BYTE(((drive->head-1)|drive->select.all)&0xBF,IDE_SELECT_REG);
-		if (!IS_PDC4030_DRIVE)
-			ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr);
+		struct hd_drive_task_hdr taskfile;
+		struct hd_drive_hob_hdr hobfile;
+		ide_handler_t *handler = NULL;
+
+		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+		s->b.set_geometry	= 0;
+		taskfile.sector_number	= drive->sect;
+		taskfile.low_cylinder	= drive->cyl;
+		taskfile.high_cylinder	= drive->cyl>>8;
+		taskfile.device_head	= ((drive->head-1)|drive->select.all)&0xBF;
+		if (!IS_PDC4030_DRIVE) {
+			taskfile.sector_count	= drive->sect;
+			taskfile.command	= WIN_SPECIFY;
+			handler			= ide_handler_parser(&taskfile, &hobfile);
+		}
+		do_taskfile(drive, &taskfile, &hobfile, handler);
 	} else if (s->b.recalibrate) {
 		s->b.recalibrate = 0;
-		if (!IS_PDC4030_DRIVE)
-			ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);
+		if (!IS_PDC4030_DRIVE) {
+			struct hd_drive_task_hdr taskfile;
+			struct hd_drive_hob_hdr hobfile;
+			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+			taskfile.sector_count	= drive->sect;
+			taskfile.command	= WIN_RESTORE;
+			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+		}
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
 		if (drive->id && drive->mult_req > drive->id->max_multsect)
 			drive->mult_req = drive->id->max_multsect;
-		if (!IS_PDC4030_DRIVE)
-			ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr);
+		if (!IS_PDC4030_DRIVE) {
+			struct hd_drive_task_hdr taskfile;
+			struct hd_drive_hob_hdr hobfile;
+			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+			taskfile.sector_count	= drive->mult_req;
+			taskfile.command	= WIN_SETMULT;
+			do_taskfile(drive, &taskfile, &hobfile, &set_multmode_intr);
+		}
 	} else if (s->all) {
 		int special = s->all;
 		s->all = 0;
@@ -564,9 +694,11 @@
 
 static void idedisk_pre_reset (ide_drive_t *drive)
 {
+	int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
+
 	drive->special.all = 0;
-	drive->special.b.set_geometry = 1;
-	drive->special.b.recalibrate  = 1;
+	drive->special.b.set_geometry = legacy;
+	drive->special.b.recalibrate  = legacy;
 	if (OK_TO_RESET_CONTROLLER)
 		drive->mult_count = 0;
 	if (!drive->keep_settings && !drive->using_dma)
@@ -579,19 +711,45 @@
 
 static int smart_enable(ide_drive_t *drive)
 {
-	return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL);
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= SMART_ENABLE;
+	taskfile.low_cylinder	= SMART_LCYL_PASS;
+	taskfile.high_cylinder	= SMART_HCYL_PASS;
+	taskfile.command	= WIN_SMART;
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
 }
 
 static int get_smart_values(ide_drive_t *drive, byte *buf)
 {
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= SMART_READ_VALUES;
+	taskfile.sector_count	= 0x01;
+	taskfile.low_cylinder	= SMART_LCYL_PASS;
+	taskfile.high_cylinder	= SMART_HCYL_PASS;
+	taskfile.command	= WIN_SMART;
 	(void) smart_enable(drive);
-	return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_VALUES, 1, buf);
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
 static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
 {
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= SMART_READ_THRESHOLDS;
+	taskfile.sector_count	= 0x01;
+	taskfile.low_cylinder	= SMART_LCYL_PASS;
+	taskfile.high_cylinder	= SMART_HCYL_PASS;
+	taskfile.command	= WIN_SMART;
 	(void) smart_enable(drive);
-	return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_THRESHOLDS, 1, buf);
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
 static int proc_idedisk_read_cache
@@ -615,7 +773,7 @@
 	int		len = 0, i = 0;
 
 	if (!get_smart_thresholds(drive, page)) {
-		unsigned short *val = ((unsigned short *)page) + 2;
+		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
@@ -634,7 +792,7 @@
 	int		len = 0, i = 0;
 
 	if (!get_smart_values(drive, page)) {
-		unsigned short *val = ((unsigned short *)page) + 2;
+		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
@@ -660,6 +818,10 @@
 
 #endif	/* CONFIG_PROC_FS */
 
+/*
+ * This is tightly woven into the driver->do_special can not touch.
+ * DON'T do it again until a total personality rewrite is committed.
+ */
 static int set_multcount(ide_drive_t *drive, int arg)
 {
 	struct request rq;
@@ -683,6 +845,79 @@
 	return 0;
 }
 
+static int write_cache (ide_drive_t *drive, int arg)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+	taskfile.command	= WIN_SETFEATURES;
+
+	if (!(drive->id->cfs_enable_2 & 0x3000))
+		return 1;
+
+	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	drive->wcache = arg;
+	return 0;
+}
+
+static int do_idedisk_standby (ide_drive_t *drive)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.command	= WIN_STANDBYNOW1;
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int do_idedisk_flushcache (ide_drive_t *drive)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	if (drive->id->cfs_enable_2 & 0x2400) {
+		taskfile.command	= WIN_FLUSH_CACHE_EXT;
+	} else {
+		taskfile.command	= WIN_FLUSH_CACHE;
+	}
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int set_acoustic (ide_drive_t *drive, int arg)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+	taskfile.feature	= (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
+	taskfile.sector_count	= arg;
+
+	taskfile.command	= WIN_SETFEATURES;
+	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	drive->acoustic = arg;
+	return 0;
+}
+
+static int probe_lba_addressing (ide_drive_t *drive, int arg)
+{
+	drive->addressing =  0;
+
+	if (!(drive->id->cfs_enable_2 & 0x0400))
+                return -EIO;
+
+	drive->addressing = arg;
+	return 0;
+}
+
+static int set_lba_addressing (ide_drive_t *drive, int arg)
+{
+	return (probe_lba_addressing(drive, arg));
+}
+
 static void idedisk_add_settings(ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
@@ -692,12 +927,15 @@
 	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->bios_cyl,		NULL);
 	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
 	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
+	ide_add_setting(drive,	"address",		SETTING_RW,					HDIO_GET_ADDRESS,	HDIO_SET_ADDRESS,	TYPE_INTA,	0,	2,				1,	1,	&drive->addressing,	set_lba_addressing);
 	ide_add_setting(drive,	"bswap",		SETTING_READ,					-1,			-1,			TYPE_BYTE,	0,	1,				1,	1,	&drive->bswap,			NULL);
-	ide_add_setting(drive,	"multcount",		id ? SETTING_RW : SETTING_READ,			HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT,	TYPE_BYTE,	0,	id ? id->max_multsect : 0,	1,	2,	&drive->mult_count,		set_multcount);
+	ide_add_setting(drive,	"multcount",		id ? SETTING_RW : SETTING_READ,			HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT,	TYPE_BYTE,	0,	id ? id->max_multsect : 0,	1,	1,	&drive->mult_count,		set_multcount);
 	ide_add_setting(drive,	"nowerr",		SETTING_RW,					HDIO_GET_NOWERR,	HDIO_SET_NOWERR,	TYPE_BYTE,	0,	1,				1,	1,	&drive->nowerr,			set_nowerr);
-	ide_add_setting(drive,	"breada_readahead",	SETTING_RW,					BLKRAGET,		BLKRASET,		TYPE_INT,	0,	255,				1,	2,	&read_ahead[major],		NULL);
+	ide_add_setting(drive,	"breada_readahead",	SETTING_RW,					BLKRAGET,		BLKRASET,		TYPE_INT,	0,	255,				1,	1,	&read_ahead[major],		NULL);
 	ide_add_setting(drive,	"file_readahead",	SETTING_RW,					BLKFRAGET,		BLKFRASET,		TYPE_INTA,	0,	4096,			PAGE_SIZE,	1024,	&max_readahead[major][minor],	NULL);
 	ide_add_setting(drive,	"lun",			SETTING_RW,					-1,			-1,			TYPE_INT,	0,	7,				1,	1,	&drive->lun,			NULL);
+	ide_add_setting(drive,	"wcache",		SETTING_RW,					HDIO_GET_WCACHE,	HDIO_SET_WCACHE,	TYPE_BYTE,	0,	1,				1,	1,	&drive->wcache,			write_cache);
+	ide_add_setting(drive,	"acoustic",		SETTING_RW,					HDIO_GET_ACOUSTIC,	HDIO_SET_ACOUSTIC,	TYPE_BYTE,	0,	254,				1,	1,	&drive->acoustic,		set_acoustic);
 	ide_add_setting(drive,	"failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->failures,		NULL);
 	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
 }
@@ -769,7 +1007,6 @@
 	if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
 	    (!drive->forced_geom) && drive->bios_sect && drive->bios_head)
 		drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
-
 	printk (KERN_INFO "%s: %ld sectors", drive->name, capacity);
 
 	/* Give size in megabytes (MB), not mebibytes (MiB). */
@@ -801,21 +1038,25 @@
 			drive->mult_req = id->max_multsect;
 		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
 			drive->special.b.set_multmode = 1;
-#endif
+#endif	/* CONFIG_IDEDISK_MULTI_MODE */
 	}
 	drive->no_io_32bit = id->dword_io ? 1 : 0;
-}
-
-static int idedisk_reinit (ide_drive_t *drive)
-{
-	return 0;
+	if (drive->id->cfs_enable_2 & 0x3000)
+		write_cache(drive, (id->cfs_enable_2 & 0x3000));
+	(void) probe_lba_addressing(drive, 1);
 }
 
 static int idedisk_cleanup (ide_drive_t *drive)
 {
+	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+		if (do_idedisk_flushcache(drive))
+			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+				drive->name);
 	return ide_unregister_subdriver(drive);
 }
 
+int idedisk_reinit(ide_drive_t *drive);
+
 /*
  *      IDE subdriver functions, registered with ide.c
  */
@@ -827,6 +1068,8 @@
 	supports_dma:		1,
 	supports_dsc_overlap:	0,
 	cleanup:		idedisk_cleanup,
+	standby:		do_idedisk_standby,
+	flushcache:		do_idedisk_flushcache,
 	do_request:		do_rw_disk,
 	end_request:		NULL,
 	ioctl:			NULL,
@@ -851,6 +1094,32 @@
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
+int idedisk_reinit (ide_drive_t *drive)
+{
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+
+	if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+		return 1;
+	}
+	DRIVER(drive)->busy++;
+	idedisk_setup(drive);
+	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
+		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+		(void) idedisk_cleanup(drive);
+		DRIVER(drive)->busy--;
+		return 1;
+	}
+	DRIVER(drive)->busy--;
+	failed--;
+
+	ide_register_module(&idedisk_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
 static void __exit idedisk_exit (void)
 {
 	ide_drive_t *drive;
@@ -882,12 +1151,15 @@
 			printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
 			continue;
 		}
+		DRIVER(drive)->busy++;
 		idedisk_setup(drive);
 		if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
 			printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
 			(void) idedisk_cleanup(drive);
+			DRIVER(drive)->busy--;
 			continue;
 		}
+		DRIVER(drive)->busy--;
 		failed--;
 	}
 	ide_register_module(&idedisk_module);
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
--- v2.5.2/linux/drivers/ide/ide-dma.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-dma.c	Tue Jan 15 11:27:30 2002
@@ -243,6 +243,44 @@
 	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
 }
 
+static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
+{
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+	ide_task_t *args = rq->special;
+#if 1
+	unsigned char *virt_addr = rq->buffer;
+	int sector_count = rq->nr_sectors;
+#else
+        nents = blk_rq_map_sg(rq->q, rq, hwif->sg_table);
+
+	if (nents > rq->nr_segments)
+		printk("ide-dma: received %d segments, build %d\n", rq->nr_segments, nents);
+#endif
+
+	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+	else
+		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+
+#if 1	
+	if (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = 128  * SECTOR_SIZE;
+		nents++;
+		virt_addr = virt_addr + (128 * SECTOR_SIZE);
+		sector_count -= 128;
+	}
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].address = virt_addr;
+	sg[nents].length =  sector_count  * SECTOR_SIZE;
+	nents++;
+ #endif
+
+	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+}
+
 /*
  * ide_build_dmatable() prepares a dma request.
  * Returns 0 if all went okay, returns 1 otherwise.
@@ -261,7 +299,11 @@
 	int i;
 	struct scatterlist *sg;
 
-	hwif->sg_nents = i = ide_build_sglist(hwif, HWGROUP(drive)->rq);
+	if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+		hwif->sg_nents = i = ide_raw_build_sglist(hwif, HWGROUP(drive)->rq);
+	} else {
+		hwif->sg_nents = i = ide_build_sglist(hwif, HWGROUP(drive)->rq);
+	}
 	if (!i)
 		return 0;
 
@@ -387,7 +429,14 @@
 	struct hd_driveid *id = drive->id;
 
 	if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	    (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
+	    (id->dma_ultra & (id->dma_ultra >> 14) & 3)) {
+		if ((id->dma_ultra >> 15) & 1) {
+			printk(", UDMA(mode 7)");	/* UDMA BIOS-enabled! */
+		} else {
+			printk(", UDMA(133)");	/* UDMA BIOS-enabled! */
+		}
+	} else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
+	  	  (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
 		if ((id->dma_ultra >> 13) & 1) {
 			printk(", UDMA(100)");	/* UDMA BIOS-enabled! */
 		} else if ((id->dma_ultra >> 12) & 1) {
@@ -414,14 +463,24 @@
 
 static int config_drive_for_dma (ide_drive_t *drive)
 {
+	int config_allows_dma = 1;
 	struct hd_driveid *id = drive->id;
 	ide_hwif_t *hwif = HWIF(drive);
 
-	if (id && (id->capability & 1) && hwif->autodma) {
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	if (drive->media != ide_disk)
+		config_allows_dma = 0;
+#endif
+
+	if (id && (id->capability & 1) && hwif->autodma && config_allows_dma) {
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive))
 			return hwif->dmaproc(ide_dma_off, drive);
 
+		/* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */
+		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
+			if ((id->dma_ultra & (id->dma_ultra >> 14) & 2))
+				return hwif->dmaproc(ide_dma_on, drive);
 		/* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */
 		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
 			if ((id->dma_ultra & (id->dma_ultra >> 11) & 7))
@@ -453,7 +512,7 @@
 	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
 #endif /* DEBUG */
 
-#if 1
+#if 0
 	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
 #endif
 
@@ -474,10 +533,10 @@
 	unsigned long flags;
 	ide_startstop_t startstop;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
 	hwgroup->handler = NULL;
 	del_timer(&hwgroup->timer);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(&ide_lock, flags);
 
 	drive->waiting_for_dma = 0;
 
@@ -555,11 +614,20 @@
 			if (drive->media != ide_disk)
 				return 0;
 #ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
+			ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);	/* issue cmd to drive */
 #else /* !CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
 #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+			if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
+			    (drive->addressing == 1)) {
+				ide_task_t *args = HWGROUP(drive)->rq->special;
+				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+			} else if (drive->addressing) {
+				OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+			} else {
+				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+			}
+			return HWIF(drive)->dmaproc(ide_dma_begin, drive);
 		case ide_dma_begin:
 			/* Note that this is done *after* the cmd has
 			 * been issued to the drive, as per the BM-IDE spec.
@@ -577,7 +645,7 @@
 			return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
 		case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
 			dma_stat = inb(dma_base+2);
-#if 0	/* do not set unless you know what you are doing */
+#if 0  /* do not set unless you know what you are doing */
 			if (dma_stat & 4) {
 				byte stat = GET_STAT();
 				outb(dma_base+2, dma_stat & 0xE4);
@@ -622,6 +690,8 @@
 				GET_STAT(), dma_stat);
 
 			return restart_request(drive);  // BUG: return types do not match!!
+//#else
+//			return HWGROUP(drive)->handler(drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 		case ide_dma_retune:
 		case ide_dma_lostirq:
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-features.c linux/drivers/ide/ide-features.c
--- v2.5.2/linux/drivers/ide/ide-features.c	Fri Feb  9 11:40:02 2001
+++ linux/drivers/ide/ide-features.c	Tue Jan 15 11:27:30 2002
@@ -127,30 +127,14 @@
 		case XFER_UDMA_3:	return XFER_UDMA_2;
 		case XFER_UDMA_2:	return XFER_UDMA_1;
 		case XFER_UDMA_1:	return XFER_UDMA_0;
+			/*
+			 * OOPS we do not goto non Ultra DMA modes
+			 * without iCRC's available we force
+			 * the system to PIO and make the user
+			 * invoke the ATA-1 ATA-2 DMA modes.
+			 */
 		case XFER_UDMA_0:
-			if (drive->id->dma_mword & 0x0004) return XFER_MW_DMA_2;
-			else if (drive->id->dma_mword & 0x0002) return XFER_MW_DMA_1;
-			else if (drive->id->dma_mword & 0x0001) return XFER_MW_DMA_0;
-			else return XFER_PIO_4;
-		case XFER_MW_DMA_2:	return XFER_MW_DMA_1;
-		case XFER_MW_DMA_1:	return XFER_MW_DMA_0;
-		case XFER_MW_DMA_0:
-			if (drive->id->dma_1word & 0x0004) return XFER_SW_DMA_2;
-			else if (drive->id->dma_1word & 0x0002) return XFER_SW_DMA_1;
-			else if (drive->id->dma_1word & 0x0001) return XFER_SW_DMA_0;
-			else return XFER_PIO_4;
-		case XFER_SW_DMA_2:	return XFER_SW_DMA_1;
-		case XFER_SW_DMA_1:	return XFER_SW_DMA_0;
-		case XFER_SW_DMA_0:
-			{
-				return XFER_PIO_4;
-			}
-		case XFER_PIO_4:	return XFER_PIO_3;
-		case XFER_PIO_3:	return XFER_PIO_2;
-		case XFER_PIO_2:	return XFER_PIO_1;
-		case XFER_PIO_1:	return XFER_PIO_0;
-		case XFER_PIO_0:
-		default:		return XFER_PIO_SLOW;
+		default:		return XFER_PIO_4;
 	}
 }
 
@@ -193,7 +177,7 @@
 		__restore_flags(flags);	/* local CPU only */
 		return 0;
 	}
-	ide_input_data(drive, id, SECTOR_WORDS);
+	ata_input_data(drive, id, SECTOR_WORDS);
 	(void) GET_STAT();	/* clear drive IRQ */
 	ide__sti();		/* local CPU only */
 	__restore_flags(flags);	/* local CPU only */
@@ -216,11 +200,11 @@
  * in combination with the device (usually a disk) properly detect
  * and acknowledge each end of the ribbon.
  */
-int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
 {
-	if ((cmd == WIN_SETFEATURES) &&
-	    (nsect > XFER_UDMA_2) &&
-	    (feature == SETFEATURES_XFER)) {
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
 		if (!HWIF(drive)->udma_four) {
 			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name);
 			return 1;
@@ -243,11 +227,11 @@
  * 1 : Safe to update drive->id DMA registers.
  * 0 : OOPs not allowed.
  */
-int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
+int set_transfer (ide_drive_t *drive, ide_task_t *args)
 {
-	if ((cmd == WIN_SETFEATURES) &&
-	    (nsect >= XFER_SW_DMA_0) &&
-	    (feature == SETFEATURES_XFER) &&
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
 	    (drive->id->dma_ultra ||
 	     drive->id->dma_mword ||
 	     drive->id->dma_1word))
@@ -389,3 +373,4 @@
 EXPORT_SYMBOL(set_transfer);
 EXPORT_SYMBOL(eighty_ninty_three);
 EXPORT_SYMBOL(ide_config_drive_speed);
+
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c
--- v2.5.2/linux/drivers/ide/ide-floppy.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ide/ide-floppy.c	Tue Jan 15 12:32:36 2002
@@ -71,9 +71,14 @@
  *                       including set_bit patch from Rusty Russel
  * Ver 0.97  Jul 22 01   Merge 0.91-0.96 onto 0.9.sv for ac series
  * Ver 0.97.sv Aug 3 01  Backported from 2.4.7-ac3
+ * Ver 0.98  Oct 26 01   Split idefloppy_transfer_pc into two pieces to
+ *                        fix a lost interrupt problem. It appears the busy
+ *                        bit was being deasserted by my IOMEGA ATAPI ZIP 100
+ *                        drive before the drive was actually ready.
+ * Ver 0.98a Oct 29 01   Expose delay value so we can play.
  */
 
-#define IDEFLOPPY_VERSION "0.97.sv"
+#define IDEFLOPPY_VERSION "0.98a"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -276,6 +281,7 @@
 	 *	Last error information
 	 */
 	byte sense_key, asc, ascq;
+	byte ticks;		/* delay this long before sending packet command */
 	int progress_indication;
 
 	/*
@@ -289,6 +295,8 @@
 	unsigned long flags;			/* Status/Action flags */
 } idefloppy_floppy_t;
 
+#define IDEFLOPPY_TICKS_DELAY	3	/* default delay for ZIP 100 */
+
 /*
  *	Floppy flag bits values.
  */
@@ -297,7 +305,7 @@
 #define IDEFLOPPY_USE_READ12		2	/* Use READ12/WRITE12 or READ10/WRITE10 */
 #define	IDEFLOPPY_FORMAT_IN_PROGRESS	3	/* Format in progress */
 #define IDEFLOPPY_CLIK_DRIVE	        4       /* Avoid commands not supported in Clik drive */
-
+#define IDEFLOPPY_ZIP_DRIVE		5	/* Requires BH algorithm for packets */
 
 /*
  *	ATAPI floppy drive packet commands
@@ -680,7 +688,7 @@
 	/* Why does this happen? */
 	if (!rq)
 		return;
-	if (rq->flags & IDEFLOPPY_RQ) {
+	if (!(rq->flags & IDEFLOPPY_RQ)) {
 		ide_end_request (uptodate, hwgroup);
 		return;
 	}
@@ -985,6 +993,11 @@
 	return ide_started;
 }
 
+/*
+ * This is the original routine that did the packet transfer.
+ * It fails at high speeds on the Iomega ZIP drive, so there's a slower version
+ * for that drive below. The algorithm is chosen based on drive type
+ */
 static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
 {
 	ide_startstop_t startstop;
@@ -1005,6 +1018,56 @@
 	return ide_started;
 }
 
+
+/*
+ * What we have here is a classic case of a top half / bottom half
+ * interrupt service routine. In interrupt mode, the device sends
+ * an interrupt to signal it's ready to receive a packet. However,
+ * we need to delay about 2-3 ticks before issuing the packet or we
+ * gets in trouble.
+ *
+ * So, follow carefully. transfer_pc1 is called as an interrupt (or
+ * directly). In either case, when the device says it's ready for a 
+ * packet, we schedule the packet transfer to occur about 2-3 ticks
+ * later in transfer_pc2.
+ */
+static int idefloppy_transfer_pc2 (ide_drive_t *drive)
+{
+	idefloppy_floppy_t *floppy = drive->driver_data;
+
+	atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+	return IDEFLOPPY_WAIT_CMD;		/* Timeout for the packet command */
+}
+
+static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
+{
+	idefloppy_floppy_t *floppy = drive->driver_data;
+	ide_startstop_t startstop;
+	idefloppy_ireason_reg_t ireason;
+
+	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
+		return startstop;
+	}
+	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	if (!ireason.b.cod || ireason.b.io) {
+		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
+		return ide_do_reset (drive);
+	}
+	/* 
+	 * The following delay solves a problem with ATAPI Zip 100 drives where the
+	 * Busy flag was apparently being deasserted before the unit was ready to
+	 * receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
+	 * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will 
+	 * not be actually used until after the packet is moved in about 50 msec.
+	 */
+	ide_set_handler (drive, 
+	  &idefloppy_pc_intr, 		/* service routine for packet command */
+	  floppy->ticks,			/* wait this long before "failing" */
+	  &idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
+	return ide_started;
+}
+
 /*
  *	Issue a packet command
  */
@@ -1013,6 +1076,7 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_bcount_reg_t bcount;
 	int dma_ok = 0;
+	ide_handler_t *pkt_xfer_routine;
 
 #if IDEFLOPPY_DEBUG_BUGS
 	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
@@ -1072,13 +1136,20 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
+	/* Can we transfer the packet when we get the interrupt or wait? */
+	if (test_bit (IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
+		pkt_xfer_routine = &idefloppy_transfer_pc1;	/* wait */
+	} else {
+		pkt_xfer_routine = &idefloppy_transfer_pc;	/* immediate */
+	}
+	
 	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
-		ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD, NULL);
+		ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
 		return ide_started;
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		return idefloppy_transfer_pc (drive);
+		return (*pkt_xfer_routine) (drive);
 	}
 }
 
@@ -1979,10 +2050,7 @@
 
 #endif	/* CONFIG_PROC_FS */
 
-static int idefloppy_reinit (ide_drive_t *drive)
-{
-	return 0;
-}
+int idefloppy_reinit(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -1995,6 +2063,8 @@
 	supports_dma:		1,
 	supports_dsc_overlap:	0,
 	cleanup:		idefloppy_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
 	do_request:		idefloppy_do_request,
 	end_request:		idefloppy_end_request,
 	ioctl:			idefloppy_ioctl,
@@ -2017,6 +2087,40 @@
 	NULL
 };
 
+int idefloppy_reinit (ide_drive_t *drive)
+{
+	idefloppy_floppy_t *floppy;
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
+		if (!idefloppy_identify_device (drive, drive->id)) {
+			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+			continue;
+		}
+		if (drive->scsi) {
+			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
+			continue;
+		}
+		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
+			kfree (floppy);
+			continue;
+		}
+		DRIVER(drive)->busy++;
+		idefloppy_setup (drive, floppy);
+		DRIVER(drive)->busy--;
+		failed--;
+	}
+	ide_register_module(&idefloppy_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
 
 static void __exit idefloppy_exit (void)
@@ -2069,7 +2173,9 @@
 			kfree (floppy);
 			continue;
 		}
+		DRIVER(drive)->busy++;
 		idefloppy_setup (drive, floppy);
+		DRIVER(drive)->busy--;
 		failed--;
 	}
 	ide_register_module(&idefloppy_module);
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-geometry.c linux/drivers/ide/ide-geometry.c
--- v2.5.2/linux/drivers/ide/ide-geometry.c	Fri Nov  9 14:23:34 2001
+++ linux/drivers/ide/ide-geometry.c	Tue Jan 15 11:27:30 2002
@@ -6,6 +6,8 @@
 #include <linux/mc146818rtc.h>
 #include <asm/io.h>
 
+#ifdef CONFIG_BLK_DEV_IDE
+
 /*
  * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
  * controller that is BIOS compatible with ST-506, and thus showing up in our
@@ -40,7 +42,11 @@
  * Consequently, also the former "drive->present = 1" below was a mistake.
  *
  * Eventually the entire routine below should be removed.
+ *
+ * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS
+ * chip.
  */
+
 void probe_cmos_for_drives (ide_hwif_t *hwif)
 {
 #ifdef __i386__
@@ -80,9 +86,10 @@
 	}
 #endif
 }
+#endif /* CONFIG_BLK_DEV_IDE */
 
 
-#ifdef CONFIG_BLK_DEV_IDE
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 
 extern ide_drive_t * get_info_ptr(kdev_t);
 extern unsigned long current_capacity (ide_drive_t *);
@@ -214,4 +221,4 @@
 		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 	return ret;
 }
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c
--- v2.5.2/linux/drivers/ide/ide-pci.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-pci.c	Tue Jan 15 11:27:30 2002
@@ -12,6 +12,13 @@
  *  configuration of all PCI IDE interfaces present in a system.  
  */
 
+/*
+ * Chipsets that are on the IDE_IGNORE list because of problems of not being
+ * set at compile time.
+ *
+ * CONFIG_BLK_DEV_PDC202XX
+ */
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -47,6 +54,8 @@
 #define DEVID_PDC20267	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267})
 #define DEVID_PDC20268  ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268})
 #define DEVID_PDC20268R ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R})
+#define DEVID_PDC20269	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
+#define DEVID_PDC20275	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275})
 #define DEVID_RZ1000	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
 #define DEVID_RZ1001	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
 #define DEVID_SAMURAI	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
@@ -55,6 +64,7 @@
 #define DEVID_CMD646	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_646})
 #define DEVID_CMD648	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_648})
 #define DEVID_CMD649	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_649})
+#define DEVID_CMD680	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_680})
 #define DEVID_SIS5513	((ide_pci_devid_t){PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5513})
 #define DEVID_OPTI621	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C621})
 #define DEVID_OPTI621V	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C558})
@@ -87,6 +97,7 @@
 #define DEVID_ITE8172G	((ide_pci_devid_t){PCI_VENDOR_ID_ITE,     PCI_DEVICE_ID_ITE_IT8172G})
 
 #define	IDE_IGNORE	((void *)-1)
+#define IDE_NO_DRIVER	((void *)-2)
 
 #ifdef CONFIG_BLK_DEV_AEC62XX
 extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *);
@@ -100,7 +111,7 @@
 #else
 #define PCI_AEC62XX	NULL
 #define ATA66_AEC62XX	NULL
-#define INIT_AEC62XX	NULL
+#define INIT_AEC62XX	IDE_NO_DRIVER
 #define DMA_AEC62XX	NULL
 #endif
 
@@ -116,7 +127,7 @@
 #else
 #define PCI_ALI15X3	NULL
 #define ATA66_ALI15X3	NULL
-#define INIT_ALI15X3	NULL
+#define INIT_ALI15X3	IDE_NO_DRIVER
 #define DMA_ALI15X3	NULL
 #endif
 
@@ -132,7 +143,7 @@
 #else
 #define PCI_AMD74XX	NULL
 #define ATA66_AMD74XX	NULL
-#define INIT_AMD74XX	NULL
+#define INIT_AMD74XX	IDE_NO_DRIVER
 #define DMA_AMD74XX	NULL
 #endif
 
@@ -150,7 +161,7 @@
 #ifdef __sparc_v9__
 #define INIT_CMD64X	IDE_IGNORE
 #else
-#define INIT_CMD64X	NULL
+#define INIT_CMD64X	IDE_NO_DRIVER
 #endif
 #endif
 
@@ -161,7 +172,7 @@
 #define INIT_CY82C693	&ide_init_cy82c693
 #else
 #define PCI_CY82C693	NULL
-#define INIT_CY82C693	NULL
+#define INIT_CY82C693	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_CS5530
@@ -171,7 +182,7 @@
 #define INIT_CS5530	&ide_init_cs5530
 #else
 #define PCI_CS5530	NULL
-#define INIT_CS5530	NULL
+#define INIT_CS5530	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_HPT34X
@@ -200,7 +211,7 @@
 static byte hpt363_shared_pin;
 #define PCI_HPT366	NULL
 #define ATA66_HPT366	NULL
-#define INIT_HPT366	NULL
+#define INIT_HPT366	IDE_NO_DRIVER
 #define DMA_HPT366	NULL
 #endif
 
@@ -215,7 +226,7 @@
 extern void ide_init_opti621(ide_hwif_t *);
 #define INIT_OPTI621	&ide_init_opti621
 #else
-#define INIT_OPTI621	NULL
+#define INIT_OPTI621	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_PDC_ADMA
@@ -242,9 +253,9 @@
 #define ATA66_PDC202XX	&ata66_pdc202xx
 #define INIT_PDC202XX	&ide_init_pdc202xx
 #else
-#define PCI_PDC202XX	NULL
-#define ATA66_PDC202XX	NULL
-#define INIT_PDC202XX	NULL
+#define PCI_PDC202XX	IDE_IGNORE
+#define ATA66_PDC202XX	IDE_IGNORE
+#define INIT_PDC202XX	IDE_IGNORE
 #endif
 
 #ifdef CONFIG_BLK_DEV_PIIX
@@ -257,7 +268,7 @@
 #else
 #define PCI_PIIX	NULL
 #define ATA66_PIIX	NULL
-#define INIT_PIIX	NULL
+#define INIT_PIIX	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_IT8172
@@ -269,7 +280,7 @@
 #else
 #define PCI_IT8172	NULL
 #define ATA66_IT8172	NULL
-#define INIT_IT8172	NULL
+#define INIT_IT8172	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_RZ1000
@@ -291,7 +302,7 @@
 #else
 #define PCI_SVWKS	NULL
 #define ATA66_SVWKS	NULL
-#define INIT_SVWKS	NULL
+#define INIT_SVWKS	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_SIS5513
@@ -304,7 +315,7 @@
 #else
 #define PCI_SIS5513	NULL
 #define ATA66_SIS5513	NULL
-#define INIT_SIS5513	NULL
+#define INIT_SIS5513	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_SLC90E66
@@ -317,7 +328,7 @@
 #else
 #define PCI_SLC90E66	NULL
 #define ATA66_SLC90E66	NULL
-#define INIT_SLC90E66	NULL
+#define INIT_SLC90E66	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_SL82C105
@@ -352,7 +363,7 @@
 #else
 #define PCI_VIA82CXXX	NULL
 #define ATA66_VIA82CXXX	NULL
-#define INIT_VIA82CXXX	NULL
+#define INIT_VIA82CXXX	IDE_NO_DRIVER
 #define DMA_VIA82CXXX	NULL
 #endif
 
@@ -394,7 +405,7 @@
 #ifdef CONFIG_PDC202XX_FORCE
         {DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
         {DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
+        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	48 },
         {DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
 #else /* !CONFIG_PDC202XX_FORCE */
 	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
@@ -402,11 +413,13 @@
 	{DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
 	{DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
 #endif
-	{DEVID_PDC20268,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
+	{DEVID_PDC20268,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
 	/* Promise used a different PCI ident for the raid card apparently to try and
 	   prevent Linux detecting it and using our own raid code. We want to detect
 	   it for the ataraid drivers, so we have to list both here.. */
-	{DEVID_PDC20268R,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
+	{DEVID_PDC20268R,"PDC20270",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_PDC20269,"PDC20269",	PCI_PDC202XX,	ATA66_PDC202XX,	 INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_PDC20275,"PDC20275",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
 	{DEVID_RZ1000,	"RZ1000",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_RZ1001,	"RZ1001",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_SAMURAI,	"SAMURAI",	NULL,		NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
@@ -417,6 +430,7 @@
 	{DEVID_CMD646,	"CMD646",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0 },
 	{DEVID_CMD648,	"CMD648",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_CMD649,	"CMD649",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CMD680,	"CMD680",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_OPTI621,	"OPTI621",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_OPTI621X,"OPTI621X",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
@@ -435,10 +449,10 @@
 	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_CS5530,	"CS5530",	PCI_CS5530,	NULL,		INIT_CS5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_AMD7401,	"AMD7401",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_AMD7401,	"AMD7401",	NULL,		NULL,		NULL,		DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
 	{DEVID_AMD7409,	"AMD7409",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
 	{DEVID_AMD7411,	"AMD7411",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7441, "AMD7441",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
+	{DEVID_AMD7441,	"AMD7441",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
 	{DEVID_PDCADMA,	"PDCADMA",	PCI_PDCADMA,	ATA66_PDCADMA,	INIT_PDCADMA,	DMA_PDCADMA,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
 	{DEVID_SLC90E66,"SLC90E66",	PCI_SLC90E66,	ATA66_SLC90E66,	INIT_SLC90E66,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
         {DEVID_OSB4,    "ServerWorks OSB4",		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
@@ -460,6 +474,9 @@
 		case PCI_DEVICE_ID_PROMISE_20265:
 		case PCI_DEVICE_ID_PROMISE_20267:
 		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20275:
 		case PCI_DEVICE_ID_ARTOP_ATP850UF:
 		case PCI_DEVICE_ID_ARTOP_ATP860:
 		case PCI_DEVICE_ID_ARTOP_ATP860R:
@@ -594,7 +611,15 @@
 		autodma = 1;
 #endif
 
-	pci_enable_device(dev);
+	if (d->init_hwif == IDE_NO_DRIVER) {
+		printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", d->name);
+		d->init_hwif = NULL;
+	}
+
+	if (pci_enable_device(dev)) {
+		printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name);
+		return;
+	}
 
 check_if_enabled:
 	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
@@ -754,7 +779,8 @@
 		}
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX))
 			goto bypass_piix_dma;
-
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA))
+			goto bypass_legacy_dma;
 		if (hwif->udma_four) {
 			printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name);
 		} else {
@@ -771,12 +797,15 @@
 			autodma = 0;
 		if (autodma)
 			hwif->autodma = 1;
+
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
@@ -787,6 +816,7 @@
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) ||
 		    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
 			unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
@@ -813,6 +843,7 @@
 			}
 		}
 #endif	/* CONFIG_BLK_DEV_IDEDMA */
+bypass_legacy_dma:
 bypass_piix_dma:
 bypass_umc_dma:
 		if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
@@ -824,6 +855,44 @@
 		printk("%s: neither IDE port enabled (BIOS)\n", d->name);
 }
 
+static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *dev2 = NULL, *findev;
+	ide_pci_device_t *d2;
+
+	if ((dev->bus->self &&
+	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
+	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+		if (PCI_SLOT(dev->devfn) & 2) {
+			return;
+		}
+		d->extra = 0;
+		pci_for_each_dev(findev) {
+			if ((findev->vendor == dev->vendor) &&
+			    (findev->device == dev->device) &&
+			    (PCI_SLOT(findev->devfn) & 2)) {
+				byte irq = 0, irq2 = 0;
+				dev2 = findev;
+				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
+                                if (irq != irq2) {
+					dev2->irq = dev->irq;
+                                        pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
+                                }
+
+			}
+		}
+	}
+
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
+	if (!dev2)
+		return;
+	d2 = d;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
+	ide_setup_pci_device(dev2, d2);
+}
+
 static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
 {
 	struct pci_dev *dev2 = NULL, *findev;
@@ -904,6 +973,8 @@
 		return;	/* UM8886A/BF pair */
 	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366))
 		hpt366_device_order_fixup(dev, d);
+	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R))
+		pdc20270_device_order_fixup(dev, d);
 	else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
 		if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
 			printk("%s: unknown IDE controller on PCI slot %s, VID=%04x, DID=%04x\n",
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-pmac.c linux/drivers/ide/ide-pmac.c
--- v2.5.2/linux/drivers/ide/ide-pmac.c	Tue Oct  2 09:08:40 2001
+++ linux/drivers/ide/ide-pmac.c	Tue Jan 15 11:27:30 2002
@@ -1101,7 +1101,7 @@
 		HWGROUP(drive)->busy = 1;
 		pmac_ide_check_dma(drive);
 		HWGROUP(drive)->busy = 0;
-		spin_unlock_irq(&io_request_lock);
+		spin_unlock_irq(&ide_lock);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 }
@@ -1220,7 +1220,7 @@
 			/* Disable irq during sleep */
 			disable_irq(pmac_ide[i].irq);
 			if (unlock)
-				spin_unlock_irq(&io_request_lock);
+				spin_unlock_irq(&ide_lock);
 			
 			/* Check if this is a media bay with an IDE device or not
 			 * a media bay.
@@ -1279,11 +1279,11 @@
 			drive->using_dma = 0;
 
 			/* We resume processing on the HW group */
-			spin_lock_irqsave(&io_request_lock, flags);
+			spin_lock_irqsave(&ide_lock, flags);
 			enable_irq(pmac_ide[i].irq);
 			if (drive->present)
 				HWGROUP(drive)->busy = 0;
-			spin_unlock_irqrestore(&io_request_lock, flags);
+			spin_unlock_irqrestore(&ide_lock, flags);
 			
 			/* Wake the device
 			 * We could handle the slave here
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
--- v2.5.2/linux/drivers/ide/ide-probe.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ide/ide-probe.c	Tue Jan 15 11:27:30 2002
@@ -58,7 +58,22 @@
 	struct hd_driveid *id;
 
 	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);	/* called with interrupts disabled! */
-	ide_input_data(drive, id, SECTOR_WORDS);		/* read 512 bytes of id info */
+	if (!id) {
+		printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
+		goto err_kmalloc;
+	}
+	/* read 512 bytes of id info */
+#if 1
+	ata_input_data(drive, id, SECTOR_WORDS);		/* read 512 bytes of id info */
+#else
+        {
+                unsigned long   *ptr = (unsigned long *)id ;
+                unsigned long   lcount = 256/2 ;
+                // printk("IDE_DATA_REG = %#lx",IDE_DATA_REG);
+                while( lcount-- )
+                        *ptr++ = inl(IDE_DATA_REG);
+        }
+#endif
 	ide__sti();	/* local CPU only */
 	ide_fix_driveid(id);
 
@@ -76,8 +91,7 @@
 	if ((id->model[0] == 'P' && id->model[1] == 'M')
 	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
 		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
-		drive->present = 0;
-		return;
+		goto err_misc;
 	}
 #endif /* CONFIG_SCSI_EATA_DMA || CONFIG_SCSI_EATA_PIO */
 
@@ -96,7 +110,7 @@
 	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
 
 	if (strstr(id->model, "E X A B Y T E N E S T"))
-		return;
+		goto err_misc;
 
 	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
 	printk("%s: %s, ", drive->name, id->model);
@@ -111,8 +125,7 @@
 #ifdef CONFIG_BLK_DEV_PDC4030
 		if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
 			printk(" -- not supported on 2nd Promise port\n");
-			drive->present = 0;
-			return;
+			goto err_misc;
 		}
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 		switch (type) {
@@ -174,6 +187,12 @@
 	printk("ATA DISK drive\n");
 	QUIRK_LIST(HWIF(drive),drive);
 	return;
+
+err_misc:
+	kfree(id);
+err_kmalloc:
+	drive->present = 0;
+	return;
 }
 
 /*
@@ -702,6 +721,10 @@
 #else /* !CONFIG_IDEPCI_SHARE_IRQ */
 		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
 #endif /* CONFIG_IDEPCI_SHARE_IRQ */
+
+		if (hwif->io_ports[IDE_CONTROL_OFFSET])
+			OUT_BYTE(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */
+
 		if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) {
 			if (!match)
 				kfree(hwgroup);
@@ -769,17 +792,32 @@
 	int *bs, *max_ra;
 	extern devfs_handle_t ide_devfs_handle;
 
+#if 1
+	units = MAX_DRIVES;
+#else
 	/* figure out maximum drive number on the interface */
 	for (units = MAX_DRIVES; units > 0; --units) {
 		if (hwif->drives[units-1].present)
 			break;
 	}
+#endif
+
 	minors    = units * (1<<PARTN_BITS);
 	gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+	if (!gd)
+		goto err_kmalloc_gd;
 	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+	if (!gd->sizes)
+		goto err_kmalloc_gd_sizes;
 	gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+	if (!gd->part)
+		goto err_kmalloc_gd_part;
 	bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	if (!bs)
+		goto err_kmalloc_bs;
 	max_ra    = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	if (!max_ra)
+		goto err_kmalloc_max_ra;
 
 	memset(gd->part, 0, minors * sizeof(struct hd_struct));
 
@@ -811,6 +849,17 @@
 	add_gendisk(gd);
 
 	for (unit = 0; unit < units; ++unit) {
+#if 1
+		char name[64];
+		ide_add_generic_settings(hwif->drives + unit);
+		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+		sprintf (name, "host%d/bus%d/target%d/lun%d",
+			(hwif->channel && hwif->mate) ?
+			hwif->mate->index : hwif->index,
+			hwif->channel, unit, hwif->drives[unit].lun);
+		if (hwif->drives[unit].present)
+			hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
+#else
 		if (hwif->drives[unit].present) {
 			char name[64];
 
@@ -822,7 +871,21 @@
 			hwif->drives[unit].de =
 				devfs_mk_dir (ide_devfs_handle, name, NULL);
 		}
+#endif
 	}
+	return;
+
+err_kmalloc_max_ra:
+	kfree(bs);
+err_kmalloc_bs:
+	kfree(gd->part);
+err_kmalloc_gd_part:
+	kfree(gd->sizes);
+err_kmalloc_gd_sizes:
+	kfree(gd);
+err_kmalloc_gd:
+	printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
+	return;
 }
 
 static int hwif_init (ide_hwif_t *hwif)
@@ -880,6 +943,19 @@
 	return hwif->present;
 }
 
+void export_ide_init_queue (ide_drive_t *drive)
+{
+	ide_init_queue(drive);
+}
+
+byte export_probe_for_drive (ide_drive_t *drive)
+{
+	return probe_for_drive(drive);
+}
+
+EXPORT_SYMBOL(export_ide_init_queue);
+EXPORT_SYMBOL(export_probe_for_drive);
+
 int ideprobe_init (void);
 static ide_module_t ideprobe_module = {
 	IDE_PROBE_MODULE,
@@ -913,6 +989,8 @@
 }
 
 #ifdef MODULE
+extern int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *);
+
 int init_module (void)
 {
 	unsigned int index;
@@ -921,12 +999,14 @@
 		ide_unregister(index);
 	ideprobe_init();
 	create_proc_ide_interfaces();
+	ide_xlate_1024_hook = ide_xlate_1024;
 	return 0;
 }
 
 void cleanup_module (void)
 {
 	ide_probe = NULL;
+	ide_xlate_1024_hook = 0;
 }
 MODULE_LICENSE("GPL");
 #endif /* MODULE */
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-proc.c linux/drivers/ide/ide-proc.c
--- v2.5.2/linux/drivers/ide/ide-proc.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-proc.c	Tue Jan 15 11:27:30 2002
@@ -65,6 +65,7 @@
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/ctype.h>
+#include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
@@ -447,7 +448,15 @@
 
 static int proc_ide_get_identify(ide_drive_t *drive, byte *buf)
 {
-	return ide_wait_cmd(drive, (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY, 0, 0, 1, buf);
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+	taskfile.sector_count = 0x01;
+	taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
+
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
 static int proc_ide_read_identify
@@ -457,7 +466,7 @@
 	int		len = 0, i = 0;
 
 	if (drive && !proc_ide_get_identify(drive, page)) {
-		unsigned short *val = ((unsigned short *)page) + 2;
+		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
@@ -588,7 +597,7 @@
 	if (!driver)
 		len = sprintf(page, "(none)\n");
         else
-		len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
+		len = sprintf(page,"%llu\n", (__u64) ((ide_driver_t *)drive->driver)->capacity(drive));
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
@@ -732,22 +741,57 @@
 	}
 }
 
-void destroy_proc_ide_drives(ide_hwif_t *hwif)
+void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
-	int	d;
+	struct proc_dir_entry *ent;
+	struct proc_dir_entry *parent = hwif->proc;
+	char name[64];
+//	ide_driver_t *driver = drive->driver;
 
-	for (d = 0; d < MAX_DRIVES; d++) {
-		ide_drive_t *drive = &hwif->drives[d];
-		ide_driver_t *driver = drive->driver;
+	if (drive->present && !drive->proc) {
+		drive->proc = proc_mkdir(drive->name, parent);
+		if (drive->proc)
+			ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
 
-		if (!drive->proc)
-			continue;
+/*
+ * assume that we have these already, however, should test FIXME!
+ * if (driver) {
+ *      ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
+ *      ide_add_proc_entries(drive->proc, driver->proc, drive);
+ * }
+ *
+ */
+		sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
+		ent = proc_symlink(drive->name, proc_ide_root, name);
+		if (!ent)
+			return;
+	}
+}
+
+void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
+{
+	ide_driver_t *driver = drive->driver;
+
+	if (drive->proc) {
 		if (driver)
 			ide_remove_proc_entries(drive->proc, driver->proc);
 		ide_remove_proc_entries(drive->proc, generic_drive_entries);
 		remove_proc_entry(drive->name, proc_ide_root);
 		remove_proc_entry(drive->name, hwif->proc);
 		drive->proc = NULL;
+	}
+}
+
+void destroy_proc_ide_drives(ide_hwif_t *hwif)
+{
+	int	d;
+
+	for (d = 0; d < MAX_DRIVES; d++) {
+		ide_drive_t *drive = &hwif->drives[d];
+//		ide_driver_t *driver = drive->driver;
+
+		if (drive->proc)
+			destroy_proc_ide_device(hwif, drive);
 	}
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c
--- v2.5.2/linux/drivers/ide/ide-tape.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-tape.c	Tue Jan 15 18:57:07 2002
@@ -721,7 +721,7 @@
 	int request_transfer;			/* Bytes to transfer */
 	int actually_transferred;		/* Bytes actually transferred */
 	int buffer_size;			/* Size of our data buffer */
-	struct buffer_head *bh;
+	struct bio *bio;
 	char *b_data;
 	int b_count;
 	byte *buffer;				/* Data buffer */
@@ -805,7 +805,7 @@
  */
 typedef struct idetape_stage_s {
 	struct request rq;			/* The corresponding request */
-	struct buffer_head *bh;			/* The data buffers */
+	struct bio *bio;			/* The data buffers */
 	struct idetape_stage_s *next;		/* Pointer to the next stage */
 	os_aux_t *aux;				/* OnStream aux ptr */
 } idetape_stage_t;
@@ -929,7 +929,7 @@
 	int stage_size;				/* Data buffer size (chosen based on the tape's recommendation */
 	idetape_stage_t *merge_stage;
 	int merge_stage_size;
-	struct buffer_head *bh;
+	struct bio *bio;
 	char *b_data;
 	int b_count;
 	
@@ -1013,7 +1013,7 @@
 	 * Measures number of frames:
 	 *
 	 * 1. written/read to/from the driver pipeline (pipeline_head).
-	 * 2. written/read to/from the tape buffers (buffer_head).
+	 * 2. written/read to/from the tape buffers (bio).
 	 * 3. written/read by the tape to/from the media (tape_head).
 	 */
 	int pipeline_head;
@@ -1493,52 +1493,52 @@
 
 static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
 {
-	struct buffer_head *bh = pc->bh;
+	struct bio *bio = pc->bio;
 	int count;
 
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_input_buffers\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_input_buffers\n");
 			idetape_discard_data (drive, bcount);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount);
-		atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count);
+		count = IDE_MIN (bio->bi_size - pc->b_count, bcount);
+		atapi_input_bytes (drive, bio_data(bio) + pc->b_count, count);
 		bcount -= count;
-		atomic_add(count, &bh->b_count);
-		if (atomic_read(&bh->b_count) == bh->b_size) {
-			bh = bh->b_reqnext;
-			if (bh)
-				atomic_set(&bh->b_count, 0);
+		pc->b_count += bio->bi_size;
+		if (pc->b_count == bio->bi_size) {
+			bio = bio->bi_next;
+			if (bio)
+				pc->b_count = 0;
 		}
 	}
-	pc->bh = bh;
+	pc->bio = bio;
 }
 
 static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
 {
-	struct buffer_head *bh = pc->bh;
+	struct bio *bio = pc->bio;
 	int count;
 
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_output_buffers\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_output_buffers\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = IDE_MIN (pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->b_data, count);
+		atapi_output_bytes (drive, bio_data(bio), count);
 		bcount -= count;
 		pc->b_data += count;
 		pc->b_count -= count;
 		if (!pc->b_count) {
-			pc->bh = bh = bh->b_reqnext;
-			if (bh) {
-				pc->b_data = bh->b_data;
-				pc->b_count = atomic_read(&bh->b_count);
+			pc->bio = bio = bio->bi_next;
+			if (bio) {
+				pc->b_data = bio_data(bio);
+				pc->b_count = bio->bi_size;
 			}
 		}
 	}
@@ -1547,25 +1547,25 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 static void idetape_update_buffers (idetape_pc_t *pc)
 {
-	struct buffer_head *bh = pc->bh;
+	struct bio *bio = pc->bio;
 	int count, bcount = pc->actually_transferred;
 
 	if (test_bit (PC_WRITING, &pc->flags))
 		return;
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_update_buffers\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_update_buffers\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size, bcount);
-		atomic_set(&bh->b_count, count);
-		if (atomic_read(&bh->b_count) == bh->b_size)
-			bh = bh->b_reqnext;
+		count = IDE_MIN (bio->bi_size, bcount);
+		pc->b_count = count;
+		if (pc->b_count == bio->bi_size)
+			bio = bio->bi_next;
 		bcount -= count;
 	}
-	pc->bh = bh;
+	pc->bio = bio;
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -1625,7 +1625,7 @@
 	pc->request_transfer = 0;
 	pc->buffer = pc->pc_buffer;
 	pc->buffer_size = IDETAPE_PC_BUFFER_SIZE;
-	pc->bh = NULL;
+	pc->bio = NULL;
 	pc->b_data = NULL;
 }
 
@@ -1706,10 +1706,10 @@
 		printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
 #endif
 	while (stage) {
-		if (stage->rq.cmd == IDETAPE_WRITE_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ;
-		else if (stage->rq.cmd == IDETAPE_READ_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_READ_RQ;
+		if (stage->rq.flags == IDETAPE_WRITE_RQ)
+			stage->rq.flags = IDETAPE_ABORTED_WRITE_RQ;
+		else if (stage->rq.flags == IDETAPE_READ_RQ)
+			stage->rq.flags = IDETAPE_ABORTED_READ_RQ;
 		stage = stage->next;
 	}
 }
@@ -1735,7 +1735,7 @@
 #endif /* IDETAPE_DEBUG_BUGS */	
 
 	rq->buffer = NULL;
-	rq->bh = stage->bh;
+	rq->bio = stage->bio;
 	tape->active_data_request = rq;
 	tape->active_stage = stage;
 	tape->next_stage = stage->next;
@@ -1769,21 +1769,21 @@
  */
 static void __idetape_kfree_stage (idetape_stage_t *stage)
 {
-	struct buffer_head *prev_bh, *bh = stage->bh;
+	struct bio *prev_bio, *bio = stage->bio;
 	int size;
 
-	while (bh != NULL) {
-		if (bh->b_data != NULL) {
-			size = (int) bh->b_size;
+	while (bio != NULL) {
+		if (bio_data(bio) != NULL) {
+			size = (int) bio->bi_size;
 			while (size > 0) {
-				free_page ((unsigned long) bh->b_data);
+				free_page ((unsigned long) bio_data(bio));
 				size -= PAGE_SIZE;
-				bh->b_data += PAGE_SIZE;
+				bio->bi_size += PAGE_SIZE;
 			}
 		}
-		prev_bh = bh;
-		bh = bh->b_reqnext;
-		kfree (prev_bh);
+		prev_bio = bio;
+		bio = bio->bi_next;
+		kfree (prev_bio);
 	}
 	kfree (stage);
 }
@@ -1868,13 +1868,13 @@
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
-		if (rq->cmd == IDETAPE_WRITE_RQ) {
+		if (rq->flags == IDETAPE_WRITE_RQ) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2) {
 				if (tape->onstream) {
 					stage = tape->first_stage;
 					aux = stage->aux;
-					p = stage->bh->b_data;
+					p = bio_data(stage->bio);
 					if (ntohl(aux->logical_blk_num) < 11300 && ntohl(aux->logical_blk_num) > 11100)
 						printk(KERN_INFO "ide-tape: finished writing logical blk %u (data %x %x %x %x)\n", ntohl(aux->logical_blk_num), *p++, *p++, *p++, *p++);
 				}
@@ -1908,7 +1908,7 @@
 						complete(tape->waiting);
 				}
 			}
-		} else if (rq->cmd == IDETAPE_READ_RQ) {
+		} else if (rq->flags == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
 				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
 				idetape_abort_pipeline(drive);
@@ -1984,7 +1984,7 @@
 {
 	ide_init_drive_cmd (rq);
 	rq->buffer = (char *) pc;
-	rq->cmd = IDETAPE_PC_RQ1;
+	rq->flags = IDETAPE_PC_RQ1;
 	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
 }
 
@@ -2164,12 +2164,12 @@
 		}
 	}
 	if (test_bit (PC_WRITING, &pc->flags)) {
-		if (pc->bh != NULL)
+		if (pc->bio != NULL)
 			idetape_output_buffers (drive, pc, bcount.all);
 		else
 			atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
 	} else {
-		if (pc->bh != NULL)
+		if (pc->bio != NULL)
 			idetape_input_buffers (drive, pc, bcount.all);
 		else
 			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
@@ -2523,21 +2523,22 @@
 	return ide_stopped;
 }
 
-static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
-	struct buffer_head *p = bh;
+	struct bio *p = bio;
+	struct bio_vec *bv = bio_iovec(p);
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_READ_CMD;
 	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
-	pc->bh = bh;
-	atomic_set(&bh->b_count, 0);
+	pc->bio = bio;
+	bv->bv_len = 0;
 	pc->buffer = NULL;
 	if (tape->onstream) {
 		while (p) {
-			atomic_set(&p->b_count, 0);
-			p = p->b_reqnext;
+			bv->bv_len = 0;
+			p = p->bi_next;
 		}
 	}
 	if (!tape->onstream) {
@@ -2553,30 +2554,31 @@
 	}
 }
 
-static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
 	int size = 32768;
 
-	struct buffer_head *p = bh;
+	struct bio *p = bio;
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_READ_BUFFER_CMD;
 	pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
 	pc->c[7] = size >> 8;
 	pc->c[8] = size & 0xff;
 	pc->callback = &idetape_pc_callback;
-	pc->bh = bh;
-	atomic_set(&bh->b_count, 0);
+	pc->bio = bio;
+	atomic_set(&bio->bi_cnt, 0);
 	pc->buffer = NULL;
 	while (p) {
-		atomic_set(&p->b_count, 0);
-		p = p->b_reqnext;
+		p->bi_size = 0;
+		p = p->bi_next;
 	}
 	pc->request_transfer = pc->buffer_size = size;
 }
 
-static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
-	struct buffer_head *p = bh;
+	struct bio *p = bio;
+	struct bio_vec *bv= bio_iovec(p);
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_WRITE_CMD;
 	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
@@ -2585,13 +2587,13 @@
 	set_bit (PC_WRITING, &pc->flags);
 	if (tape->onstream) {
 		while (p) {
-			atomic_set(&p->b_count, p->b_size);
-			p = p->b_reqnext;
+			bv->bv_len = p->bi_size;
+			p = p->bi_next;
 		}
 	}
-	pc->bh = bh;
-	pc->b_data = bh->b_data;
-	pc->b_count = atomic_read(&bh->b_count);
+	pc->bio = bio;
+	pc->b_data = bio_data(bio);
+	pc->b_count = bio->bi_size;
 	pc->buffer = NULL;
 	if (!tape->onstream) {
 		pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
@@ -2618,16 +2620,16 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
+/*		printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %ld, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->flags,rq->errors); */
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+		printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (!IDETAPE_RQ_CMD (rq->cmd)) {
+	if (!IDETAPE_RQ_CMD (rq->flags)) {
 		/*
 		 *	We do not support buffer cache originated requests.
 		 */
-		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd);
+		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%ld)\n", drive->name, rq->flags);
 		ide_end_request (0, HWGROUP (drive));			/* Let the common code handle it */
 		return ide_stopped;
 	}
@@ -2661,7 +2663,7 @@
 	 */
 	if (tape->onstream)
 		status.b.dsc = 1;
-	if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
+	if (!drive->dsc_overlap && rq->flags != IDETAPE_PC_RQ2)
 		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
 
 	/*
@@ -2674,7 +2676,7 @@
 	 */
 	if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
 		tape->measure_insert_time = 1;
-	if (tape->req_buffer_fill && (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
+	if (tape->req_buffer_fill && (rq->flags == IDETAPE_WRITE_RQ || rq->flags == IDETAPE_READ_RQ)) {
 		tape->req_buffer_fill = 0;
 		tape->writes_since_buffer_fill = 0;
 		tape->reads_since_buffer_fill = 0;
@@ -2688,19 +2690,19 @@
 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
 	calculate_speeds(drive);
 	if (tape->onstream && tape->max_frames &&
-	    ((rq->cmd == IDETAPE_WRITE_RQ &&
+	    ((rq->flags == IDETAPE_WRITE_RQ &&
               ( tape->cur_frames == tape->max_frames ||
                 ( tape->speed_control && tape->cur_frames > 5 &&
                        (tape->insert_speed > tape->max_insert_speed ||
                         (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */) ) ) ) ) ||
-	     (rq->cmd == IDETAPE_READ_RQ &&
+	     (rq->flags == IDETAPE_READ_RQ &&
 	      ( tape->cur_frames == 0 ||
 		( tape->speed_control && (tape->cur_frames < tape->max_frames - 5) &&
 			tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 4)
-			printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n",
-				rq->cmd, tape->cur_frames, tape->max_frames);
+			printk(KERN_INFO "ide-tape: postponing request, cmd %ld, cur %d, max %d\n",
+				rq->flags, tape->cur_frames, tape->max_frames);
 #endif
 		if (tape->postpone_cnt++ < 500) {
 			status.b.dsc = 0;
@@ -2718,7 +2720,7 @@
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
 		} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
 			printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
-			if (rq->cmd == IDETAPE_PC_RQ2) {
+			if (rq->flags == IDETAPE_PC_RQ2) {
 				idetape_media_access_finished (drive);
 				return ide_stopped;
 			} else {
@@ -2729,7 +2731,7 @@
 		idetape_postpone_request (drive);
 		return ide_stopped;
 	}
-	switch (rq->cmd) {
+	switch (rq->flags) {
 		case IDETAPE_READ_RQ:
 			tape->buffer_head++;
 #if USE_IOTRACE
@@ -2744,7 +2746,7 @@
 					tape->req_buffer_fill = 1;
 			}
 			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
 			break;
 		case IDETAPE_WRITE_RQ:
 			tape->buffer_head++;
@@ -2761,15 +2763,15 @@
 				calculate_speeds(drive);
 			}
 			pc = idetape_next_pc_storage (drive);
-			idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
 			break;
 		case IDETAPE_READ_BUFFER_RQ:
 			tape->postpone_cnt = 0;
 			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
 			break;
 		case IDETAPE_ABORTED_WRITE_RQ:
-			rq->cmd = IDETAPE_WRITE_RQ;
+			rq->flags = IDETAPE_WRITE_RQ;
 			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
 			return ide_stopped;
 		case IDETAPE_ABORTED_READ_RQ:
@@ -2777,12 +2779,12 @@
 			if (tape->debug_level >= 2)
 				printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
 #endif
-			rq->cmd = IDETAPE_READ_RQ;
+			rq->flags = IDETAPE_READ_RQ;
 			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
 			return ide_stopped;
 		case IDETAPE_PC_RQ1:
 			pc = (idetape_pc_t *) rq->buffer;
-			rq->cmd = IDETAPE_PC_RQ2;
+			rq->flags = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
 			idetape_media_access_finished (drive);
@@ -2822,61 +2824,65 @@
 static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear)
 {
 	idetape_stage_t *stage;
-	struct buffer_head *prev_bh, *bh;
+	struct bio *prev_bio, *bio;
 	int pages = tape->pages_per_stage;
-	char *b_data;
+	char *b_data = NULL;
+	struct bio_vec *bv; 
 
 	if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
 		return NULL;
 	stage->next = NULL;
 
-	bh = stage->bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL);
-	if (bh == NULL)
+	bio = stage->bio = bio_alloc(GFP_KERNEL,1);
+	bv = bio_iovec(bio);	
+	bv->bv_len = 0;
+	if (bio == NULL)
 		goto abort;
-	bh->b_reqnext = NULL;
-	if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+	bio->bi_next = NULL;
+	if ((bio->bi_io_vec[0].bv_page = alloc_page(GFP_KERNEL)) == NULL)
 		goto abort;
 	if (clear)
-		memset(bh->b_data, 0, PAGE_SIZE);
-	bh->b_size = PAGE_SIZE;
-	atomic_set(&bh->b_count, full ? bh->b_size : 0);
-	set_bit (BH_Lock, &bh->b_state);
+		memset(bio_data(bio), 0, PAGE_SIZE);
+	bio->bi_size = PAGE_SIZE;
+	if(bv->bv_len == full) bv->bv_len = bio->bi_size;
+	set_bit (BH_Lock, &bio->bi_flags);
 
 	while (--pages) {
-		if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+		if ((bio->bi_io_vec[pages].bv_page = alloc_page(GFP_KERNEL)) == NULL)
 			goto abort;
 		if (clear)
-			memset(b_data, 0, PAGE_SIZE);
-		if (bh->b_data == b_data + PAGE_SIZE) {
-			bh->b_size += PAGE_SIZE;
-			bh->b_data -= PAGE_SIZE;
+			memset(bio_data(bio), 0, PAGE_SIZE);
+		if (bio->bi_size == bv->bv_len + PAGE_SIZE) {
+			bio->bi_size += PAGE_SIZE;
+			bv->bv_len += PAGE_SIZE;
+			bv->bv_offset -= PAGE_SIZE;
 			if (full)
-				atomic_add(PAGE_SIZE, &bh->b_count);
+				bio->bi_size += PAGE_SIZE;
 			continue;
 		}
-		if (b_data == bh->b_data + bh->b_size) {
-			bh->b_size += PAGE_SIZE;
+		if (b_data == bio_data(bio) + bio->bi_size) {
+			bio->bi_size += PAGE_SIZE;
 			if (full)
-				atomic_add(PAGE_SIZE, &bh->b_count);
+				bio->bi_size += PAGE_SIZE;
 			continue;
 		}
-		prev_bh = bh;
-		if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) {
-			free_page ((unsigned long) b_data);
+		prev_bio = bio;
+		if ((bio = bio_alloc(GFP_KERNEL,1)) == NULL) {
+			free_page ((unsigned long) bio_data(bio));
 			goto abort;
 		}
-		bh->b_reqnext = NULL;
-		bh->b_data = b_data;
-		bh->b_size = PAGE_SIZE;
-		atomic_set(&bh->b_count, full ? bh->b_size : 0);
-		set_bit (BH_Lock, &bh->b_state);
-		prev_bh->b_reqnext = bh;
+		bio->bi_next = NULL;
+		//bio->bi_io_vec[0].bv_offset = b_data;
+		bio->bi_size = PAGE_SIZE;
+		atomic_set(&bio->bi_cnt, full ? bio->bi_size : 0);
+		set_bit (BH_Lock, &bio->bi_flags);
+		prev_bio->bi_next = bio;
 	}
-	bh->b_size -= tape->excess_bh_size;
+	bio->bi_size -= tape->excess_bh_size;
 	if (full)
-		atomic_sub(tape->excess_bh_size, &bh->b_count);
+		atomic_sub(tape->excess_bh_size, &bio->bi_cnt);
 	if (tape->onstream)
-		stage->aux = (os_aux_t *) (bh->b_data + bh->b_size - OS_AUX_SIZE);
+		stage->aux = (os_aux_t *) (bio_data(bio) + bio->bi_size - OS_AUX_SIZE);
 	return stage;
 abort:
 	__idetape_kfree_stage (stage);
@@ -2903,39 +2909,39 @@
 
 static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
 {
-	struct buffer_head *bh = tape->bh;
+	struct bio *bio = tape->bio;
 	int count;
 
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_from_user\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n);
-		copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count);
+		count = IDE_MIN (bio->bi_size - tape->b_count, n);
+		copy_from_user (bio_data(bio) + tape->b_count, buf, count);
 		n -= count;
-		atomic_add(count, &bh->b_count);
+		bio->bi_size += count;
 		buf += count;
-		if (atomic_read(&bh->b_count) == bh->b_size) {
-			bh = bh->b_reqnext;
-			if (bh)
-				atomic_set(&bh->b_count, 0);
+		if (tape->b_count == bio->bi_size) {
+			bio = bio->bi_next;
+			if (bio)
+				tape->b_count = 0;
 		}
 	}
-	tape->bh = bh;
+	tape->bio = bio;
 }
 
 static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape_stage_t *stage, int n)
 {
-	struct buffer_head *bh = tape->bh;
+	struct bio *bio = tape->bio;
 	int count;
 
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_to_user\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -2946,10 +2952,10 @@
 		tape->b_count -= count;
 		buf += count;
 		if (!tape->b_count) {
-			tape->bh = bh = bh->b_reqnext;
-			if (bh) {
-				tape->b_data = bh->b_data;
-				tape->b_count = atomic_read(&bh->b_count);
+			tape->bio = bio = bio->bi_next;
+			if (bio) {
+				tape->b_data = bio_data(bio);
+				tape->b_count = bio->bi_size;
 			}
 		}
 	}
@@ -2957,25 +2963,25 @@
 
 static void idetape_init_merge_stage (idetape_tape_t *tape)
 {
-	struct buffer_head *bh = tape->merge_stage->bh;
+	struct bio *bio = tape->merge_stage->bio;
 	
-	tape->bh = bh;
+	tape->bio = bio;
 	if (tape->chrdev_direction == idetape_direction_write)
-		atomic_set(&bh->b_count, 0);
+		atomic_set(&bio->bi_cnt, 0);
 	else {
-		tape->b_data = bh->b_data;
-		tape->b_count = atomic_read(&bh->b_count);
+		tape->b_data = bio_data(bio);
+		tape->b_count = atomic_read(&bio->bi_cnt);
 	}
 }
 
 static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage)
 {
-	struct buffer_head *tmp;
+	struct bio *tmp;
 	os_aux_t *tmp_aux;
 
-	tmp = stage->bh; tmp_aux = stage->aux;
-	stage->bh = tape->merge_stage->bh; stage->aux = tape->merge_stage->aux;
-	tape->merge_stage->bh = tmp; tape->merge_stage->aux = tmp_aux;
+	tmp = stage->bio; tmp_aux = stage->aux;
+	stage->bio = tape->merge_stage->bio; stage->aux = tape->merge_stage->aux;
+	tape->merge_stage->bio = tmp; tape->merge_stage->aux = tmp_aux;
 	idetape_init_merge_stage (tape);
 }
 
@@ -3077,7 +3083,7 @@
 	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_BUGS
-	if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) {
+	if (rq == NULL || !IDETAPE_RQ_CMD (rq->flags)) {
 		printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
 		return;
 	}
@@ -3185,7 +3191,7 @@
 
 	ide_init_drive_cmd (&rq);
 	rq.buffer = (char *) pc;
-	rq.cmd = IDETAPE_PC_RQ1;
+	rq.flags = IDETAPE_PC_RQ1;
 	return ide_do_drive_cmd (drive, &rq, ide_wait);
 }
 
@@ -3430,7 +3436,7 @@
  *	idetape_queue_rw_tail generates a read/write request for the block
  *	device interface and wait for it to be serviced.
  */
-static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct buffer_head *bh)
+static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct bio *bio)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	struct request rq;
@@ -3447,8 +3453,8 @@
 #endif /* IDETAPE_DEBUG_BUGS */	
 
 	ide_init_drive_cmd (&rq);
-	rq.bh = bh;
-	rq.cmd = cmd;
+	rq.bio = bio;
+	rq.flags = cmd;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (tape->onstream)
@@ -3489,15 +3495,15 @@
 		if (!first)
 			first = stage;
 		aux = stage->aux;
-		p = stage->bh->b_data;
-		idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bh);
+		p = bio_data(stage->bio);
+		idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bio);
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
 			printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %x\n", tape->name, logical_blk_num, *p++, *p++, *p++, *p++);
 #endif
 		rq = &stage->rq;
 		ide_init_drive_cmd (rq);
-		rq->cmd = IDETAPE_WRITE_RQ;
+		rq->flags = IDETAPE_WRITE_RQ;
 		rq->sector = tape->first_frame_position;
 		rq->nr_sectors = rq->current_nr_sectors = tape->capabilities.ctl;
 		idetape_init_stage(drive, stage, OS_FRAME_TYPE_DATA, logical_blk_num++);
@@ -3646,18 +3652,18 @@
 	os_aux_t *aux = stage->aux;
 	os_partition_t *par = &aux->partition;
 	struct request *rq = &stage->rq;
-	struct buffer_head *bh;
+	struct bio *bio;
 
 	if (!tape->onstream)
 		return 1;
 	if (tape->raw) {
 		if (rq->errors) {
-			bh = stage->bh;
-			while (bh) {
-				memset(bh->b_data, 0, bh->b_size);
-				bh = bh->b_reqnext;
+			bio = stage->bio;
+			while (bio) {
+				memset(bio_data(bio), 0, bio->bi_size);
+				bio = bio->bi_next;
 			}
-			strcpy(stage->bh->b_data, "READ ERROR ON FRAME");
+			strcpy(bio_data(stage->bio), "READ ERROR ON FRAME");
 		}
 		return 1;
 	}
@@ -3767,12 +3773,12 @@
 			 *	Linux is short on memory. Fallback to
 			 *	non-pipelined operation mode for this request.
 			 */
-			return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+			return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
 		}
 	}
 	rq = &new_stage->rq;
 	ide_init_drive_cmd (rq);
-	rq->cmd = IDETAPE_WRITE_RQ;
+	rq->flags = IDETAPE_WRITE_RQ;
 	rq->sector = tape->first_frame_position;	/* Doesn't actually matter - We always assume sequential access */
 	rq->nr_sectors = rq->current_nr_sectors = blocks;
 
@@ -3843,7 +3849,7 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int blocks, i, min;
-	struct buffer_head *bh;
+	struct bio *bio;
 	
 #if IDETAPE_DEBUG_BUGS
 	if (tape->chrdev_direction != idetape_direction_write) {
@@ -3860,22 +3866,22 @@
 		if (tape->merge_stage_size % tape->tape_block_size) {
 			blocks++;
 			i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
-			bh = tape->bh->b_reqnext;
-			while (bh) {
-				atomic_set(&bh->b_count, 0);
-				bh = bh->b_reqnext;
+			bio = tape->bio->bi_next;
+			while (bio) {
+				atomic_set(&bio->bi_cnt, 0);
+				bio = bio->bi_next;
 			}
-			bh = tape->bh;
+			bio = tape->bio;
 			while (i) {
-				if (bh == NULL) {
-					printk(KERN_INFO "ide-tape: bug, bh NULL\n");
+				if (bio == NULL) {
+					printk(KERN_INFO "ide-tape: bug, bio NULL\n");
 					break;
 				}
-				min = IDE_MIN(i, bh->b_size - atomic_read(&bh->b_count));
-				memset(bh->b_data + atomic_read(&bh->b_count), 0, min);
-				atomic_add(min, &bh->b_count);
+				min = IDE_MIN(i, bio->bi_size - atomic_read(&bio->bi_cnt));
+				memset(bio_data(bio) + bio->bi_size, 0, min);
+				atomic_add(min, &bio->bi_cnt);
 				i -= min;
-				bh = bh->b_reqnext;
+				bio = bio->bi_next;
 			}
 		}
 		(void) idetape_add_chrdev_write_request (drive, blocks);
@@ -3949,7 +3955,7 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
+		bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bio);
 		if (bytes_read < 0) {
 			kfree (tape->merge_stage);
 			tape->merge_stage = NULL;
@@ -3960,7 +3966,7 @@
 	if (tape->restart_speed_control_req)
 		idetape_restart_speed_control(drive);
 	ide_init_drive_cmd (&rq);
-	rq.cmd = IDETAPE_READ_RQ;
+	rq.flags = IDETAPE_READ_RQ;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) {
@@ -4083,7 +4089,7 @@
 		}
 		if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
 		 	return 0;
-		return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh);
+		return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bio);
 	}
 	rq_ptr = &tape->first_stage->rq;
 	bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
@@ -4137,21 +4143,21 @@
 static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct buffer_head *bh;
+	struct bio *bio;
 	int count, blocks;
 	
 	while (bcount) {
-		bh = tape->merge_stage->bh;
+		bio = tape->merge_stage->bio;
 		count = IDE_MIN (tape->stage_size, bcount);
 		bcount -= count;
 		blocks = count / tape->tape_block_size;
 		while (count) {
-			atomic_set(&bh->b_count, IDE_MIN (count, bh->b_size));
-			memset (bh->b_data, 0, atomic_read(&bh->b_count));
-			count -= atomic_read(&bh->b_count);
-			bh = bh->b_reqnext;
+			atomic_set(&bio->bi_cnt, IDE_MIN (count, bio->bi_size));
+			memset (bio_data(bio), 0, bio->bi_size);
+			count -= atomic_read(&bio->bi_cnt);
+			bio = bio->bi_next;
 		}
-		idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+		idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
 	}
 }
 
@@ -4276,7 +4282,7 @@
  */
 static ide_drive_t *get_drive_ptr (kdev_t i_rdev)
 {
-	unsigned int i = MINOR(i_rdev) & ~0xc0;
+	unsigned int i = minor(i_rdev) & ~0xc0;
 
 	if (i >= MAX_HWIFS * MAX_DRIVES)
 		return NULL;
@@ -4654,7 +4660,7 @@
 		printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position);
 #endif
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) {
 		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n", tape->name);
 		__idetape_kfree_stage (stage);
 		idetape_position_tape(drive, position, 0, 0);
@@ -4673,7 +4679,7 @@
 #endif
 	aux->next_mark_addr = htonl(next_mark_addr);
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+	if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
 		printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %d\n", tape->name, last_mark_addr);
 		__idetape_kfree_stage (stage);
 		idetape_position_tape(drive, position, 0, 0);
@@ -4705,9 +4711,9 @@
 	if (rc != 0) 
 		return;	/* don't write fillers if we cannot position the tape. */
 
-	strcpy(stage->bh->b_data, "Filler");
+	strcpy(bio_data(stage->bio), "Filler");
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
 			printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name);
 			__idetape_kfree_stage (stage);
 			return;
@@ -4739,9 +4745,9 @@
 	header.partition.last_frame_addr = htonl(tape->capacity);
 	header.partition.wrt_pass_cntr = htons(tape->wrt_pass_cntr);
 	header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
-	memcpy(stage->bh->b_data, &header, sizeof(header));
+	memcpy(bio_data(stage->bio), &header, sizeof(header));
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
 			printk(KERN_INFO "ide-tape: %s: couldn't write header frame\n", tape->name);
 			__idetape_kfree_stage (stage);
 			return;
@@ -4860,7 +4866,7 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
+		retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bio);
 		if (retval < 0) {
 			kfree (tape->merge_stage);
 			tape->merge_stage = NULL;
@@ -5326,12 +5332,12 @@
 		printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name);
 #endif
 	idetape_position_tape(drive, block, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) {
 		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n", tape->name);
 		__idetape_kfree_stage (stage);
 		return 0;
 	}
-	header = (os_header_t *) stage->bh->b_data;
+	header = (os_header_t *) bio_data(stage->bio);
 	aux = stage->aux;
 	if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) {
 		printk(KERN_INFO "ide-tape: %s: invalid header identification string\n", tape->name);
@@ -5403,7 +5409,7 @@
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
 	idetape_pc_t pc;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor=minor(inode->i_rdev);
 			
 #if IDETAPE_DEBUG_LOG
 	printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
@@ -5460,7 +5466,7 @@
 {
 	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor=minor(inode->i_rdev);
 
 	idetape_empty_write_pipeline (drive);
 	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
@@ -5486,7 +5492,7 @@
 	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
 	idetape_tape_t *tape;
 	idetape_pc_t pc;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor=minor(inode->i_rdev);
 
 	tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
@@ -6130,10 +6136,7 @@
 
 #endif
 
-static int idetape_reinit (ide_drive_t *drive)
-{
-	return 0;
-}
+int idetape_reinit(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -6146,6 +6149,8 @@
 	supports_dma:		1,
 	supports_dsc_overlap: 	1,
 	cleanup:		idetape_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
 	do_request:		idetape_do_request,
 	end_request:		idetape_end_request,
 	ioctl:			idetape_blkdev_ioctl,
@@ -6179,6 +6184,92 @@
 	release:	idetape_chrdev_release,
 };
 
+int idetape_reinit (ide_drive_t *drive)
+{
+#if 0
+	idetape_tape_t *tape;
+	int minor, failed = 0, supported = 0;
+/* DRIVER(drive)->busy++; */
+	MOD_INC_USE_COUNT;
+#if ONSTREAM_DEBUG
+        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
+#endif
+	if (!idetape_chrdev_present)
+		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
+			idetape_chrdevs[minor].drive = NULL;
+
+	if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
+		ide_register_module (&idetape_module);
+		MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+		return 0;
+	}
+	if (!idetape_chrdev_present &&
+	    devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
+		printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
+		MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+		return -EBUSY;
+	}
+	do {
+		if (!idetape_identify_device (drive, drive->id)) {
+			printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+			continue;
+		}
+		if (drive->scsi) {
+			if (strstr(drive->id->model, "OnStream DI-30")) {
+				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
+			} else {
+				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+				continue;
+			}
+		}
+		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+		if (tape == NULL) {
+			printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
+			printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
+			kfree (tape);
+			continue;
+		}
+		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
+		idetape_setup (drive, tape, minor);
+		idetape_chrdevs[minor].drive = drive;
+		tape->de_r =
+		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+				    HWIF(drive)->major, minor,
+				    S_IFCHR | S_IRUGO | S_IWUGO,
+				    &idetape_fops, NULL);
+		tape->de_n =
+		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
+				    HWIF(drive)->major, minor + 128,
+				    S_IFCHR | S_IRUGO | S_IWUGO,
+				    &idetape_fops, NULL);
+		devfs_register_tape (tape->de_r);
+		supported++; failed--;
+	} while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
+	if (!idetape_chrdev_present && !supported) {
+		devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
+	} else
+		idetape_chrdev_present = 1;
+	ide_register_module (&idetape_module);
+	MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+
+	return 0;
+#else
+	return 1;
+#endif
+}
+
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
 MODULE_LICENSE("GPL");
 
@@ -6203,7 +6294,7 @@
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
 	int minor, failed = 0, supported = 0;
-
+/* DRIVER(drive)->busy++; */
 	MOD_INC_USE_COUNT;
 #if ONSTREAM_DEBUG
         printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- v2.5.2/linux/drivers/ide/ide-taskfile.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/ide/ide-taskfile.c	Thu Jan 17 13:58:35 2002
@@ -0,0 +1,1863 @@
+/*
+ * linux/drivers/ide/ide-taskfile.c	Version 0.20	Oct 11, 2000
+ *
+ *  Copyright (C) 2000		Michael Cornwell <cornwell@acm.org>
+ *  Copyright (C) 2000		Andre Hedrick <andre@linux-ide.org>
+ *
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ * IDE_DEBUG(__LINE__);
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#define DEBUG_TASKFILE	0	/* unset when fixed */
+
+#if DEBUG_TASKFILE
+#define DTF(x...) printk(##x)
+#else
+#define DTF(x...)
+#endif
+
+inline u32 task_read_24 (ide_drive_t *drive)
+{
+	return	(IN_BYTE(IDE_HCYL_REG)<<16) |
+		(IN_BYTE(IDE_LCYL_REG)<<8) |
+		 IN_BYTE(IDE_SECTOR_REG);
+}
+
+static void ata_bswap_data (void *buffer, int wcount)
+{
+	u16 *p = buffer;
+
+	while (wcount--) {
+		*p = *p << 8 | *p >> 8; p++;
+		*p = *p << 8 | *p >> 8; p++;
+	}
+}
+
+#if SUPPORT_VLB_SYNC
+/*
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data.  We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
+ */
+static inline void task_vlb_sync (ide_ioreg_t port) {
+	(void) IN_BYTE (port);
+	(void) IN_BYTE (port);
+	(void) IN_BYTE (port);
+}
+#endif /* SUPPORT_VLB_SYNC */
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	byte io_32bit;
+
+	/*
+	 * first check if this controller has defined a special function
+	 * for handling polled ide transfers
+	 */
+
+	if (HWIF(drive)->ideproc) {
+		HWIF(drive)->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
+		return;
+	}
+
+	io_32bit = drive->io_32bit;
+
+	if (io_32bit) {
+#if SUPPORT_VLB_SYNC
+		if (io_32bit & 2) {
+			unsigned long flags;
+			__save_flags(flags);	/* local CPU only */
+			__cli();		/* local CPU only */
+			task_vlb_sync(IDE_NSECTOR_REG);
+			insl(IDE_DATA_REG, buffer, wcount);
+			__restore_flags(flags);	/* local CPU only */
+		} else
+#endif /* SUPPORT_VLB_SYNC */
+			insl(IDE_DATA_REG, buffer, wcount);
+	} else {
+#if SUPPORT_SLOW_DATA_PORTS
+		if (drive->slow) {
+			unsigned short *ptr = (unsigned short *) buffer;
+			while (wcount--) {
+				*ptr++ = inw_p(IDE_DATA_REG);
+				*ptr++ = inw_p(IDE_DATA_REG);
+			}
+		} else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+			insw(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	byte io_32bit;
+
+	if (HWIF(drive)->ideproc) {
+		HWIF(drive)->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
+		return;
+	}
+
+	io_32bit = drive->io_32bit;
+
+	if (io_32bit) {
+#if SUPPORT_VLB_SYNC
+		if (io_32bit & 2) {
+			unsigned long flags;
+			__save_flags(flags);	/* local CPU only */
+			__cli();		/* local CPU only */
+			task_vlb_sync(IDE_NSECTOR_REG);
+			outsl(IDE_DATA_REG, buffer, wcount);
+			__restore_flags(flags);	/* local CPU only */
+		} else
+#endif /* SUPPORT_VLB_SYNC */
+			outsl(IDE_DATA_REG, buffer, wcount);
+	} else {
+#if SUPPORT_SLOW_DATA_PORTS
+		if (drive->slow) {
+			unsigned short *ptr = (unsigned short *) buffer;
+			while (wcount--) {
+				outw_p(*ptr++, IDE_DATA_REG);
+				outw_p(*ptr++, IDE_DATA_REG);
+			}
+		} else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+			outsw(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+/*
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd bytecount is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+	if (HWIF(drive)->ideproc) {
+		HWIF(drive)->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
+		return;
+	}
+
+	++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+		return;
+	}
+#endif /* CONFIG_ATARI */
+	ata_input_data (drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
+}
+
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+	if (HWIF(drive)->ideproc) {
+		HWIF(drive)->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
+		return;
+	}
+
+	++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+		return;
+	}
+#endif /* CONFIG_ATARI */
+	ata_output_data (drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
+}
+
+void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	ata_input_data(drive, buffer, wcount);
+	if (drive->bswap)
+		ata_bswap_data(buffer, wcount);
+}
+
+void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	if (drive->bswap) {
+		ata_bswap_data(buffer, wcount);
+		ata_output_data(drive, buffer, wcount);
+		ata_bswap_data(buffer, wcount);
+	} else {
+		ata_output_data(drive, buffer, wcount);
+	}
+}
+
+/*
+ * Needed for PCI irq sharing
+ */
+int drive_is_ready (ide_drive_t *drive)
+{
+	byte stat = 0;
+	if (drive->waiting_for_dma)
+		return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
+#if 0
+	/* need to guarantee 400ns since last command was issued */
+	udelay(1);
+#endif
+
+#ifdef CONFIG_IDEPCI_SHARE_IRQ
+	/*
+	 * We do a passive status test under shared PCI interrupts on
+	 * cards that truly share the ATA side interrupt, but may also share
+	 * an interrupt with another pci card/device.  We make no assumptions
+	 * about possible isa-pnp and pci-pnp issues yet.
+	 */
+	if (IDE_CONTROL_REG)
+		stat = GET_ALTSTAT();
+	else
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+	stat = GET_STAT();	/* Note: this may clear a pending IRQ!! */
+
+	if (stat & BUSY_STAT)
+		return 0;	/* drive busy:  definitely not interrupting */
+	return 1;		/* drive ready: *might* be interrupting */
+}
+
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
+	struct hd_driveid *id = drive->id;
+	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
+
+	/* (ks/hs): Moved to start, do not use for multiple out commands */
+	if (task->handler != task_mulout_intr) {
+		if (IDE_CONTROL_REG)
+			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+		SELECT_MASK(HWIF(drive), drive, 0);
+	}
+
+	if ((id->command_set_2 & 0x0400) &&
+	    (id->cfs_enable_2 & 0x0400) &&
+	    (drive->addressing == 1)) {
+		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
+		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+	}
+
+	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+	if (task->handler != NULL) {
+		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+		/*
+		 * warning check for race between handler and prehandler for
+		 * writing first block of data.  however since we are well
+		 * inside the boundaries of the seek, we should be okay.
+		 */
+		if (task->prehandler != NULL) {
+			return task->prehandler(drive, task->rq);
+		}
+	} else {
+		/* for dma commands we down set the handler */
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+	}
+
+	return ide_started;
+}
+
+void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler)
+{
+	struct hd_driveid *id = drive->id;
+	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
+
+	/* (ks/hs): Moved to start, do not use for multiple out commands */
+	if (*handler != task_mulout_intr) {
+		if (IDE_CONTROL_REG)
+			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
+		SELECT_MASK(HWIF(drive), drive, 0);
+	}
+
+	if ((id->command_set_2 & 0x0400) &&
+	    (id->cfs_enable_2 & 0x0400) &&
+	    (drive->addressing == 1)) {
+		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
+		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+	}
+
+	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+	if (handler != NULL) {
+		ide_set_handler (drive, handler, WAIT_CMD, NULL);
+		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+	} else {
+		/* for dma commands we down set the handler */
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+	}
+}
+
+#if 0
+ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
+	struct hd_driveid *id = drive->id;
+
+	/*
+	 * (KS) Check taskfile in/out flags.
+	 * If set, then execute as it is defined.
+	 * If not set, then define default settings.
+	 * The default values are:
+	 *	write and read all taskfile registers (except data) 
+	 *	write and read the hob registers (sector,nsector,lcyl,hcyl)
+	 */
+	if (task->tf_out_flags.all == 0) {
+		task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
+		if ((id->command_set_2 & 0x0400) &&
+		    (id->cfs_enable_2 & 0x0400) &&
+		    (drive->addressing == 1)) {
+			task->tf_out_flags.all != (IDE_HOB_STD_OUT_FLAGS << 8);
+		}
+        }
+
+	if (task->tf_in_flags.all == 0) {
+		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+		if ((id->command_set_2 & 0x0400) &&
+		    (id->cfs_enable_2 & 0x0400) &&
+		    (drive->addressing == 1)) {
+			task->tf_in_flags.all  != (IDE_HOB_STD_IN_FLAGS  << 8);
+		}
+        }
+
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(HWIF(drive), drive, 0);
+
+	if (task->tf_out_flags.b.data) {
+		unsigned short data =  taskfile->data + (hobfile->data << 8);
+		OUT_WORD (data, IDE_DATA_REG);
+	}
+
+	/* (KS) send hob registers first */
+	if (task->tf_out_flags.b.nsector_hob)
+		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+	if (task->tf_out_flags.b.sector_hob)
+		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl_hob)
+		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl_hob)
+		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+
+
+	/* (KS) Send now the standard registers */
+	if (task->tf_out_flags.b.error_feature)
+		OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	/* refers to number of sectors to transfer */
+	if (task->tf_out_flags.b.nsector)
+		OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to sector offset or start sector */
+	if (task->tf_out_flags.b.sector)
+		OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl)
+		OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl)
+		OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+        /*
+	 * (KS) Do not modify the specified taskfile. We want to have a
+	 * universal pass through, so we must execute ALL specified values.
+	 *
+	 * (KS) The drive head register is mandatory.
+	 * Don't care about the out flags !
+	 */
+	OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+	if (task->handler != NULL) {
+		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+		/*
+		 * warning check for race between handler and prehandler for
+		 * writing first block of data.  however since we are well
+		 * inside the boundaries of the seek, we should be okay.
+		 */
+		if (task->prehandler != NULL) {
+			return task->prehandler(drive, task->rq);
+		}
+	} else {
+		/* for dma commands we down set the handler */
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+	}
+
+	return ide_started;
+}
+#endif
+
+#if 0
+/*
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte taskfile_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+{
+	unsigned long flags;
+	byte err = 0;
+
+	__save_flags (flags);	/* local CPU only */
+	ide__sti();		/* local CPU only */
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (stat & BUSY_STAT)
+		printk("Busy ");
+	else {
+		if (stat & READY_STAT)	printk("DriveReady ");
+		if (stat & WRERR_STAT)	printk("DeviceFault ");
+		if (stat & SEEK_STAT)	printk("SeekComplete ");
+		if (stat & DRQ_STAT)	printk("DataRequest ");
+		if (stat & ECC_STAT)	printk("CorrectedError ");
+		if (stat & INDEX_STAT)	printk("Index ");
+		if (stat & ERR_STAT)	printk("Error ");
+	}
+	printk("}");
+#endif  /* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		err = GET_ERR();
+		printk("%s: %s: error=0x%02x", drive->name, msg, err);
+#if FANCY_STATUS_DUMPS
+		if (drive->media == ide_disk) {
+			printk(" { ");
+			if (err & ABRT_ERR)	printk("DriveStatusError ");
+			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
+			if (err & ECC_ERR)	printk("UncorrectableError ");
+			if (err & ID_ERR)	printk("SectorIdNotFound ");
+			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+			printk("}");
+			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+				if ((drive->id->command_set_2 & 0x0400) &&
+				    (drive->id->cfs_enable_2 & 0x0400) &&
+				    (drive->addressing == 1)) {
+					__u64 sectors = 0;
+					u32 low = 0, high = 0;
+					low = task_read_24(drive);
+					OUT_BYTE(0x80, IDE_CONTROL_REG);
+					high = task_read_24(drive);
+					sectors = ((__u64)high << 24) | low;
+					printk(", LBAsect=%lld", sectors);
+				} else {
+					byte cur = IN_BYTE(IDE_SELECT_REG);
+					if (cur & 0x40) {	/* using LBA? */
+						printk(", LBAsect=%ld", (unsigned long)
+						 ((cur&0xf)<<24)
+						 |(IN_BYTE(IDE_HCYL_REG)<<16)
+						 |(IN_BYTE(IDE_LCYL_REG)<<8)
+						 | IN_BYTE(IDE_SECTOR_REG));
+					} else {
+						printk(", CHS=%d/%d/%d",
+						  (IN_BYTE(IDE_HCYL_REG)<<8) +
+						   IN_BYTE(IDE_LCYL_REG),
+						  cur & 0xf,
+						  IN_BYTE(IDE_SECTOR_REG));
+					}
+				}
+				if (HWGROUP(drive)->rq)
+					printk(", sector=%llu", (__u64) HWGROUP(drive)->rq->sector);
+			}
+		}
+#endif  /* FANCY_STATUS_DUMPS */
+		printk("\n");
+	}
+	__restore_flags (flags);	/* local CPU only */
+	return err;
+}
+
+/*
+ * Clean up after success/failure of an explicit taskfile operation.
+ */
+void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err)
+{
+	unsigned long flags;
+	struct request *rq;
+	ide_task_t *args;
+	task_ioreg_t command;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	rq = HWGROUP(drive)->rq;
+	spin_unlock_irqrestore(&ide_lock, flags);
+	args = (ide_task_t *) rq->special;
+
+	command = args->tfRegister[IDE_COMMAND_OFFSET];
+
+	rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+	args->tfRegister[IDE_ERROR_OFFSET]   = err;
+	args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
+	args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
+	args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
+	args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
+	args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
+	args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+	if ((drive->id->command_set_2 & 0x0400) &&
+	    (drive->id->cfs_enable_2 & 0x0400) &&
+	    (drive->addressing == 1)) {
+		OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+		args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
+		args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
+		args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
+		args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
+		args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
+	}
+
+/*	taskfile_settings_update(drive, args, command); */
+
+	spin_lock_irqsave(&ide_lock, flags);
+	blkdev_dequeue_request(rq);
+	HWGROUP(drive)->rq = NULL;
+	end_that_request_last(rq);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * try_to_flush_leftover_data() is invoked in response to a drive
+ * unexpectedly having its DRQ_STAT bit set.  As an alternative to
+ * resetting the drive, this routine tries to clear the condition
+ * by read a sector's worth of data from the drive.  Of course,
+ * this may not help if the drive is *waiting* for data from *us*.
+ */
+void task_try_to_flush_leftover_data (ide_drive_t *drive)
+{
+	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+
+	if (drive->media != ide_disk)
+		return;
+	while (i > 0) {
+		u32 buffer[16];
+		unsigned int wcount = (i > 16) ? 16 : i;
+		i -= wcount;
+		taskfile_input_data (drive, buffer, wcount);
+	}
+}
+
+/*
+ * taskfile_error() takes action based on the error returned by the drive.
+ */
+ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+	struct request *rq;
+	byte err;
+
+        err = taskfile_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+	/* retry only "normal" I/O: */
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
+		rq->errors = 1;
+		ide_end_taskfile(drive, stat, err);
+		return ide_stopped;
+	}
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	} else {
+		if (drive->media == ide_disk && (stat & ERR_STAT)) {
+			/* err has different meaning on cdrom and tape */
+			if (err == ABRT_ERR) {
+				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
+					return ide_stopped;	/* some newer drives don't support WIN_SPECIFY */
+			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
+				drive->crc_count++;	/* UDMA crc error -- just retry the operation */
+			} else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
+				rq->errors = ERROR_MAX;
+			else if (err & TRK0_ERR)	/* help it find track zero */
+				rq->errors |= ERROR_RECAL;
+		}
+		/* pre bio (rq->cmd != WRITE) */
+		if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
+			task_try_to_flush_leftover_data(drive);
+	}
+	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
+		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
+
+	if (rq->errors >= ERROR_MAX) {
+		if (drive->driver != NULL)
+			DRIVER(drive)->end_request(0, HWGROUP(drive));
+		else
+			ide_end_request(0, HWGROUP(drive));
+	} else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			drive->special.b.recalibrate = 1;
+		++rq->errors;
+	}
+	return ide_stopped;
+}
+#endif
+
+/*
+ * Handler for special commands without a data phase from ide-disk
+ */
+
+/*
+ * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ */
+ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+{
+	byte stat;
+
+	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
+		drive->mult_count = drive->mult_req;
+	} else {
+		drive->mult_req = drive->mult_count = 0;
+		drive->special.b.recalibrate = 1;
+		(void) ide_dump_status(drive, "set_multmode", stat);
+	}
+	return ide_stopped;
+}
+
+/*
+ * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
+ */
+ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+{
+	byte stat;
+
+	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
+		return ide_stopped;
+
+	if (stat & (ERR_STAT|DRQ_STAT))
+		return ide_error(drive, "set_geometry_intr", stat);
+
+	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
+
+/*
+ * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ */
+ide_startstop_t recal_intr (ide_drive_t *drive)
+{
+	byte stat = GET_STAT();
+
+	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
+		return ide_error(drive, "recal_intr", stat);
+	return ide_stopped;
+}
+
+/*
+ * Handler for commands without a data phase
+ */
+ide_startstop_t task_no_data_intr (ide_drive_t *drive)
+{
+	ide_task_t *args	= HWGROUP(drive)->rq->special;
+	byte stat		= GET_STAT();
+
+	ide__sti();	/* local CPU only */
+
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+		return ide_error(drive, "task_no_data_intr", stat);
+		/* calls ide_end_drive_cmd */
+	if (args)
+		ide_end_drive_cmd (drive, stat, GET_ERR());
+
+	return ide_stopped;
+}
+
+/*
+ * Handler for command with PIO data-in phase
+ */
+ide_startstop_t task_in_intr (ide_drive_t *drive)
+{
+	byte stat		= GET_STAT();
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned long flags;
+
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return ide_error(drive, "task_in_intr", stat);
+		}
+		if (!(stat & BUSY_STAT)) {
+			DTF("task_in_intr to Soon wait for next interrupt\n");
+			ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+			return ide_started;  
+		}
+	}
+	DTF("stat: %02x\n", stat);
+	pBuf = ide_map_rq(rq, &flags);
+	DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
+
+	drive->io_32bit = 0;
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+	ide_unmap_rq(rq, pBuf, &flags);
+	drive->io_32bit = io_32bit;
+
+	if (--rq->current_nr_sectors <= 0) {
+		/* (hs): swapped next 2 lines */
+		DTF("Request Ended stat: %02x\n", GET_STAT());
+		if (ide_end_request(1, HWGROUP(drive))) {
+			ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
+			return ide_started;
+		}
+	} else {
+		ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
+		return ide_started;
+	}
+	return ide_stopped;
+}
+
+#undef ALTSTAT_SCREW_UP
+
+#ifdef ALTSTAT_SCREW_UP
+/*
+ * (ks/hs): Poll Alternate Status Register to ensure
+ * that drive is not busy.
+ */
+byte altstat_multi_busy (ide_drive_t *drive, byte stat, const char *msg)
+{
+	int i;
+
+	DTF("multi%s: ASR = %x\n", msg, stat);
+	if (stat & BUSY_STAT) {
+		/* (ks/hs): FIXME: Replace hard-coded 100, error handling? */
+		for (i=0; i<100; i++) {
+			stat = GET_ALTSTAT();
+			if ((stat & BUSY_STAT) == 0)
+				break;
+		}
+	}
+	/*
+	 * (ks/hs): Read Status AFTER Alternate Status Register
+	 */
+	return(GET_STAT());
+}
+
+/*
+ * (ks/hs): Poll Alternate status register to wait for drive
+ * to become ready for next transfer
+ */
+byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg)
+{
+	/* (ks/hs): FIXME: Error handling, time-out? */
+	while (stat & BUSY_STAT)
+		stat = GET_ALTSTAT();
+	DTF("multi%s: nsect=1, ASR = %x\n", msg, stat);
+	return(GET_STAT());	/* (ks/hs): Clear pending IRQ */
+}
+#endif /* ALTSTAT_SCREW_UP */
+
+/*
+ * Handler for command with Read Multiple
+ */
+ide_startstop_t task_mulin_intr (ide_drive_t *drive)
+{
+	unsigned int		msect, nsect;
+
+#ifdef ALTSTAT_SCREW_UP
+	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "read");
+#else
+	byte stat		= GET_STAT();
+#endif /* ALTSTAT_SCREW_UP */
+
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned long flags;
+
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return ide_error(drive, "task_mulin_intr", stat);
+		}
+		/* no data yet, so wait for another interrupt */
+		ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+
+	/* (ks/hs): Fixed Multi-Sector transfer */
+	msect = drive->mult_count;
+
+#ifdef ALTSTAT_SCREW_UP
+	/*
+	 * Screw the request we do not support bad data-phase setups!
+	 * Either read and learn the ATA standard or crash yourself!
+	 */
+	if (!msect) {
+		/*
+		 * (ks/hs): Drive supports multi-sector transfer,
+		 * drive->mult_count was not set
+		 */
+		nsect = 1;
+		while (rq->current_nr_sectors) {
+			pBuf = ide_map_rq(rq, &flags);
+			DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
+			drive->io_32bit = 0;
+			taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+			ide_unmap_rq(rq, pBuf, &flags);
+			drive->io_32bit = io_32bit;
+			rq->errors = 0;
+			rq->current_nr_sectors -= nsect;
+			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read");
+		}
+		ide_end_request(1, HWGROUP(drive));
+		return ide_stopped;
+	}
+#endif /* ALTSTAT_SCREW_UP */
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+
+		pBuf = ide_map_rq(rq, &flags);
+
+		DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, rq->current_nr_sectors);
+		drive->io_32bit = 0;
+		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+		ide_unmap_rq(rq, pBuf, &flags);
+		drive->io_32bit = io_32bit;
+		rq->errors = 0;
+		rq->current_nr_sectors -= nsect;
+		msect -= nsect;
+		if (!rq->current_nr_sectors) {
+			if (!ide_end_request(1, HWGROUP(drive)))
+				return ide_stopped;
+		}
+	} while (msect);
+
+
+	/*
+	 * more data left
+	 */
+	ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
+
+ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_task_t *args = rq->special;
+	ide_startstop_t startstop;
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
+		return startstop;
+	}
+
+	/* (ks/hs): Fixed Multi Write */
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
+	    (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
+		unsigned long flags;
+		char *buf = ide_map_rq(rq, &flags);
+		/* For Write_sectors we need to stuff the first sector */
+		taskfile_output_data(drive, buf, SECTOR_WORDS);
+		rq->current_nr_sectors--;
+		ide_unmap_rq(rq, buf, &flags);
+	} else {
+		/*
+		 * (ks/hs): Stuff the first sector(s)
+		 * by implicitly calling the handler
+		 */
+		if (!(drive_is_ready(drive))) {
+			int i;
+			/*
+			 * (ks/hs): FIXME: Replace hard-coded
+			 *               100, error handling?
+			 */
+			for (i=0; i<100; i++) {
+				if (drive_is_ready(drive))
+					break;
+			}
+		}
+		return args->handler(drive);
+	}
+	return ide_started;
+}
+
+/*
+ * Handler for command with PIO data-out phase
+ */
+ide_startstop_t task_out_intr (ide_drive_t *drive)
+{
+	byte stat		= GET_STAT();
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned long flags;
+
+	if (!rq->current_nr_sectors) { 
+		printk("task_out_intr: should not trigger\n");
+		ide_end_request(1, HWGROUP(drive));
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+		return ide_error(drive, "task_out_intr", stat);
+	}
+
+	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
+		rq = HWGROUP(drive)->rq;
+		pBuf = ide_map_rq(rq, &flags);
+		DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
+		drive->io_32bit = 0;
+		taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+		ide_unmap_rq(rq, pBuf, &flags);
+		drive->io_32bit = io_32bit;
+		rq->errors = 0;
+		rq->current_nr_sectors--;
+	}
+
+	if (rq->current_nr_sectors <= 0) {
+		if (ide_end_request(1, HWGROUP(drive))) {
+			ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
+			return ide_started;
+		}
+	} else {
+		ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+	return ide_stopped;
+}
+
+/*
+ * Handler for command write multiple
+ * Called directly from execute_drive_cmd for the first bunch of sectors,
+ * afterwards only by the ISR
+ */
+ide_startstop_t task_mulout_intr (ide_drive_t *drive)
+{
+	unsigned int		msect, nsect;
+
+#ifdef ALTSTAT_SCREW_UP
+	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "write");
+#else
+	byte stat		= GET_STAT();
+#endif /* ALTSTAT_SCREW_UP */
+
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	char *pBuf		= NULL;
+	unsigned long flags;
+
+	/*
+	 * (ks/hs): Handle last IRQ on multi-sector transfer,
+	 * occurs after all data was sent in this chunk
+	 */
+	if (rq->current_nr_sectors == 0) {
+		if (stat & (ERR_STAT|DRQ_STAT))
+			return ide_error(drive, "task_mulout_intr", stat);
+
+		/*
+		 * there may be more, ide_do_request will restart it if
+		 * necessary
+		 */
+		ide_end_request(1, HWGROUP(drive));
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return ide_error(drive, "task_mulout_intr", stat);
+		}
+		/* no data yet, so wait for another interrupt */
+		if (hwgroup->handler == NULL)
+			ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+
+	/* (ks/hs): See task_mulin_intr */
+	msect = drive->mult_count;
+
+#ifdef ALTSTAT_SCREW_UP
+	/*
+	 * Screw the request we do not support bad data-phase setups!
+	 * Either read and learn the ATA standard or crash yourself!
+	 */
+	if (!msect) {
+		nsect = 1;
+		while (rq->current_nr_sectors) {
+			pBuf = ide_map_rq(rq, &flags);
+			DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
+			drive->io_32bit = 0;
+			taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+			ide_unmap_rq(pBuf, &flags);
+			drive->io_32bit = io_32bit;
+			rq->errors = 0;
+			rq->current_nr_sectors -= nsect;
+			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write");
+		}
+		ide_end_request(1, HWGROUP(drive));
+		return ide_stopped;
+	}
+#endif /* ALTSTAT_SCREW_UP */
+
+	nsect = rq->current_nr_sectors;
+	if (nsect > msect)
+		nsect = msect;
+
+	pBuf = ide_map_rq(rq, &flags);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+		pBuf, nsect, rq->current_nr_sectors);
+	drive->io_32bit = 0;
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+	ide_unmap_rq(rq, pBuf, &flags);
+	drive->io_32bit = io_32bit;
+	rq->errors = 0;
+	rq->current_nr_sectors -= nsect;
+	if (hwgroup->handler == NULL)
+		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
+
+/* Called by internal to feature out type of command being called */
+ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+	switch(taskfile->command) {
+				/* IDE_DRIVE_TASK_RAW_WRITE */
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
+				/* IDE_DRIVE_TASK_OUT */
+		case WIN_WRITE:
+		case WIN_WRITE_EXT:
+		case WIN_WRITE_VERIFY:
+		case WIN_WRITE_BUFFER:
+		case CFA_WRITE_SECT_WO_ERASE:
+		case WIN_DOWNLOAD_MICROCODE:
+			return &pre_task_out_intr;
+				/* IDE_DRIVE_TASK_OUT */
+		case WIN_SMART:
+			if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
+				return &pre_task_out_intr;
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+				/* IDE_DRIVE_TASK_OUT */
+		default:
+			break;
+	}
+	return(NULL);
+}
+
+/* Called by internal to feature out type of command being called */
+ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+	switch(taskfile->command) {
+		case WIN_IDENTIFY:
+		case WIN_PIDENTIFY:
+		case CFA_TRANSLATE_SECTOR:
+		case WIN_READ_BUFFER:
+		case WIN_READ:
+		case WIN_READ_EXT:
+			return &task_in_intr;
+		case WIN_SECURITY_DISABLE:
+		case WIN_SECURITY_ERASE_UNIT:
+		case WIN_SECURITY_SET_PASS:
+		case WIN_SECURITY_UNLOCK:
+		case WIN_DOWNLOAD_MICROCODE:
+		case CFA_WRITE_SECT_WO_ERASE:
+		case WIN_WRITE_BUFFER:
+		case WIN_WRITE_VERIFY:
+		case WIN_WRITE:
+		case WIN_WRITE_EXT:
+			return &task_out_intr;
+		case WIN_MULTREAD:
+		case WIN_MULTREAD_EXT:
+			return &task_mulin_intr;
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
+			return &task_mulout_intr;
+		case WIN_SMART:
+			switch(taskfile->feature) {
+				case SMART_READ_VALUES:
+				case SMART_READ_THRESHOLDS:
+				case SMART_READ_LOG_SECTOR:
+					return &task_in_intr;
+				case SMART_WRITE_LOG_SECTOR:
+					return &task_out_intr;
+				default:
+					return &task_no_data_intr;
+			}
+		case CFA_REQ_EXT_ERROR_CODE:
+		case CFA_ERASE_SECTORS:
+		case WIN_VERIFY:
+		case WIN_VERIFY_EXT:
+		case WIN_SEEK:
+			return &task_no_data_intr;
+		case WIN_SPECIFY:
+			return &set_geometry_intr;
+		case WIN_RESTORE:
+			return &recal_intr;
+		case WIN_DIAGNOSE:
+		case WIN_FLUSH_CACHE:
+		case WIN_FLUSH_CACHE_EXT:
+		case WIN_STANDBYNOW1:
+		case WIN_STANDBYNOW2:
+		case WIN_SLEEPNOW1:
+		case WIN_SLEEPNOW2:
+		case WIN_SETIDLE1:
+		case WIN_CHECKPOWERMODE1:
+		case WIN_CHECKPOWERMODE2:
+		case WIN_GETMEDIASTATUS:
+		case WIN_MEDIAEJECT:
+			return &task_no_data_intr;
+		case WIN_SETMULT:
+			return &set_multmode_intr;
+		case WIN_READ_NATIVE_MAX:
+		case WIN_SET_MAX:
+		case WIN_READ_NATIVE_MAX_EXT:
+		case WIN_SET_MAX_EXT:
+		case WIN_SECURITY_ERASE_PREPARE:
+		case WIN_SECURITY_FREEZE_LOCK:
+		case WIN_DOORLOCK:
+		case WIN_DOORUNLOCK:
+		case WIN_SETFEATURES:
+			return &task_no_data_intr;
+		case DISABLE_SEAGATE:
+		case EXABYTE_ENABLE_NEST:
+			return &task_no_data_intr;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case WIN_READDMA:
+		case WIN_IDENTIFY_DMA:
+		case WIN_READDMA_QUEUED:
+		case WIN_READDMA_EXT:
+		case WIN_READDMA_QUEUED_EXT:
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+#endif
+		case WIN_FORMAT:
+		case WIN_INIT:
+		case WIN_DEVICE_RESET:
+		case WIN_QUEUED_SERVICE:
+		case WIN_PACKETCMD:
+		default:
+			return(NULL);
+	}	
+}
+
+/* Called by ioctl to feature out type of command being called */
+int ide_cmd_type_parser (ide_task_t *args)
+{
+	struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister;
+	struct hd_drive_hob_hdr *hobfile = (struct hd_drive_hob_hdr *) args->hobRegister;
+
+	args->prehandler = ide_pre_handler_parser(taskfile, hobfile);
+	args->handler = ide_handler_parser(taskfile, hobfile);
+
+	switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
+		case WIN_IDENTIFY:
+		case WIN_PIDENTIFY:
+			return IDE_DRIVE_TASK_IN;
+		case CFA_TRANSLATE_SECTOR:
+		case WIN_READ:
+		case WIN_READ_EXT:
+		case WIN_READ_BUFFER:
+			return IDE_DRIVE_TASK_IN;
+		case WIN_WRITE:
+		case WIN_WRITE_EXT:
+		case WIN_WRITE_VERIFY:
+		case WIN_WRITE_BUFFER:
+		case CFA_WRITE_SECT_WO_ERASE:
+		case WIN_DOWNLOAD_MICROCODE:
+			return IDE_DRIVE_TASK_RAW_WRITE;
+		case WIN_MULTREAD:
+		case WIN_MULTREAD_EXT:
+			return IDE_DRIVE_TASK_IN;
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
+			return IDE_DRIVE_TASK_RAW_WRITE;
+		case WIN_SECURITY_DISABLE:
+		case WIN_SECURITY_ERASE_UNIT:
+		case WIN_SECURITY_SET_PASS:
+		case WIN_SECURITY_UNLOCK:
+			return IDE_DRIVE_TASK_OUT;
+		case WIN_SMART:
+			args->tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
+			args->tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
+			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+				case SMART_READ_VALUES:
+				case SMART_READ_THRESHOLDS:
+				case SMART_READ_LOG_SECTOR:
+					return IDE_DRIVE_TASK_IN;
+				case SMART_WRITE_LOG_SECTOR:
+					return IDE_DRIVE_TASK_OUT;
+				default:
+					return IDE_DRIVE_TASK_NO_DATA;
+			}
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case WIN_READDMA:
+		case WIN_IDENTIFY_DMA:
+		case WIN_READDMA_QUEUED:
+		case WIN_READDMA_EXT:
+		case WIN_READDMA_QUEUED_EXT:
+			return IDE_DRIVE_TASK_IN;
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+			return IDE_DRIVE_TASK_RAW_WRITE;
+#endif
+		case WIN_SETFEATURES:
+			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+				case SETFEATURES_XFER:
+					return IDE_DRIVE_TASK_SET_XFER;
+				case SETFEATURES_DIS_DEFECT:
+				case SETFEATURES_EN_APM:
+				case SETFEATURES_DIS_MSN:
+				case SETFEATURES_EN_RI:
+				case SETFEATURES_EN_SI:
+				case SETFEATURES_DIS_RPOD:
+				case SETFEATURES_DIS_WCACHE:
+				case SETFEATURES_EN_DEFECT:
+				case SETFEATURES_DIS_APM:
+				case SETFEATURES_EN_MSN:
+				case SETFEATURES_EN_RLA:
+				case SETFEATURES_PREFETCH:
+				case SETFEATURES_EN_RPOD:
+				case SETFEATURES_DIS_RI:
+				case SETFEATURES_DIS_SI:
+				default:
+					return IDE_DRIVE_TASK_NO_DATA;
+			}
+		case WIN_NOP:
+		case CFA_REQ_EXT_ERROR_CODE:
+		case CFA_ERASE_SECTORS:
+		case WIN_VERIFY:
+		case WIN_VERIFY_EXT:
+		case WIN_SEEK:
+		case WIN_SPECIFY:
+		case WIN_RESTORE:
+		case WIN_DIAGNOSE:
+		case WIN_FLUSH_CACHE:
+		case WIN_FLUSH_CACHE_EXT:
+		case WIN_STANDBYNOW1:
+		case WIN_STANDBYNOW2:
+		case WIN_SLEEPNOW1:
+		case WIN_SLEEPNOW2:
+		case WIN_SETIDLE1:
+		case DISABLE_SEAGATE:
+		case WIN_CHECKPOWERMODE1:
+		case WIN_CHECKPOWERMODE2:
+		case WIN_GETMEDIASTATUS:
+		case WIN_MEDIAEJECT:
+		case WIN_SETMULT:
+		case WIN_READ_NATIVE_MAX:
+		case WIN_SET_MAX:
+		case WIN_READ_NATIVE_MAX_EXT:
+		case WIN_SET_MAX_EXT:
+		case WIN_SECURITY_ERASE_PREPARE:
+		case WIN_SECURITY_FREEZE_LOCK:
+		case EXABYTE_ENABLE_NEST:
+		case WIN_DOORLOCK:
+		case WIN_DOORUNLOCK:
+			return IDE_DRIVE_TASK_NO_DATA;
+		case WIN_FORMAT:
+		case WIN_INIT:
+		case WIN_DEVICE_RESET:
+		case WIN_QUEUED_SERVICE:
+		case WIN_PACKETCMD:
+		default:
+			return IDE_DRIVE_TASK_INVALID;
+	}
+}
+
+/*
+ * This function is intended to be used prior to invoking ide_do_drive_cmd().
+ */
+void ide_init_drive_taskfile (struct request *rq)
+{
+	memset(rq, 0, sizeof(*rq));
+	rq->flags = REQ_DRIVE_TASKFILE;
+}
+
+/*
+ * This is kept for internal use only !!!
+ * This is an internal call and nobody in user-space has a damn
+ * reason to call this taskfile.
+ *
+ * ide_raw_taskfile is the one that user-space executes.
+ */
+int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf)
+{
+	struct request rq;
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	args.tfRegister[IDE_DATA_OFFSET]         = taskfile->data;
+	args.tfRegister[IDE_FEATURE_OFFSET]      = taskfile->feature;
+	args.tfRegister[IDE_NSECTOR_OFFSET]      = taskfile->sector_count;
+	args.tfRegister[IDE_SECTOR_OFFSET]       = taskfile->sector_number;
+	args.tfRegister[IDE_LCYL_OFFSET]         = taskfile->low_cylinder;
+	args.tfRegister[IDE_HCYL_OFFSET]         = taskfile->high_cylinder;
+	args.tfRegister[IDE_SELECT_OFFSET]       = taskfile->device_head;
+	args.tfRegister[IDE_COMMAND_OFFSET]      = taskfile->command;
+
+	args.hobRegister[IDE_DATA_OFFSET_HOB]    = hobfile->data;
+	args.hobRegister[IDE_FEATURE_OFFSET_HOB] = hobfile->feature;
+	args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = hobfile->sector_count;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]  = hobfile->sector_number;
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]    = hobfile->low_cylinder;
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]    = hobfile->high_cylinder;
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]  = hobfile->device_head;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB] = hobfile->control;
+
+	ide_init_drive_taskfile(&rq);
+	/* This is kept for internal use only !!! */
+	args.command_type = ide_cmd_type_parser (&args);
+	if (args.command_type != IDE_DRIVE_TASK_NO_DATA)
+		rq.current_nr_sectors = rq.nr_sectors = (hobfile->sector_count << 8) | taskfile->sector_count;
+
+	rq.buffer = buf;
+	rq.special = &args;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf)
+{
+	struct request rq;
+	ide_init_drive_taskfile(&rq);
+	rq.buffer = buf;
+
+	if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
+		rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+
+	rq.special = args;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+char * ide_ioctl_verbose (unsigned int cmd)
+{
+	return("unknown");
+}
+
+char * ide_task_cmd_verbose (byte task)
+{
+	return("unknown");
+}
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+/*
+ *  The taskfile glue table
+ *
+ *  reqtask.data_phase	reqtask.req_cmd
+ *  			args.command_type		args.handler
+ *
+ *  TASKFILE_P_OUT_DMAQ	??				??
+ *  TASKFILE_P_IN_DMAQ	??				??
+ *  TASKFILE_P_OUT_DMA	??				??
+ *  TASKFILE_P_IN_DMA	??				??
+ *  TASKFILE_P_OUT	??				??
+ *  TASKFILE_P_IN	??				??
+ *
+ *  TASKFILE_OUT_DMAQ	IDE_DRIVE_TASK_RAW_WRITE	NULL
+ *  TASKFILE_IN_DMAQ	IDE_DRIVE_TASK_IN		NULL
+ *
+ *  TASKFILE_OUT_DMA	IDE_DRIVE_TASK_RAW_WRITE	NULL
+ *  TASKFILE_IN_DMA	IDE_DRIVE_TASK_IN		NULL
+ *
+ *  TASKFILE_IN_OUT	??				??
+ *
+ *  TASKFILE_MULTI_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_mulout_intr
+ *  TASKFILE_MULTI_IN	IDE_DRIVE_TASK_IN		task_mulin_intr
+ *
+ *  TASKFILE_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_out_intr
+ *  TASKFILE_OUT	IDE_DRIVE_TASK_OUT		task_out_intr
+ *
+ *  TASKFILE_IN		IDE_DRIVE_TASK_IN		task_in_intr
+ *  TASKFILE_NO_DATA	IDE_DRIVE_TASK_NO_DATA		task_no_data_intr
+ *
+ *  			IDE_DRIVE_TASK_SET_XFER		task_no_data_intr
+ *  			IDE_DRIVE_TASK_INVALID
+ *
+ */
+
+#define MAX_DMA		(256*SECTOR_WORDS)
+
+int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	ide_task_request_t	*req_task;
+	ide_task_t		args;
+
+	byte *outbuf		= NULL;
+	byte *inbuf		= NULL;
+	task_ioreg_t *argsptr	= args.tfRegister;
+	task_ioreg_t *hobsptr	= args.hobRegister;
+	int err			= 0;
+	int tasksize		= sizeof(struct ide_task_request_s);
+	int taskin		= 0;
+	int taskout		= 0;
+
+	req_task = kmalloc(tasksize, GFP_KERNEL);
+	if (req_task == NULL) return -ENOMEM;
+	memset(req_task, 0, tasksize);
+	if (copy_from_user(req_task, (void *) arg, tasksize)) {
+		kfree(req_task);
+		return -EFAULT;
+	}
+
+	taskout = (int) req_task->out_size;
+	taskin  = (int) req_task->in_size;
+
+	if (taskout) {
+		int outtotal = tasksize;
+		outbuf = kmalloc(taskout, GFP_KERNEL);
+		if (outbuf == NULL) {
+			err = -ENOMEM;
+			goto abort;
+		}
+		memset(outbuf, 0, taskout);
+		if (copy_from_user(outbuf, (void *)arg + outtotal, taskout)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+
+	if (taskin) {
+		int intotal = tasksize + taskout;
+		inbuf = kmalloc(taskin, GFP_KERNEL);
+		if (inbuf == NULL) {
+			err = -ENOMEM;
+			goto abort;
+		}
+		memset(inbuf, 0, taskin);
+		if (copy_from_user(inbuf, (void *)arg + intotal , taskin)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+
+	memset(argsptr, 0, HDIO_DRIVE_TASK_HDR_SIZE);
+	memset(hobsptr, 0, HDIO_DRIVE_HOB_HDR_SIZE);
+	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
+	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
+
+	args.tf_in_flags  = req_task->in_flags;
+	args.tf_out_flags = req_task->out_flags;
+	args.data_phase   = req_task->data_phase;
+	args.command_type = req_task->req_cmd;
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	DTF("%s: ide_ioctl_cmd %s:  ide_task_cmd %s\n",
+		drive->name,
+		ide_ioctl_verbose(cmd),
+		ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET]));
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+	switch(req_task->data_phase) {
+		case TASKFILE_OUT_DMAQ:
+		case TASKFILE_OUT_DMA:
+			args.prehandler = NULL;
+			args.handler = NULL;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, outbuf);
+			break;
+		case TASKFILE_IN_DMAQ:
+		case TASKFILE_IN_DMA:
+			args.prehandler = NULL;
+			args.handler = NULL;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, inbuf);
+			break;
+		case TASKFILE_IN_OUT:
+#if 0
+			args.prehandler = &pre_task_out_intr;
+			args.handler = &task_out_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, outbuf);
+			args.prehandler = NULL;
+			args.handler = &task_in_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, inbuf);
+			break;
+#else
+			err = -EFAULT;
+			goto abort;
+#endif
+		case TASKFILE_MULTI_OUT:
+			if (drive->mult_count) {
+				args.prehandler = &pre_task_out_intr;
+				args.handler = &task_mulout_intr;
+				args.posthandler = NULL;
+				err = ide_raw_taskfile(drive, &args, outbuf);
+			} else {
+				/* (hs): give up if multcount is not set */
+				printk("%s: %s Multimode Write " \
+					"multcount is not set\n",
+					 drive->name, __FUNCTION__);
+				err = -EPERM;
+				goto abort;
+			}
+			break;
+		case TASKFILE_OUT:
+			args.prehandler = &pre_task_out_intr;
+			args.handler = &task_out_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, outbuf);
+			break;
+		case TASKFILE_MULTI_IN:
+			if (drive->mult_count) {
+				args.prehandler = NULL;
+				args.handler = &task_mulin_intr;
+				args.posthandler = NULL;
+				err = ide_raw_taskfile(drive, &args, inbuf);
+			} else {
+				/* (hs): give up if multcount is not set */
+				printk("%s: %s Multimode Read failure " \
+					"multcount is not set\n",
+					drive->name, __FUNCTION__);
+				err = -EPERM;
+				goto abort;
+			}
+			break;
+		case TASKFILE_IN:
+			args.prehandler = NULL;
+			args.handler = &task_in_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, inbuf);
+			break;
+		case TASKFILE_NO_DATA:
+			args.prehandler = NULL;
+			args.handler = &task_no_data_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, NULL);
+			break;
+		default:
+			args.prehandler = NULL;
+			args.handler = NULL;
+			args.posthandler = NULL;
+			err = -EFAULT;
+			goto abort;
+	}
+
+	memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
+	memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
+	req_task->in_flags  = args.tf_in_flags;
+	req_task->out_flags = args.tf_out_flags;
+
+	if (copy_to_user((void *)arg, req_task, tasksize)) {
+		err = -EFAULT;
+		goto abort;
+	}
+	if (taskout) {
+		int outtotal = tasksize;
+		if (copy_to_user((void *)arg+outtotal, outbuf, taskout)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+	if (taskin) {
+		int intotal = tasksize + taskout;
+		if (copy_to_user((void *)arg+intotal, inbuf, taskin)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+abort:
+	kfree(req_task);
+	if (outbuf != NULL)
+		kfree(outbuf);
+	if (inbuf != NULL)
+		kfree(inbuf);
+	return err;
+}
+
+int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	byte args[4], *argbuf = args;
+	byte xfer_rate = 0;
+	int argsize = 4;
+	ide_task_t tfargs;
+
+	if (NULL == (void *) arg) {
+		struct request rq;
+		ide_init_drive_cmd(&rq);
+		return ide_do_drive_cmd(drive, &rq, ide_wait);
+	}
+	if (copy_from_user(args, (void *)arg, 4))
+		return -EFAULT;
+
+	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
+	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
+	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
+	if (args[3]) {
+		argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
+		argbuf = kmalloc(argsize, GFP_KERNEL);
+		if (argbuf == NULL)
+			return -ENOMEM;
+		memcpy(argbuf, args, 4);
+	}
+	if (set_transfer(drive, &tfargs)) {
+		xfer_rate = args[1];
+		if (ide_ata66_check(drive, &tfargs))
+			goto abort;
+	}
+
+	err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+
+	if (!err && xfer_rate) {
+		/* active-retuning-calls future */
+		if ((HWIF(drive)->speedproc) != NULL)
+			HWIF(drive)->speedproc(drive, xfer_rate);
+		ide_driveid_update(drive);
+	}
+abort:
+	if (copy_to_user((void *)arg, argbuf, argsize))
+		err = -EFAULT;
+	if (argsize > 4)
+		kfree(argbuf);
+	return err;
+}
+
+int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	byte args[7], *argbuf = args;
+	int argsize = 7;
+
+	if (copy_from_user(args, (void *)arg, 7))
+		return -EFAULT;
+	err = ide_wait_cmd_task(drive, argbuf);
+	if (copy_to_user((void *)arg, argbuf, argsize))
+		err = -EFAULT;
+	return err;
+}
+
+EXPORT_SYMBOL(drive_is_ready);
+EXPORT_SYMBOL(task_read_24);
+EXPORT_SYMBOL(ata_input_data);
+EXPORT_SYMBOL(ata_output_data);
+EXPORT_SYMBOL(atapi_input_bytes);
+EXPORT_SYMBOL(atapi_output_bytes);
+EXPORT_SYMBOL(taskfile_input_data);
+EXPORT_SYMBOL(taskfile_output_data);
+EXPORT_SYMBOL(do_rw_taskfile);
+EXPORT_SYMBOL(do_taskfile);
+// EXPORT_SYMBOL(flagged_taskfile);
+
+//EXPORT_SYMBOL(ide_end_taskfile);
+
+EXPORT_SYMBOL(set_multmode_intr);
+EXPORT_SYMBOL(set_geometry_intr);
+EXPORT_SYMBOL(recal_intr);
+
+EXPORT_SYMBOL(task_no_data_intr);
+EXPORT_SYMBOL(task_in_intr);
+EXPORT_SYMBOL(task_mulin_intr);
+EXPORT_SYMBOL(pre_task_out_intr);
+EXPORT_SYMBOL(task_out_intr);
+EXPORT_SYMBOL(task_mulout_intr);
+
+EXPORT_SYMBOL(ide_init_drive_taskfile);
+EXPORT_SYMBOL(ide_wait_taskfile);
+EXPORT_SYMBOL(ide_raw_taskfile);
+EXPORT_SYMBOL(ide_pre_handler_parser);
+EXPORT_SYMBOL(ide_handler_parser);
+EXPORT_SYMBOL(ide_cmd_type_parser);
+EXPORT_SYMBOL(ide_taskfile_ioctl);
+EXPORT_SYMBOL(ide_cmd_ioctl);
+EXPORT_SYMBOL(ide_task_ioctl);
+
+
+#ifdef CONFIG_PKT_TASK_IOCTL
+
+#if 0
+{
+
+{ /* start cdrom */
+
+	struct cdrom_info *info = drive->driver_data;
+
+	if (info->dma) {
+		if (info->cmd == READ) {
+			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+		} else if (info->cmd == WRITE) {
+			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+		} else {
+			printk("ide-cd: DMA set, but not allowed\n");
+		}
+	}
+
+	/* Set up the controller registers. */
+	OUT_BYTE (info->dma, IDE_FEATURE_REG);
+	OUT_BYTE (0, IDE_NSECTOR_REG);
+	OUT_BYTE (0, IDE_SECTOR_REG);
+
+	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
+	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+
+	if (info->dma)
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+
+	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
+		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		return ide_started;
+	} else {
+		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		return (*handler) (drive);
+	}
+
+} /* end cdrom */
+
+{ /* start floppy */
+
+	idefloppy_floppy_t *floppy = drive->driver_data;
+	idefloppy_bcount_reg_t bcount;
+	int dma_ok = 0;
+
+	floppy->pc=pc;		/* Set the current packet command */
+
+	pc->retries++;
+	pc->actually_transferred=0; /* We haven't transferred any data yet */
+	pc->current_position=pc->buffer;
+	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	}
+	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
+	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
+	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
+	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (dma_ok) {	/* Begin DMA, if necessary */
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+} /* end floppy */
+
+{ /* start tape */
+
+	idetape_tape_t *tape = drive->driver_data;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
+		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	}
+	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
+	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
+	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
+	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (dma_ok) {	/* Begin DMA, if necessary */
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return ide_started;
+	} else {
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return idetape_transfer_pc(drive);
+	}
+
+} /* end tape */
+
+}
+#endif
+
+int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 0
+	switch(req_task->data_phase) {
+		case TASKFILE_P_OUT_DMAQ:
+		case TASKFILE_P_IN_DMAQ:
+		case TASKFILE_P_OUT_DMA:
+		case TASKFILE_P_IN_DMA:
+		case TASKFILE_P_OUT:
+		case TASKFILE_P_IN:
+	}
+#endif
+	return -ENOMSG;
+}
+
+EXPORT_SYMBOL(pkt_taskfile_ioctl);
+
+#endif /* CONFIG_PKT_TASK_IOCTL */
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide.c linux/drivers/ide/ide.c
--- v2.5.2/linux/drivers/ide/ide.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ide/ide.c	Thu Jan 17 13:58:35 2002
@@ -151,6 +151,7 @@
 #include <linux/ide.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/completion.h>
+#include <linux/reboot.h>
 #include <linux/cdrom.h>
 
 #include <asm/byteorder.h>
@@ -371,186 +372,6 @@
 	return system_bus_speed;
 }
 
-#if SUPPORT_VLB_SYNC
-/*
- * Some localbus EIDE interfaces require a special access sequence
- * when using 32-bit I/O instructions to transfer data.  We call this
- * the "vlb_sync" sequence, which consists of three successive reads
- * of the sector count register location, with interrupts disabled
- * to ensure that the reads all happen together.
- */
-static inline void do_vlb_sync (ide_ioreg_t port) {
-	(void) inb (port);
-	(void) inb (port);
-	(void) inb (port);
-}
-#endif /* SUPPORT_VLB_SYNC */
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- */
-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit;
-
-	/* first check if this controller has defined a special function
-	 * for handling polled ide transfers
-	 */
-
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_ide_input_data,
-				     drive, buffer, wcount);
-		return;
-	}
-
-	io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			do_vlb_sync(IDE_NSECTOR_REG);
-			insl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			insl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				*ptr++ = inw_p(IDE_DATA_REG);
-				*ptr++ = inw_p(IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			insw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit;
-
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_ide_output_data,
-				     drive, buffer, wcount);
-		return;
-	}
-
-	io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			do_vlb_sync(IDE_NSECTOR_REG);
-			outsl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			outsl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				outw_p(*ptr++, IDE_DATA_REG);
-				outw_p(*ptr++, IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			outsw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
-/*
- * The following routines are mainly used by the ATAPI drivers.
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd bytecount is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_atapi_input_bytes,
-				     drive, buffer, bytecount);
-		return;
-	}
-
-	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
-		return;
-	}
-#endif /* CONFIG_ATARI */
-	ide_input_data (drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_atapi_output_bytes,
-				     drive, buffer, bytecount);
-		return;
-	}
-
-	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
-		return;
-	}
-#endif /* CONFIG_ATARI */
-	ide_output_data (drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-/*
- * Needed for PCI irq sharing
- */
-static inline int drive_is_ready (ide_drive_t *drive)
-{
-	byte stat = 0;
-	if (drive->waiting_for_dma)
-		return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
-#if 0
-	udelay(1);	/* need to guarantee 400ns since last command was issued */
-#endif
-
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
-	/*
-	 * We do a passive status test under shared PCI interrupts on
-	 * cards that truly share the ATA side interrupt, but may also share
-	 * an interrupt with another pci card/device.  We make no assumptions
-	 * about possible isa-pnp and pci-pnp issues yet.
-	 */
-	if (IDE_CONTROL_REG)
-		stat = GET_ALTSTAT();
-	else
-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
-	stat = GET_STAT();	/* Note: this may clear a pending IRQ!! */
-
-	if (stat & BUSY_STAT)
-		return 0;	/* drive busy:  definitely not interrupting */
-	return 1;		/* drive ready: *might* be interrupting */
-}
-
 inline int __ide_end_request(ide_hwgroup_t *hwgroup, int uptodate, int nr_secs)
 {
 	ide_drive_t *drive = hwgroup->drive;
@@ -836,7 +657,11 @@
 	 */
 	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set SRST and nIEN */
 	udelay(10);			/* more than enough time */
-	OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
+	if (drive->quirk_list == 2) {
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear SRST and nIEN */
+	} else {
+		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
+	}
 	udelay(10);			/* more than enough time */
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 	ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
@@ -863,6 +688,13 @@
 	return do_reset1 (drive, 0);
 }
 
+static inline u32 read_24 (ide_drive_t *drive)
+{
+	return  (IN_BYTE(IDE_HCYL_REG)<<16) |
+		(IN_BYTE(IDE_LCYL_REG)<<8) |
+		 IN_BYTE(IDE_SECTOR_REG);
+}
+
 /*
  * Clean up after success/failure of an explicit drive cmd
  */
@@ -894,6 +726,33 @@
 			args[5] = IN_BYTE(IDE_HCYL_REG);
 			args[6] = IN_BYTE(IDE_SELECT_REG);
 		}
+	} else if (rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = (ide_task_t *) rq->special;
+		rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+		if (args) {
+			if (args->tf_in_flags.b.data) {
+				unsigned short data			= IN_WORD(IDE_DATA_REG);
+				args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
+				args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
+			}
+			args->tfRegister[IDE_ERROR_OFFSET]   = err;
+			args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
+			args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
+			args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
+			args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
+			args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
+			args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+			if ((drive->id->command_set_2 & 0x0400) &&
+			    (drive->id->cfs_enable_2 & 0x0400) &&
+			    (drive->addressing == 1)) {
+				OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+				args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
+				args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
+				args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
+				args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
+				args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
+			}
+		}
 	}
 
 	blkdev_dequeue_request(rq);
@@ -944,19 +803,32 @@
 			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
 			printk("}");
 			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-				byte cur = IN_BYTE(IDE_SELECT_REG);
-				if (cur & 0x40) {	/* using LBA? */
-					printk(", LBAsect=%ld", (unsigned long)
-					 ((cur&0xf)<<24)
-					 |(IN_BYTE(IDE_HCYL_REG)<<16)
-					 |(IN_BYTE(IDE_LCYL_REG)<<8)
-					 | IN_BYTE(IDE_SECTOR_REG));
+				if ((drive->id->command_set_2 & 0x0400) &&
+				    (drive->id->cfs_enable_2 & 0x0400) &&
+				    (drive->addressing == 1)) {
+					__u64 sectors = 0;
+					u32 low = 0, high = 0;
+					low = read_24(drive);
+					OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
+					high = read_24(drive);
+
+					sectors = ((__u64)high << 24) | low;
+					printk(", LBAsect=%lld, high=%d, low=%d", sectors, high, low);
 				} else {
-					printk(", CHS=%d/%d/%d",
-					 (IN_BYTE(IDE_HCYL_REG)<<8) +
-					  IN_BYTE(IDE_LCYL_REG),
-					  cur & 0xf,
-					  IN_BYTE(IDE_SECTOR_REG));
+					byte cur = IN_BYTE(IDE_SELECT_REG);
+					if (cur & 0x40) {	/* using LBA? */
+						printk(", LBAsect=%ld", (unsigned long)
+						 ((cur&0xf)<<24)
+						 |(IN_BYTE(IDE_HCYL_REG)<<16)
+						 |(IN_BYTE(IDE_LCYL_REG)<<8)
+						 | IN_BYTE(IDE_SECTOR_REG));
+					} else {
+						printk(", CHS=%d/%d/%d",
+						 (IN_BYTE(IDE_HCYL_REG)<<8) +
+						  IN_BYTE(IDE_LCYL_REG),
+						  cur & 0xf,
+						  IN_BYTE(IDE_SECTOR_REG));
+					}
 				}
 				if (HWGROUP(drive) && HWGROUP(drive)->rq)
 					printk(", sector=%ld", HWGROUP(drive)->rq->sector);
@@ -986,7 +858,7 @@
 		u32 buffer[16];
 		unsigned int wcount = (i > 16) ? 16 : i;
 		i -= wcount;
-		ide_input_data (drive, buffer, wcount);
+		ata_input_data (drive, buffer, wcount);
 	}
 }
 
@@ -1004,9 +876,15 @@
 	/* retry only "normal" I/O: */
 	if (!(rq->flags & REQ_CMD)) {
 		rq->errors = 1;
+#if 0
+		if (rq->flags & REQ_DRIVE_TASKFILE)
+			ide_end_taskfile(drive, stat, err);
+		else
+#endif
 		ide_end_drive_cmd(drive, stat, err);
 		return ide_stopped;
 	}
+
 	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
 	} else {
@@ -1022,6 +900,7 @@
 			else if (err & TRK0_ERR)	/* help it find track zero */
 				rq->errors |= ERROR_RECAL;
 		}
+		/* pre bio (rq->cmd != WRITE) */
 		if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
 			try_to_flush_leftover_data(drive);
 	}
@@ -1073,7 +952,7 @@
 	if ((stat & DRQ_STAT) && args && args[3]) {
 		byte io_32bit = drive->io_32bit;
 		drive->io_32bit = 0;
-		ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
+		ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
 		drive->io_32bit = io_32bit;
 		while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
 			udelay(100);
@@ -1168,14 +1047,63 @@
  */
 static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
 {
-	byte *args = rq->buffer;
-	if (args && (rq->flags & REQ_DRIVE_TASK)) {
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+
+		if (!(args)) goto args_error;
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	{
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]);
+	printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]);
+	printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
+	printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
+	printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
+	printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
+	printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
+	printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
+	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
+	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
+	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
+	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
+	printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
+	printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
+	printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
+	}
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+//		if (args->tf_out_flags.all == 0) {
+			do_taskfile(drive,
+				(struct hd_drive_task_hdr *)&args->tfRegister,
+				(struct hd_drive_hob_hdr *)&args->hobRegister,
+				args->handler);
+//		} else {
+//				return flagged_taskfile(drive, args);
+//		}
+
+		if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
+		     (args->command_type == IDE_DRIVE_TASK_OUT)) &&
+		      args->prehandler && args->handler)
+			return args->prehandler(drive, rq);
+		return ide_started;
+
+	} else if (rq->flags & REQ_DRIVE_TASK) {
+		byte *args = rq->buffer;
 		byte sel;
+
+		if (!(args)) goto args_error;
 #ifdef DEBUG
-		printk("%s: DRIVE_TASK_CMD data=x%02x cmd=0x%02x fr=0x%02x ns=0x%02x sc=0x%02x lcyl=0x%02x hcyl=0x%02x sel=0x%02x\n",
-			drive->name,
-			args[0], args[1], args[2], args[3],
-			args[4], args[5], args[6], args[7]);
+			printk("%s: DRIVE_TASK_CMD ", drive->name);
+			printk("cmd=0x%02x ", args[0]);
+			printk("fr=0x%02x ", args[1]);
+			printk("ns=0x%02x ", args[2]);
+			printk("sc=0x%02x ", args[3]);
+			printk("lcyl=0x%02x ", args[4]);
+			printk("hcyl=0x%02x ", args[5]);
+			printk("sel=0x%02x\n", args[6]);
 #endif
 		OUT_BYTE(args[1], IDE_FEATURE_REG);
 		OUT_BYTE(args[3], IDE_SECTOR_REG);
@@ -1187,10 +1115,16 @@
 		OUT_BYTE(sel, IDE_SELECT_REG);
 		ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
 		return ide_started;
-	} else if (args) {
+	} else if (rq->flags & REQ_DRIVE_CMD) {
+
+		byte *args = rq->buffer;
+		if (!(args)) goto args_error;
 #ifdef DEBUG
-		printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n",
-		 drive->name, args[0], args[1], args[2], args[3]);
+		printk("%s: DRIVE_CMD ", drive->name);
+		printk("cmd=0x%02x ", args[0]);
+		printk("sc=0x%02x ", args[1]);
+		printk("fr=0x%02x ", args[2]);
+		printk("xx=0x%02x\n", args[3]);
 #endif
 		if (args[0] == WIN_SMART) {
 			OUT_BYTE(0x4f, IDE_LCYL_REG);
@@ -1203,17 +1137,18 @@
 		OUT_BYTE(args[2],IDE_FEATURE_REG);
 		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
 		return ide_started;
-	} else {
-		/*
-		 * NULL is actually a valid way of waiting for
-		 * all current requests to be flushed from the queue.
-		 */
+	}
+
+args_error:
+	/*
+	 * NULL is actually a valid way of waiting for
+	 * all current requests to be flushed from the queue.
+	 */
 #ifdef DEBUG
-		printk("%s: DRIVE_CMD (null)\n", drive->name);
+	printk("%s: DRIVE_CMD (null)\n", drive->name);
 #endif
-		ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
-		return ide_stopped;
-	}
+	ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
+	return ide_stopped;
 }
 
 /*
@@ -1264,7 +1199,7 @@
 		return startstop;
 	}
 	if (!drive->special.all) {
-		if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK))
+		if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE))
 			return execute_drive_cmd(drive, rq);
 
 		if (drive->driver != NULL) {
@@ -1384,7 +1319,7 @@
  * will start the next request from the queue.  If no more work remains,
  * the driver will clear the hwgroup->flags IDE_BUSY flag and exit.
  */
-static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
+static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
 {
 	ide_drive_t	*drive;
 	ide_hwif_t	*hwif;
@@ -1523,14 +1458,11 @@
 	HWGROUP(drive)->rq = NULL;
 
 	rq->errors = 0;
-	rq->sector = rq->bio->bi_sector;
-	rq->current_nr_sectors = bio_sectors(rq->bio);
-
-	/*
-	 * just to make sure...
-	 */
-	if (rq->bio)
+	if (rq->bio) {
+		rq->sector = rq->bio->bi_sector;
+		rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
 		rq->buffer = NULL;
+	}
 }
 
 /*
@@ -1986,6 +1918,10 @@
 			(void) request_module("ide-tape");
 		if (drive->media == ide_floppy)
 			(void) request_module("ide-floppy");
+#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
+		if (drive->media == ide_scsi)
+			(void) request_module("ide-scsi");
+#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
 	}
 #endif /* CONFIG_KMOD */
 	while (drive->busy)
@@ -2609,6 +2545,61 @@
 	return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
 }
 
+int ide_reinit_drive (ide_drive_t *drive)
+{
+	switch (drive->media) {
+#ifdef CONFIG_BLK_DEV_IDECD
+		case ide_cdrom:
+		{
+			extern int ide_cdrom_reinit(ide_drive_t *drive);
+			if (ide_cdrom_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDEDISK
+		case ide_disk:
+		{
+			extern int idedisk_reinit(ide_drive_t *drive);
+			if (idedisk_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDEDISK */
+#ifdef CONFIG_BLK_DEV_IDEFLOPPY
+		case ide_floppy:
+		{
+			extern int idefloppy_reinit(ide_drive_t *drive);
+			if (idefloppy_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+		case ide_tape:
+		{
+			extern int idetape_reinit(ide_drive_t *drive);
+			if (idetape_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+#ifdef CONFIG_BLK_DEV_IDESCSI
+/*
+ *              {
+ *                      extern int idescsi_reinit(ide_drive_t *drive);
+ *                      if (idescsi_reinit(drive))
+ *                              return 1;
+ *                      break;
+ * }
+ */
+#endif /* CONFIG_BLK_DEV_IDESCSI */
+		default:
+			return 1;
+	}
+	return 0;
+}
+
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -2695,57 +2686,35 @@
 					drive->nice1		<<	IDE_NICE_1		|
 					drive->nice2		<<	IDE_NICE_2,
 					(long *) arg);
+
+#ifdef CONFIG_IDE_TASK_IOCTL
+		case HDIO_DRIVE_TASKFILE:
+		        if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			switch(drive->media) {
+				case ide_disk:
+					return ide_taskfile_ioctl(drive, inode, file, cmd, arg);
+#ifdef CONFIG_PKT_TASK_IOCTL
+				case ide_cdrom:
+				case ide_tape:
+				case ide_floppy:
+					return pkt_taskfile_ioctl(drive, inode, file, cmd, arg);
+#endif /* CONFIG_PKT_TASK_IOCTL */
+				default:
+					return -ENOMSG;
+			}
+#endif /* CONFIG_IDE_TASK_IOCTL */
+
 		case HDIO_DRIVE_CMD:
-		{
-			byte args[4], *argbuf = args;
-			byte xfer_rate = 0;
-			int argsize = 4;
-			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
-			if (NULL == (void *) arg)
-				return ide_do_drive_cmd(drive, &rq, ide_wait);
-			if (copy_from_user(args, (void *)arg, 4))
-				return -EFAULT;
-			if (args[3]) {
-				argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
-				argbuf = kmalloc(argsize, GFP_KERNEL);
-				if (argbuf == NULL)
-					return -ENOMEM;
-				memcpy(argbuf, args, 4);
-			}
-
-			if (set_transfer(drive, args[0], args[1], args[2])) {
-				xfer_rate = args[1];
-				if (ide_ata66_check(drive, args[0], args[1], args[2]))
-					goto abort;
-			}
-
-			err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
-
-			if (!err && xfer_rate) {
-				/* active-retuning-calls future */
-				if ((HWIF(drive)->speedproc) != NULL)
-					HWIF(drive)->speedproc(drive, xfer_rate);
-				ide_driveid_update(drive);
-			}
-		abort:
-			if (copy_to_user((void *)arg, argbuf, argsize))
-				err = -EFAULT;
-			if (argsize > 4)
-				kfree(argbuf);
-			return err;
-		}
+			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			return ide_cmd_ioctl(drive, inode, file, cmd, arg);
+
 		case HDIO_DRIVE_TASK:
-		{
-			byte args[7], *argbuf = args;
-			int argsize = 7;
-			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
-			if (copy_from_user(args, (void *)arg, 7))
-				return -EFAULT;
-			err = ide_wait_cmd_task(drive, argbuf);
-			if (copy_to_user((void *)arg, argbuf, argsize))
-				err = -EFAULT;
-			return err;
-		}
+			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			return ide_task_ioctl(drive, inode, file, cmd, arg);
+
 		case HDIO_SCAN_HWIF:
 		{
 			int args[3];
@@ -2775,7 +2744,24 @@
 			drive->nice1 = (arg >> IDE_NICE_1) & 1;
 			return 0;
 		case HDIO_DRIVE_RESET:
+		{
+			unsigned long flags;
+			ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+#if 1
+			spin_lock_irqsave(&ide_lock, flags);
+			if (hwgroup->handler != NULL) {
+				printk("%s: ide_set_handler: handler not null; %p\n", drive->name, hwgroup->handler);
+				(void) hwgroup->handler(drive);
+//				hwgroup->handler = NULL;
+//				hwgroup->expiry	= NULL;
+				hwgroup->timer.expires = jiffies + 0;;
+				del_timer(&hwgroup->timer);
+			}
+			spin_unlock_irqrestore(&ide_lock, flags);
+
+#endif
 			(void) ide_do_reset(drive);
 			if (drive->suspend_reset) {
 /*
@@ -2790,7 +2776,7 @@
 				return ide_revalidate_disk(inode->i_rdev);
 			}
 			return 0;
-
+		}
 		case BLKGETSIZE:
 		case BLKGETSIZE64:
 		case BLKROSET:
@@ -2822,7 +2808,7 @@
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
 			if (HWIF(drive)->busproc)
-				HWIF(drive)->busproc(HWIF(drive), arg);
+				HWIF(drive)->busproc(drive, (int)arg);
 			return 0;
 
 		default:
@@ -3483,6 +3469,16 @@
 	return ide_unregister_subdriver(drive);
 }
 
+static int default_standby (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int default_flushcache (ide_drive_t *drive)
+{
+	return 0;
+}
+
 static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	ide_end_request(0, HWGROUP(drive));
@@ -3545,6 +3541,8 @@
 	ide_driver_t *d = drive->driver;
 
 	if (d->cleanup == NULL)		d->cleanup = default_cleanup;
+	if (d->standby == NULL)		d->standby = default_standby;
+	if (d->flushcache == NULL)	d->flushcache = default_flushcache;
 	if (d->do_request == NULL)	d->do_request = default_do_request;
 	if (d->end_request == NULL)	d->end_request = default_end_request;
 	if (d->ioctl == NULL)		d->ioctl = default_ioctl;
@@ -3696,10 +3694,6 @@
 EXPORT_SYMBOL(ide_register_subdriver);
 EXPORT_SYMBOL(ide_unregister_subdriver);
 EXPORT_SYMBOL(ide_replace_subdriver);
-EXPORT_SYMBOL(ide_input_data);
-EXPORT_SYMBOL(ide_output_data);
-EXPORT_SYMBOL(atapi_input_bytes);
-EXPORT_SYMBOL(atapi_output_bytes);
 EXPORT_SYMBOL(ide_set_handler);
 EXPORT_SYMBOL(ide_dump_status);
 EXPORT_SYMBOL(ide_error);
@@ -3724,6 +3718,8 @@
 EXPORT_SYMBOL(ide_remove_proc_entries);
 EXPORT_SYMBOL(proc_ide_read_geometry);
 EXPORT_SYMBOL(create_proc_ide_interfaces);
+EXPORT_SYMBOL(recreate_proc_ide_device);
+EXPORT_SYMBOL(destroy_proc_ide_device);
 #endif
 EXPORT_SYMBOL(ide_add_setting);
 EXPORT_SYMBOL(ide_remove_setting);
@@ -3738,6 +3734,54 @@
 
 EXPORT_SYMBOL(system_bus_clock);
 
+EXPORT_SYMBOL(ide_reinit_drive);
+
+static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
+{
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	int i, unit;
+
+	switch (event) {
+		case SYS_HALT:
+		case SYS_POWER_OFF:
+		case SYS_RESTART:
+			break;
+		default:
+			return NOTIFY_DONE;
+	}
+
+	printk("flushing ide devices: ");
+
+	for (i = 0; i < MAX_HWIFS; i++) {
+		hwif = &ide_hwifs[i];
+		if (!hwif->present)
+			continue;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			drive = &hwif->drives[unit];
+			if (!drive->present)
+				continue;
+
+			/* set the drive to standby */
+			printk("%s ", drive->name);
+			if (event != SYS_RESTART)
+				if (drive->driver != NULL && DRIVER(drive)->standby(drive))
+				continue;
+
+			if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+				continue;
+		}
+	}
+	printk("\n");
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ide_notifier = {
+	ide_notify_reboot,
+	NULL,
+	5
+};
+
 /*
  * This is gets invoked once during initialization, to set *everything* up
  */
@@ -3765,6 +3809,7 @@
 			ide_geninit(hwif);
 	}
 
+	register_reboot_notifier(&ide_notifier);
 	return 0;
 }
 
@@ -3797,6 +3842,7 @@
 {
 	int index;
 
+	unregister_reboot_notifier(&ide_notifier);
 	for (index = 0; index < MAX_HWIFS; ++index) {
 		ide_unregister(index);
 #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c
--- v2.5.2/linux/drivers/ide/pdc202xx.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/pdc202xx.c	Tue Jan 15 11:27:30 2002
@@ -108,7 +108,7 @@
 	u32 bibma  = pci_resource_start(dev, 4);
 	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
 	u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
-	u8 hi = 0, lo = 0, invalid_data_set = 0;
+	u8 hi = 0, lo = 0;
 
         /*
          * at that point bibma+0x2 et bibma+0xa are byte registers
@@ -132,11 +132,6 @@
 	pci_read_config_dword(dev, 0x6c, &reg6ch);
 
 	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-			p += sprintf(p, "\n                                PDC20268 TX2 Chipset.\n");
-			invalid_data_set = 1;
-			break;
 		case PCI_DEVICE_ID_PROMISE_20267:
 			p += sprintf(p, "\n                                PDC20267 Chipset.\n");
 			break;
@@ -180,45 +175,77 @@
 	p += sprintf(p, "           Mode %s                      Mode %s\n",
 		(sc1a & 0x01) ? "MASTER" : "PCI   ",
 		(sc1b & 0x01) ? "MASTER" : "PCI   ");
-	if (!(invalid_data_set))
-		p += sprintf(p, "                %s                     %s\n",
-			(sc1d & 0x08) ? "Error       " :
-			((sc1d & 0x05) == 0x05) ? "Not My INTR " :
-			(sc1d & 0x04) ? "Interrupting" :
-			(sc1d & 0x02) ? "FIFO Full   " :
-			(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
-			(sc1d & 0x80) ? "Error       " :
-			((sc1d & 0x50) == 0x50) ? "Not My INTR " :
-			(sc1d & 0x40) ? "Interrupting" :
-			(sc1d & 0x20) ? "FIFO Full   " :
-			(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
+	p += sprintf(p, "                %s                     %s\n",
+		(sc1d & 0x08) ? "Error       " :
+		((sc1d & 0x05) == 0x05) ? "Not My INTR " :
+		(sc1d & 0x04) ? "Interrupting" :
+		(sc1d & 0x02) ? "FIFO Full   " :
+		(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
+		(sc1d & 0x80) ? "Error       " :
+		((sc1d & 0x50) == 0x50) ? "Not My INTR " :
+		(sc1d & 0x40) ? "Interrupting" :
+		(sc1d & 0x20) ? "FIFO Full   " :
+		(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
 	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
 	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
 		(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
-	if (!(invalid_data_set))
-		p += sprintf(p, "DMA Mode:       %s           %s          %s            %s\n",
-			pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
-			pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
-			pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
-			pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
-	if (!(invalid_data_set))
-		p += sprintf(p, "PIO Mode:       %s            %s           %s            %s\n",
-			pdc202xx_pio_verbose(reg60h),
-			pdc202xx_pio_verbose(reg64h),
-			pdc202xx_pio_verbose(reg68h),
-			pdc202xx_pio_verbose(reg6ch));
+	p += sprintf(p, "DMA Mode:       %s           %s          %s            %s\n",
+		pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
+		pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
+	p += sprintf(p, "PIO Mode:       %s            %s           %s            %s\n",
+		pdc202xx_pio_verbose(reg60h),
+		pdc202xx_pio_verbose(reg64h),
+		pdc202xx_pio_verbose(reg68h),
+		pdc202xx_pio_verbose(reg6ch));
 #if 0
 	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
 #endif
-	if (invalid_data_set)
-		p += sprintf(p, "--------------- Cannot Decode HOST ---------------\n");
+	return (char *)p;
+}
+
+static char * pdc202xx_info_new (char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+//	u32 bibma = pci_resource_start(dev, 4);
+
+//	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+//	u16 reg50h = 0, word88 = 0;
+//	int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+			p += sprintf(p, "\n                                PDC20275 Chipset.\n");
+			break;
+		case PCI_DEVICE_ID_PROMISE_20269:
+			p += sprintf(p, "\n                                PDC20269 TX2 Chipset.\n");
+			break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			p += sprintf(p, "\n                                PDC20268 TX2 Chipset.\n");
+			break;
+default:
+			p += sprintf(p, "\n                                PDC202XX Chipset.\n");
+			break;
+	}
 	return (char *)p;
 }
 
 static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
 {
 	char *p = buffer;
-	p = pdc202xx_info(buffer, bmide_dev);
+	switch(bmide_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			p = pdc202xx_info_new(buffer, bmide_dev);
+			break;
+		default:
+			p = pdc202xx_info(buffer, bmide_dev);
+			break;
+	}
 	return p-buffer;	/* => must be less than 4k! */
 }
 #endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -387,9 +414,6 @@
 
 	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))	return -1;
 
-	if (dev->device == PCI_DEVICE_ID_PROMISE_20268)
-		goto skip_register_hell;
-
 	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	pci_read_config_byte(dev, (drive_pci), &AP);
 	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
@@ -432,6 +456,7 @@
 
 	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
+		/* case XFER_UDMA_6: */
 		case XFER_UDMA_5:
 		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;	/* speed 8 == UDMA mode 4 */
 		case XFER_UDMA_3:	TB = 0x40; TC = 0x02; break;	/* speed 7 == UDMA mode 3 */
@@ -477,8 +502,6 @@
 	decode_registers(REG_D, DP);
 #endif /* PDC202XX_DECODE_REGISTER_INFO */
 
-skip_register_hell:
-
 	if (!drive->init_speed)
 		drive->init_speed = speed;
 	err = ide_config_drive_speed(drive, speed);
@@ -494,6 +517,159 @@
 	return err;
 }
 
+static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	unsigned long indexreg	= (hwif->dma_base + 1);
+	unsigned long datareg	= (hwif->dma_base + 3);
+#else
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long indexreg	= high_16 + (hwif->channel ? 0x09 : 0x01);
+	unsigned long datareg	= (indexreg + 2);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	byte thold		= 0x10;
+	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
+
+	int                     err;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (speed == XFER_UDMA_2) {
+		OUT_BYTE((thold + adj), indexreg);
+		OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg);
+	}
+	switch (speed) {
+		case XFER_UDMA_7:
+			speed = XFER_UDMA_6;
+		case XFER_UDMA_6:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x01, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcb, datareg);
+			break;
+		case XFER_UDMA_5:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x02, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcb, datareg);
+			break;
+		case XFER_UDMA_4:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x03, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcd, datareg);
+			break;
+		case XFER_UDMA_3:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x05, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcd, datareg);
+			break;
+		case XFER_UDMA_2:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x2a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x07, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcd, datareg);
+			break;
+		case XFER_UDMA_1:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x3a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x0a, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xd0, datareg);
+			break;
+		case XFER_UDMA_0:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x4a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x0f, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xd5, datareg);
+			break;
+		case XFER_MW_DMA_2:
+			OUT_BYTE((0x0e + adj), indexreg);
+			OUT_BYTE(0x69, datareg);
+			OUT_BYTE((0x0f + adj), indexreg);
+			OUT_BYTE(0x25, datareg);
+			break;
+		case XFER_MW_DMA_1:
+			OUT_BYTE((0x0e + adj), indexreg);
+			OUT_BYTE(0x6b, datareg);
+			OUT_BYTE((0x0f+ adj), indexreg);
+			OUT_BYTE(0x27, datareg);
+			break;
+		case XFER_MW_DMA_0:
+			OUT_BYTE((0x0e + adj), indexreg);
+			OUT_BYTE(0xdf, datareg);
+			OUT_BYTE((0x0f + adj), indexreg);
+			OUT_BYTE(0x5f, datareg);
+			break;
+#else
+	switch (speed) {
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x23, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x09, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0x25, datareg);
+			break;
+		case XFER_PIO_3:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x27, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x0d, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0x35, datareg);
+			break;
+		case XFER_PIO_2:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x23, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x26, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0x64, datareg);
+			break;
+		case XFER_PIO_1:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x46, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x29, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0xa4, datareg);
+			break;
+		case XFER_PIO_0:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0xfb, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x2b, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0xac, datareg);
+			break;
+		default:
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	err = ide_config_drive_speed(drive, speed);
+	drive->current_speed = speed;
+
+	return err;
+}
+
 /*   0    1    2    3    4    5    6   7   8
  * 960, 480, 390, 300, 240, 180, 120, 90, 60
  *           180, 150, 120,  90,  60
@@ -524,18 +700,75 @@
 	struct pci_dev *dev	= hwif->pci_dev;
 	unsigned long high_16   = pci_resource_start(dev, 4);
 	unsigned long dma_base  = hwif->dma_base;
+	unsigned long indexreg	= dma_base + 1;
+	unsigned long datareg	= dma_base + 3;
+	byte iordy		= 0x13;
+	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
+	byte cable		= 0;
+	byte jumpbit		= 0;
 	byte unit		= (drive->select.b.unit & 0x01);
-
 	unsigned int		drive_conf;
-	byte			drive_pci;
+	byte			drive_pci = 0;
 	byte			test1, test2, speed = -1;
 	byte			AP;
 	unsigned short		EP;
-	byte CLKSPD		= IN_BYTE(high_16 + 0x11);
-	byte udma_33		= ultra ? (inb(high_16 + 0x001f) & 1) : 0;
+	byte CLKSPD		= 0;
+	byte udma_33		= ultra;
+//	byte udma_33		= ultra ? (IN_BYTE(high_16 + 0x001f) & 1) : 0;
 	byte udma_66		= ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0;
-	byte udma_100		= (((dev->device == PCI_DEVICE_ID_PROMISE_20265) || (dev->device == PCI_DEVICE_ID_PROMISE_20267) || (dev->device == PCI_DEVICE_ID_PROMISE_20268)) && udma_66) ? 1 : 0;
+	byte udma_100		= 0;
+	byte udma_133		= 0;
+	byte mask		= hwif->channel ? 0x08 : 0x02;
+	unsigned short c_mask	= hwif->channel ? (1<<11) : (1<<10);
+
+	byte ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+	byte ultra_100		= ((id->dma_ultra & 0x0020) ||
+				   (ultra_66)) ? 1 : 0;
+	byte ultra_133		= ((id->dma_ultra & 0x0040) ||
+				   (ultra_100)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+			udma_133 = (udma_66) ? 1 : 0;
+			udma_100 = (udma_66) ? 1 : 0;
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			udma_100 = 1;
+			udma_66 = 1;
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+			udma_100 = (udma_66) ? 1 : 0;
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			udma_100 = (udma_66) ? 1 : 0;
+			pci_read_config_word(dev, 0x50, &EP);
+			cable = (EP & c_mask);
+			jumpbit = 0;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20262:
+			pci_read_config_word(dev, 0x50, &EP);
+			cable = (EP & c_mask);
+			jumpbit = 0;
+			break;
+		default:
+			udma_100 = 0; udma_133 = 0; cable = 1; jumpbit = 0;
+			break;
+	}
 
+	if (!jumpbit)
+		CLKSPD = IN_BYTE(high_16 + 0x11);
 	/*
 	 * Set the control register to use the 66Mhz system
 	 * clock for UDMA 3/4 mode operation. If one drive on
@@ -549,47 +782,52 @@
 	 * parameters.
 	 */
 
-	byte mask		= hwif->channel ? 0x08 : 0x02;
-	unsigned short c_mask	= hwif->channel ? (1<<11) : (1<<10);
-	byte ultra_66		= ((id->dma_ultra & 0x0010) ||
-				   (id->dma_ultra & 0x0008)) ? 1 : 0;
-	byte ultra_100		= ((id->dma_ultra & 0x0020) ||
-				   (id->dma_ultra & 0x0010) ||
-				   (id->dma_ultra & 0x0008)) ? 1 : 0;
-
-	if (dev->device == PCI_DEVICE_ID_PROMISE_20268)
-		goto jump_pci_mucking;
-
-	pci_read_config_word(dev, 0x50, &EP);
-
-	if (((ultra_66) || (ultra_100)) && (EP & c_mask)) {
+	if (((ultra_66) || (ultra_100) || (ultra_133)) && (cable)) {
 #ifdef DEBUG
 		printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary");
 		printk("         Switching to Ultra33 mode.\n");
 #endif /* DEBUG */
 		/* Primary   : zero out second bit */
 		/* Secondary : zero out fourth bit */
-		OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+		if (!jumpbit)
+			OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk("%s reduced to Ultra33 mode.\n", drive->name);
+		udma_66 = 0; udma_100 = 0; udma_133 = 0;
 	} else {
-		if ((ultra_66) || (ultra_100)) {
+		if ((ultra_66) || (ultra_100) || (ultra_133)) {
 			/*
 			 * check to make sure drive on same channel
 			 * is u66 capable
 			 */
 			if (hwif->drives[!(drive->dn%2)].id) {
-				if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0020) ||
+				if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0040) ||
+				    (hwif->drives[!(drive->dn%2)].id->dma_ultra
+& 0x0020) ||
 				    (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) ||
 				    (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) {
-					OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+					if (!jumpbit)
+						OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
 				} else {
-					OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+					if (!jumpbit)
+						OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
 				}
 			} else { /* udma4 drive by itself */
-				OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+				if (!jumpbit)
+					OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
 			}
 		}
 	}
 
+	if (jumpbit) {
+		if (drive->media != ide_disk)	return ide_dma_off_quietly;
+		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
+			OUT_BYTE((iordy + adj), indexreg);
+			OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
+		}
+		goto jumpbit_is_set;
+	}
+
 	switch(drive->dn) {
 		case 0:	drive_pci = 0x60;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
@@ -640,31 +878,33 @@
 	if (drive->media == ide_disk)	/* PREFETCH_EN */
 		pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
 
-jump_pci_mucking:
+jumpbit_is_set:
 
-	if ((id->dma_ultra & 0x0020) && (udma_100))	speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010) && (udma_66))	speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008) && (udma_66))	speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004) && (udma_33))	speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002) && (udma_33))	speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001) && (udma_33))	speed = XFER_UDMA_0;
+	if ((id->dma_ultra & 0x0040)&&(udma_133))	speed = XFER_UDMA_6;
+	else if ((id->dma_ultra & 0x0020)&&(udma_100))	speed = XFER_UDMA_5;
+	else if ((id->dma_ultra & 0x0010)&&(udma_66))	speed = XFER_UDMA_4;
+	else if ((id->dma_ultra & 0x0008)&&(udma_66))	speed = XFER_UDMA_3;
+	else if ((id->dma_ultra & 0x0004)&&(udma_33))	speed = XFER_UDMA_2;
+	else if ((id->dma_ultra & 0x0002)&&(udma_33))	speed = XFER_UDMA_1;
+	else if ((id->dma_ultra & 0x0001)&&(udma_33))	speed = XFER_UDMA_0;
 	else if (id->dma_mword & 0x0004)		speed = XFER_MW_DMA_2;
 	else if (id->dma_mword & 0x0002)		speed = XFER_MW_DMA_1;
 	else if (id->dma_mword & 0x0001)		speed = XFER_MW_DMA_0;
-	else if (id->dma_1word & 0x0004)		speed = XFER_SW_DMA_2;
-	else if (id->dma_1word & 0x0002)		speed = XFER_SW_DMA_1;
-	else if (id->dma_1word & 0x0001)		speed = XFER_SW_DMA_0;
+	else if ((id->dma_1word & 0x0004)&&(!jumpbit))	speed = XFER_SW_DMA_2;
+	else if ((id->dma_1word & 0x0002)&&(!jumpbit))	speed = XFER_SW_DMA_1;
+	else if ((id->dma_1word & 0x0001)&&(!jumpbit))	speed = XFER_SW_DMA_0;
 	else {
 		/* restore original pci-config space */
-		if (dev->device != PCI_DEVICE_ID_PROMISE_20268)
+		if (!jumpbit)
 			pci_write_config_dword(dev, drive_pci, drive_conf);
 		return ide_dma_off_quietly;
 	}
 
 	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) pdc202xx_tune_chipset(drive, speed);
+	(void) hwif->speedproc(drive, speed);
 
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+	return ((int)	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
 			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
 			((id->dma_mword >> 8) & 7) ? ide_dma_on : 
 			((id->dma_1word >> 8) & 7) ? ide_dma_on :
@@ -685,7 +925,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x007F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive, 1);
 				if ((id->field_valid & 2) &&
@@ -732,16 +972,65 @@
  */
 int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	byte dma_stat = 0, sc1d = 0;
-	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
-	unsigned long dma_base	= HWIF(drive)->dma_base;
+	byte dma_stat		= 0;
+	byte sc1d		= 0;
+	byte newchip		= 0;
+	byte clock		= 0;
+	byte hardware48hack	= 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x00);
+	unsigned long dma_base	= hwif->dma_base;
+
+	switch (dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			newchip = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			hardware48hack = 1;
+			clock = IN_BYTE(high_16 + 0x11);
+		default:
+			break;
+	}
 
 	switch (func) {
 		case ide_dma_check:
 			return config_drive_xfer_rate(drive);
+		case ide_dma_begin:
+			/* Note that this is done *after* the cmd has
+			 * been issued to the drive, as per the BM-IDE spec.
+			 * The Promise Ultra33 doesn't work correctly when
+			 * we do this part before issuing the drive cmd.
+			 */
+			if ((drive->addressing) && (hardware48hack)) {
+				struct request *rq = HWGROUP(drive)->rq;
+				unsigned long word_count = 0;
+
+				outb(clock|(hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
+				word_count = (rq->nr_sectors << 8);
+				word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000;
+				outl(word_count, atapi_reg);
+			}
+			break;
+		case ide_dma_end:
+			if ((drive->addressing) && (hardware48hack)) {
+				outl(0, atapi_reg);	/* zero out extra */
+				clock = IN_BYTE(high_16 + 0x11);
+				OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
+			}
+			break;
 		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
-			sc1d = inb(high_16 + 0x001d);
+			dma_stat = IN_BYTE(dma_base+2);
+			if (newchip)
+				return (dma_stat & 4) == 4;
+
+			sc1d = IN_BYTE(high_16 + 0x001d);
 			if (HWIF(drive)->channel) {
 				if ((sc1d & 0x50) == 0x50) goto somebody_else;
 				else if ((sc1d & 0x40) == 0x40)
@@ -764,61 +1053,113 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
+void pdc202xx_new_reset (ide_drive_t *drive)
+{
+	OUT_BYTE(0x04,IDE_CONTROL_REG);
+	mdelay(1000);
+	OUT_BYTE(0x00,IDE_CONTROL_REG);
+	mdelay(1000);
+	printk("PDC202XX: %s channel reset.\n",
+		HWIF(drive)->channel ? "Secondary" : "Primary");
+}
+
 void pdc202xx_reset (ide_drive_t *drive)
 {
 	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
-	byte udma_speed_flag	= inb(high_16 + 0x001f);
+	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
 
 	OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
 	mdelay(100);
 	OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
 	mdelay(2000);		/* 2 seconds ?! */
+	printk("PDC202XX: %s channel reset.\n",
+		HWIF(drive)->channel ? "Secondary" : "Primary");
 }
 
-unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+static int pdc202xx_tristate (ide_drive_t * drive, int state)
 {
-	unsigned long high_16 = pci_resource_start(dev, 4);
-	byte udma_speed_flag	= inb(high_16 + 0x001f);
-	byte primary_mode	= inb(high_16 + 0x001a);
-	byte secondary_mode	= inb(high_16 + 0x001b);
-
-	if ((dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
-	    (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
-	    (dev->device == PCI_DEVICE_ID_PROMISE_20267)) {
-		/*
-		 * software reset -  this is required because the bios
-		 * will set UDMA timing on if the hdd supports it. The
-		 * user may want to turn udma off. A bug in the pdc20262
-		 * is that it cannot handle a downgrade in timing from UDMA
-		 * to DMA. Disk accesses after issuing a set feature command
-		 * will result in errors. A software reset leaves the timing
-		 * registers intact, but resets the drives.
-		 */
-
-		OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
-		mdelay(100);
-		OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
-		mdelay(2000);	/* 2 seconds ?! */
+#if 0
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+	byte sc1f		= inb(high_16 + 0x001f);
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	if (state) {
+		outb(sc1f | 0x08, high_16 + 0x001f);
+	} else {
+		outb(sc1f & ~0x08, high_16 + 0x001f);
 	}
+#endif
+	return 0;
+}
+
+unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
+{
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
+	byte primary_mode	= IN_BYTE(high_16 + 0x001a);
+	byte secondary_mode	= IN_BYTE(high_16 + 0x001b);
+	byte newchip		= 0;
 
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
 		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
 		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
 	}
 
-	if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
-		byte irq = 0, irq2 = 0;
-		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-		pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);	/* 0xbc */
-		if ((irq != irq2) &&
-		    (dev->device != PCI_DEVICE_ID_PROMISE_20265) &&
-		    (dev->device != PCI_DEVICE_ID_PROMISE_20267) &&
-		    (dev->device != PCI_DEVICE_ID_PROMISE_20268)) {
-			pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq);	/* 0xbc */
-			printk("%s: pci-config space interrupt mirror fixed.\n", name);
-		}
+	switch (dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			newchip = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+			mdelay(100);
+			OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
+			mdelay(2000);   /* 2 seconds ?! */
+			break;
+		case PCI_DEVICE_ID_PROMISE_20262:
+			/*
+			 * software reset -  this is required because the bios
+			 * will set UDMA timing on if the hdd supports it. The
+			 * user may want to turn udma off. A bug in the pdc20262
+			 * is that it cannot handle a downgrade in timing from
+			 * UDMA to DMA. Disk accesses after issuing a set
+			 * feature command will result in errors. A software
+			 * reset leaves the timing registers intact,
+			 * but resets the drives.
+			 */
+			OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+			mdelay(100);
+			OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
+			mdelay(2000);	/* 2 seconds ?! */
+		default:
+			if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+				byte irq = 0, irq2 = 0;
+				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);	/* 0xbc */
+				if (irq != irq2) {
+					pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq);	/* 0xbc */
+					printk("%s: pci-config space interrupt mirror fixed.\n", name);
+				}
+			}
+			break;
 	}
 
+	if (newchip)
+		goto fttk_tx_series;
+
 	printk("%s: (U)DMA Burst Bit %sABLED " \
 		"Primary %s Mode " \
 		"Secondary %s Mode.\n",
@@ -830,8 +1171,8 @@
 #ifdef CONFIG_PDC202XX_BURST
 	if (!(udma_speed_flag & 1)) {
 		printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
-		outb(udma_speed_flag|1, high_16 + 0x001f);
-		printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA");
+		OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f);
+		printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA");
 	}
 #endif /* CONFIG_PDC202XX_BURST */
 
@@ -839,18 +1180,20 @@
 	if (!(primary_mode & 1)) {
 		printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
 			name, primary_mode, (primary_mode|1));
-		outb(primary_mode|1, high_16 + 0x001a);
-		printk("%s\n", (inb(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
+		OUT_BYTE(primary_mode|1, high_16 + 0x001a);
+		printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
 	}
 
 	if (!(secondary_mode & 1)) {
 		printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ",
 			name, secondary_mode, (secondary_mode|1));
-		outb(secondary_mode|1, high_16 + 0x001b);
-		printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
+		OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
+		printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
 	}
 #endif /* CONFIG_PDC202XX_MASTER */
 
+fttk_tx_series:
+
 #if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!pdc202xx_proc) {
 		pdc202xx_proc = 1;
@@ -866,20 +1209,41 @@
 	unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
 	unsigned short CIS;
 
-	pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
-	return ((CIS & mask) ? 0 : 1);
+        switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04));
+		default:
+			pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+			return (!(CIS & mask));
+	}
 }
 
 void __init ide_init_pdc202xx (ide_hwif_t *hwif)
 {
-	hwif->tuneproc	= &pdc202xx_tune_drive;
-	hwif->speedproc	= &pdc202xx_tune_chipset;
-	hwif->quirkproc	= &pdc202xx_quirkproc;
-
-	if ((hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
-	    (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
-	    (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20267)) {
-		hwif->resetproc	= &pdc202xx_reset;
+	hwif->tuneproc  = &pdc202xx_tune_drive;
+	hwif->quirkproc = &pdc202xx_quirkproc;
+
+        switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			hwif->speedproc = &pdc202xx_new_tune_chipset;
+			hwif->resetproc = &pdc202xx_new_reset;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			hwif->busproc   = &pdc202xx_tristate;
+			hwif->resetproc	= &pdc202xx_reset;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			hwif->speedproc = &pdc202xx_tune_chipset;
+		default:
+			break;
 	}
 
 #undef CONFIG_PDC202XX_32_UNMASK
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c
--- v2.5.2/linux/drivers/ide/pdc4030.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ide/pdc4030.c	Tue Jan 15 11:44:21 2002
@@ -183,7 +183,7 @@
 			"%s: Failed Promise read config!\n",hwif->name);
 		return 0;
 	}
-	ide_input_data(drive,&ident,SECTOR_WORDS);
+	ata_input_data(drive, &ident, SECTOR_WORDS);
 	if (ident.id[1] != 'P' || ident.id[0] != 'T') {
 		return 0;
 	}
@@ -300,8 +300,6 @@
 	}
 }
 
-
-
 /*
  * promise_read_intr() is the handler for disk read/multread interrupts
  */
@@ -335,7 +333,7 @@
 		nsect = sectors_avail;
 	sectors_avail -= nsect;
 	to = ide_map_buffer(rq, &flags);
-	idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
+	ata_input_data(drive, to, nsect * SECTOR_WORDS);
 #ifdef DEBUG_READ
 	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
 	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
@@ -393,7 +391,6 @@
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	struct request *rq = hwgroup->rq;
-	int i;
 
 	if (GET_STAT() & BUSY_STAT) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
@@ -415,6 +412,61 @@
 }
 
 /*
+ * promise_multwrite() transfers a block of up to mcount sectors of data
+ * to a drive as part of a disk multiple-sector write operation.
+ *
+ * Returns 0 on success.
+ *
+ * Note that we may be called from two contexts - the do_rw_disk context
+ * and IRQ context. The IRQ can happen any time after we've output the
+ * full "mcount" number of sectors, so we must make sure we update the
+ * state _before_ we output the final part of the data!
+ */
+int promise_multwrite (ide_drive_t *drive, unsigned int mcount)
+{
+	ide_hwgroup_t   *hwgroup= HWGROUP(drive);
+	struct request  *rq = &hwgroup->wrq;
+
+	do {
+		char *buffer;
+		int nsect = rq->current_nr_sectors;
+		unsigned long flags;
+
+		if (nsect > mcount)
+			nsect = mcount;
+		mcount -= nsect;
+
+		buffer = ide_map_buffer(rq, &flags);
+		rq->sector += nsect;
+		rq->nr_sectors -= nsect;
+		rq->current_nr_sectors -= nsect;
+
+		/* Do we move to the next bh after this? */
+		if (!rq->current_nr_sectors) {
+			struct bio *bio = rq->bio->bi_next;
+
+			/* end early early we ran out of requests */
+			if (!bio) {
+				mcount = 0;
+			} else {
+				rq->bio = bio;
+				rq->current_nr_sectors = bio_sectors(bio);
+				rq->hard_cur_sectors = rq->current_nr_sectors;
+			}
+		}
+
+		/*
+		 * Ok, we're all setup for the interrupt
+		 * re-entering us on the last transfer.
+		 */
+		taskfile_output_data(drive, buffer, nsect<<7);
+		ide_unmap_buffer(buffer, &flags);
+	} while (mcount);
+
+	return 0;
+}
+
+/*
  * promise_write_pollfunc() is the handler for disk write completion polling.
  */
 static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
@@ -434,7 +486,7 @@
 	/*
 	 * Now write out last 4 sectors and poll for not BUSY
 	 */
-	ide_multwrite(drive, 4);
+	promise_multwrite(drive, 4);
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
 #ifdef DEBUG_WRITE
@@ -467,7 +519,7 @@
 	 * the polling strategy as defined above.
 	 */
 	if (rq->nr_sectors > 4) {
-		if (ide_multwrite(drive, rq->nr_sectors - 4))
+		if (promise_multwrite(drive, rq->nr_sectors - 4))
 			return ide_stopped;
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
@@ -477,7 +529,7 @@
 	 * There are 4 or fewer sectors to transfer, do them all in one go
 	 * and wait for NOT BUSY.
 	 */
-		if (ide_multwrite(drive, rq->nr_sectors))
+		if (promise_multwrite(drive, rq->nr_sectors))
 			return ide_stopped;
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
@@ -494,11 +546,28 @@
  * already set up. It issues a READ or WRITE command to the Promise
  * controller, assuming LBA has been used to set up the block number.
  */
-ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
 {
+	struct request *rq	= HWGROUP(drive)->rq;
+	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+	ide_startstop_t startstop;
 	unsigned long timeout;
 	byte stat;
 
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
+	SELECT_MASK(HWIF(drive), drive, 0);
+
+	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+	OUT_BYTE(taskfile->device_head, IDE_SELECT_REG);
+	OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+
 /* Check that it's a regular command. If not, bomb out early. */
 	if (!(rq->flags & REQ_CMD)) {
 		blk_dump_rq_flags(rq, "pdc4030 bad flags");
@@ -540,9 +609,8 @@
 		printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n",
 			drive->name);
 		return ide_stopped;
-		break;
 
-	case WRITE:
+	case WRITE: {
 		ide_startstop_t startstop;
 		OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
 /*
@@ -561,11 +629,40 @@
 			__cli();	/* local CPU only */
 		HWGROUP(drive)->wrq = *rq; /* scratchpad */
 		return promise_write(drive);
-		break;
+	}
 
 	default:
 		printk(KERN_ERR "pdc4030: command not READ or WRITE! Huh?\n");
 		ide_end_request(0, HWGROUP(drive));
-		break;
+		return ide_stopped;
 	}
 }
+
+ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	struct hd_drive_task_hdr taskfile;
+	ide_task_t		 args;
+
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+
+	taskfile.sector_count	= rq->nr_sectors;
+	taskfile.sector_number	= block;
+	taskfile.low_cylinder	= (block>>=8);
+	taskfile.high_cylinder	= (block>>=8);
+	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
+	taskfile.command	= (rq_data_dir(rq)==READ)?PROMISE_READ:PROMISE_WRITE;
+
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memcpy(args.hobRegister, NULL, sizeof(struct hd_drive_hob_hdr));
+	args.command_type	= ide_cmd_type_parser(&args);
+	args.prehandler		= NULL;
+	args.handler		= NULL;
+	args.posthandler	= NULL;
+	args.rq			= (struct request *) rq;
+	args.block		= block;
+	rq->special		= NULL;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_pdc4030_io(drive, &args);
+}
+
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/pdcadma.c linux/drivers/ide/pdcadma.c
--- v2.5.2/linux/drivers/ide/pdcadma.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/ide/pdcadma.c	Tue Jan 15 11:27:47 2002
@@ -0,0 +1,109 @@
+/*
+ * linux/drivers/ide/pdcadma.c		Version 0.01	June 21, 2001
+ *
+ * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+
+#undef DISPLAY_PDCADMA_TIMINGS
+
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int pdcadma_get_info(char *, char **, off_t, int);
+extern int (*pdcadma_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+
+	p += sprintf(p, "\n                                PDC ADMA %04X Chipset.\n", bmide_dev->device);
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte pdcadma_proc = 0;
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * pdcadma_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ */
+
+int pdcadma_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			func = ide_dma_off_quietly;
+		default:
+			break;
+	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+unsigned int __init pci_init_pdcadma (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!pdcadma_proc) {
+		pdcadma_proc = 1;
+		bmide_dev = dev;
+		pdcadma_display_info = &pdcadma_get_info;
+	}
+#endif /* DISPLAY_PDCADMA_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+unsigned int __init ata66_pdcadma (ide_hwif_t *hwif)
+{
+	return 1;
+}
+
+void __init ide_init_pdcadma (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->dma_base = 0;
+
+//	hwif->tuneproc = &pdcadma_tune_drive;
+//	hwif->speedproc = &pdcadma_tune_chipset;
+
+//	if (hwif->dma_base) {
+//		hwif->dmaproc = &pdcadma_dmaproc;
+//		hwif->autodma = 1;
+//	}
+}
+
+void __init ide_dmacapable_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
+{
+//	ide_setup_dma(hwif, dmabase, 8);
+}
+
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/piix.c linux/drivers/ide/piix.c
--- v2.5.2/linux/drivers/ide/piix.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/piix.c	Tue Jan 15 11:27:47 2002
@@ -402,7 +402,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x003F) {
 				/* Force if Capable UltraDMA */
 				dma_func = piix_config_drive_for_dma(drive);
 				if ((id->field_valid & 2) &&
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/qd65xx.c linux/drivers/ide/qd65xx.c
--- v2.5.2/linux/drivers/ide/qd65xx.c	Fri Sep  7 09:28:38 2001
+++ linux/drivers/ide/qd65xx.c	Tue Jan 15 11:27:47 2002
@@ -1,14 +1,15 @@
 /*
- *  linux/drivers/ide/qd65xx.c		Version 0.06	Aug 3, 2000
+ *  linux/drivers/ide/qd65xx.c		Version 0.07	Sep 30, 2001
  *
- *  Copyright (C) 1996-2000  Linus Torvalds & author (see below)
+ *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
  */
 
 /*
  *  Version 0.03	Cleaned auto-tune, added probe
  *  Version 0.04	Added second channel tuning
  *  Version 0.05	Enhanced tuning ; added qd6500 support
- *  Version 0.06	added dos driver's list
+ *  Version 0.06	Added dos driver's list
+ *  Version 0.07	Second channel bug fix 
  *
  * QDI QD6500/QD6580 EIDE controller fast support
  *
@@ -67,6 +68,7 @@
  *        qd6500: 1100
  *        qd6580: either 1010 or 0101
  *
+ *
  * base+0x02: Timer2 (qd6580 only)
  *
  *
@@ -137,12 +139,12 @@
 {
 	byte active_cycle,recovery_cycle;
 
-	if (system_bus_clock()<=33) {
-		active_cycle =   9  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 9);
-		recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15);
+	if (ide_system_bus_speed()<=33) {
+		active_cycle =   9  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 9);
+		recovery_cycle = 15 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 0, 15);
 	} else {
-		active_cycle =   8  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 1, 8);
-		recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18);
+		active_cycle =   8  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 1, 8);
+		recovery_cycle = 18 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 3, 18);
 	}
 
 	return((recovery_cycle<<4) | 0x08 | active_cycle);
@@ -156,8 +158,8 @@
 
 static byte qd6580_compute_timing (int active_time, int recovery_time)
 {
-	byte active_cycle   = 17-IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 17);
-	byte recovery_cycle = 15-IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15);
+	byte active_cycle   = 17-IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 17);
+	byte recovery_cycle = 15-IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 2, 15);
 
 	return((recovery_cycle<<4) | active_cycle);
 }
@@ -427,7 +429,8 @@
 				ide_hwifs[i].tuneproc = &qd6580_tune_drive;
 
 				for (j=0;j<2;j++) {
-					ide_hwifs[i].drives[j].drive_data = QD6580_DEF_DATA;
+					ide_hwifs[i].drives[j].drive_data =
+					       i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
 					ide_hwifs[i].drives[j].io_32bit = 1;
 				}
 			}
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/qd65xx.h linux/drivers/ide/qd65xx.h
--- v2.5.2/linux/drivers/ide/qd65xx.h	Fri Sep  7 09:28:38 2001
+++ linux/drivers/ide/qd65xx.h	Tue Jan 15 11:27:47 2002
@@ -29,7 +29,7 @@
 
 #define QD_CONTR_SEC_DISABLED	0x01
 
-#define QD_ID3			(config & QD_CONFIG_ID3)
+#define QD_ID3			((config & QD_CONFIG_ID3)!=0)
 
 #define QD_CONFIG(hwif)		((hwif)->config_data & 0x00ff)
 #define QD_CONTROL(hwif)	(((hwif)->config_data & 0xff00) >> 8)
@@ -39,6 +39,7 @@
 
 #define QD6500_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
 #define QD6580_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+#define QD6580_DEF_DATA2	((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
 #define QD_DEF_CONTR		(0x40 | ((control & 0x02) ? 0x9f : 0x1f))
 
 #define QD_TESTVAL		0x19	/* safe value */
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/serverworks.c linux/drivers/ide/serverworks.c
--- v2.5.2/linux/drivers/ide/serverworks.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/serverworks.c	Tue Jan 15 11:27:47 2002
@@ -1,16 +1,26 @@
 /*
- * linux/drivers/ide/serverworks.c		Version 0.2	17 Oct 2000
+ * linux/drivers/ide/serverworks.c		Version 0.3	26 Oct 2001
  *
- *  Copyright (C) 2000 Cobalt Networks, Inc. <asun@cobalt.com>
- *  May be copied or modified under the terms of the GNU General Public License
+ * May be copied or modified under the terms of the GNU General Public License
  *
- *  interface borrowed from alim15x3.c:
- *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
- *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions copyright (c) 2001 Sun Microsystems
  *
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
  *
- *  IDE support for the ServerWorks OSB4 IDE chipset
+ * RCC/ServerWorks IDE driver for Linux
+ *
+ *   OSB4: `Open South Bridge' IDE Interface (fn 1)
+ *         supports UDMA mode 2 (33 MB/s)
+ *
+ *   CSB5: `Champion South Bridge' IDE Interface (fn 1)
+ *         all revisions support UDMA mode 4 (66 MB/s)
+ *         revision A2.0 and up support UDMA mode 5 (100 MB/s)
+ *
+ *         *** The CSB5 does not provide ANY register ***
+ *         *** to detect 80-conductor cable presence. ***
+ *
  *
  * here's the default lspci:
  *
@@ -83,15 +93,15 @@
 
 #include "ide_modes.h"
 
-#define SVWKS_DEBUG_DRIVE_INFO		0
-
-#define DISPLAY_SVWKS_TIMINGS
+#define DISPLAY_SVWKS_TIMINGS	1
+#undef SVWKS_DEBUG_DRIVE_INFO
 
 #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
 static struct pci_dev *bmide_dev;
+static byte svwks_revision = 0;
 
 static int svwks_get_info(char *, char **, off_t, int);
 extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
@@ -103,7 +113,7 @@
 	u32 bibma = pci_resource_start(bmide_dev, 4);
 	u32 reg40, reg44;
 	u16 reg48, reg56;
-	u8  c0 = 0, c1 = 0, reg54;
+	u8  reg54, c0=0, c1=0;
 
 	pci_read_config_dword(bmide_dev, 0x40, &reg40);
 	pci_read_config_dword(bmide_dev, 0x44, &reg44);
@@ -120,20 +130,23 @@
 
 	switch(bmide_dev->device) {
 		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-			p += sprintf(p, "\n                                ServerWorks CSB5 Chipset.\n");
+			p += sprintf(p, "\n                            "
+				     "ServerWorks CSB5 Chipset (rev %02x)\n",
+				     svwks_revision);
 			break;
-		case PCI_DEVICE_ID_SERVERWORKS_OSB4:
-			p += sprintf(p, "\n                                ServerWorks OSB4 Chipset.\n");
+		case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
+			p += sprintf(p, "\n                            "
+				     "ServerWorks OSB4 Chipset (rev %02x)\n",
+				     svwks_revision);
 			break;
 		default:
-			p += sprintf(p, "\n                                ServerWorks 0x%04x Chipset.\n", bmide_dev->device);
+			p += sprintf(p, "\n                            "
+				     "ServerWorks %04x Chipset (rev %02x)\n",
+				     bmide_dev->device, svwks_revision);
 			break;
 	}
 
 	p += sprintf(p, "------------------------------- General Status ---------------------------------\n");
-#if 0
-	p += sprintf(p, "                                     : %s\n", "str");
-#endif
 	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
 	p += sprintf(p, "                %sabled                         %sabled\n",
 			(c0&0x80) ? "dis" : " en",
@@ -191,11 +204,7 @@
 				((reg44&0x00210000)==0x00210000)?"1":
 				((reg44&0x00770000)==0x00770000)?"0":
 				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
-#if 0
-	if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-		p += sprintf(p, "PIO  enabled:   %s                %s               %s                 %s\n",
-	if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4)
-#endif
+
 		p += sprintf(p, "PIO  enabled:   %s                %s               %s                 %s\n",
 			((reg40&0x00002000)==0x00002000)?"4":
 				((reg40&0x00002200)==0x00002200)?"3":
@@ -221,7 +230,7 @@
 }
 #endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-static byte svwks_revision = 0;
+#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
 
 byte svwks_proc = 0;
 
@@ -292,6 +301,7 @@
 			pio_timing |= pio_modes[speed - XFER_PIO_0];
 			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
 			break;
+
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
@@ -307,9 +317,9 @@
 		case XFER_UDMA_2:
 		case XFER_UDMA_1:
 		case XFER_UDMA_0:
-			pio_timing |= pio_modes[pio];
-			csb5_pio   |= (pio << (4*drive->dn));
-			dma_timing |= dma_modes[2];
+			pio_timing   |= pio_modes[pio];
+			csb5_pio     |= (pio << (4*drive->dn));
+			dma_timing   |= dma_modes[2];
 			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
 			ultra_enable |= (0x01 << drive->dn);
 #endif
@@ -322,9 +332,9 @@
 		drive->name, ultra_timing, dma_timing, pio_timing);
 #endif
 
-#if OSB4_DEBUG_DRIVE_INFO
+#if SVWKS_DEBUG_DRIVE_INFO
 	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* OSB4_DEBUG_DRIVE_INFO */
+#endif /* SVWKS_DEBUG_DRIVE_INFO */
 
 	if (!drive->init_speed)
 		drive->init_speed = speed;
@@ -338,11 +348,10 @@
 	pci_write_config_byte(dev, drive_pci3, ultra_timing);
 	pci_write_config_byte(dev, 0x54, ultra_enable);
 	
-	if (speed > XFER_PIO_4) {
+	if (speed > XFER_PIO_4)
 		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	} else {
+	else
 		outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	err = ide_config_drive_speed(drive, speed);
@@ -354,25 +363,24 @@
 {
 	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
 	unsigned short xfer_pio = drive->id->eide_pio_modes;
-	byte			timing, speed, pio;
+	byte timing, speed, pio;
 
 	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
 
 	if (xfer_pio> 4)
 		xfer_pio = 0;
 
-	if (drive->id->eide_pio_iordy > 0) {
+	if (drive->id->eide_pio_iordy > 0)
 		for (xfer_pio = 5;
 			xfer_pio>0 &&
 			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
 			xfer_pio--);
-	} else {
+	else
 		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
 			   (drive->id->eide_pio_modes & 2) ? 0x04 :
 			   (drive->id->eide_pio_modes & 1) ? 0x03 :
 			   (drive->id->tPIO & 2) ? 0x02 :
 			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
-	}
 
 	timing = (xfer_pio >= pio) ? xfer_pio : pio;
 
@@ -407,12 +415,10 @@
 {
 	struct hd_driveid *id	= drive->id;
 	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte			speed;
-
-	int ultra66		= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
-	/* need specs to figure out if osb4 is capable of ata/66/100 */
-	int ultra100		= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+	byte udma_66	= eighty_ninty_three(drive);
+	int ultra66	= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+	int ultra100 	= (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0;
+	byte speed;
 
 	if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
 		speed = XFER_UDMA_5;
@@ -458,7 +464,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x003F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive);
 				if ((id->field_valid & 2) &&
@@ -499,7 +505,41 @@
 	switch (func) {
 		case ide_dma_check:
 			return config_drive_xfer_rate(drive);
-		default :
+		case ide_dma_end:
+		{
+			ide_hwif_t *hwif		= HWIF(drive);
+			unsigned long dma_base		= hwif->dma_base;
+	
+			if(inb(dma_base+0x02)&1)
+			{
+#if 0		
+				int i;
+				printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n");
+				for(i=0;i<10;i++)
+				{
+					if(!(inb(dma_base+0x02)&1))
+					{
+						printk(KERN_ERR "OSB4 now finished.\n");
+						break;
+					}
+					udelay(5);
+				}
+#endif		
+				printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
+				printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
+				printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
+#if 0		
+				/* Panic might sys_sync -> death by corrupt disk */
+				panic("OSB4: continuing might cause disk corruption.\n");
+#else
+				printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
+				while(1)
+					cpu_relax();
+#endif				
+			}
+			/* and drop through */
+		}
+		default:
 			break;
 	}
 	/* Other cases are done by generic IDE-DMA code. */
@@ -509,30 +549,43 @@
 
 unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
 {
-	unsigned int reg64;
+	unsigned int reg;
+	byte btr;
 
+	/* save revision id to determine DMA capability */
 	pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
 
-	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
-		isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+	/* force Master Latency Timer value to 64 PCICLKs */
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
 
-		pci_read_config_dword(isa_dev, 0x64, &reg64);
-#ifdef DEBUG
-		printk("%s: reg64 == 0x%08x\n", name, reg64);
-#endif
+	/* OSB4 : South Bridge and IDE */
+	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+		isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+			  PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+		if (isa_dev) {
+			pci_read_config_dword(isa_dev, 0x64, &reg);
+			reg &= ~0x00002000; /* disable 600ns interrupt mask */
+			reg |=  0x00004000; /* enable UDMA/33 support */
+			pci_write_config_dword(isa_dev, 0x64, reg);
+		}
+	}
 
-//		reg64 &= ~0x0000A000;
-//#ifdef CONFIG_SMP
-//		reg64 |= 0x00008000;
-//#endif
-	/* Assume the APIC was set up properly by the BIOS for now . If it
-	   wasnt we need to do a fix up _way_ earlier. Bits 15,10,3 control
-	   APIC enable, routing and decode */
-	   
-		reg64 &= ~0x00002000;	
-		pci_write_config_dword(isa_dev, 0x64, reg64);
+	/* setup CSB5 : South Bridge and IDE */
+	else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) {
+		/* setup the UDMA Control register
+		 *
+		 * 1. clear bit 6 to enable DMA
+		 * 2. enable DMA modes with bits 0-1
+		 *      00 : legacy
+		 *      01 : udma2
+		 *      10 : udma2/udma4
+		 *      11 : udma2/udma4/udma5
+		 */
+		pci_read_config_byte(dev, 0x5A, &btr);
+		btr &= ~0x40;
+		btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+		pci_write_config_byte(dev, 0x5A, btr);
 	}
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
 
 #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!svwks_proc) {
@@ -551,26 +604,46 @@
  * Bit 14 clear = primary IDE channel does not have 80-pin cable.
  * Bit 14 set   = primary IDE channel has 80-pin cable.
  */
-
 static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
 {
-	struct pci_dev *dev	= hwif->pci_dev;
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL        &&
-	    dev->vendor           == PCI_VENDOR_ID_SERVERWORKS &&
-	    dev->device           == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+	struct pci_dev *dev = hwif->pci_dev;
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
 		return ((1 << (hwif->channel + 14)) &
 			dev->subsystem_device) ? 1 : 0;
-
 	return 0;
+}
 
+/* Sun Cobalt Alpine hardware avoids the 80-pin cable
+ * detect issue by attaching the drives directly to the board.
+ * This check follows the Dell precedent (how scary is that?!)
+ *
+ * WARNING: this only works on Alpine hardware!
+ */
+static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+		return ((1 << (hwif->channel + 14)) &
+			dev->subsystem_device) ? 1 : 0;
+	return 0;
 }
 
 unsigned int __init ata66_svwks (ide_hwif_t *hwif)
 {
-	struct pci_dev *dev	= hwif->pci_dev;
+	struct pci_dev *dev = hwif->pci_dev;
+
+	/* Dell PowerEdge */
 	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
 		return ata66_svwks_dell (hwif);
-	
+
+	/* Cobalt Alpine */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
+		return ata66_svwks_cobalt (hwif);
+
 	return 0;
 }
 
@@ -586,9 +659,7 @@
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
 	hwif->autodma = 0;
-	return;
 #else /* CONFIG_BLK_DEV_IDEDMA */
-
 	if (hwif->dma_base) {
 		if (!noautodma)
 			hwif->autodma = 1;
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/slc90e66.c linux/drivers/ide/slc90e66.c
--- v2.5.2/linux/drivers/ide/slc90e66.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/slc90e66.c	Tue Jan 15 11:27:47 2002
@@ -86,8 +86,13 @@
          * at that point bibma+0x2 et bibma+0xa are byte registers
          * to investigate:
          */
+#ifdef __mips__	/* only for mips? */
+	c0 = inb_p(bibma + 0x02);
+	c1 = inb_p(bibma + 0x0a);
+#else
 	c0 = inb_p((unsigned short)bibma + 0x02);
 	c1 = inb_p((unsigned short)bibma + 0x0a);
+#endif
 
 	p += sprintf(p, "                                SLC90E66 Chipset.\n");
 	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
@@ -253,7 +258,9 @@
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
 		case XFER_SW_DMA_2:	break;
+#if 0	/* allow PIO modes */
 		default:		return -1;
+#endif
 	}
 
 	if (speed >= XFER_UDMA_0) {
@@ -291,6 +298,13 @@
 	byte speed		= 0;
 	byte udma_66		= eighty_ninty_three(drive);
 
+#if 1 /* allow PIO modes */
+	if (!HWIF(drive)->autodma) {
+		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+		(void) slc90e66_tune_chipset(drive, speed);
+		return ((int) ide_dma_off_quietly);
+	}
+#endif
 	if ((id->dma_ultra & 0x0010) && (ultra)) {
 		speed = (udma_66) ? XFER_UDMA_4 : XFER_UDMA_2;
 	} else if ((id->dma_ultra & 0x0008) && (ultra)) {
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/Config.help linux/drivers/ieee1394/Config.help
--- v2.5.2/linux/drivers/ieee1394/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/ieee1394/Config.help	Fri Jan 25 16:03:40 2002
@@ -0,0 +1,102 @@
+CONFIG_IEEE1394
+  IEEE 1394 describes a high performance serial bus, which is also
+  known as FireWire(tm) or i.Link(tm) and is used for connecting all
+  sorts of devices (most notably digital video cameras) to your
+  computer.
+
+  If you have FireWire hardware and want to use it, say Y here.  This
+  is the core support only, you will also need to select a driver for
+  your IEEE 1394 adapter.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ieee1394.o.
+
+CONFIG_IEEE1394_PCILYNX
+  Say Y here if you have an IEEE-1394 controller with the Texas
+  Instruments PCILynx chip.  Note: this driver is written for revision
+  2 of this chip and may not work with revision 0.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called pcilynx.o.
+
+CONFIG_IEEE1394_PCILYNX_LOCALRAM
+  This option makes the PCILynx driver use local RAM available on some
+  PCILynx setups for Packet Control Lists. Local RAM is random access
+  memory which resides on the PCILynx board as opposed to on your
+  computer's motherboard. Local RAM may speed up command processing
+  because no PCI transfers are necessary during use of the Packet
+  Control Lists.
+
+  Note that there are no known PCILynx systems providing local RAM
+  except for the evaluation boards by Texas Instruments and that the
+  PCILynx does not reliably report missing RAM. This means that it is
+  dangerous to say Y here if you are not absolutely sure that your
+  board provides 64KB of local RAM.
+
+  If unsure, say N.
+
+CONFIG_IEEE1394_PCILYNX_PORTS
+  This option enables driver code to access the RAM, ROM and AUX ports
+  of the PCILynx through character devices in /dev.  If you don't know
+  what this is about then you won't need it.
+
+  If unsure, say N.
+
+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
+  chipsets made by Texas Instruments and NEC. Most third-party vendors
+  use one of these chipsets.  It should work with any OHCI-1394
+  compliant card, however.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ohci1394.o.
+
+CONFIG_IEEE1394_VIDEO1394
+  This option enables video device usage for OHCI-1394 cards.  Enable
+  this option only if you have an IEEE 1394 video device connected to
+  an OHCI-1394 card.
+
+CONFIG_IEEE1394_DV1394
+  This driver allows you to transmit and receive DV (digital video)
+  streams on an OHCI-1394 card using a simple frame-oriented
+  interface.
+
+  The user-space API for dv1394 is documented in dv1394.h.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called dv1394.o.
+
+CONFIG_IEEE1394_SBP2
+  This option enables you to use SBP-2 devices connected to your IEEE
+  1394 bus.  SBP-2 devices include harddrives and DVD devices.
+
+CONFIG_IEEE1394_RAWIO
+  Say Y here if you want support for the raw device. This is generally
+  a good idea, so you should say Y here. The raw device enables
+  direct communication of user programs with the IEEE 1394 bus and
+  thus with the attached peripherals.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called raw1394.o.
+
+CONFIG_IEEE1394_VERBOSEDEBUG
+  If you say Y here, you will get very verbose debugging logs from the
+  subsystem which includes a dump of the header of every sent and
+  received packet.  This can amount to a high amount of data collected
+  in a very short time which is usually also saved to disk by the
+  system logging daemons.
+
+  Say Y if you really want or need the debugging output, everyone else
+  says N.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/Config.in linux/drivers/ieee1394/Config.in
--- v2.5.2/linux/drivers/ieee1394/Config.in	Thu Jul 19 17:48:15 2001
+++ linux/drivers/ieee1394/Config.in	Mon Jan 21 15:57:51 2002
@@ -19,6 +19,7 @@
 	comment "Protocol Drivers"
 	dep_tristate '  OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394
 	dep_tristate '  SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394
+	dep_tristate '  OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394
 	dep_tristate '  Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
 
 	bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/Makefile linux/drivers/ieee1394/Makefile
--- v2.5.2/linux/drivers/ieee1394/Makefile	Wed Oct 17 14:19:20 2001
+++ linux/drivers/ieee1394/Makefile	Mon Jan 21 15:57:51 2002
@@ -16,6 +16,7 @@
 obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o
 obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o
 obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
+obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/csr.c linux/drivers/ieee1394/csr.c
--- v2.5.2/linux/drivers/ieee1394/csr.c	Thu Jul 19 17:48:15 2001
+++ linux/drivers/ieee1394/csr.c	Mon Jan 21 15:57:51 2002
@@ -70,7 +70,7 @@
 {
         host->csr.lock = SPIN_LOCK_UNLOCKED;
 
-        host->csr.rom_size = host->template->get_rom(host, &host->csr.rom);
+        host->csr.rom_size = host->ops->get_rom(host, &host->csr.rom);
 
         host->csr.state                 = 0;
         host->csr.node_ids              = 0;
@@ -152,7 +152,7 @@
         case CSR_CYCLE_TIME:
                 oldcycle = host->csr.cycle_time;
                 host->csr.cycle_time =
-                        host->template->devctl(host, GET_CYCLE_COUNTER, 0);
+                        host->ops->devctl(host, GET_CYCLE_COUNTER, 0);
 
                 if (oldcycle > host->csr.cycle_time) {
                         /* cycle time wrapped around */
@@ -163,7 +163,7 @@
         case CSR_BUS_TIME:
                 oldcycle = host->csr.cycle_time;
                 host->csr.cycle_time =
-                        host->template->devctl(host, GET_CYCLE_COUNTER, 0);
+                        host->ops->devctl(host, GET_CYCLE_COUNTER, 0);
 
                 if (oldcycle > host->csr.cycle_time) {
                         /* cycle time wrapped around */
@@ -181,32 +181,32 @@
                 return RCODE_ADDRESS_ERROR;
 
         case CSR_BUS_MANAGER_ID:
-                if (host->template->hw_csr_reg)
-                        ret = host->template->hw_csr_reg(host, 0, 0, 0);
+                if (host->ops->hw_csr_reg)
+                        ret = host->ops->hw_csr_reg(host, 0, 0, 0);
                 else
                         ret = host->csr.bus_manager_id;
 
                 *(buf++) = cpu_to_be32(ret);
                 out;
         case CSR_BANDWIDTH_AVAILABLE:
-                if (host->template->hw_csr_reg)
-                        ret = host->template->hw_csr_reg(host, 1, 0, 0);
+                if (host->ops->hw_csr_reg)
+                        ret = host->ops->hw_csr_reg(host, 1, 0, 0);
                 else
                         ret = host->csr.bandwidth_available;
 
                 *(buf++) = cpu_to_be32(ret);
                 out;
         case CSR_CHANNELS_AVAILABLE_HI:
-                if (host->template->hw_csr_reg)
-                        ret = host->template->hw_csr_reg(host, 2, 0, 0);
+                if (host->ops->hw_csr_reg)
+                        ret = host->ops->hw_csr_reg(host, 2, 0, 0);
                 else
                         ret = host->csr.channels_available_hi;
 
                 *(buf++) = cpu_to_be32(ret);
                 out;
         case CSR_CHANNELS_AVAILABLE_LO:
-                if (host->template->hw_csr_reg)
-                        ret = host->template->hw_csr_reg(host, 3, 0, 0);
+                if (host->ops->hw_csr_reg)
+                        ret = host->ops->hw_csr_reg(host, 3, 0, 0);
                 else
                         ret = host->csr.channels_available_lo;
 
@@ -244,7 +244,7 @@
                 host->csr.node_ids &= NODE_MASK << 16;
                 host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
                 host->node_id = host->csr.node_ids >> 16;
-                host->template->devctl(host, SET_BUS_ID, host->node_id >> 6);
+                host->ops->devctl(host, SET_BUS_ID, host->node_id >> 6);
                 out;
 
         case CSR_RESET_START:
@@ -269,7 +269,7 @@
         case CSR_CYCLE_TIME:
                 /* should only be set by cycle start packet, automatically */
                 host->csr.cycle_time = be32_to_cpu(*data);
-                host->template->devctl(host, SET_CYCLE_COUNTER,
+                host->ops->devctl(host, SET_CYCLE_COUNTER,
                                        be32_to_cpu(*(data++)));
                 out;
         case CSR_BUS_TIME:
@@ -318,10 +318,10 @@
         data = be32_to_cpu(data);
         arg = be32_to_cpu(arg);
 
-        if (host->template->hw_csr_reg) {
+        if (host->ops->hw_csr_reg) {
                 quadlet_t old;
 
-                old = host->template->
+                old = host->ops->
                         hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
                                    data, arg);
 
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/dv1394-private.h linux/drivers/ieee1394/dv1394-private.h
--- v2.5.2/linux/drivers/ieee1394/dv1394-private.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/ieee1394/dv1394-private.h	Mon Jan 21 15:57:51 2002
@@ -0,0 +1,606 @@
+/*
+ * dv1394-private.h - DV input/output over IEEE 1394 on OHCI chips
+ *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
+ *     receive, proc_fs by Dan Dennedy <dan@dennedy.org>
+ *
+ * based on:
+ *   video1394.h - driver for OHCI 1394 boards
+ *   Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
+ *                          Peter Schlaile <udbz@rz.uni-karlsruhe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DV_1394_PRIVATE_H
+#define _DV_1394_PRIVATE_H
+
+#include "ieee1394.h"
+#include <linux/pci.h>
+#include <asm/scatterlist.h>
+
+/* data structures private to the dv1394 driver */
+/* none of this is exposed to user-space */
+
+
+/* 
+   the 8-byte CIP (Common Isochronous Packet) header that precedes
+   each packet of DV data.
+
+   See the IEC 61883 standard. 
+*/
+
+struct CIP_header { unsigned char b[8]; };
+
+static inline void fill_cip_header(struct CIP_header *cip,
+				   unsigned char source_node_id,
+				   unsigned long counter,
+				   enum pal_or_ntsc format,
+				   unsigned long timestamp)
+{
+	cip->b[0] = source_node_id;
+	cip->b[1] = 0x78; /* packet size in quadlets (480/4) - even for empty packets! */
+	cip->b[2] = 0x00;
+	cip->b[3] = counter;
+
+	cip->b[4] = 0x80; /* const */
+
+	switch(format) {
+	case DV1394_PAL:
+		cip->b[5] = 0x80;
+		break;
+	case DV1394_NTSC:
+		cip->b[5] = 0x00;
+		break;
+	}
+
+	cip->b[6] = timestamp >> 8;
+	cip->b[7] = timestamp & 0xFF;
+}
+
+
+
+/* 
+   DMA commands used to program the OHCI's DMA engine
+
+   See the Texas Instruments OHCI 1394 chipset documentation. 
+*/
+
+struct output_more_immediate { u32 q[8]; };
+struct output_more { u32 q[4]; };
+struct output_last { u32 q[4]; };
+struct input_more { u32 q[4]; };
+struct input_last { u32 q[4]; };
+
+/* outputs */
+
+static inline void fill_output_more_immediate(struct output_more_immediate *omi,
+					      unsigned char tag,
+					      unsigned char channel,
+					      unsigned char sync_tag,
+					      unsigned int  payload_size)
+{
+	omi->q[0] = 0x02000000 | 8 ; /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */
+	omi->q[1] = 0;
+	omi->q[2] = 0;
+	omi->q[3] = 0;
+	
+	/* IT packet header */
+	omi->q[4] = (0x0 << 16)  /* DMA_SPEED_100 */
+			| (tag << 14)
+			| (channel << 8)
+			| (TCODE_ISO_DATA << 4) 
+			| (sync_tag);
+
+	omi->q[5] = payload_size << 16;
+	omi->q[5] |= (0x7F << 8) | 0xA0; /* reserved field; mimic behavior of my Sony DSR-40 */
+	
+	omi->q[6] = 0;
+	omi->q[7] = 0;
+}
+
+static inline void fill_output_more(struct output_more *om,
+				    unsigned int data_size,
+				    unsigned long data_phys_addr)
+{
+	om->q[0] = 0; /* OUTPUT_MORE */
+	om->q[0] |= data_size;
+
+	om->q[1] = data_phys_addr;
+	om->q[2] = 0;
+	om->q[3] = 0;
+}
+
+static inline void fill_output_last(struct output_last *ol,
+				    int want_timestamp,
+				    int want_interrupt,
+				    unsigned int data_size,
+				    unsigned long data_phys_addr)
+{
+	ol->q[0] = 0;
+	ol->q[0] |= 1 << 28; /* OUTPUT_LAST */
+
+	if(want_timestamp) /* controller will update timestamp at DMA time */
+		ol->q[0] |= 1 << 27;
+
+	if(want_interrupt)
+		ol->q[0] |= 3 << 20;
+
+	ol->q[0] |= 3 << 18; /* must take branch */
+	ol->q[0] |= data_size;
+	
+	ol->q[1] = data_phys_addr;
+	ol->q[2] = 0;
+	ol->q[3] = 0;
+}
+
+/* inputs */
+
+static inline void fill_input_more(struct input_more *im,
+				   int want_interrupt,
+				   unsigned int data_size,
+				   unsigned long data_phys_addr)
+{
+	im->q[0] =  2 << 28; /* INPUT_MORE */
+	im->q[0] |= 8 << 24; /* s = 1, update xferStatus and resCount */
+	if (want_interrupt)
+		im->q[0] |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */
+	im->q[0] |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */
+	                       /* disable wait on sync field, not used in DV :-( */
+       	im->q[0] |= data_size;
+
+	im->q[1] = data_phys_addr;
+	im->q[2] = 0; /* branchAddress and Z not use in packet-per-buffer mode */
+	im->q[3] = 0; /* xferStatus & resCount, resCount must be initialize to data_size */
+}
+ 
+static inline void fill_input_last(struct input_last *il,
+				    unsigned int data_size,
+				    unsigned long data_phys_addr)
+{
+	il->q[0] =  3 << 28; /* INPUT_LAST */
+	il->q[0] |= 8 << 24; /* s = 1, update xferStatus and resCount */
+	il->q[0] |= 3 << 20; /* enable interrupts */
+	il->q[0] |= 0xC << 16; /* enable branch to address */
+	                       /* disable wait on sync field, not used in DV :-( */
+	il->q[0] |= data_size;
+
+	il->q[1] = data_phys_addr;
+	il->q[2] = 1; /* branchAddress (filled in later) and Z = 1 descriptor in next block */
+	il->q[3] = data_size; /* xferStatus & resCount, resCount must be initialize to data_size */
+}
+
+
+
+/* 
+   A "DMA descriptor block" consists of several contiguous DMA commands.
+   struct DMA_descriptor_block encapsulates all of the commands necessary 
+   to send one packet of DV data. 
+   
+   There are three different types of these blocks:
+
+        1) command to send an empty packet (CIP header only, no DV data):
+
+	    OUTPUT_MORE-Immediate <-- contains the iso header in-line
+	    OUTPUT_LAST           <-- points to the CIP header
+
+	2) command to send a full packet when the DV data payload does NOT
+	   cross a page boundary:
+
+	    OUTPUT_MORE-Immediate <-- contains the iso header in-line
+	    OUTPUT_MORE           <-- points to the CIP header
+	    OUTPUT_LAST           <-- points to entire DV data payload
+
+	3) command to send a full packet when the DV payload DOES cross
+	   a page boundary:
+
+	    OUTPUT_MORE-Immediate <-- contains the iso header in-line
+	    OUTPUT_MORE           <-- points to the CIP header
+	    OUTPUT_MORE           <-- points to first part of DV data payload
+	    OUTPUT_LAST           <-- points to second part of DV data payload
+
+   This struct describes all three block types using unions.
+
+   !!! It is vital that an even number of these descriptor blocks fit on one
+   page of memory, since a block cannot cross a page boundary !!!
+
+ */
+
+struct DMA_descriptor_block {
+
+	union {
+		struct {
+			/*  iso header, common to all output block types */
+			struct output_more_immediate omi; 
+			
+			union {
+				/* empty packet */
+				struct {
+					struct output_last ol;  /* CIP header */
+				} empty;
+			
+				/* full packet */
+				struct {
+					struct output_more om;  /* CIP header */
+					
+					union {
+				               /* payload does not cross page boundary */
+						struct {
+							struct output_last ol;  /* data payload */
+						} nocross;
+						
+				               /* payload crosses page boundary */
+						struct {
+							struct output_more om;  /* data payload */
+							struct output_last ol;  /* data payload */
+						} cross;
+					} u;
+					
+				} full;
+			} u;
+		} out;
+
+		struct {
+			struct input_last il; 
+		} in;
+
+	} u;
+
+	/* ensure that PAGE_SIZE % sizeof(struct DMA_descriptor_block) == 0 
+	   by padding out to 128 bytes */
+	u32 __pad__[12]; 
+};
+
+
+/* struct frame contains all data associated with one frame in the
+   ringbuffer these are allocated when the DMA context is initialized
+   do_dv1394_init().  They are re-used after the card finishes
+   transmitting the frame. */
+
+struct video_card; /* forward declaration */
+
+struct frame {
+
+	/* points to the struct video_card that owns this frame */
+	struct video_card *video;
+
+	/* index of this frame in video_card->frames[] */
+	unsigned int frame_num;
+
+	/* FRAME_CLEAR - DMA program not set up, waiting for data 
+	   FRAME_READY - DMA program written, ready to transmit
+
+	   Changes to these should be locked against the interrupt
+	*/
+	enum {
+		FRAME_CLEAR = 0,
+		FRAME_READY
+	} state;
+	
+	/* whether this frame has been DMA'ed already; used only from
+	   the IRQ handler to determine whether the frame can be reset */
+	int done;
+
+
+	/* kernel virtual pointer to the start of this frame's data in
+	   the user ringbuffer. Use only for CPU access; to get the DMA
+	   bus address you must go through the video->user_dma mapping */
+	unsigned long data; 
+
+	/* Max # of packets per frame */
+        #define MAX_PACKETS 320
+
+
+	/* a PAGE_SIZE memory pool for allocating CIP headers
+	   !header_pool must be aligned to PAGE_SIZE! */
+	struct CIP_header *header_pool;
+	dma_addr_t         header_pool_dma;
+
+	
+	/* a physically contiguous memory pool for allocating DMA
+	   descriptor blocks; usually around 64KB in size
+	   !descriptor_pool must be aligned to PAGE_SIZE! */
+	struct DMA_descriptor_block *descriptor_pool;
+	dma_addr_t                   descriptor_pool_dma;
+	unsigned long                descriptor_pool_size;
+
+
+	/* # of packets allocated for this frame */
+	unsigned int n_packets;
+
+
+	/* below are several pointers (kernel virtual addresses, not
+	   DMA bus addresses) to parts of the DMA program.  These are
+	   set each time the DMA program is written in
+	   frame_prepare(). They are used later on, e.g. from the
+	   interrupt handler, to check the status of the frame */
+
+	/* points to status/timestamp field of first DMA packet */
+	/* (we'll check it later to monitor timestamp accuracy) */
+	u32 *frame_begin_timestamp;
+
+	/* the timestamp we assigned to the first packet in the frame */
+	u32 assigned_timestamp;
+
+	/* pointer to the first packet's CIP header (where the timestamp goes) */
+	struct CIP_header *cip_syt1;
+	
+	/* pointer to the second packet's CIP header
+	   (only set if the first packet was empty) */
+	struct CIP_header *cip_syt2;
+
+	/* in order to figure out what caused an interrupt,
+	   store pointers to the status fields of the two packets
+	   that can cause interrupts. We'll check these from the
+	   interrupt handler.
+	*/
+	u32 *mid_frame_timestamp;
+	u32 *frame_end_timestamp;
+
+	/* branch address field of final packet. This is effectively
+	   the "tail" in the chain of DMA descriptor blocks.
+	   We will fill it with the address of the first DMA descriptor
+	   block in the subsequent frame, once it is ready.
+	*/
+	u32 *frame_end_branch;
+
+	/* the number of descriptors in the first descriptor block
+	   of the frame. Needed to start DMA */
+	int first_n_descriptors;
+};
+
+
+struct packet {
+	u16	timestamp;
+	u16	invalid;
+	u16	iso_header;
+	u16	data_length;
+	u32	cip_h1;
+	u32	cip_h2;
+	unsigned char data[480];
+	unsigned char padding[16]; /* force struct size =512 for page alignment */
+};
+
+
+/* allocate/free a frame */
+static struct frame* frame_new(unsigned int frame_num, struct video_card *video);
+static void frame_delete(struct frame *f);
+
+/* reset f so that it can be used again */
+static void frame_reset(struct frame *f);
+
+
+/* structure for bookkeeping of a large non-physically-contiguous DMA buffer */
+
+struct dma_region {
+	unsigned int n_pages;
+	unsigned int n_dma_pages;
+	struct scatterlist *sglist;
+};
+
+/* return the DMA bus address of the byte with the given offset
+   relative to the beginning of the dma_region */
+
+static inline dma_addr_t dma_offset_to_bus(struct dma_region *dma, unsigned long offset)
+{
+	int i;
+	struct scatterlist *sg;
+	
+	for(i = 0, sg = &dma->sglist[0]; i < dma->n_dma_pages; i++, sg++) {
+		if(offset < sg_dma_len(sg)) {
+			return sg_dma_address(sg) + offset;
+		} 
+		offset -= sg_dma_len(sg);
+	}
+	
+	printk(KERN_ERR "dv1394: dma_offset_to_bus failed for offset %lu!\n", offset);
+	return 0;
+}
+
+
+/* struct video_card contains all data associated with one instance
+   of the dv1394 driver 
+*/
+
+struct video_card {
+
+	/* ohci card to which this instance corresponds */
+	struct ti_ohci *ohci;
+
+	/* OHCI card id; the link between the VFS inode and a specific video_card
+	   (essentially the device minor number) */
+	int id;
+
+	/* entry in dv1394_cards */
+	struct list_head list;
+
+	/* handle to /dev/ieee1394/dv/N, NULL if devfs not in use */
+	devfs_handle_t devfs_handle;
+
+	/* OHCI card IT DMA context number, -1 if not in use */
+	int ohci_it_ctx;
+
+	/* register offsets for current IT DMA context, 0 if not in use */
+	u32 ohci_IsoXmitContextControlSet;
+	u32 ohci_IsoXmitContextControlClear;
+	u32 ohci_IsoXmitCommandPtr;
+	
+	/* OHCI card IR DMA context number, -1 if not in use */
+	int ohci_ir_ctx;
+
+	/* register offsets for current IR DMA context, 0 if not in use */
+	u32 ohci_IsoRcvContextControlSet;
+	u32 ohci_IsoRcvContextControlClear;
+	u32 ohci_IsoRcvCommandPtr;
+	u32 ohci_IsoRcvContextMatch;
+	
+	
+	/* CONCURRENCY CONTROL */
+	
+	/* there are THREE levels of locking associated with video_card. */
+
+	/*
+	   1) the 'open' flag - this prevents more than one process from
+	   opening the device. (the driver currently assumes only one opener).
+	   This is a regular int, but use test_and_set_bit() (on bit zero) 
+	   for atomicity.
+	 */
+	int open;
+
+	/* 
+	   2) the spinlock - this provides mutual exclusion between the interrupt
+	   handler and process-context operations. Generally you must take the
+	   spinlock under the following conditions:
+	     1) DMA (and hence the interrupt handler) may be running
+	     AND
+	     2) you need to operate on the video_card, especially active_frame
+
+	     It is OK to play with video_card without taking the spinlock if
+	     you are certain that DMA is not running. Even if DMA is running,
+	     it is OK to *read* active_frame with the lock, then drop it
+	     immediately. This is safe because the interrupt handler will never
+	     advance active_frame onto a frame that is not READY (and the spinlock
+	     must be held while marking a frame READY).
+	 */
+	spinlock_t spinlock;
+
+	/*
+	  3) the sleeping semaphore 'sem' - this is used from process context only,
+	  to serialize various operations on the video_card. Even though only one
+	  open() is allowed, we still need to prevent multiple threads of execution
+	  from entering calls like read, write, ioctl, etc.
+
+	  I honestly can't think of a good reason to use dv1394 from several threads
+	  at once, but we need to serialize anyway to prevent oopses =).
+
+	  NOTE: if you need both spinlock and sem, take sem first to avoid deadlock!
+	 */
+	struct semaphore sem;
+
+	/* people waiting for buffer space, please form a line here... */
+	wait_queue_head_t waitq;
+
+	/* support asynchronous I/O signals (SIGIO) */
+	struct fasync_struct *fasync;
+	
+	/* the large, non-contiguous (rvmalloc()) ringbuffer for DV
+           data, exposed to user-space via mmap() */
+	unsigned char     *user_buf;
+	unsigned long      user_buf_size;
+	struct dma_region  user_dma;
+	
+	/* next byte in the ringbuffer that a write() call will fill */
+	size_t write_off;
+
+	struct frame *frames[DV1394_MAX_FRAMES];
+	
+	/* n_frames also serves as an indicator that this struct video_card is
+	   intialized and ready to run DMA buffers */
+
+	int n_frames;
+
+	/* this is the frame that is currently "owned" by the OHCI DMA controller
+	   (set to -1 iff DMA is not running) 
+
+	   ! must lock against the interrupt handler when accessing it !
+
+	   RULES:
+
+	       Only the interrupt handler may change active_frame if DMA
+	          is running; if not, process may change it
+
+	       If the next frame is READY, the interrupt handler will advance
+	       active_frame when the current frame is finished.
+
+	       If the next frame is CLEAR, the interrupt handler will re-transmit
+	       the current frame, and the dropped_frames counter will be  incremented.
+
+	       The interrupt handler will NEVER advance active_frame to a
+	       frame that is not READY.
+	       
+	*/
+	int active_frame;
+	int first_run;
+
+	/* the same locking rules apply to these three fields also: */
+
+	/* altered ONLY from process context. Must check first_clear_frame->state;
+	   if it's READY, that means the ringbuffer is full with READY frames;
+	   if it's CLEAR, that means one or more ringbuffer frames are CLEAR */
+	unsigned int first_clear_frame; 
+
+	/* altered both by process and interrupt */
+	unsigned int n_clear_frames;   
+
+	/* only altered by the interrupt */
+	unsigned int dropped_frames;
+
+
+
+	/* the CIP accumulator and continuity counter are properties
+	   of the DMA stream as a whole (not a single frame), so they
+	   are stored here in the video_card */
+
+	unsigned long cip_accum;
+	unsigned long cip_n, cip_d;
+	unsigned int syt_offset;
+	unsigned int continuity_counter;
+
+	enum pal_or_ntsc pal_or_ntsc;
+
+	/* redundant, but simplifies the code somewhat */
+	unsigned int frame_size; /* in bytes */
+
+	/* the isochronous channel to use, -1 if video card is inactive */
+	int channel;
+
+	
+	/* physically contiguous packet ringbuffer for receive */
+#define MAX_PACKET_BUFFER 30
+	struct packet *packet_buffer;
+	dma_addr_t     packet_buffer_dma;
+	unsigned long  packet_buffer_size;
+	
+	unsigned int current_packet;
+	int first_frame; 	/* received first start frame marker? */
+};
+
+/* 
+   if the video_card is not initialized, then the ONLY fields that are valid are:
+   ohci
+   open
+   n_frames
+*/
+
+static inline int video_card_initialized(struct video_card *v)
+{
+	return v->n_frames > 0;
+}
+
+static int do_dv1394_init(struct video_card *video, struct dv1394_init *init);
+static int do_dv1394_init_default(struct video_card *video);
+static int do_dv1394_shutdown(struct video_card *video, int free_user_buf);
+
+
+/* NTSC empty packet rate accurate to within 0.01%, 
+   calibrated against a Sony DSR-40 DVCAM deck */
+
+#define CIP_N_NTSC   68000000
+#define CIP_D_NTSC 1000000000
+
+#define CIP_N_PAL  1
+#define CIP_D_PAL 16
+
+#endif /* _DV_1394_PRIVATE_H */
+
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/dv1394.c linux/drivers/ieee1394/dv1394.c
--- v2.5.2/linux/drivers/ieee1394/dv1394.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/ieee1394/dv1394.c	Mon Jan 21 15:57:51 2002
@@ -0,0 +1,2722 @@
+/*
+ * dv1394.c - DV input/output over IEEE 1394 on OHCI chips
+ *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
+ *     receive, proc_fs by Dan Dennedy <dan@dennedy.org>
+ *
+ * based on:
+ *  video1394.c - video driver for OHCI 1394 boards
+ *  Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+  OVERVIEW
+
+  I designed dv1394 as a "pipe" that you can use to shoot DV onto a
+  FireWire bus. In transmission mode, dv1394 does the following:
+
+   1. accepts contiguous frames of DV data from user-space, via write()
+      or mmap() (see dv1394.h for the complete API)
+   2. wraps IEC 61883 packets around the DV data, inserting
+      empty synchronization packets as necessary
+   3. assigns accurate SYT timestamps to the outgoing packets
+   4. shoots them out using the OHCI card's IT DMA engine
+
+   Thanks to Dan Dennedy, we now have a receive mode that does the following:
+
+   1. accepts raw IEC 61883 packets from the OHCI card
+   2. re-assembles the DV data payloads into contiguous frames,
+      discarding empty packets
+   3. sends the DV data to user-space via read() or mmap()
+*/
+
+/*
+  TODO:
+
+  - expose xmit and recv as separate devices
+
+  - tunable frame-drop behavior: either loop last frame, or halt transmission
+  
+  - use a scatter/gather buffer for DMA programs (f->descriptor_pool)
+    so that we don't rely on allocating 64KB of contiguous kernel memory
+    via pci_alloc_consistent()
+    
+  DONE:
+  - safely obtain and release ISO Tx channels in cooperation with OHCI driver
+  - map received DIF blocks to their proper location in DV frame (ensure
+    recovery if dropped packet)
+  - handle bus resets gracefully (OHCI card seems to take care of this itself(!))
+  - do not allow resizing the user_buf once allocated; eliminate nuke_buffer_mappings
+  - eliminated #ifdef DV1394_DEBUG_LEVEL by inventing macros debug_printk and irq_printk
+  - added wmb() and mb() to places where PCI read/write ordering needs to be enforced
+  - set video->id correctly
+  - store video_cards in an array indexed by OHCI card ID, rather than a list
+  - implement DMA context allocation to cooperate with other users of the OHCI
+  - fix all XXX showstoppers
+  - disable IR/IT DMA interrupts on shutdown
+  - flush pci writes to the card by issuing a read
+  - devfs and character device dispatching (* needs testing with Linux 2.2.x)
+  - switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!)
+  - keep all video_cards in a list (for open() via chardev), set file->private_data = video
+  - dv1394_poll should indicate POLLIN when receiving buffers are available
+  - add proc fs interface to set cip_n, cip_d, syt_offset, and video signal
+
+*/
+     
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/smp_lock.h>
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/tqueue.h>
+#include <linux/delay.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+
+#include "ieee1394.h"
+#include "ieee1394_types.h"
+#include "hosts.h"
+#include "ieee1394_core.h"
+#include "highlevel.h"	
+#include "dv1394.h"
+#include "dv1394-private.h"
+
+#include "ohci1394.h"
+
+#ifndef virt_to_page
+#define virt_to_page(x) MAP_NR(x)
+#endif
+
+#ifndef vmalloc_32
+#define vmalloc_32(x) vmalloc(x)
+#endif
+
+
+/* DEBUG LEVELS:
+   0 - no debugging messages
+   1 - some debugging messages, but none during DMA frame transmission
+   2 - lots of messages, including during DMA frame transmission
+       (will cause undeflows if your machine is too slow!)
+*/
+
+#define DV1394_DEBUG_LEVEL 0
+
+/* for debugging use ONLY: allow more than one open() of the device */
+/* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */
+
+#if DV1394_DEBUG_LEVEL >= 2
+#define irq_printk( args... ) printk( args )
+#else
+#define irq_printk( args... )
+#endif
+
+#if DV1394_DEBUG_LEVEL >= 1
+#define debug_printk( args... ) printk( args)
+#else
+#define debug_printk( args... )
+#endif
+
+/* issue a dummy PCI read to force the preceding write
+   to be posted to the PCI bus immediately */
+
+static inline void flush_pci_write(struct ti_ohci *ohci)
+{
+	mb();
+	reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+}
+
+static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
+			quadlet_t isoXmitIntEvent, void *data);
+
+
+/* GLOBAL DATA */
+
+/* list of all video_cards */
+static LIST_HEAD(dv1394_cards);
+static spinlock_t dv1394_cards_lock = SPIN_LOCK_UNLOCKED;
+
+static struct hpsb_highlevel *hl_handle; /* = NULL; */
+
+static devfs_handle_t dv1394_devfs_handle;
+
+/* translate from a struct file* to the corresponding struct video_card* */
+
+static inline struct video_card* file_to_video_card(struct file *file)
+{
+	return (struct video_card*) file->private_data;
+}
+
+
+/* Taken from bttv.c */
+/*******************************/
+/* Memory management functions */
+/*******************************/
+
+#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
+
+/* [DaveM] I've recoded most of this so that:
+ * 1) It's easier to tell what is happening
+ * 2) It's more portable, especially for translating things
+ *    out of vmalloc mapped areas in the kernel.
+ * 3) Less unnecessary translations happen.
+ *
+ * The code used to assume that the kernel vmalloc mappings
+ * existed in the page tables of every process, this is simply
+ * not guarenteed.  We now use pgd_offset_k which is the
+ * defined way to get at the kernel page tables.
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#define page_address(x)	(x)
+#endif
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline struct page *uvirt_to_page(pgd_t *pgd, unsigned long adr)
+{
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+	struct page *ret = NULL;
+	
+	if (!pgd_none(*pgd)) {
+                pmd = pmd_offset(pgd, adr);
+                if (!pmd_none(*pmd)) {
+                        ptep = pte_offset(pmd, adr);
+                        pte = *ptep;
+                        if(pte_present(pte))
+				ret = pte_page(pte);
+                }
+        }
+	return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved, and for
+ * handling page faults on the rvmalloc()ed buffer
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr) 
+{
+        unsigned long va, kva, ret;
+
+        va = VMALLOC_VMADDR(adr);
+	kva = (unsigned long) page_address(uvirt_to_page(pgd_offset_k(va), va));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+	ret = __pa(kva);
+        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
+        return ret;
+}
+
+static void * rvmalloc(unsigned long size)
+{
+	void * mem;
+	unsigned long adr, page;
+        
+	mem=vmalloc_32(size);
+	if (mem) {
+		memset(mem, 0, size); /* Clear the ram out, 
+					 no junk to the user */
+	        adr=(unsigned long) mem;
+		while (size > 0) {
+	                page = kvirt_to_pa(adr);
+			mem_map_reserve(virt_to_page(__va(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+	}
+	return mem;
+}
+
+static void rvfree(void * mem, unsigned long size)
+{
+        unsigned long adr, page;
+        
+	if (mem) {
+	        adr=(unsigned long) mem;
+		while (size > 0) {
+	                page = kvirt_to_pa(adr);
+			mem_map_unreserve(virt_to_page(__va(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+		vfree(mem);
+	}
+}
+
+/***********************************/
+/* END Memory management functions */
+/***********************************/
+
+
+/*** FRAME METHODS *********************************************************/
+
+static void frame_reset(struct frame *f)
+{
+	f->state = FRAME_CLEAR;
+	f->done = 0;
+	f->n_packets = 0;
+	f->frame_begin_timestamp = NULL;
+	f->assigned_timestamp = 0;
+	f->cip_syt1 = NULL;
+	f->cip_syt2 = NULL;
+	f->mid_frame_timestamp = NULL;
+	f->frame_end_timestamp = NULL;
+	f->frame_end_branch = NULL;
+}
+
+static struct frame* frame_new(unsigned int frame_num, struct video_card *video)
+{
+	struct frame *f = kmalloc(sizeof(*f), GFP_KERNEL);
+	if(!f)
+		return NULL;
+
+	f->video = video;
+	f->frame_num = frame_num;
+
+	f->header_pool = pci_alloc_consistent(f->video->ohci->dev, PAGE_SIZE, &f->header_pool_dma);
+	if(!f->header_pool) {
+		printk(KERN_ERR "dv1394: failed to allocate CIP header pool\n");
+		kfree(f);
+		return NULL;
+	}
+
+	debug_printk("dv1394: frame_new: allocated CIP header pool at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
+		     (unsigned long) f->header_pool, (unsigned long) f->header_pool_dma, PAGE_SIZE);
+	
+	f->descriptor_pool_size = MAX_PACKETS * sizeof(struct DMA_descriptor_block);
+	/* make it an even # of pages */
+	f->descriptor_pool_size += PAGE_SIZE - (f->descriptor_pool_size%PAGE_SIZE);
+
+	f->descriptor_pool = pci_alloc_consistent(f->video->ohci->dev,
+						  f->descriptor_pool_size,
+						  &f->descriptor_pool_dma);
+	if(!f->descriptor_pool) {
+		pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
+		kfree(f);
+		return NULL;
+	}
+	
+	debug_printk("dv1394: frame_new: allocated DMA program memory at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
+		     (unsigned long) f->descriptor_pool, (unsigned long) f->descriptor_pool_dma, f->descriptor_pool_size);
+	
+	f->data = 0;
+	frame_reset(f);
+
+	return f;
+}
+
+static void frame_delete(struct frame *f)
+{
+	pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
+	pci_free_consistent(f->video->ohci->dev, f->descriptor_pool_size, f->descriptor_pool, f->descriptor_pool_dma);
+	kfree(f);
+}
+
+
+
+
+/* 
+   frame_prepare() - build the DMA program for transmitting
+   
+   Frame_prepare() must be called OUTSIDE the video->spinlock.
+   However, frame_prepare() must still be serialized, so
+   it should be called WITH the video->sem taken.
+ */
+
+static void frame_prepare(struct video_card *video, unsigned int this_frame)
+{
+	struct frame *f = video->frames[this_frame];
+	int last_frame;
+
+	struct DMA_descriptor_block *block;
+	dma_addr_t block_dma;
+	struct CIP_header *cip;
+	dma_addr_t cip_dma;
+	
+	unsigned int n_descriptors, full_packets, packets_per_frame, payload_size;
+
+	/* these flags denote packets that need special attention */
+	int empty_packet, first_packet, last_packet, mid_packet;
+
+	u32 *branch_address, *last_branch_address = NULL;
+	unsigned long data_p;
+	int first_packet_empty = 0;
+	u32 cycleTimer, ct_sec, ct_cyc, ct_off;
+	unsigned long irq_flags;
+
+	irq_printk("frame_prepare( %d ) ---------------------\n", this_frame);
+	
+	full_packets = 0;
+
+
+
+	if(video->pal_or_ntsc == DV1394_PAL)
+		packets_per_frame = DV1394_PAL_PACKETS_PER_FRAME;
+	else
+		packets_per_frame = DV1394_NTSC_PACKETS_PER_FRAME;
+
+	while( full_packets < packets_per_frame ) {
+		empty_packet = first_packet = last_packet = mid_packet = 0;
+
+		data_p = f->data + full_packets * 480;
+
+		/************************************************/
+		/* allocate a descriptor block and a CIP header */
+		/************************************************/
+
+		/* note: these should NOT cross a page boundary (DMA restriction) */
+
+		if(f->n_packets >= MAX_PACKETS) {
+			printk(KERN_ERR "dv1394: FATAL ERROR: max packet count exceeded\n");
+			return;
+		}
+
+		/* the block surely won't cross a page boundary, 
+		   since an even number of descriptor_blocks fit on a page */
+		block = &(f->descriptor_pool[f->n_packets]);
+
+		/* DMA address of the block = offset of block relative
+		    to the kernel base address of the descriptor pool
+		    + DMA base address of the descriptor pool */
+		block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
+		
+
+		/* the whole CIP pool fits on one page, so no worries about boundaries */
+		if( ((unsigned long) &(f->header_pool[f->n_packets]) - (unsigned long) f->header_pool) 
+		    > PAGE_SIZE) {
+			printk(KERN_ERR "dv1394: FATAL ERROR: no room to allocate CIP header\n");
+			return;
+		}
+
+		cip = &(f->header_pool[f->n_packets]);
+		
+		/* DMA address of the CIP header = offset of cip
+		   relative to kernel base address of the header pool
+		   + DMA base address of the header pool */
+		cip_dma = (unsigned long) cip % PAGE_SIZE + f->header_pool_dma;
+		
+		/* is this an empty packet? */
+
+		if(video->cip_accum > video->cip_d) {
+			empty_packet = 1;
+			payload_size = 8;
+			video->cip_accum -= video->cip_d;
+		} else {
+			payload_size = 488;
+			video->cip_accum += video->cip_n;
+		}
+
+		/* there are three important packets each frame:
+
+		   the first packet in the frame - we ask the card to record the timestamp when
+		                                   this packet is actually sent, so we can monitor
+						   how accurate our timestamps are. Also, the first
+						   packet serves as a semaphore to let us know that
+						   it's OK to free the *previous* frame's DMA buffer
+
+		   the last packet in the frame -  this packet is used to detect buffer underflows.
+		                                   if this is the last ready frame, the last DMA block
+						   will have a branch back to the beginning of the frame
+						   (so that the card will re-send the frame on underflow).
+						   if this branch gets taken, we know that at least one
+						   frame has been dropped. When the next frame is ready,
+						   the branch is pointed to its first packet, and the
+						   semaphore is disabled.
+
+		   a "mid" packet slightly before the end of the frame - this packet should trigger
+		                   an interrupt so we can go and assign a timestamp to the first packet
+				   in the next frame. We don't use the very last packet in the frame
+				   for this purpose, because that would leave very little time to set
+				   the timestamp before DMA starts on the next frame.
+		*/
+		
+		if(f->n_packets == 0) {
+			first_packet = 1;
+		} else if ( full_packets == (packets_per_frame-1) ) {
+			last_packet = 1;
+		} else if (f->n_packets == packets_per_frame) {
+			mid_packet = 1;
+		}
+		
+
+		/********************/
+		/* setup CIP header */
+		/********************/
+
+		/* the timestamp will be written later from the
+		   mid-frame interrupt handler. For now we just
+		   store the address of the CIP header(s) that
+		   need a timestamp. */
+
+		/* first packet in the frame needs a timestamp */
+		if(first_packet) {
+			f->cip_syt1 = cip;
+			if(empty_packet)
+				first_packet_empty = 1;
+
+		} else if(first_packet_empty && (f->n_packets == 1) ) {
+			/* if the first packet was empty, the second
+			   packet's CIP header also needs a timestamp */
+			f->cip_syt2 = cip;
+		}
+
+		fill_cip_header(cip,
+				/* the node ID number of the OHCI card */
+				reg_read(video->ohci, OHCI1394_NodeID) & 0x3F,
+				video->continuity_counter, 
+				video->pal_or_ntsc,
+				0xFFFF /* the timestamp is filled in later */);
+		
+		/* advance counter, only for full packets */
+		if( ! empty_packet )
+			video->continuity_counter++;
+
+		/******************************/
+		/* setup DMA descriptor block */
+		/******************************/
+
+		/* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */
+		fill_output_more_immediate( &(block->u.out.omi),
+					    /* tag - what is this??? */ 1,
+					    video->channel,
+					    /* sync tag - what is this??? */ 0,
+					    payload_size);
+
+		if(empty_packet) {
+			/* second descriptor - OUTPUT_LAST for CIP header */
+			fill_output_last( &(block->u.out.u.empty.ol),
+
+					  /* want completion status on all interesting packets */
+					  (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+					  /* want interrupts on all interesting packets */
+					  (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+					  sizeof(struct CIP_header), /* data size */
+					  cip_dma);
+			
+			if(first_packet)
+				f->frame_begin_timestamp = &(block->u.out.u.empty.ol.q[3]);
+			else if(mid_packet)
+				f->mid_frame_timestamp = &(block->u.out.u.empty.ol.q[3]);
+			else if(last_packet) {
+				f->frame_end_timestamp = &(block->u.out.u.empty.ol.q[3]);
+				f->frame_end_branch = &(block->u.out.u.empty.ol.q[2]);
+			}
+
+			branch_address = &(block->u.out.u.empty.ol.q[2]);
+			n_descriptors = 3;
+			if(first_packet)
+				f->first_n_descriptors = n_descriptors;
+
+		} else { /* full packet */
+
+			/* second descriptor - OUTPUT_MORE for CIP header */
+			fill_output_more( &(block->u.out.u.full.om),
+					  sizeof(struct CIP_header), /* data size */
+					  cip_dma);
+
+			
+			/* third (and possibly fourth) descriptor - for DV data */
+			/* the 480-byte payload can cross a page boundary; if so,
+			   we need to split it into two DMA descriptors */
+
+			/* does the 480-byte data payload cross a page boundary? */
+			if( (PAGE_SIZE- ((unsigned long)data_p % PAGE_SIZE) ) < 480 ) {
+
+				/* page boundary crossed */
+
+				fill_output_more( &(block->u.out.u.full.u.cross.om),
+						  /* data size - how much of data_p fits on the first page */
+						  PAGE_SIZE - (data_p % PAGE_SIZE),
+
+						  /* DMA address of data_p */
+						  dma_offset_to_bus(&f->video->user_dma,
+								    data_p - (unsigned long) f->video->user_buf));
+
+				fill_output_last( &(block->u.out.u.full.u.cross.ol),
+					  
+						  /* want completion status on all interesting packets */
+						  (first_packet || mid_packet || last_packet) ? 1 : 0, 
+
+						  /* want interrupt on all interesting packets */
+						  (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+						  /* data size - remaining portion of data_p */
+						  480 - (PAGE_SIZE - (data_p % PAGE_SIZE)),
+
+						  /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */
+						  dma_offset_to_bus(&f->video->user_dma,
+								    data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) f->video->user_buf));
+
+				if(first_packet)
+					f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
+				else if(mid_packet)
+					f->mid_frame_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
+				else if(last_packet) {
+					f->frame_end_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
+					f->frame_end_branch = &(block->u.out.u.full.u.cross.ol.q[2]);
+				}
+
+				branch_address = &(block->u.out.u.full.u.cross.ol.q[2]);
+
+				n_descriptors = 5;
+				if(first_packet)
+					f->first_n_descriptors = n_descriptors;
+				
+				full_packets++;
+
+			} else {
+				/* fits on one page */
+
+				fill_output_last( &(block->u.out.u.full.u.nocross.ol),
+					  
+						  /* want completion status on all interesting packets */
+						  (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+						  /* want interrupt on all interesting packets */
+						  (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+						  480, /* data size (480 bytes of DV data) */
+
+						  
+						  /* DMA address of data_p */
+						  dma_offset_to_bus(&f->video->user_dma,
+								    data_p - (unsigned long) f->video->user_buf));
+				
+				if(first_packet)
+					f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
+				else if(mid_packet)
+					f->mid_frame_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
+				else if(last_packet) {
+					f->frame_end_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
+					f->frame_end_branch = &(block->u.out.u.full.u.nocross.ol.q[2]);
+				}
+
+				branch_address = &(block->u.out.u.full.u.nocross.ol.q[2]);
+
+				n_descriptors = 4;
+				if(first_packet)
+					f->first_n_descriptors = n_descriptors;
+
+				full_packets++;
+			}
+		}
+		
+		/* link this descriptor block into the DMA program by filling in 
+		   the branch address of the previous block */
+
+		/* note: we are not linked into the active DMA chain yet */
+
+		if(last_branch_address) {
+			*(last_branch_address) = block_dma | n_descriptors; 
+		}
+
+		last_branch_address = branch_address;
+
+
+		f->n_packets++;
+		
+	}
+
+	/* when we first assemble a new frame, set the final branch 
+	   to loop back up to the top */
+	*(f->frame_end_branch) = f->descriptor_pool_dma | f->first_n_descriptors;
+
+
+	/* make the latest version of the frame buffer visible to the PCI card */
+	/* could optimize this by only syncing the pages associated with this frame */
+	pci_dma_sync_sg(video->ohci->dev,
+			&video->user_dma.sglist[0],
+			video->user_dma.n_dma_pages,
+			PCI_DMA_TODEVICE);
+
+	/* lock against DMA interrupt */
+	spin_lock_irqsave(&video->spinlock, irq_flags);
+
+	f->state = FRAME_READY;
+
+	video->n_clear_frames--;
+
+	last_frame = video->first_clear_frame - 1;
+	if(last_frame == -1)
+		last_frame = video->n_frames-1;
+
+	video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
+
+	irq_printk("   frame %d prepared, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n last=%d\n",
+		   this_frame, video->active_frame, video->n_clear_frames, video->first_clear_frame, last_frame);
+
+	irq_printk("   begin_ts %08lx mid_ts %08lx end_ts %08lx end_br %08lx\n",
+		   (unsigned long) f->frame_begin_timestamp, 
+		   (unsigned long) f->mid_frame_timestamp, 
+		   (unsigned long) f->frame_end_timestamp, 
+		   (unsigned long) f->frame_end_branch);
+	
+	if(video->active_frame != -1) {
+
+		/* if DMA is already active, we are almost done */
+		/* just link us onto the active DMA chain */
+		if(video->frames[last_frame]->frame_end_branch) {
+
+			/* point the previous frame's tail to this frame's head */
+			*(video->frames[last_frame]->frame_end_branch) = f->descriptor_pool_dma | f->first_n_descriptors; 
+
+			/* this write MUST precede the next one, or we could silently drop frames */
+			wmb();
+			
+			/* disable the want_status semaphore on the last packet */
+			*(video->frames[last_frame]->frame_end_branch - 2) &= 0xF7CFFFFF;
+
+			/* flush these writes to memory ASAP */
+			flush_pci_write(video->ohci);
+
+			/* NOTE:
+			   ideally the writes should be "atomic": if
+			   the OHCI card reads the want_status flag in
+			   between them, we'll falsely report a
+			   dropped frame. Hopefully this window is too
+			   small to really matter, and the consequence
+			   is rather harmless. */
+			
+
+			irq_printk("     new frame %d linked onto DMA chain\n", this_frame);
+
+		} else {
+			printk(KERN_ERR "dv1394: last frame not ready???\n");
+		}
+
+	} else {
+		
+		u32 transmit_sec, transmit_cyc;
+		u32 ts_cyc, ts_off;
+
+		/* DMA is stopped, so this is the very first frame */
+		video->active_frame = this_frame;
+		
+	        /* set CommandPtr to address and size of first descriptor block */
+		reg_write(video->ohci, video->ohci_IsoXmitCommandPtr,
+			  video->frames[video->active_frame]->descriptor_pool_dma |
+			  f->first_n_descriptors);
+
+		/* assign a timestamp based on the current cycle time...
+		   We'll tell the card to begin DMA 100 cycles from now,
+		   and assign a timestamp 103 cycles from now */
+
+		cycleTimer = reg_read(video->ohci, OHCI1394_IsochronousCycleTimer);
+
+		ct_sec = cycleTimer >> 25;
+		ct_cyc = (cycleTimer >> 12) & 0x1FFF;
+		ct_off = cycleTimer & 0xFFF;
+
+		transmit_sec = ct_sec;
+		transmit_cyc = ct_cyc + 100;
+
+		transmit_sec += transmit_cyc/8000;
+		transmit_cyc %= 8000;
+		
+		ts_off = ct_off;
+		ts_cyc = transmit_cyc + 3;
+		ts_cyc %= 8000;
+
+		f->assigned_timestamp = (ts_cyc&0xF) << 12;
+
+		/* now actually write the timestamp into the appropriate CIP headers */
+		if(f->cip_syt1) {
+			f->cip_syt1->b[6] = f->assigned_timestamp >> 8;
+			f->cip_syt1->b[7] = f->assigned_timestamp & 0xFF;
+		}
+		if(f->cip_syt2) {
+			f->cip_syt2->b[6] = f->assigned_timestamp >> 8;
+			f->cip_syt2->b[7] = f->assigned_timestamp & 0xFF;
+		}
+		
+		/* --- start DMA --- */
+
+		/* clear all bits in ContextControl register */
+
+		reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, 0xFFFFFFFF);
+		wmb();
+
+		/* the OHCI card has the ability to start ISO transmission on a
+		   particular cycle (start-on-cycle). This way we can ensure that
+		   the first DV frame will have an accurate timestamp.
+		   
+		   However, start-on-cycle only appears to work if the OHCI card 
+		   is cycle master! Since the consequences of messing up the first
+		   timestamp are minimal*, just disable start-on-cycle for now.
+
+		   * my DV deck drops the first few frames before it "locks in;"
+		     so the first frame having an incorrect timestamp is inconsequential.
+		*/
+
+#if 0
+		reg_write(video->ohci, video->ohci_IsoXmitContextControlSet,
+			  (1 << 31) /* enable start-on-cycle */
+			  | ( (transmit_sec & 0x3) << 29)
+			  | (transmit_cyc << 16));
+		wmb();
+#endif
+
+		
+
+		/* set the 'run' bit */
+		reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000);
+		flush_pci_write(video->ohci);
+		
+		/* --- DMA should be running now --- */
+
+		debug_printk("    Cycle = %4u ContextControl = %08x CmdPtr = %08x\n",
+			     (reg_read(video->ohci, OHCI1394_IsochronousCycleTimer) >> 12) & 0x1FFF,
+			     reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
+			     reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
+
+		debug_printk("    DMA start - current cycle %4u, transmit cycle %4u (%2u), assigning ts cycle %2u\n",
+			     ct_cyc, transmit_cyc, transmit_cyc & 0xF, ts_cyc & 0xF);
+
+#if DV1394_DEBUG_LEVEL >= 2
+		{
+			/* check if DMA is really running */
+			int i = 0;
+			while(i < 20) {
+				mb();
+				mdelay(1);
+				if(reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) {
+					printk("DMA ACTIVE after %d msec\n", i);
+					break;
+				}
+				i++;
+			}
+
+			printk("set = %08x, cmdPtr = %08x\n", 
+			       reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
+			       reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
+			       );
+			
+			if( ! (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) &  (1 << 10)) ) {
+				printk("DMA did NOT go active after 20ms, event = %x\n", 
+				       reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & 0x1F);
+			} else
+				printk("DMA is RUNNING!\n");
+		}
+#endif
+		
+	}
+
+
+	spin_unlock_irqrestore(&video->spinlock, irq_flags);
+}
+
+
+
+/*** RECEIVE FUNCTIONS *****************************************************/
+
+/* 
+	frame method put_packet
+
+	map and copy the packet data to its location in the frame 
+	based upon DIF section and sequence 
+*/
+
+static void inline
+frame_put_packet (struct frame *f, struct packet *p)
+{
+	int section_type = p->data[0] >> 5;           /* section type is in bits 5 - 7 */
+	int dif_sequence = p->data[1] >> 4;           /* dif sequence number is in bits 4 - 7 */
+	int dif_block = p->data[2];
+
+	switch (section_type) {
+	case 0:           /* 1 Header block */
+	        memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480);
+	        break;
+	
+	case 1:           /* 2 Subcode blocks */
+	        memcpy( (void *) f->data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p->data, 480);
+	        break;
+	
+	case 2:           /* 3 VAUX blocks */
+	        memcpy( (void *) f->data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p->data, 480);
+	        break;
+	
+	case 3:           /* 9 Audio blocks interleaved with video */
+	        memcpy( (void *) f->data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p->data, 480);
+	        break;
+	
+	case 4:           /* 135 Video blocks interleaved with audio */
+	        memcpy( (void *) f->data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) + dif_block) * 80, p->data, 480);
+	        break;
+	
+	default:           /* we can not handle any other data */
+	        break;
+	}
+}
+
+
+static void start_dma_receive(struct video_card *video, struct frame *frame)
+{
+	/* reset iso recv control register */
+	reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
+	wmb();
+	
+	/* clear bufferFill, set isochHeader and speed (0=100) */
+	reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
+
+	/* match on all tags, listen on channel */
+	reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
+	
+	/* address and first descriptor block + Z=1 */
+	reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,             
+		  frame->descriptor_pool_dma | 1); /* Z=1 */
+	wmb();
+	
+	/* run */
+	reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
+	flush_pci_write(video->ohci);
+	
+	debug_printk("dv1394: DMA started\n");
+
+#if DV1394_DEBUG_LEVEL >= 2
+	{
+		int i;
+	
+		for(i = 0; i < 1000; ++i) {
+			mdelay(1);
+			if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
+				printk("DMA ACTIVE after %d msec\n", i);
+				break;
+			}
+		}
+		if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
+			printk("DEAD, event = %x\n", 
+			       reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+		} else
+			printk("RUNNING!\n");
+	}
+#endif
+}
+
+
+/* 
+   receive_packets() - build the DMA program for receiving
+*/
+
+static void receive_packets(struct video_card *video, struct frame *f)
+{
+	struct DMA_descriptor_block *block = NULL;
+	dma_addr_t block_dma = 0;
+	struct packet *data = NULL;
+	dma_addr_t data_dma = 0;
+	u32 *last_branch_address = NULL;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&video->spinlock, irq_flags);
+
+	video->n_clear_frames = 0;
+	video->first_clear_frame = -1;
+
+	for (video->current_packet = 0; video->current_packet < MAX_PACKET_BUFFER; ++video->current_packet) {
+		/* locate a descriptor block and packet from the buffer */
+		block = &(f->descriptor_pool[video->current_packet]);
+		block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
+		
+		data = &(video->packet_buffer[video->current_packet]);
+		data_dma = ((unsigned long) data - (unsigned long) video->packet_buffer) + video->packet_buffer_dma;
+		
+		/* setup DMA descriptor block */
+		fill_input_last( &(block->u.in.il), 512, data_dma);
+
+		/* link descriptors */
+		last_branch_address = f->frame_end_branch;
+
+		if (last_branch_address)
+			*(last_branch_address) = block_dma | 1; /* set Z=1 */
+
+		f->frame_end_branch = &(block->u.in.il.q[2]);
+	}
+	
+	/* loop tail to head */
+	if (f->frame_end_branch)
+		*(f->frame_end_branch) =  f->descriptor_pool_dma | 1; /* set Z=1 */
+
+	spin_unlock_irqrestore(&video->spinlock, irq_flags);
+
+	if (video->first_run) {
+		/* start DMA once all of the frames are READY */
+		video->first_run = 0;
+		video->current_packet = 0;
+		video->active_frame = f->frame_num;
+		start_dma_receive(video, f);
+	} 
+	else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
+		debug_printk("DEAD, event = %x\n", 
+			     reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+
+		/* wake */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
+	}
+}
+
+
+
+/*** MANAGEMENT FUNCTIONS **************************************************/
+
+static int do_dv1394_init(struct video_card *video, struct dv1394_init *init)
+{
+	unsigned long flags, new_buf_size;
+	int i;
+	u64 chan_mask;
+	int retval = -EINVAL;
+
+	if(init->api_version != DV1394_API_VERSION)
+		goto err;
+	
+	/* first sanitize all the parameters */
+	if( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )
+		goto err;
+
+	if( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )
+		goto err;
+
+	if( (init->syt_offset == 0) || (init->syt_offset > 50) )
+		/* default SYT offset is 3 cycles */
+		init->syt_offset = 3;
+
+	if( (init->channel > 63) || (init->channel < 0) )
+		init->channel = 63;
+
+	chan_mask = (u64)1 << init->channel;
+
+	/* calculate what size DMA buffer is needed */
+	if(init->format == DV1394_NTSC)
+		new_buf_size = DV1394_NTSC_FRAME_SIZE * init->n_frames;
+	else
+		new_buf_size = DV1394_PAL_FRAME_SIZE * init->n_frames;
+
+	/* round up to PAGE_SIZE */
+	if(new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE);
+
+	/* don't allow the user to allocate the DMA buffer more than once */
+	if( (video->user_buf) &&
+	    (video->user_buf_size != new_buf_size) ) {
+		goto err;
+	}
+	
+	/* shutdown the card if it's currently active */
+	/* (the card should not be reset if the parameters are screwy) */
+	if( video_card_initialized(video) )
+		do_dv1394_shutdown(video, 0);
+
+
+	/* try to claim the ISO channel */
+	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
+	if(video->ohci->ISO_channel_usage & chan_mask) {
+		spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+		retval = -EBUSY;
+		goto err;
+	}
+	video->ohci->ISO_channel_usage |= chan_mask;
+	spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+
+	video->channel = init->channel;
+
+	
+	/* find and claim DMA contexts on the OHCI card */
+	
+	if(video->ohci_it_ctx == -1) {
+
+		for(i = 0; i < video->ohci->nb_iso_xmit_ctx; i++) {
+
+			if(! test_and_set_bit(i, &video->ohci->it_ctx_usage)) {
+				video->ohci_it_ctx = i;
+				debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
+				break;
+			}
+		}
+				
+		if(i == video->ohci->nb_iso_xmit_ctx) {
+			printk(KERN_ERR "dv1394: could not find an available IT DMA context\n");
+			retval = -EBUSY;
+			goto err_ctx;
+		}
+	}
+	
+
+	if(video->ohci_ir_ctx == -1) {
+		for(i = 0; i < video->ohci->nb_iso_rcv_ctx; i++) {
+
+			if(! test_and_set_bit(i, &video->ohci->ir_ctx_usage)) {
+				video->ohci_ir_ctx = i;
+				debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
+				break;
+			}
+		}
+				
+		if(i == video->ohci->nb_iso_rcv_ctx) {
+			printk(KERN_ERR "dv1394: could not find an available IR DMA context\n");
+			retval = -EBUSY;
+			goto err_ctx;
+		}
+	}
+
+	
+	/* allocate struct frames */
+	for(i = 0; i < init->n_frames; i++) {
+		video->frames[i] = frame_new(i, video);
+
+		if(!video->frames[i]) {
+			printk(KERN_ERR "dv1394: Cannot allocate frame structs\n");
+			retval = -ENOMEM;
+			goto err_frames;
+		}
+	}
+
+	/* initialize misc. fields of video */
+	video->n_frames = init->n_frames;
+	video->pal_or_ntsc = init->format;
+	
+
+	video->cip_accum = 0;
+	video->continuity_counter = 0;
+
+	video->active_frame = -1;
+	video->first_clear_frame = 0;
+	video->n_clear_frames = video->n_frames;
+	video->dropped_frames = 0;
+
+	video->write_off = 0;
+
+	video->first_run = 1;
+	video->current_packet = -1;
+	video->first_frame = 0;
+
+
+	if(video->pal_or_ntsc == DV1394_NTSC) {
+		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
+		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
+		video->frame_size = DV1394_NTSC_FRAME_SIZE;
+	} else {
+		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL;
+		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL;
+		video->frame_size = DV1394_PAL_FRAME_SIZE;
+	}
+
+	video->syt_offset = init->syt_offset;
+
+	if(video->user_buf == NULL) {
+		unsigned int i;
+		
+		/* allocate the ringbuffer */
+		video->user_buf = rvmalloc(new_buf_size);
+		if(!video->user_buf) {
+			printk(KERN_ERR "dv1394: Cannot allocate frame buffers\n");
+			goto err_frames;
+		}
+		video->user_buf_size = new_buf_size;
+
+		/* allocate the sglist to hold the DMA addresses */
+		video->user_dma.n_pages = video->user_buf_size / PAGE_SIZE;
+		video->user_dma.sglist = kmalloc(video->user_dma.n_pages * sizeof(struct scatterlist), GFP_KERNEL);
+		if(!video->user_dma.sglist) {
+			printk(KERN_ERR "dv1394: Cannot allocate sglist for user buffer\n");
+			goto err_user_buf;
+		}
+
+		/* initialize all fields of all sglist entries to zero
+		   (new requirement due to PCI changes in 2.4.13) */
+
+		memset(video->user_dma.sglist, 0, video->user_dma.n_pages * sizeof(struct scatterlist));
+
+		
+		/* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */
+		for(i = 0; i < video->user_dma.n_pages; i++) {
+			unsigned long va = VMALLOC_VMADDR( (unsigned long) video->user_buf + i * PAGE_SIZE );
+			
+			video->user_dma.sglist[i].page = uvirt_to_page(pgd_offset_k(va), va);
+			video->user_dma.sglist[i].length = PAGE_SIZE;
+		}
+		
+		/* map the buffer in the IOMMU */
+		/* the user_data buffer only allows DMA *to* the card for transmission;
+		   incoming DV data comes through the packet_buffer first, and then is copied to user_data */
+		video->user_dma.n_dma_pages = pci_map_sg(video->ohci->dev,
+							 &video->user_dma.sglist[0],
+							 video->user_dma.n_pages,
+							 PCI_DMA_TODEVICE);
+		if(video->user_dma.n_dma_pages == 0) {
+			printk(KERN_ERR "dv1394: Error mapping user buffer to the IOMMU\n");
+			goto err_user_buf;
+		}
+		
+		debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n", 
+			     video->n_frames, video->user_dma.n_pages,
+			     video->user_dma.n_dma_pages, video->user_buf_size);
+	}
+	
+	/* set up the frame->data pointers */
+	for(i = 0; i < video->n_frames; i++)
+		video->frames[i]->data = (unsigned long) video->user_buf + i * video->frame_size;
+
+	/* allocate packet buffers */
+	video->packet_buffer_size = sizeof(struct packet) * MAX_PACKET_BUFFER;
+	if (video->packet_buffer_size % PAGE_SIZE)
+		video->packet_buffer_size += PAGE_SIZE - (video->packet_buffer_size % PAGE_SIZE);
+
+	
+	video->packet_buffer = kmalloc(video->packet_buffer_size, GFP_KERNEL);
+	
+	if(!video->packet_buffer) {
+		printk(KERN_ERR "dv1394: Cannot allocate packet buffers");
+		retval = -ENOMEM;
+		goto err_user_buf;
+	}
+
+	/* map the packet buffer into the IOMMU */
+	video->packet_buffer_dma = pci_map_single(video->ohci->dev,
+						  video->packet_buffer,
+						  video->packet_buffer_size,
+						  PCI_DMA_FROMDEVICE);
+	if(!video->packet_buffer_dma) {
+		printk(KERN_ERR "dv1394: Cannot map packet buffer to IOMMU");
+		kfree(video->packet_buffer);
+		video->packet_buffer = NULL;
+		retval = -ENOMEM;
+		goto err_user_buf;
+	}
+
+	debug_printk("dv1394: Allocated %d packet buffers for receive, total %lu bytes\n", 
+		     MAX_PACKET_BUFFER, video->packet_buffer_size);
+
+
+	/* set up register offsets for IT context */
+	/* IT DMA context registers are spaced 16 bytes apart */
+	video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx;
+	video->ohci_IsoXmitContextControlClear = OHCI1394_IsoXmitContextControlClear+16*video->ohci_it_ctx;
+	video->ohci_IsoXmitCommandPtr = OHCI1394_IsoXmitCommandPtr+16*video->ohci_it_ctx;
+
+	/* enable interrupts for IT context */
+	reg_write(video->ohci, OHCI1394_IsoXmitIntMaskSet, (1 << video->ohci_it_ctx));
+	debug_printk("dv1394: interrupts enabled for IT context %d\n", video->ohci_it_ctx);
+
+	/* set up register offsets for IR context */
+	/* IR DMA context registers are spaced 32 bytes apart */
+	video->ohci_IsoRcvContextControlSet = OHCI1394_IsoRcvContextControlSet+32*video->ohci_ir_ctx;
+	video->ohci_IsoRcvContextControlClear = OHCI1394_IsoRcvContextControlClear+32*video->ohci_ir_ctx;
+	video->ohci_IsoRcvCommandPtr = OHCI1394_IsoRcvCommandPtr+32*video->ohci_ir_ctx;
+	video->ohci_IsoRcvContextMatch = OHCI1394_IsoRcvContextMatch+32*video->ohci_ir_ctx;
+
+	/* enable interrupts for IR context */
+	reg_write(video->ohci, OHCI1394_IsoRecvIntMaskSet, (1 << video->ohci_ir_ctx) );
+	debug_printk("dv1394: interrupts enabled for IR context %d\n", video->ohci_ir_ctx);
+	
+	return 0;
+
+ err_user_buf:
+	if(video->user_buf) {
+		if(video->user_dma.sglist) {
+			if(video->user_dma.n_dma_pages > 0) {
+				/* unmap it from the IOMMU */
+				pci_unmap_sg(video->ohci->dev,
+					     video->user_dma.sglist,
+					     video->user_dma.n_pages,
+					     PCI_DMA_TODEVICE);
+				video->user_dma.n_dma_pages = 0;
+			}
+			kfree(video->user_dma.sglist);
+			video->user_dma.sglist = NULL;
+			video->user_dma.n_pages = 0;
+		}
+		rvfree(video->user_buf, video->user_buf_size);
+		video->user_buf = NULL;
+		video->user_buf_size = 0;
+	}
+		
+ err_frames:
+	for(i = 0; i < DV1394_MAX_FRAMES; i++) {
+		if(video->frames[i])
+			frame_delete(video->frames[i]);
+	}	
+	video->n_frames = 0;
+
+ err_ctx:
+	if(video->ohci_it_ctx != -1) {
+		clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage);
+		video->ohci_it_ctx = -1;
+	}
+	if(video->ohci_ir_ctx != -1) {
+		clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage);
+		video->ohci_ir_ctx = -1;
+	}
+	
+	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
+	video->ohci->ISO_channel_usage &= ~chan_mask;
+	spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+ err:
+	return retval;
+}
+
+/* if the user doesn't bother to call ioctl(INIT) before starting
+   mmap() or read()/write(), just give him some default values */
+
+static int do_dv1394_init_default(struct video_card *video)
+{
+	struct dv1394_init init;
+
+	init.api_version = DV1394_API_VERSION;
+	init.channel = 63;
+	init.n_frames = 2;
+	/* the following are now set via proc_fs */
+	init.format = video->pal_or_ntsc;
+	init.cip_n = video->cip_n; 
+	init.cip_d = video->cip_d;
+	init.syt_offset = video->syt_offset;
+
+	return do_dv1394_init(video, &init);
+}
+
+/* do NOT call from interrupt context */
+static void stop_dma(struct video_card *video)
+{
+	unsigned long flags;
+	int i;
+	
+	/* no interrupts */
+	spin_lock_irqsave(&video->spinlock, flags);
+
+	/* stop DMA if in progress */
+	if( (video->active_frame != -1) ||
+	    (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
+	    (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) &  (1 << 10)) ) {
+
+		/* clear the .run bits */
+		reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
+		flush_pci_write(video->ohci);
+		
+		video->active_frame = -1;
+		video->first_run = 1;
+
+		
+		/* wait until DMA really stops */
+		i = 0;
+		while(i < 1000) {
+				
+			/* wait 0.1 millisecond */
+			udelay(100); 
+			
+			if( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
+			    (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear)  & (1 << 10)) ) {
+				/* still active */
+				mb();
+			} else {
+				debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10);
+				break;
+			}
+				
+			i++;
+		}
+			
+		if(i == 1000) {
+			printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10);
+		}
+	}
+
+	spin_unlock_irqrestore(&video->spinlock, flags);
+}
+
+
+
+static int do_dv1394_shutdown(struct video_card *video, int free_user_buf)
+{
+	int i;
+
+	debug_printk("dv1394: shutdown...\n");
+
+	/* stop DMA if in progress */
+	stop_dma(video);
+	
+	/* release the ISO channel */
+	if(video->channel != -1) {
+		u64 chan_mask;
+		unsigned long flags;
+		
+		chan_mask = (u64)1 << video->channel;
+		
+		spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
+		video->ohci->ISO_channel_usage &= ~(chan_mask);
+		spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+		
+		video->channel = -1;
+	}
+
+	/* release the DMA contexts */
+	if(video->ohci_it_ctx != -1) {
+		video->ohci_IsoXmitContextControlSet = 0;
+		video->ohci_IsoXmitContextControlClear = 0;
+		video->ohci_IsoXmitCommandPtr = 0;
+
+		/* disable interrupts for IT context */
+		reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx));
+		
+		clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage);
+		debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx);
+		video->ohci_it_ctx = -1;
+	}
+
+	if(video->ohci_ir_ctx != -1) {
+		video->ohci_IsoRcvContextControlSet = 0;
+		video->ohci_IsoRcvContextControlClear = 0;
+		video->ohci_IsoRcvCommandPtr = 0;
+		video->ohci_IsoRcvContextMatch = 0;
+
+		/* disable interrupts for IR context */
+		reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx));
+
+		clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage);
+		debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx);
+		video->ohci_ir_ctx = -1;
+	}
+
+	/* free the frame structs */
+	for(i = 0; i < DV1394_MAX_FRAMES; i++) {
+		if(video->frames[i])
+			frame_delete(video->frames[i]);
+		video->frames[i] = NULL;
+	}
+
+	video->n_frames = 0;
+		
+	/* we can't free the DMA buffer unless it is guaranteed that
+	   no more user-space mappings exist */
+	
+	if(free_user_buf && video->user_buf) {
+		if(video->user_dma.sglist) {
+			if(video->user_dma.n_dma_pages > 0) {
+				/* unmap it from the IOMMU */
+				pci_unmap_sg(video->ohci->dev,
+					     video->user_dma.sglist,
+					     video->user_dma.n_pages,
+					     PCI_DMA_TODEVICE);
+				video->user_dma.n_dma_pages = 0;
+			}
+			kfree(video->user_dma.sglist);
+			video->user_dma.sglist = NULL;
+			video->user_dma.n_pages = 0;
+		}
+		rvfree(video->user_buf, video->user_buf_size);
+		video->user_buf = NULL;
+		video->user_buf_size = 0;
+	}
+	
+	if (video->packet_buffer) {
+		pci_unmap_single(video->ohci->dev,
+				 video->packet_buffer_dma,
+				 video->packet_buffer_size,
+				 PCI_DMA_FROMDEVICE);
+		kfree(video->packet_buffer);
+		video->packet_buffer = NULL;
+		video->packet_buffer_size = 0;
+	}
+
+	debug_printk("dv1394: shutdown complete\n");
+
+	return 0;
+}
+
+
+
+/*
+       **********************************
+       *** MMAP() THEORY OF OPERATION ***
+       **********************************
+
+        The ringbuffer cannot be re-allocated or freed while
+        a user program maintains a mapping of it. (note that a mapping
+	can persist even after the device fd is closed!)
+
+	So, only let the user process allocate the DMA buffer once.
+	To resize or deallocate it, you must close the device file
+	and open it again.
+
+	Previously Dan M. hacked out a scheme that allowed the DMA
+	buffer to change by forcefully unmapping it from the user's
+	address space. It was prone to error because it's very hard to
+	track all the places the buffer could have been mapped (we
+	would have had to walk the vma list of every process in the
+	system to be sure we found all the mappings!). Instead, we
+	force the user to choose one buffer size and stick with
+	it. This small sacrifice is worth the huge reduction in
+	error-prone code in dv1394.
+
+	Note: dv1394_mmap does no page table manipulation. The page
+	table entries are created by the dv1394_nopage() handler as
+	page faults are taken by the user.
+*/
+
+static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access)
+{
+	unsigned long offset;
+	unsigned long page, kernel_virt_addr;
+	struct page *ret = NOPAGE_SIGBUS;
+
+	struct video_card *video = (struct video_card*) area->vm_private_data;
+	
+	/* guard against process-context operations and the interrupt */
+	/* (by definition page faults are taken in interrupt context) */
+	spin_lock(&video->spinlock);
+
+	if(!video->user_buf)
+		goto out;
+
+	if( (address < (unsigned long) area->vm_start) ||
+	    (address > (unsigned long) area->vm_start + video->user_buf_size) )
+		goto out;
+
+	offset = address - area->vm_start;
+	kernel_virt_addr = (unsigned long) video->user_buf + offset;
+
+	page = kvirt_to_pa(kernel_virt_addr);
+	
+	ret = virt_to_page(__va(page));
+	get_page(ret);
+
+ out:
+	spin_unlock(&video->spinlock);
+	return ret;
+}
+
+static struct vm_operations_struct dv1394_vm_ops = {
+	nopage: dv1394_nopage
+};
+
+/*
+  dv1394_mmap does no page table manipulation. The page table entries
+  are created by the dv1394_nopage() handler as page faults are taken
+  by the user.
+*/
+
+int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct video_card *video = file_to_video_card(file);
+	unsigned long size;
+	int res = -EINVAL;
+
+	/* serialize mmap */
+	down(&video->sem);
+
+	if( ! video_card_initialized(video) ) {
+		res = do_dv1394_init_default(video);
+		if(res)
+			goto err;
+	}
+
+	/* region must be page-aligned */
+	if(vma->vm_pgoff != 0)
+		goto err;
+	
+	/* check the size the user is trying to map */
+	size = vma->vm_end - vma->vm_start;
+	if(size > video->user_buf_size)
+		goto err;
+
+	/* 
+	   we don't actually mess with the page tables here.
+	   (nopage() takes care of that from the page fault handler)
+	   Just set up the vma->vm_ops.
+	*/
+
+        vma->vm_ops = &dv1394_vm_ops;
+	vma->vm_private_data = video;
+	vma->vm_file = file;
+
+	/* don't try to swap this out =) */
+	vma->vm_flags |= VM_RESERVED;
+
+	up(&video->sem);
+	return 0;
+ err:
+	up(&video->sem);
+	return res;
+}
+
+
+/*** DEVICE FILE INTERFACE *************************************************/
+
+/* no need to serialize, multiple threads OK */
+static unsigned int dv1394_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct video_card *video = file_to_video_card(file);
+	unsigned int mask = 0;
+	unsigned long flags;
+
+	poll_wait(file, &video->waitq, wait);
+
+	spin_lock_irqsave(&video->spinlock, flags);
+	if( video->n_frames == 0 ) {
+
+	} else if( video->active_frame == -1 ) {
+		/* nothing going on */
+		mask |= POLLOUT;
+	} else {
+		/* any clear/ready buffers? */
+		if(video->n_clear_frames >0)
+			mask |= POLLOUT | POLLIN;
+	}
+	spin_unlock_irqrestore(&video->spinlock, flags);
+
+	return mask;
+}
+
+static int dv1394_fasync(int fd, struct file *file, int on)
+{
+	/* I just copied this code verbatim from Alan Cox's mouse driver example
+	   (linux/Documentation/DocBook/) */
+	
+	struct video_card *video = file_to_video_card(file);
+	
+	int retval = fasync_helper(fd, file, on, &video->fasync);
+	 
+	if (retval < 0)
+		return retval;
+        return 0;
+}
+
+static ssize_t dv1394_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct video_card *video = file_to_video_card(file);
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t ret;
+	size_t cnt;
+	unsigned long flags;
+	int target_frame;
+
+	/* serialize this to prevent multi-threaded mayhem */
+	if(file->f_flags & O_NONBLOCK) {
+		if(down_trylock(&video->sem))
+			return -EAGAIN;
+	} else {
+		if(down_interruptible(&video->sem))
+			return -ERESTARTSYS;
+	}
+
+	if( !video_card_initialized(video) ) {
+		ret = do_dv1394_init_default(video);
+		if(ret) {
+			up(&video->sem);
+			return ret;
+		}
+	}
+
+	ret = 0;
+	add_wait_queue(&video->waitq, &wait);
+	
+	while(count > 0) {
+
+		/* must set TASK_INTERRUPTIBLE *before* checking for free
+		   buffers; otherwise we could miss a wakeup if the interrupt
+		   fires between the check and the schedule() */
+		
+		set_current_state(TASK_INTERRUPTIBLE);
+		
+		spin_lock_irqsave(&video->spinlock, flags);
+		
+		target_frame = video->first_clear_frame;
+		
+		spin_unlock_irqrestore(&video->spinlock, flags);
+
+		if(video->frames[target_frame]->state == FRAME_CLEAR) {
+
+			/* how much room is left in the target frame buffer */
+			cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
+
+		} else {
+			/* buffer is already used */
+			cnt = 0;
+		}
+
+		if(cnt > count)
+			cnt = count;
+
+		if (cnt <= 0) { 
+			/* no room left, gotta wait */
+			if(file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
+
+			schedule();
+			
+			continue; /* start over from 'while(count > 0)...' */
+		}
+
+		if(copy_from_user(video->user_buf + video->write_off, buffer, cnt)) {
+			if(!ret)
+				ret = -EFAULT;
+			break;
+		}
+
+		video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
+
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+
+		if(video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames))
+				frame_prepare(video, target_frame);
+	}
+	
+	remove_wait_queue(&video->waitq, &wait);
+	set_current_state(TASK_RUNNING);
+	up(&video->sem);
+	return ret;
+}
+
+
+static ssize_t dv1394_read(struct file *file,  char *buffer, size_t count, loff_t *ppos)
+{
+	struct video_card *video = file_to_video_card(file);
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t ret;
+	size_t cnt;
+	unsigned long flags;
+	int target_frame;
+
+	/* serialize this to prevent multi-threaded mayhem */
+	if(file->f_flags & O_NONBLOCK) {
+		if(down_trylock(&video->sem))
+			return -EAGAIN;
+	} else {
+		if(down_interruptible(&video->sem))
+			return -ERESTARTSYS;
+	}
+
+	if( !video_card_initialized(video) ) {
+		ret = do_dv1394_init_default(video);
+		if(ret) {
+			up(&video->sem);
+			return ret;
+		}
+		receive_packets(video, video->frames[video->first_clear_frame]);
+	}
+
+	ret = 0;
+	add_wait_queue(&video->waitq, &wait);
+
+	while(count > 0) {
+
+		/* must set TASK_INTERRUPTIBLE *before* checking for free
+		   buffers; otherwise we could miss a wakeup if the interrupt
+		   fires between the check and the schedule() */
+		
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irqsave(&video->spinlock, flags);
+
+		target_frame = video->first_clear_frame;
+
+		spin_unlock_irqrestore(&video->spinlock, flags);
+
+		if(target_frame >= 0 &&
+			video->n_clear_frames > 0 &&
+			video->frames[target_frame]->state == FRAME_CLEAR) {
+
+			/* how much room is left in the target frame buffer */
+			cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
+
+		} else {
+			/* buffer is already used */
+			cnt = 0;
+		}
+
+		if(cnt > count)
+			cnt = count;
+
+		if (cnt <= 0) { 
+			/* no room left, gotta wait */
+			if(file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
+
+			schedule();
+			
+			continue; /* start over from 'while(count > 0)...' */
+		}
+
+		if(copy_to_user(buffer, video->user_buf + video->write_off, cnt)) {
+				if(!ret)
+					ret = -EFAULT;
+				break;
+		}
+
+		video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
+
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+
+		if(video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) {
+			spin_lock_irqsave(&video->spinlock, flags);
+			video->n_clear_frames--;
+			video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
+			spin_unlock_irqrestore(&video->spinlock, flags);
+		}
+	}
+	
+	remove_wait_queue(&video->waitq, &wait);
+	set_current_state(TASK_RUNNING);
+	up(&video->sem);
+	return ret;
+}
+
+
+/*** DEVICE IOCTL INTERFACE ************************************************/
+
+/* I *think* the VFS serializes ioctl() for us, so we don't have to worry
+   about situations like having two threads in here at once... */
+
+static int dv1394_ioctl(struct inode *inode, struct file *file,
+			   unsigned int cmd, unsigned long arg)
+{
+	struct video_card *video = file_to_video_card(file);
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	DECLARE_WAITQUEUE(wait, current);
+
+	/* serialize this to prevent multi-threaded mayhem */
+	if(file->f_flags & O_NONBLOCK) {
+		if(down_trylock(&video->sem))
+			return -EAGAIN;
+	} else {
+		if(down_interruptible(&video->sem))
+			return -ERESTARTSYS;
+	}
+
+	switch(cmd)
+	{
+	case DV1394_SUBMIT_FRAMES: {
+		unsigned int n_submit;
+
+		if( !video_card_initialized(video) ) {
+			ret = do_dv1394_init_default(video);
+			if(ret)
+				goto out;
+		}
+
+		n_submit = (unsigned int) arg;
+
+		if(n_submit > video->n_frames) {
+			ret = -EINVAL;
+			goto out;
+		}
+			
+		while(n_submit > 0) {
+
+			add_wait_queue(&video->waitq, &wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+				
+			spin_lock_irqsave(&video->spinlock, flags);
+
+			/* wait until video->first_clear_frame is really CLEAR */
+			while(video->frames[video->first_clear_frame]->state != FRAME_CLEAR) {
+
+				spin_unlock_irqrestore(&video->spinlock, flags);
+					
+				if(signal_pending(current)) {
+					remove_wait_queue(&video->waitq, &wait);
+					set_current_state(TASK_RUNNING);
+					ret = -EINTR;
+					goto out;
+				}
+
+				schedule();
+				set_current_state(TASK_INTERRUPTIBLE);
+				
+				spin_lock_irqsave(&video->spinlock, flags);
+			}
+			spin_unlock_irqrestore(&video->spinlock, flags);
+
+			remove_wait_queue(&video->waitq, &wait);
+			set_current_state(TASK_RUNNING);
+				
+			frame_prepare(video, video->first_clear_frame);
+
+			n_submit--;
+		}
+
+		ret = 0;
+		break;
+	}
+
+	case DV1394_WAIT_FRAMES: {
+		unsigned int n_wait;
+
+		if( !video_card_initialized(video) ) {
+			ret = -EINVAL;
+			goto out;
+		}
+		
+		n_wait = (unsigned int) arg;
+
+		/* since we re-run the last frame on underflow, we will
+		   never actually have n_frames clear frames; at most only
+		   n_frames - 1 */
+
+		if(n_wait > (video->n_frames-1) ) {
+			ret = -EINVAL;
+			goto out;
+		}
+			
+		add_wait_queue(&video->waitq, &wait);
+		set_current_state(TASK_INTERRUPTIBLE);
+		
+		spin_lock_irqsave(&video->spinlock, flags);
+
+		while(video->n_clear_frames < n_wait) {
+			
+			spin_unlock_irqrestore(&video->spinlock, flags);
+					
+			if(signal_pending(current)) {
+				remove_wait_queue(&video->waitq, &wait);
+				set_current_state(TASK_RUNNING);
+				ret = -EINTR;
+				goto out;
+			}
+
+			schedule();
+			set_current_state(TASK_INTERRUPTIBLE);
+			
+			spin_lock_irqsave(&video->spinlock, flags);
+		}
+
+		spin_unlock_irqrestore(&video->spinlock, flags);
+
+		remove_wait_queue(&video->waitq, &wait);
+		set_current_state(TASK_RUNNING);
+		ret = 0;
+		break;
+	}
+
+	case DV1394_RECEIVE_FRAMES: {
+		unsigned int n_recv;
+
+		if( !video_card_initialized(video) ) {
+			ret = -EINVAL;
+			goto out;
+		}
+		
+		n_recv = (unsigned int) arg;
+
+		/* at least one frame must be active */
+		if(n_recv > (video->n_frames-1) ) {
+			ret = -EINVAL;
+			goto out;
+		}
+			
+		spin_lock_irqsave(&video->spinlock, flags);
+
+		/* release the clear frames */
+		video->n_clear_frames -= n_recv;
+
+		/* advance the clear frame cursor */
+		video->first_clear_frame = (video->first_clear_frame + n_recv) % video->n_frames;
+
+		/* reset dropped_frames */
+		video->dropped_frames = 0;
+			
+		spin_unlock_irqrestore(&video->spinlock, flags);
+
+		ret = 0;
+		break;
+	}
+
+	case DV1394_START_RECEIVE: {
+
+		if( !video_card_initialized(video) ) {
+			ret = do_dv1394_init_default(video);
+			if(ret)
+				goto out;
+		}
+	
+		receive_packets(video, video->frames[video->first_clear_frame]);
+
+		ret = 0;
+		break;
+	}
+
+	case DV1394_INIT: {
+		struct dv1394_init init;
+		if(arg == (unsigned long) NULL) {
+			ret = do_dv1394_init_default(video);
+		} else {
+			if(copy_from_user(&init, (void*)arg, sizeof(init))) {
+				ret = -EFAULT;
+				goto out;
+			}
+			ret = do_dv1394_init(video, &init);
+		}
+		break;
+	}
+
+	case DV1394_SHUTDOWN:
+		ret = do_dv1394_shutdown(video, 0);
+		break;
+
+
+        case DV1394_GET_STATUS: {
+		struct dv1394_status status;
+
+		if( !video_card_initialized(video) ) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		status.init.api_version = DV1394_API_VERSION;
+		status.init.channel = video->channel;
+		status.init.n_frames = video->n_frames;
+		status.init.format = video->pal_or_ntsc;
+		status.init.cip_n = video->cip_n;
+		status.init.cip_d = video->cip_d;
+		status.init.syt_offset = video->syt_offset;
+
+		status.first_clear_frame = video->first_clear_frame;
+
+		/* the rest of the fields need to be locked against the interrupt */
+		spin_lock_irqsave(&video->spinlock, flags);
+
+		status.active_frame = video->active_frame;
+		status.n_clear_frames = video->n_clear_frames;
+
+		status.dropped_frames = video->dropped_frames;
+
+		/* reset dropped_frames */
+		video->dropped_frames = 0;
+			
+		spin_unlock_irqrestore(&video->spinlock, flags);
+
+		if(copy_to_user((void*)arg, &status, sizeof(status))) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		ret = 0;
+		break;
+	}
+
+	default:
+		break;
+	}
+
+ out:
+	up(&video->sem);
+	return ret;
+}
+
+
+
+/*** DEVICE FILE INTERFACE CONTINUED ***************************************/
+
+static int dv1394_open(struct inode *inode, struct file *file)
+{
+	struct video_card *video = NULL;
+
+	/* if the device was opened through devfs, then file->private_data
+	   has already been set to video by devfs */
+	if(file->private_data) {
+		video = (struct video_card*) file->private_data;
+		
+	} else {
+		/* look up the card by ID */
+		
+		struct list_head *lh;
+		unsigned long flags;
+		
+		spin_lock_irqsave(&dv1394_cards_lock, flags);
+		if(!list_empty(&dv1394_cards)) {
+			struct video_card *p;
+			list_for_each(lh, &dv1394_cards) {
+				p = list_entry(lh, struct video_card, list);
+				if(p->id == ieee1394_file_to_instance(file)) {
+					video = p;
+					break;
+				}
+			}
+		}
+		spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+
+		if(!video) {
+			debug_printk("dv1394: OHCI card %d not found", ieee1394_file_to_instance(file));
+			return -ENODEV;
+		}
+		
+		file->private_data = (void*) video;
+	}
+	
+#ifndef DV1394_ALLOW_MORE_THAN_ONE_OPEN
+
+	if( test_and_set_bit(0, &video->open) ) {
+		/* video is already open by someone else */
+		return -EBUSY;
+ 	}
+
+#endif
+
+	V22_COMPAT_MOD_INC_USE_COUNT;
+	return 0;
+}
+
+
+static int dv1394_release(struct inode *inode, struct file *file)
+{
+	struct video_card *video = file_to_video_card(file);
+
+	/* OK to free the DMA buffer, no more mappings can exist */
+	do_dv1394_shutdown(video, 1);
+
+	/* clean up async I/O users */
+	dv1394_fasync(-1, file, 0);
+	
+	/* give someone else a turn */
+	clear_bit(0, &video->open);
+
+	V22_COMPAT_MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+/*** PROC_FS INTERFACE ******************************************************/
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *dv1394_procfs_entry;
+
+static int dv1394_procfs_read( char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	struct video_card *video = (struct video_card*) data;
+
+	V22_COMPAT_MOD_INC_USE_COUNT;
+	snprintf( page, count, 
+		"\
+dv1394 settings for host %d:\n\
+----------------------------\n\
+format=%s\n\
+cip_n=%lu\n\
+cip_d=%lu\n\
+syt_offset=%u\n",
+		video->id,
+		(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
+		video->cip_n, video->cip_d, video->syt_offset );
+	V22_COMPAT_MOD_DEC_USE_COUNT;
+	return strlen(page);
+}
+#endif /* CONFIG_PROC_FS */
+
+/* lifted from the stallion.c driver */
+#undef  TOLOWER
+#define TOLOWER(x)      ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x))
+static unsigned long atol(char *str)
+{
+	unsigned long   val;
+	int             base, c;
+	char            *sp;
+
+	val = 0;
+	sp = str;
+	if ((*sp == '0') && (*(sp+1) == 'x')) {
+		base = 16;
+		sp += 2;
+	} else if (*sp == '0') {
+		base = 8;
+		sp++;
+	} else {
+		base = 10;
+	}
+
+	for (; (*sp != 0); sp++) {
+		c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0');
+		if ((c < 0) || (c >= base)) {
+			printk(KERN_ERR "dv1394: atol() invalid argument %s\n", str);
+			val = 0;
+			break;
+		}
+		val = (val * base) + c;
+	}
+	return(val);
+}
+
+#ifdef CONFIG_PROC_FS
+static int dv1394_procfs_write( struct file *file,
+			const char *buffer, unsigned long count, void *data)
+{
+	int len = 0;
+	char new_value[64];
+	char *pos;
+	struct video_card *video = (struct video_card*) data;
+	
+	V22_COMPAT_MOD_INC_USE_COUNT;
+	
+	if (count > 64)
+		len = 64;
+	else
+		len = count;
+				
+	if (copy_from_user( new_value, buffer, len)) {
+		V22_COMPAT_MOD_DEC_USE_COUNT;
+		return -EFAULT;
+	}
+	
+	pos = strchr(new_value, '=');
+	if (pos != NULL) {
+		int val_len = len - (pos-new_value) - 1;
+		char buf[64];
+		memset(buf, 0, 64);
+		strncpy(buf, pos+1, val_len);
+		if (buf[val_len-1] == '\n') buf[val_len-1] = 0;
+		
+		if (strnicmp( new_value, "format", (pos-new_value)) == 0) {
+			if (strnicmp( buf, "NTSC", val_len) == 0)
+				video->pal_or_ntsc = DV1394_NTSC;
+			else if (strnicmp( buf, "PAL", val_len) == 0)
+				video->pal_or_ntsc = DV1394_PAL;
+				
+		} else if (strnicmp( new_value, "cip_n", (pos-new_value)) == 0) {
+			video->cip_n = atol(buf);
+		} else if (strnicmp( new_value, "cip_d", (pos-new_value)) == 0) {
+			video->cip_d = atol(buf);
+		} else if (strnicmp( new_value, "syt_offset", (pos-new_value)) == 0) {
+			video->syt_offset = atol(buf);
+		}
+	}
+	
+	V22_COMPAT_MOD_DEC_USE_COUNT;
+	return len;
+}
+
+static int dv1394_procfs_add_entry(struct video_card *video)
+{
+	struct proc_dir_entry *procfs_entry = NULL;
+	char buf[16];
+	
+	snprintf(buf, sizeof(buf), "%d", video->id);
+
+	procfs_entry = create_proc_entry( buf, 0666, dv1394_procfs_entry);
+	if (procfs_entry == NULL) {
+		printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv/X\n");
+		return -ENOMEM;
+	}
+	procfs_entry->owner = THIS_MODULE;
+	procfs_entry->data = video;
+	procfs_entry->read_proc = dv1394_procfs_read;
+	procfs_entry->write_proc = dv1394_procfs_write;
+	
+	return 0;
+}
+#endif /* CONFIG_PROC_FS */
+
+/*** DEVICE DRIVER HANDLERS ************************************************/
+
+static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
+			quadlet_t isoXmitIntEvent, void *data)
+{
+	int wake = 0;
+	struct video_card *video = (struct video_card*) data;
+
+	irq_printk("INTERRUPT! Video = %08lx Iso event Recv: %08x Xmit: %08x\n",
+		   (unsigned long) video, isoRecvIntEvent, isoXmitIntEvent);
+	irq_printk("ContextControl = %08x, CommandPtr = %08x\n", 
+	       reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
+	       reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
+	       );
+
+	
+	if( (video->ohci_it_ctx != -1) &&
+	    (isoXmitIntEvent & (1 << video->ohci_it_ctx)) &&
+	    (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
+
+		struct frame *f;
+		unsigned int frame, i;
+
+		spin_lock(&video->spinlock);
+		if(video->active_frame == -1)
+			frame = 0;
+		else
+			frame = video->active_frame;
+
+		/* check all the DMA-able frames */
+		for(i = 0; i < video->n_frames; i++, frame = (frame+1) % video->n_frames) {
+
+			irq_printk("IRQ checking frame %d...", frame);
+			f = video->frames[frame];
+			if(f->state != FRAME_READY) {
+				irq_printk("clear, skipping\n");
+				/* we don't own this frame */
+				continue;
+			}
+
+			irq_printk("DMA\n");
+
+			/* check the frame begin semaphore to see if we can free the previous frame */
+			if( *(f->frame_begin_timestamp) ) {
+				int prev_frame;
+				struct frame *prev_f;
+
+				
+
+				/* don't reset, need this later *(f->frame_begin_timestamp) = 0; */
+				irq_printk("  BEGIN\n");
+
+				prev_frame = frame - 1;
+				if(prev_frame == -1)
+					prev_frame += video->n_frames;
+				prev_f = video->frames[prev_frame];
+				
+				/* make sure we can actually garbage collect
+				   this frame */
+				if( (prev_f->state == FRAME_READY) &&
+				    prev_f->done && (!f->done) ) 
+				{
+					frame_reset(prev_f);
+					video->n_clear_frames++;
+					wake = 1;
+					video->active_frame = frame;
+
+					irq_printk("  BEGIN - freeing previous frame %d, new active frame is %d\n", prev_frame, frame);
+				} else {
+					irq_printk("  BEGIN - can't free yet\n");
+				}
+
+				f->done = 1;
+			}
+
+		     
+			/* see if we need to set the timestamp for the next frame */
+			if( *(f->mid_frame_timestamp) ) {
+				struct frame *next_frame;
+				u32 ts_cyc, ts_off;
+
+				*(f->mid_frame_timestamp) = 0;
+
+				irq_printk("  MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n",
+				       *(f->frame_begin_timestamp) & 0x1FFF, *(f->frame_begin_timestamp) & 0xF,
+				       f->assigned_timestamp >> 12,       f->assigned_timestamp & 0xFFF);
+
+				/* prepare next frame and assign timestamp */
+				next_frame = video->frames[ (frame+1) % video->n_frames ];
+
+				if(next_frame->state == FRAME_READY) {
+					irq_printk("  MIDDLE - next frame is ready, good\n");
+				} else {
+					debug_printk("dv1394: Underflow! At least one frame has been dropped.\n");
+					next_frame = f;
+				}
+
+				/* set the timestamp to the timestamp of the last frame sent,
+				   plus the length of the last frame sent, plus the syt latency */
+				ts_cyc = *(f->frame_begin_timestamp) & 0xF;
+				/* advance one frame, plus syt latency (typically 2-3) */
+				ts_cyc += f->n_packets + video->syt_offset ; 
+
+				ts_off = 0; 
+
+				ts_cyc += ts_off/3072;
+				ts_off %= 3072;
+
+				next_frame->assigned_timestamp = ((ts_cyc&0xF) << 12) + ts_off;
+				if(next_frame->cip_syt1) {
+					next_frame->cip_syt1->b[6] = next_frame->assigned_timestamp >> 8;
+					next_frame->cip_syt1->b[7] = next_frame->assigned_timestamp & 0xFF;
+				}
+				if(next_frame->cip_syt2) {
+					next_frame->cip_syt2->b[6] = next_frame->assigned_timestamp >> 8;
+					next_frame->cip_syt2->b[7] = next_frame->assigned_timestamp & 0xFF;
+				}
+
+			}
+
+			/* see if the frame looped */
+			if( *(f->frame_end_timestamp) ) {
+
+				*(f->frame_end_timestamp) = 0;
+
+				debug_printk("  END - the frame looped at least once\n");
+
+				video->dropped_frames++;
+			}
+
+
+		
+		} /* for(each frame) */
+
+		spin_unlock(&video->spinlock);
+		
+	} /* end XMIT portion */
+
+	/***** RECEIVE INTERRUPT and DMA ACTIVE *****/
+
+	else if( (video->ohci_ir_ctx != -1) &&
+		 (isoRecvIntEvent & (1 << video->ohci_ir_ctx)) &&
+		 (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { 
+
+		int sof=0; /* start-of-frame flag */
+		struct frame *f;
+
+		spin_lock(&video->spinlock);
+
+		irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet,
+			   video->packet_buffer[video->current_packet].timestamp, video->packet_buffer[video->current_packet].data_length, 
+			   video->packet_buffer[video->current_packet].data[0], video->packet_buffer[video->current_packet].data[1]);
+		
+		f = video->frames[video->active_frame];
+
+		/* exclude empty packet */
+		if (video->packet_buffer[video->current_packet].data_length > 8) {
+		
+			/* check for start of frame */
+			sof = (video->packet_buffer[video->current_packet].data[0] == 0x1f &&
+				video->packet_buffer[video->current_packet].data[1] == 0x07);
+
+			if (!video->first_frame) {
+				if (sof) {
+					video->first_frame = 1;
+				}
+
+			} else if (sof) {
+				/* close current frame */
+				frame_reset(f);  /* f->state = STATE_CLEAR */
+				video->n_clear_frames++;
+				if (video->n_clear_frames > video->n_frames) {
+					video->n_clear_frames = video->n_frames;
+					video->dropped_frames++;
+				}
+				if (video->first_clear_frame == -1)
+					video->first_clear_frame = video->active_frame;
+
+				/* get the next frame */
+				video->active_frame = (video->active_frame + 1) % video->n_frames;
+				f = video->frames[video->active_frame];
+			
+				irq_printk("   frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
+					   video->active_frame, video->n_clear_frames, video->first_clear_frame);
+ 			}
+			if (video->first_frame) {
+				if (sof) {
+					/* open next frame */
+					f->state = FRAME_READY;
+				}
+				
+				/* copy to buffer */
+				if (f->n_packets > (video->frame_size / 480)) {
+					printk(KERN_ERR "frame buffer overflow during receive\n");
+				}
+
+				/* make sure we are seeing the latest changes to packet_buffer */
+				pci_dma_sync_single(video->ohci->dev,
+						    video->packet_buffer_dma,
+						    video->packet_buffer_size,
+						    PCI_DMA_FROMDEVICE);
+				
+				frame_put_packet( f, &video->packet_buffer[video->current_packet]);
+				
+			} /* first_frame */
+ 
+		} /* not empty packet */
+ 
+		/* advance packet_buffer cursor */
+		video->current_packet = (video->current_packet + 1) % MAX_PACKET_BUFFER;
+ 
+ 		spin_unlock(&video->spinlock);
+
+		wake = 1; /* why the hell not? */
+
+	} /* receive interrupt */
+
+	if(wake) {
+		
+		/* send SIGIO */
+		
+		if(isoRecvIntEvent & (1))
+			kill_fasync(&video->fasync, SIGIO, POLL_IN);
+		
+		if(isoXmitIntEvent & (1))
+			kill_fasync(&video->fasync, SIGIO, POLL_OUT);
+		
+		/* wake readers/writers/ioctl'ers */
+		wake_up_interruptible(&video->waitq);
+	}
+}
+
+static struct file_operations dv1394_fops=
+{
+        OWNER_THIS_MODULE
+	poll:           dv1394_poll,
+	ioctl:		dv1394_ioctl,
+	mmap:		dv1394_mmap,
+	open:		dv1394_open,
+	write:          dv1394_write,
+	read:           dv1394_read,
+	release:	dv1394_release,
+	fasync:         dv1394_fasync,
+};
+
+
+static int dv1394_init(struct ti_ohci *ohci)
+{
+	struct video_card *video;
+	unsigned long flags;
+	char buf[16];
+	int i;
+
+	video = kmalloc(sizeof(struct video_card), GFP_KERNEL);
+	if(!video) {
+		printk(KERN_ERR "dv1394: cannot allocate video_card\n");
+		goto err;
+	}
+	
+	memset(video, 0, sizeof(struct video_card));
+	
+	if (ohci1394_hook_irq(ohci, irq_handler, (void*) video) != 0) {
+		printk(KERN_ERR "dv1394: ohci1394_hook_irq() failed\n");
+		goto err_free;
+	}
+
+	
+	video->ohci = ohci;
+	video->id = ohci->id;
+
+	if ( dv1394_procfs_add_entry(video) < 0 )
+		goto err_free;
+
+	video->ohci_it_ctx = -1;
+	video->ohci_ir_ctx = -1;
+
+	video->ohci_IsoXmitContextControlSet = 0;
+	video->ohci_IsoXmitContextControlClear = 0;
+	video->ohci_IsoXmitCommandPtr = 0;
+	
+	video->ohci_IsoRcvContextControlSet = 0;
+	video->ohci_IsoRcvContextControlClear = 0;
+	video->ohci_IsoRcvCommandPtr = 0;
+	video->ohci_IsoRcvContextMatch = 0;
+		
+	video->n_frames = 0; /* flag that video is not initialized */
+	video->channel = -1;
+	video->active_frame = -1;
+	
+	/* initialize the following for proc_fs */
+	video->pal_or_ntsc = DV1394_NTSC;
+	video->cip_n = 0; /* 0 = use builtin default */
+	video->cip_d = 0;
+	video->syt_offset = 0;
+
+	for(i = 0; i < DV1394_MAX_FRAMES; i++)
+		video->frames[i] = NULL;
+
+	video->user_buf = NULL;
+	video->user_buf_size = 0;
+
+	clear_bit(0, &video->open);
+	spin_lock_init(&video->spinlock);
+	init_MUTEX(&video->sem);
+	init_waitqueue_head(&video->waitq);
+	video->fasync = NULL;
+
+	spin_lock_irqsave(&dv1394_cards_lock, flags);
+	INIT_LIST_HEAD(&video->list);
+	list_add_tail(&video->list, &dv1394_cards);
+	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+	
+	snprintf(buf, sizeof(buf), "%d", video->id);
+	
+	video->devfs_handle = devfs_register(dv1394_devfs_handle,
+					     buf, DEVFS_FL_NONE,
+					     IEEE1394_MAJOR,
+					     IEEE1394_MINOR_BLOCK_DV1394*16 + video->id,
+					     S_IFCHR | S_IRUGO | S_IWUGO,
+					     &dv1394_fops,
+					     (void*) video);
+
+	debug_printk("dv1394: dv1394_init() OK on ID %d\n", ohci->id);
+	
+	return 0;
+
+ err_free:
+	kfree(video);
+ err:
+	return -1;
+}
+
+static void dv1394_un_init(struct video_card *video)
+{
+	unsigned long flags;
+	
+	/* obviously nobody has the driver open at this point */
+	do_dv1394_shutdown(video, 1);
+	ohci1394_unhook_irq(video->ohci, irq_handler, (void*) video);
+	if(video->devfs_handle)
+		devfs_unregister(video->devfs_handle);
+
+	spin_lock_irqsave(&dv1394_cards_lock, flags);
+	list_del(&video->list);
+	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+	
+	kfree(video);
+}
+
+	
+static void dv1394_remove_host (struct hpsb_host *host)
+{
+	struct ti_ohci *ohci;
+	struct video_card *video = NULL;
+	unsigned long flags;
+	struct list_head *lh;
+	
+	/* We only work with the OHCI-1394 driver */
+	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
+		return;
+
+	ohci = (struct ti_ohci *)host->hostdata;
+
+
+	/* find the corresponding video_card */
+	spin_lock_irqsave(&dv1394_cards_lock, flags);
+	if(!list_empty(&dv1394_cards)) {
+		struct video_card *p;
+		list_for_each(lh, &dv1394_cards) {
+			p = list_entry(lh, struct video_card, list);
+			if(p->id == ohci->id) {
+				video = p;
+				break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+
+	if(video) {
+		char buf[16];
+		dv1394_un_init(video);
+		snprintf( buf, sizeof(buf), "%i", video->id);
+#ifdef CONFIG_PROC_FS
+		remove_proc_entry( buf, dv1394_procfs_entry);
+#endif
+	}
+}
+
+static void dv1394_add_host (struct hpsb_host *host)
+{
+	struct ti_ohci *ohci;
+
+	/* We only work with the OHCI-1394 driver */
+	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
+		return;
+
+	ohci = (struct ti_ohci *)host->hostdata;
+
+	dv1394_init(ohci);
+}
+
+static struct hpsb_highlevel_ops hl_ops = {
+	add_host:	dv1394_add_host,
+	remove_host:	dv1394_remove_host,
+};
+
+
+/*** KERNEL MODULE HANDLERS ************************************************/
+
+MODULE_AUTHOR("Dan Maas <dmaas@dcine.com>, Dan Dennedy <dan@dennedy.org>");
+MODULE_DESCRIPTION("driver for DV input/output on OHCI board");
+MODULE_SUPPORTED_DEVICE("dv1394");
+MODULE_LICENSE("GPL");
+
+static void __exit dv1394_exit_module(void)
+{
+	hpsb_unregister_highlevel (hl_handle);
+	ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+	devfs_unregister(dv1394_devfs_handle);
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry( "dv", ieee1394_procfs_entry);
+#endif
+}
+
+static int __init dv1394_init_module(void)
+{
+	if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_DV1394,
+				      THIS_MODULE, &dv1394_fops)) {
+		printk(KERN_ERR "dv1394: unable to register character device\n");
+		return -EIO;
+	}
+
+	dv1394_devfs_handle = devfs_mk_dir(ieee1394_devfs_handle, "dv", NULL);
+
+#ifdef CONFIG_PROC_FS
+	dv1394_procfs_entry = proc_mkdir( "dv", ieee1394_procfs_entry);
+	if (dv1394_procfs_entry == NULL) {
+		printk(KERN_ERR "dv1394: unable to create /proc/ieee1394/dv\n");
+		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+		devfs_unregister(dv1394_devfs_handle);
+		return -ENOMEM;
+	}
+	dv1394_procfs_entry->owner = THIS_MODULE;
+#endif
+
+	hl_handle = hpsb_register_highlevel ("dv1394", &hl_ops);
+	if (hl_handle == NULL) {
+		printk(KERN_ERR "dv1394: hpsb_register_highlevel failed\n");
+		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+		devfs_unregister(dv1394_devfs_handle);
+#ifdef CONFIG_PROC_FS
+		remove_proc_entry( "dv", ieee1394_procfs_entry);
+#endif
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+module_init(dv1394_init_module);
+module_exit(dv1394_exit_module);
+
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/dv1394.h linux/drivers/ieee1394/dv1394.h
--- v2.5.2/linux/drivers/ieee1394/dv1394.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/ieee1394/dv1394.h	Mon Jan 21 15:57:51 2002
@@ -0,0 +1,277 @@
+/*
+ * dv1394.h - DV input/output over IEEE 1394 on OHCI chips
+ *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
+ *     receive, proc_fs by Dan Dennedy <dan@dennedy.org>
+ *
+ * based on:
+ *   video1394.h - driver for OHCI 1394 boards
+ *   Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
+ *                          Peter Schlaile <udbz@rz.uni-karlsruhe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DV_1394_H
+#define _DV_1394_H
+
+/* This is the public user-space interface. Try not to break it. */
+
+#define DV1394_API_VERSION 0x20011127
+
+/* ********************
+   **                **
+   **   DV1394 API   **
+   **                **
+   ********************
+
+   There are two methods of operating the DV1394 DV output device.
+
+   1)
+
+   The simplest is an interface based on write(): simply write
+   full DV frames of data to the device, and they will be transmitted
+   as quickly as possible. The FD may be set for non-blocking I/O,
+   in which case you can use select() or poll() to wait for output
+   buffer space.
+
+   To set the DV output parameters (e.g. whether you want NTSC or PAL
+   video), use the DV1394_INIT ioctl, passing in the parameters you
+   want in a struct dv1394_init.
+ 
+   Example 1:
+         To play a raw .DV file:   cat foo.DV > /dev/dv1394
+	 (cat will use write() internally)
+
+   Example 2:
+           static struct dv1394_init init = {
+	      0x63,        (broadcast channel)
+              4,           (four-frame ringbuffer)
+	      DV1394_NTSC, (send NTSC video)
+	      0, 0         (default empty packet rate)
+           }
+
+	   ioctl(fd, DV1394_INIT, &init);
+
+	   while(1) {
+	          read( <a raw DV file>, buf, DV1394_NTSC_FRAME_SIZE );
+		  write( <the dv1394 FD>, buf, DV1394_NTSC_FRAME_SIZE );
+           }
+
+   2)
+
+   For more control over buffering, and to avoid unnecessary copies
+   of the DV data, you can use the more sophisticated the mmap() interface. 
+   First, call the DV1394_INIT ioctl to specify your parameters, 
+   including the number of frames in the ringbuffer. Then, calling mmap() 
+   on the dv1394 device will give you direct access to the ringbuffer
+   from which the DV card reads your frame data.
+
+   The ringbuffer is simply one large, contiguous region of memory
+   containing two or more frames of packed DV data. Each frame of DV data
+   is 120000 bytes (NTSC) or 144000 bytes (PAL).
+
+   Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES
+   ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl
+   or select()/poll() to wait until the frames are transmitted. Next, you'll
+   need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer
+   frames are clear (ready to be filled with new DV data). Finally, use
+   DV1394_SUBMIT_FRAMES again to send the new data to the DV output.
+
+
+   Example: here is what a four-frame ringbuffer might look like
+            during DV transmission:
+
+
+         frame 0   frame 1   frame 2   frame 3
+
+	*--------------------------------------*
+        | CLEAR   | DV data | DV data | CLEAR  |
+        *--------------------------------------*
+                   <ACTIVE> 
+
+	transmission goes in this direction --->>>
+
+
+   The DV hardware is currently transmitting the data in frame 1.
+   Once frame 1 is finished, it will automatically transmit frame 2.
+   (if frame 2 finishes before frame 3 is submitted, the device
+   will continue to transmit frame 2, and will increase the dropped_frames
+   counter each time it repeats the transmission).
+
+ 
+   If you called DV1394_GET_STATUS at this instant, you would
+   receive the following values:
+   
+                  n_frames          = 4
+		  active_frame      = 1
+		  first_clear_frame = 3
+		  n_clear_frames    = 2
+
+   At this point, you should write new DV data into frame 3 and optionally
+   frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that
+   it may transmit the new frames.
+
+*/
+
+
+/* maximum number of frames in the ringbuffer */
+#define DV1394_MAX_FRAMES 32
+
+/* number of *full* isochronous packets per DV frame */
+#define DV1394_NTSC_PACKETS_PER_FRAME 250
+#define DV1394_PAL_PACKETS_PER_FRAME  300
+
+/* size of one frame's worth of DV data, in bytes */
+#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME)
+#define DV1394_PAL_FRAME_SIZE  (480 * DV1394_PAL_PACKETS_PER_FRAME)
+
+
+/* ioctl() commands */
+
+enum {
+	/* I don't like using 0 as a valid ioctl() */
+	DV1394_INVALID = 0,
+
+
+	/* get the driver ready to transmit video.
+	   pass a struct dv1394_init* as the parameter (see below),
+	   or NULL to get default parameters */
+	DV1394_INIT,
+
+
+	/* stop transmitting video and free the ringbuffer */
+	DV1394_SHUTDOWN,
+
+
+	/* submit N new frames to be transmitted, where
+	   the index of the first new frame is first_clear_buffer,
+	   and the index of the last new frame is
+	   (first_clear_buffer + N) % n_frames */
+	DV1394_SUBMIT_FRAMES,
+
+
+	/* block until N buffers are clear (pass N as the parameter)
+	   Because we re-transmit the last frame on underrun, there
+	   will at most be n_frames - 1 clear frames at any time */
+	DV1394_WAIT_FRAMES,
+
+	/* capture new frames that have been received, where
+	   the index of the first new frame is first_clear_buffer,
+	   and the index of the last new frame is
+	   (first_clear_buffer + N) % n_frames */
+	DV1394_RECEIVE_FRAMES,
+
+
+	DV1394_START_RECEIVE,
+
+
+	/* pass a struct dv1394_status* as the parameter (see below) */
+	DV1394_GET_STATUS,
+};
+
+
+
+enum pal_or_ntsc {
+	DV1394_NTSC = 0,
+	DV1394_PAL
+};
+
+
+
+
+/* this is the argument to DV1394_INIT */
+struct dv1394_init {
+	/* DV1394_API_VERSION */
+	unsigned int api_version;
+	
+	/* isochronous transmission channel to use */
+	unsigned int channel;
+
+	/* number of frames in the ringbuffer. Must be at least 2
+	   and at most DV1394_MAX_FRAMES. */
+	unsigned int n_frames;
+
+	/* send/receive PAL or NTSC video format */
+	enum pal_or_ntsc format;
+
+	/* the following are used only for transmission */
+ 
+	/* set these to zero unless you want a
+	   non-default empty packet rate (see below) */
+	unsigned long cip_n;
+	unsigned long cip_d;
+
+	/* set this to zero unless you want a
+	   non-default SYT cycle offset (default = 3 cycles) */
+	unsigned int syt_offset;
+};
+
+/* Q: What are cip_n and cip_d? */
+
+/*
+  A: DV video streams do not utilize 100% of the potential bandwidth offered
+  by IEEE 1394 (FireWire). To achieve the correct rate of data transmission,
+  DV devices must periodically insert empty packets into the 1394 data stream.
+  Typically there is one empty packet per 14-16 data-carrying packets.
+
+  Some DV devices will accept a wide range of empty packet rates, while others
+  require a precise rate. If the dv1394 driver produces empty packets at
+  a rate that your device does not accept, you may see ugly patterns on the
+  DV output, or even no output at all.
+
+  The default empty packet insertion rate seems to work for many people; if
+  your DV output is stable, you can simply ignore this discussion. However,
+  we have exposed the empty packet rate as a parameter to support devices that
+  do not work with the default rate. 
+
+  The decision to insert an empty packet is made with a numerator/denominator
+  algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D.
+  You can alter the empty packet rate by passing non-zero values for cip_n
+  and cip_d to the INIT ioctl.
+  
+ */
+
+
+
+struct dv1394_status {
+	/* this embedded init struct returns the current dv1394
+	   parameters in use */
+	struct dv1394_init init;
+
+	/* the ringbuffer frame that is currently being
+	   displayed. (-1 if the device is not transmitting anything) */
+	int active_frame;
+
+	/* index of the first buffer (ahead of active_frame) that
+	   is ready to be filled with data */
+	unsigned int first_clear_frame;
+
+	/* how many buffers, including first_clear_buffer, are
+	   ready to be filled with data */
+	unsigned int n_clear_frames;
+
+	/* how many times the DV output has underflowed
+	   since the last call to DV1394_GET_STATUS */
+	unsigned int dropped_frames;
+
+	/* N.B. The dropped_frames counter is only a lower bound on the actual
+	   number of dropped frames, with the special case that if dropped_frames
+	   is zero, then it is guaranteed that NO frames have been dropped
+	   since the last call to DV1394_GET_STATUS.
+	*/
+};
+
+
+#endif /* _DV_1394_H */
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/highlevel.c linux/drivers/ieee1394/highlevel.c
--- v2.5.2/linux/drivers/ieee1394/highlevel.c	Mon Oct  1 21:24:24 2001
+++ linux/drivers/ieee1394/highlevel.c	Mon Jan 21 15:57:51 2002
@@ -44,10 +44,11 @@
         hl->op = ops;
 
         write_lock_irq(&hl_drivers_lock);
-        hl_all_hosts(hl, 1);
         list_add_tail(&hl->hl_list, &hl_drivers);
         write_unlock_irq(&hl_drivers_lock);
 
+        hl_all_hosts(hl->op->add_host);
+
         return hl;
 }
 
@@ -73,9 +74,11 @@
 
         write_lock_irq(&hl_drivers_lock);
         list_del(&hl->hl_list);
-        hl_all_hosts(hl, 0);
         write_unlock_irq(&hl_drivers_lock);
 
+        if (hl->op->remove_host)
+		hl_all_hosts(hl->op->remove_host);
+
         kfree(hl);
 }
 
@@ -87,7 +90,7 @@
         int retval = 0;
 
         if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) {
-                HPSB_ERR(__FUNCTION__ " called with invalid addresses");
+                HPSB_ERR("%s called with invalid addresses", __FUNCTION__);
                 return 0;
         }
 
@@ -131,12 +134,12 @@
                          unsigned int channel)
 {
         if (channel > 63) {
-                HPSB_ERR(__FUNCTION__ " called with invalid channel");
+                HPSB_ERR("%s called with invalid channel", __FUNCTION__);
                 return;
         }
 
         if (host->iso_listen_count[channel]++ == 0) {
-                host->template->devctl(host, ISO_LISTEN_CHANNEL, channel);
+                host->ops->devctl(host, ISO_LISTEN_CHANNEL, channel);
         }
 }
 
@@ -144,46 +147,58 @@
                            unsigned int channel)
 {
         if (channel > 63) {
-                HPSB_ERR(__FUNCTION__ " called with invalid channel");
+                HPSB_ERR("%s called with invalid channel", __FUNCTION__);
                 return;
         }
 
         if (--host->iso_listen_count[channel] == 0) {
-                host->template->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
+                host->ops->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
         }
 }
 
 
-#define DEFINE_MULTIPLEXER(Function)			\
-void highlevel_##Function(struct hpsb_host *host)	\
-{							\
-	struct list_head *lh;				\
-	void (*funcptr)(struct hpsb_host*);		\
-	read_lock(&hl_drivers_lock);			\
-	list_for_each(lh, &hl_drivers) {		\
-		funcptr = list_entry(lh, struct hpsb_highlevel, hl_list) \
-				->op->Function;		\
-		if (funcptr) funcptr(host);		\
-	}						\
-	read_unlock(&hl_drivers_lock);			\
-}
-
-DEFINE_MULTIPLEXER(add_host)
-DEFINE_MULTIPLEXER(remove_host)
-DEFINE_MULTIPLEXER(host_reset)
-#undef DEFINE_MULTIPLEXER
-
-/* Add one host to our list */
-void highlevel_add_one_host (struct hpsb_host *host)
-{
-	if (host->template->initialize_host)
-		if (!host->template->initialize_host(host))
-			goto fail;
-	host->initialized = 1;
-	highlevel_add_host (host);
-	hpsb_reset_bus (host, LONG_RESET);
-fail:
-	host->template->number_of_hosts++;
+void highlevel_add_host(struct hpsb_host *host)
+{
+        struct list_head *entry;
+        struct hpsb_highlevel *hl;
+
+        read_lock(&hl_drivers_lock);
+        list_for_each(entry, &hl_drivers) {
+                hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+
+		hl->op->add_host(host);
+        }
+        read_unlock(&hl_drivers_lock);
+}
+
+void highlevel_remove_host(struct hpsb_host *host)
+{
+        struct list_head *entry;
+        struct hpsb_highlevel *hl;
+
+        write_lock_irq(&hl_drivers_lock);
+	list_for_each(entry, &hl_drivers) {
+                hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+
+		if (hl->op->remove_host)
+			hl->op->remove_host(host);
+        }
+        write_unlock_irq(&hl_drivers_lock);
+}
+
+void highlevel_host_reset(struct hpsb_host *host)
+{
+        struct list_head *entry;
+        struct hpsb_highlevel *hl;
+
+	read_lock(&hl_drivers_lock);
+	list_for_each(entry, &hl_drivers) {
+                hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+
+                if (hl->op->host_reset)
+                        hl->op->host_reset(host);
+        }
+	read_unlock(&hl_drivers_lock);
 }
 
 void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
@@ -242,12 +257,11 @@
 
         while (as->start <= addr) {
                 if (as->end > addr) {
-                        partlength = MIN((unsigned int)(as->end - addr),
-                                         length);
+                        partlength = min(as->end - addr, (u64) length);
 
                         if (as->op->read != NULL) {
-                                rcode = as->op->read(host, nodeid, buffer, addr,
-                                                     partlength);
+                                rcode = as->op->read(host, nodeid, buffer,
+						     addr, partlength);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -288,12 +302,11 @@
 
         while (as->start <= addr) {
                 if (as->end > addr) {
-                        partlength = MIN((unsigned int)(as->end - addr),
-                                         length);
+                        partlength = min(as->end - addr, (u64) length);
 
                         if (as->op->write != NULL) {
-                                rcode = as->op->write(host, nodeid, destid, data,
-						      addr, partlength);
+                                rcode = as->op->write(host, nodeid, destid,
+						      data, addr, partlength);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/highlevel.h linux/drivers/ieee1394/highlevel.h
--- v2.5.2/linux/drivers/ieee1394/highlevel.h	Thu Jul 19 17:48:15 2001
+++ linux/drivers/ieee1394/highlevel.h	Mon Jan 21 15:57:51 2002
@@ -91,7 +91,6 @@
 void init_hpsb_highlevel(void);
 
 void highlevel_add_host(struct hpsb_host *host);
-void highlevel_add_one_host(struct hpsb_host *host);
 void highlevel_remove_host(struct hpsb_host *host);
 void highlevel_host_reset(struct hpsb_host *host);
 
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/hosts.c linux/drivers/ieee1394/hosts.c
--- v2.5.2/linux/drivers/ieee1394/hosts.c	Mon Oct  1 21:24:24 2001
+++ linux/drivers/ieee1394/hosts.c	Mon Jan 21 15:57:51 2002
@@ -11,101 +11,86 @@
  */
 
 #include <linux/config.h>
-
 #include <linux/types.h>
+#include <linux/list.h>
 #include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
+#include <linux/slab.h>
 
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394_core.h"
 #include "highlevel.h"
 
+static struct list_head hosts = LIST_HEAD_INIT(hosts);
+static struct list_head host_drivers = LIST_HEAD_INIT(host_drivers);
 
-static LIST_HEAD(templates);
-static spinlock_t templates_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t hosts_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t host_drivers_lock = SPIN_LOCK_UNLOCKED;
 
-/*
- * This function calls the add_host/remove_host hooks for every host currently
- * registered.  Init == TRUE means add_host.
- */
-void hl_all_hosts(struct hpsb_highlevel *hl, int init)
+
+static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
 {
-	struct list_head *tlh, *hlh;
-        struct hpsb_host_template *tmpl;
-        struct hpsb_host *host;
+        return 0;
+}
 
-        spin_lock(&templates_lock);
+static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg)
+{
+        return -1;
+}
 
-	list_for_each(tlh, &templates) {
-                tmpl = list_entry(tlh, struct hpsb_host_template, list);
-		list_for_each(hlh, &tmpl->hosts) {
-			host = list_entry(hlh, struct hpsb_host, list);
-                        if (host->initialized) {
-                                if (init) {
-                                        if (hl->op->add_host) {
-                                                hl->op->add_host(host);
-                                        }
-                                } else {
-                                        if (hl->op->remove_host) {
-                                                hl->op->remove_host(host);
-                                        }
-                                }
-                        }
-                }
-        }
+static struct hpsb_host_operations dummy_ops = {
+        transmit_packet:  dummy_transmit_packet,
+        devctl:           dummy_devctl
+};
 
-        spin_unlock(&templates_lock);
-}
 
-int hpsb_inc_host_usage(struct hpsb_host *host)
+int hpsb_ref_host(struct hpsb_host *host)
 {
-	struct list_head *tlh, *hlh;
-        struct hpsb_host_template *tmpl;
-        int retval = 0;
+        struct list_head *lh;
 	unsigned long flags;
+        int retval = 0;
 
-        spin_lock_irqsave(&templates_lock, flags);
-
-	list_for_each(tlh, &templates) {
-                tmpl = list_entry(tlh, struct hpsb_host_template, list);
-		list_for_each(hlh, &tmpl->hosts) {
-			if (host == list_entry(hlh, struct hpsb_host, list)) {
-                                tmpl->devctl(host, MODIFY_USAGE, 1);
+        spin_lock_irqsave(&hosts_lock, flags);
+        list_for_each(lh, &hosts) {
+                if (host == list_entry(lh, struct hpsb_host, host_list)) {
+                        if (host->ops->devctl(host, MODIFY_USAGE, 1)) {
+				host->refcount++;
                                 retval = 1;
-                                break;
-                        }
                 }
-		if (retval)
 			break;
         }
-
-        spin_unlock_irqrestore(&templates_lock, flags);
+        }
+        spin_unlock_irqrestore(&hosts_lock, flags);
 
         return retval;
 }
 
-void hpsb_dec_host_usage(struct hpsb_host *host)
+void hpsb_unref_host(struct hpsb_host *host)
 {
-        host->template->devctl(host, MODIFY_USAGE, 0);
+        unsigned long flags;
+
+        host->ops->devctl(host, MODIFY_USAGE, 0);
+
+        spin_lock_irqsave(&hosts_lock, flags);
+        host->refcount--;
+
+        if (!host->refcount && !host->is_shutdown)
+                kfree(host);
+        spin_unlock_irqrestore(&hosts_lock, flags);
 }
 
-/*
- * The following function is exported for module usage.  It will be called from
- * the detect function of a adapter driver.
- */
-struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl, 
-                                size_t hd_size)
+struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra)
 {
         struct hpsb_host *h;
 
-        h = vmalloc(sizeof(struct hpsb_host) + hd_size);
+        h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL);
         if (!h) return NULL;
 
-        memset(h, 0, sizeof(struct hpsb_host) + hd_size);
+        memset(h, 0, sizeof(struct hpsb_host) + extra);
 
-        atomic_set(&h->generation, 0);
+        h->driver = drv;
+        h->ops = drv->ops;
+	h->hostdata = h + 1;
 
         INIT_LIST_HEAD(&h->pending_packets);
         spin_lock_init(&h->pending_pkt_lock);
@@ -113,113 +98,92 @@
         sema_init(&h->tlabel_count, 64);
         spin_lock_init(&h->tlabel_lock);
 
+	atomic_set(&h->generation, 0);
+
 	INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h);
 
         h->topology_map = h->csr.topology_map + 3;
         h->speed_map = (u8 *)(h->csr.speed_map + 2);
 
-        h->template = tmpl;
-        if (hd_size)
-                h->hostdata = &h->embedded_hostdata[0];
+	return h;
+}
+
+void hpsb_add_host(struct hpsb_host *host)
+{
+        unsigned long flags;
 
-	list_add_tail(&h->list, &tmpl->hosts);
+        spin_lock_irqsave(&hosts_lock, flags);
+        host->driver->number_of_hosts++;
+        list_add_tail(&host->driver_list, &host->driver->hosts);
+        list_add_tail(&host->host_list, &hosts);
+        spin_unlock_irqrestore(&hosts_lock, flags);
 
-        return h;
+        highlevel_add_host(host);
+        host->ops->devctl(host, RESET_BUS, 0);
 }
 
-static void free_all_hosts(struct hpsb_host_template *tmpl)
+void hpsb_remove_host(struct hpsb_host *host)
 {
-	struct list_head *hlh, *next;
-        struct hpsb_host *host;
+        struct hpsb_host_driver *drv = host->driver;
+        unsigned long flags;
 
-	list_for_each_safe(hlh, next, &tmpl->hosts) {
-		host = list_entry(hlh, struct hpsb_host, list);
-                vfree(host);
-        }
+        host->is_shutdown = 1;
+        host->ops = &dummy_ops;
+        highlevel_remove_host(host);
+
+        spin_lock_irqsave(&hosts_lock, flags);
+        list_del(&host->driver_list);
+        list_del(&host->host_list);
+
+        drv->number_of_hosts--;
+        if (!host->refcount) kfree(host);
+        spin_unlock_irqrestore(&hosts_lock, flags);
 }
 
 
-static void init_hosts(struct hpsb_host_template *tmpl)
+struct hpsb_host_driver *hpsb_register_lowlevel(struct hpsb_host_operations *op,
+                                                const char *name)
 {
-        int count;
-	struct list_head *hlh;
-        struct hpsb_host *host;
+        struct hpsb_host_driver *drv;
 
-        count = tmpl->detect_hosts(tmpl);
+        drv = kmalloc(sizeof(struct hpsb_host_driver), SLAB_KERNEL);
+        if (!drv) return NULL;
 
-	list_for_each(hlh, &tmpl->hosts) {
-		host = list_entry(hlh, struct hpsb_host, list);
-                if (tmpl->initialize_host(host)) {
-                        host->initialized = 1;
+        INIT_LIST_HEAD(&drv->list);
+        INIT_LIST_HEAD(&drv->hosts);
+        drv->number_of_hosts = 0;
+        drv->name = name;
+        drv->ops = op;
 
-                        highlevel_add_host(host);
-                        hpsb_reset_bus(host, LONG_RESET);
-                }
-        }
+        spin_lock(&host_drivers_lock);
+        list_add_tail(&drv->list, &host_drivers);
+        spin_unlock(&host_drivers_lock);
 
-        tmpl->number_of_hosts = count;
-        HPSB_INFO("detected %d %s adapter%s", count, tmpl->name,
-                  (count != 1 ? "s" : ""));
+        return drv;
 }
 
-static void shutdown_hosts(struct hpsb_host_template *tmpl)
+void hpsb_unregister_lowlevel(struct hpsb_host_driver *drv)
 {
-	struct list_head *hlh;
-        struct hpsb_host *host;
+        spin_lock(&host_drivers_lock);
+        list_del(&drv->list);
+        spin_unlock(&host_drivers_lock);
 
-	list_for_each(hlh, &tmpl->hosts) {
-		host = list_entry(hlh, struct hpsb_host, list);
-                if (host->initialized) {
-                        host->initialized = 0;
-                        abort_requests(host);
-
-                        highlevel_remove_host(host);
-
-                        tmpl->release_host(host);
-                        while (test_bit(0, &host->timeout_tq.sync)) {
-                                schedule();
-                        }
-                }
-        }
-        free_all_hosts(tmpl);
-        tmpl->release_host(NULL);
-
-        tmpl->number_of_hosts = 0;
+        kfree(drv);
 }
 
 
 /*
- * The following two functions are exported symbols for module usage.
+ * This function calls the given function for every host currently registered.
  */
-int hpsb_register_lowlevel(struct hpsb_host_template *tmpl)
+void hl_all_hosts(void (*function)(struct hpsb_host*))
 {
-	INIT_LIST_HEAD(&tmpl->hosts);
-	tmpl->number_of_hosts = 0;
-
-        spin_lock(&templates_lock);
-	list_add_tail(&tmpl->list, &templates);
-        spin_unlock(&templates_lock);
-
-	/* PCI cards should be smart and use the PCI detection layer, and
-	 * not this one shot deal. detect_hosts() will be obsoleted soon. */
-	if (tmpl->detect_hosts != NULL) {
-		HPSB_DEBUG("Registered %s driver, initializing now", tmpl->name);
-		init_hosts(tmpl);
-	}
-
-        return 0;
-}
-
-void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl)
-{
-        shutdown_hosts(tmpl);
+        struct list_head *lh;
+        struct hpsb_host *host;
 
-        if (tmpl->number_of_hosts)
-                HPSB_PANIC("attempted to remove busy host template "
-			   "of %s at address 0x%p", tmpl->name, tmpl);
-	else {
-		spin_lock(&templates_lock);
-		list_del(&tmpl->list);
-		spin_unlock(&templates_lock);
+        spin_lock_irq(&hosts_lock);
+        list_for_each (lh, &hosts) {
+                host = list_entry(lh, struct hpsb_host, host_list);
+                function(host);
 	}
+        spin_unlock_irq(&hosts_lock);
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/hosts.h linux/drivers/ieee1394/hosts.h
--- v2.5.2/linux/drivers/ieee1394/hosts.h	Mon Oct  1 21:24:24 2001
+++ linux/drivers/ieee1394/hosts.h	Mon Jan 21 15:57:51 2002
@@ -13,11 +13,15 @@
 struct hpsb_packet;
 
 struct hpsb_host {
-/* private fields (hosts, do not use them) */
-	struct list_head list;
+        struct list_head host_list;
+
+        struct hpsb_host_operations *ops;
+        void *hostdata;
 
         atomic_t generation;
 
+        int refcount;
+
         struct list_head pending_packets;
         spinlock_t pending_pkt_lock;
         struct tq_struct timeout_tq;
@@ -28,16 +32,8 @@
         struct semaphore tlabel_count;
         spinlock_t tlabel_lock;
 
-        int reset_retries;
-        quadlet_t *topology_map;
-        u8 *speed_map;
-        struct csr_control csr;
-
         unsigned char iso_listen_count[64];
 
-/* readonly fields for hosts */
-        struct hpsb_host_template *template;
-
         int node_count; /* number of identified nodes on this bus */
         int selfid_count; /* total number of SelfIDs received */
 
@@ -45,9 +41,9 @@
         nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
         nodeid_t busmgr_id; /* ID of this bus' bus manager */
 
-        unsigned initialized:1; /* initialized and usable */
-        unsigned in_bus_reset:1; /* in bus reset / SelfID stage */
-        unsigned attempt_root:1; /* attempt to become root during next reset */
+        /* this nodes state */
+        unsigned in_bus_reset:1;
+        unsigned is_shutdown:1;
 
         /* this nodes' duties on the bus */
         unsigned is_root:1;
@@ -55,11 +51,15 @@
         unsigned is_irm:1;
         unsigned is_busmgr:1;
 
-/* fields readable and writeable by the hosts */
+        int reset_retries;
+        quadlet_t *topology_map;
+        u8 *speed_map;
+        struct csr_control csr;
+
+        struct hpsb_host_driver *driver;
+        struct list_head driver_list;
 
-        void *hostdata;
 	struct pci_dev *pdev;
-        int embedded_hostdata[0];
 };
 
 
@@ -88,8 +88,10 @@
          * Return void. */
         CANCEL_REQUESTS,
 
-        /* Decrease module usage count if arg == 0, increase otherwise.  Return
-         * void. */
+        /* Decrease host usage count if arg == 0, increase otherwise.  Return
+         * 1 for success, 0 for failure.  Increase usage may fail if the driver
+         * is in the process of shutting itself down.  Decrease usage can not
+         * fail. */
         MODIFY_USAGE,
 
         /* Start or stop receiving isochronous channel in arg.  Return void.
@@ -109,37 +111,7 @@
         SHORT_RESET
 };
 
-struct hpsb_host_template {
-	struct list_head list;
-
-        struct list_head hosts;
-        int number_of_hosts;
-
-        /* fields above will be ignored and overwritten after registering */
-
-        /* This should be the name of the driver (single word) and must not be
-         * NULL. */
-        const char *name;
-
-        /* This function shall detect all available adapters of this type and
-         * call hpsb_get_host for each one.  The initialize_host function will
-         * be called to actually set up these adapters.  The number of detected
-         * adapters or zero if there are none must be returned.
-         */
-        int (*detect_hosts) (struct hpsb_host_template *template);
-
-        /* After detecting and registering hosts, this function will be called
-         * for every registered host.  It shall set up the host to be fully
-         * functional for bus operations and return 0 for failure.
-         */
-        int (*initialize_host) (struct hpsb_host *host);
-
-        /* To unload modules, this function is provided.  It shall free all
-         * resources this host is using (if host is not NULL) or free all
-         * resources globally allocated by the driver (if host is NULL).
-         */
-        void (*release_host) (struct hpsb_host *host); 
-
+struct hpsb_host_operations {
         /* This function must store a pointer to the configuration ROM into the
          * location referenced to by pointer and return the size of the ROM. It
          * may not fail.  If any allocation is required, it must be done
@@ -175,34 +147,43 @@
                                  quadlet_t data, quadlet_t compare);
 };
 
+struct hpsb_host_driver {
+        struct list_head list;
 
+        struct list_head hosts;
 
-/* mid level internal use */
+        int number_of_hosts;
+        const char *name;
+
+        struct hpsb_host_operations *ops;
+};
+
+
+/* core internal use */
 void register_builtin_lowlevels(void);
 
 /* high level internal use */
 struct hpsb_highlevel;
-void hl_all_hosts(struct hpsb_highlevel *hl, int init);
+void hl_all_hosts(void (*function)(struct hpsb_host*));
 
-/* 
- * These functions are for lowlevel (host) driver use.
- */
-int hpsb_register_lowlevel(struct hpsb_host_template *tmpl);
-void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl);
 
 /*
- * Get a initialized host structure with hostdata_size bytes allocated in
- * embedded_hostdata for free usage.  Returns NULL for failure.  
+ * In order to prevent hosts from unloading, use hpsb_ref_host().  This prevents
+ * the host from going away (e.g. makes module unloading of the driver
+ * impossible), but still can not guarantee it (e.g. PC-Card being pulled by the
+ * user).  hpsb_ref_host() returns false if host could not be locked.  If it is
+ * successful, host is valid as a pointer until hpsb_unref_host() (not just
+ * until after remove_host).
  */
-struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl, 
-                                size_t hostdata_size);
+int hpsb_ref_host(struct hpsb_host *host);
+void hpsb_unref_host(struct hpsb_host *host);
 
-/*
- * Increase / decrease host usage counter.  Increase function will return true
- * only if successful (host still existed).  Decrease function expects host to
- * exist.
- */
-int hpsb_inc_host_usage(struct hpsb_host *host);
-void hpsb_dec_host_usage(struct hpsb_host *host);
+struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra);
+void hpsb_add_host(struct hpsb_host *host);
+void hpsb_remove_host(struct hpsb_host *h);
+
+struct hpsb_host_driver *hpsb_register_lowlevel(struct hpsb_host_operations *op,
+                                                const char *name);
+void hpsb_unregister_lowlevel(struct hpsb_host_driver *drv);
 
 #endif /* _IEEE1394_HOSTS_H */
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/ieee1394.h linux/drivers/ieee1394/ieee1394.h
--- v2.5.2/linux/drivers/ieee1394/ieee1394.h	Wed Oct 17 14:19:20 2001
+++ linux/drivers/ieee1394/ieee1394.h	Mon Jan 21 15:57:51 2002
@@ -39,10 +39,10 @@
 #define ACK_TYPE_ERROR           0xe 
 
 /* Non-standard "ACK codes" for internal use */
-#define ACKX_NONE                -1
-#define ACKX_SEND_ERROR          -2
-#define ACKX_ABORTED             -3
-#define ACKX_TIMEOUT             -4
+#define ACKX_NONE                (-1)
+#define ACKX_SEND_ERROR          (-2)
+#define ACKX_ABORTED             (-3)
+#define ACKX_TIMEOUT             (-4)
 
 
 #define SPEED_100                0x0
@@ -116,7 +116,7 @@
 
 /*
  * Note: these mean to be bit fields of a big endian SelfID as seen on a little
- * endian machine.
+ * endian machine.  Without swapping.
  */
 
 struct selfid {
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c
--- v2.5.2/linux/drivers/ieee1394/ieee1394_core.c	Wed Oct 17 14:19:20 2001
+++ linux/drivers/ieee1394/ieee1394_core.c	Mon Jan 21 15:57:51 2002
@@ -18,9 +18,11 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/proc_fs.h>
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/semaphore.h>
+#include <asm/smplock.h>
 
 #include "ieee1394_types.h"
 #include "ieee1394.h"
@@ -135,12 +137,8 @@
 
 int hpsb_reset_bus(struct hpsb_host *host, int type)
 {
-        if (!host->initialized) {
-                return 1;
-        }
-
         if (!host->in_bus_reset) {
-                host->template->devctl(host, RESET_BUS, type);
+                host->ops->devctl(host, RESET_BUS, type);
                 return 0;
         } else {
                 return 1;
@@ -151,8 +149,8 @@
 int hpsb_bus_reset(struct hpsb_host *host)
 {
         if (host->in_bus_reset) {
-                HPSB_NOTICE(__FUNCTION__ 
-                            " called while bus reset already in progress");
+                HPSB_NOTICE("%s called while bus reset already in progress",
+			    __FUNCTION__);
                 return 1;
         }
 
@@ -171,10 +169,10 @@
  * Verify num_of_selfids SelfIDs and return number of nodes.  Return zero in
  * case verification failed.
  */
-static int check_selfids(struct hpsb_host *host, unsigned int num_of_selfids)
+static int check_selfids(struct hpsb_host *host)
 {
         int nodeid = -1;
-        int rest_of_selfids = num_of_selfids;
+        int rest_of_selfids = host->selfid_count;
         struct selfid *sid = (struct selfid *)host->topology_map;
         struct ext_selfid *esid;
         int esid_seq = 23;
@@ -318,15 +316,18 @@
 
 void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
 {
-        host->node_id = 0xffc0 | phyid;
-        host->in_bus_reset = 0;
+	if (!host->in_bus_reset)
+		HPSB_NOTICE("SelfID completion called outside of bus reset!");
+
+        host->node_id = LOCAL_BUS | phyid;
         host->is_root = isroot;
 
-        host->node_count = check_selfids(host, host->selfid_count);
+        host->node_count = check_selfids(host);
         if (!host->node_count) {
                 if (host->reset_retries++ < 20) {
                         /* selfid stage did not complete without error */
                         HPSB_NOTICE("Error in SelfID stage, resetting");
+			host->in_bus_reset = 0;
                         hpsb_reset_bus(host, LONG_RESET);
                         return;
                 } else {
@@ -346,8 +347,9 @@
         }
 
         host->reset_retries = 0;
-        atomic_inc(&host->generation);
-        if (isroot) host->template->devctl(host, ACT_CYCLE_MASTER, 1);
+        if (isroot) host->ops->devctl(host, ACT_CYCLE_MASTER, 1);
+	atomic_inc(&host->generation);
+	host->in_bus_reset = 0;
         highlevel_host_reset(host);
 }
 
@@ -402,7 +404,7 @@
 {
         struct hpsb_host *host = packet->host;
 
-        if (!host->initialized || host->in_bus_reset 
+        if (host->is_shutdown || host->in_bus_reset
             || (packet->generation != get_hpsb_generation(host))) {
                 return 0;
         }
@@ -431,7 +433,7 @@
         }
 #endif
 
-        return host->template->transmit_packet(host, packet);
+        return host->ops->transmit_packet(host, packet);
 }
 
 static void send_packet_nocare(struct hpsb_packet *packet)
@@ -727,7 +729,7 @@
         struct list_head *lh;
         LIST_HEAD(llist);
 
-        host->template->devctl(host, CANCEL_REQUESTS, 0);
+        host->ops->devctl(host, CANCEL_REQUESTS, 0);
 
         spin_lock_irqsave(&host->pending_pkt_lock, flags);
         list_splice(&host->pending_packets, &llist);
@@ -786,10 +788,228 @@
 }
 
 
+/*
+ * character device dispatching (see ieee1394_core.h)
+ * Dan Maas <dmaas@dcine.com>
+ */
+
+static struct {
+	struct file_operations *file_ops;
+	struct module *module;
+} ieee1394_chardevs[16];
+
+static rwlock_t ieee1394_chardevs_lock = RW_LOCK_UNLOCKED;
+
+static int ieee1394_dispatch_open(struct inode *inode, struct file *file);
+
+static struct file_operations ieee1394_chardev_ops = {
+	OWNER_THIS_MODULE
+	open: ieee1394_dispatch_open,
+};
+
+devfs_handle_t ieee1394_devfs_handle;
+
+
+/* claim a block of minor numbers */
+int ieee1394_register_chardev(int blocknum,
+			      struct module *module,
+			      struct file_operations *file_ops)
+{
+	int retval;
+	
+	if( (blocknum < 0) || (blocknum > 15) )
+		return -EINVAL;
+
+	write_lock(&ieee1394_chardevs_lock);
+
+	if(ieee1394_chardevs[blocknum].file_ops == NULL) {
+		/* grab the minor block */
+		ieee1394_chardevs[blocknum].file_ops = file_ops;
+		ieee1394_chardevs[blocknum].module = module;
+		
+		retval = 0;
+
+		V22_COMPAT_MOD_INC_USE_COUNT;
+	} else {
+		/* block already taken */
+		retval = -EBUSY;
+	}
+	
+	write_unlock(&ieee1394_chardevs_lock);
+
+	return retval;
+}
+
+/* release a block of minor numbers */
+void ieee1394_unregister_chardev(int blocknum)
+{
+	if( (blocknum < 0) || (blocknum > 15) )
+		return;
+	
+	write_lock(&ieee1394_chardevs_lock);
+	
+	if(ieee1394_chardevs[blocknum].file_ops) {
+		ieee1394_chardevs[blocknum].file_ops = NULL;
+		ieee1394_chardevs[blocknum].module = NULL;
+		V22_COMPAT_MOD_DEC_USE_COUNT;
+	}
+	
+	write_unlock(&ieee1394_chardevs_lock);
+}
+
+/* the point of entry for open() on any ieee1394 character device */
+static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
+{
+	struct file_operations *file_ops;
+	struct module *module;
+	int blocknum;
+	int retval = -ENODEV;
+
+	/*
+	  Maintaining correct module reference counts is tricky here!
+
+	  For Linux v2.2:
+
+	  The task-specific driver is expected to maintain its own
+	  reference count via V22_COMPAT_MOD_[INC,DEC]_USE_COUNT.
+	  We don't need to do anything special.
+	  
+	  For Linux v2.4 and later:
+	  
+	  The key thing to remember is that the VFS increments the
+	  reference count of ieee1394 before it calls
+	  ieee1394_dispatch_open().
+
+	  If the open() succeeds, then we need to transfer this extra
+	  reference to the task-specific driver module (e.g. raw1394).
+	  The VFS will deref the driver module automatically when the
+	  file is later released.
+
+	  If the open() fails, then the VFS will drop the
+	  reference count of whatever module file->f_op->owner points
+	  to, immediately after this function returns.
+
+	  The comments below refer to the 2.4 case, since the 2.2
+	  case is trivial.
+	  
+	*/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+	/* 2.2 */
+#define INCREF(mod) do {} while (0)
+#define DECREF(mod) do {} while (0)
+#else
+	/* 2.4 */
+#define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \
+                          if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0)
+#define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \
+                          if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0)
+#endif
+	
+        /* shift away lower four bits of the minor
+	   to get the index of the ieee1394_driver
+	   we want */
+	
+	blocknum = (minor(inode->i_rdev) >> 4) & 0xF;
+
+	/* printk("ieee1394_dispatch_open(%d)", blocknum); */
+
+	/* lock the whole kernel here, to prevent a driver from
+	   being unloaded between the file_ops lookup and the open */
+
+	lock_kernel();
+
+	read_lock(&ieee1394_chardevs_lock);
+	file_ops = ieee1394_chardevs[blocknum].file_ops;
+	module = ieee1394_chardevs[blocknum].module;
+	read_unlock(&ieee1394_chardevs_lock);
+
+	if(file_ops == NULL) {
+		goto out_fail;
+	}
+
+	/* redirect all subsequent requests to the driver's
+	   own file_operations */
+	file->f_op = file_ops;
+
+	/* bump the reference count of the driver that
+	   will receive the open() */
+	INCREF(module);
+	
+	/* at this point BOTH ieee1394 and the task-specific driver have
+	   an extra reference */
+
+	/* follow through with the open() */
+	retval = file_ops->open(inode, file);
+
+	if(retval) {
+		
+		/* if the open() failed, then we need to drop the
+                   extra reference we gave to the task-specific
+                   driver */
+
+		DECREF(module);
+		goto out_fail;
+		
+	} else {
+
+		/* if the open() succeeded, then ieee1394 will be left
+		   with an extra module reference, so we discard it here.*/
+
+		DECREF(THIS_MODULE);
+
+		/* the task-specific driver still has the extra
+		   reference we gave it. This extra reference prevents
+		   the module from unloading while the file is open,
+		   and will be dropped by the VFS when the file is
+		   released. */
+		
+		unlock_kernel();
+		return 0;
+	}
+	       
+out_fail:
+	/* point the file's f_ops back to ieee1394. The VFS will then
+	   decrement ieee1394's reference count immediately after this
+	   function returns. */
+	
+	file->f_op = &ieee1394_chardev_ops;
+	unlock_kernel();
+	return retval;
+
+#undef INCREF
+#undef DECREF
+	     
+}
+
+struct proc_dir_entry *ieee1394_procfs_entry;
+
 static int __init ieee1394_init(void)
 {
 	hpsb_packet_cache = kmem_cache_create("hpsb_packet", sizeof(struct hpsb_packet),
 					      0, 0, NULL, NULL);
+
+	ieee1394_devfs_handle = devfs_mk_dir(NULL, "ieee1394", NULL);
+
+	if (register_chrdev(IEEE1394_MAJOR, "ieee1394", &ieee1394_chardev_ops)) {
+		HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
+		devfs_unregister(ieee1394_devfs_handle);
+		return -ENODEV;
+	}
+
+#ifdef CONFIG_PROC_FS
+	/* Must be done before we start everything else, since the drivers
+	 * may use it.  */
+	ieee1394_procfs_entry = proc_mkdir( "ieee1394", proc_bus);
+	if (ieee1394_procfs_entry == NULL) {
+		HPSB_ERR("unable to create /proc/bus/ieee1394\n");
+		unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
+		devfs_unregister(ieee1394_devfs_handle);
+		return -ENOMEM;
+	}
+	ieee1394_procfs_entry->owner = THIS_MODULE;
+#endif
+
 	init_hpsb_highlevel();
 	init_csr();
 	if (!disable_nodemgr)
@@ -807,6 +1027,13 @@
 
 	cleanup_csr();
 	kmem_cache_destroy(hpsb_packet_cache);
+
+	unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
+	
+	/* it's ok to pass a NULL devfs_handle to devfs_unregister */
+	devfs_unregister(ieee1394_devfs_handle);
+	
+	remove_proc_entry("ieee1394", proc_bus);
 }
 
 module_init(ieee1394_init);
@@ -815,9 +1042,11 @@
 /* Exported symbols */
 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(hpsb_alloc_host);
+EXPORT_SYMBOL(hpsb_add_host);
+EXPORT_SYMBOL(hpsb_remove_host);
+EXPORT_SYMBOL(hpsb_ref_host);
+EXPORT_SYMBOL(hpsb_unref_host);
 EXPORT_SYMBOL(hpsb_speedto_str);
 
 EXPORT_SYMBOL(alloc_hpsb_packet);
@@ -867,7 +1096,6 @@
 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);
@@ -876,3 +1104,9 @@
 EXPORT_SYMBOL(hpsb_register_protocol);
 EXPORT_SYMBOL(hpsb_unregister_protocol);
 EXPORT_SYMBOL(hpsb_release_unit_directory);
+
+EXPORT_SYMBOL(ieee1394_register_chardev);
+EXPORT_SYMBOL(ieee1394_unregister_chardev);
+EXPORT_SYMBOL(ieee1394_devfs_handle);
+
+EXPORT_SYMBOL(ieee1394_procfs_entry);
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/ieee1394_core.h linux/drivers/ieee1394/ieee1394_core.h
--- v2.5.2/linux/drivers/ieee1394/ieee1394_core.h	Mon Oct  1 21:24:24 2001
+++ linux/drivers/ieee1394/ieee1394_core.h	Mon Jan 21 15:57:51 2002
@@ -4,6 +4,8 @@
 
 #include <linux/tqueue.h>
 #include <linux/slab.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/proc_fs.h>
 #include <asm/semaphore.h>
 #include "hosts.h"
 
@@ -96,7 +98,6 @@
         return atomic_read(&host->generation);
 }
 
-
 /*
  * Queue packet for transmitting, return 0 for failure.
  */
@@ -151,5 +152,66 @@
  */
 void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
                           int write_acked);
+
+
+/*
+ * CHARACTER DEVICE DISPATCHING
+ *
+ * All ieee1394 character device drivers share the same major number
+ * (major 171).  The 256 minor numbers are allocated to the various
+ * task-specific interfaces (raw1394, video1394, dv1394, etc) in
+ * blocks of 16.
+ *
+ * The core ieee1394.o modules handles the initial open() for all
+ * character devices on major 171; it then dispatches to the
+ * appropriate task-specific driver.
+ *
+ * Minor device number block allocations:
+ *
+ * Block 0  (  0- 15)  raw1394
+ * Block 1  ( 16- 31)  video1394
+ * Block 2  ( 32- 47)  dv1394
+ *
+ * Blocks 3-14 free for future allocation
+ *
+ * Block 15 (240-255)  reserved for drivers under development, etc.
+ */
+
+#define IEEE1394_MAJOR               171
+
+#define IEEE1394_MINOR_BLOCK_RAW1394       0
+#define IEEE1394_MINOR_BLOCK_VIDEO1394     1
+#define IEEE1394_MINOR_BLOCK_DV1394        2
+#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
+
+/* return the index (within a minor number block) of a file */
+static inline unsigned char ieee1394_file_to_instance(struct file *file)
+{
+	unsigned char minor = minor(file->f_dentry->d_inode->i_rdev);
+	
+	/* return lower 4 bits */
+	return minor & 0xF;
+}
+
+/* 
+ * Task-specific drivers should call ieee1394_register_chardev() to
+ * request a block of 16 minor numbers.
+ *
+ * Returns 0 if the request was successful, -EBUSY if the block was
+ * already taken.
+ */
+
+int  ieee1394_register_chardev(int blocknum,           /* 0-15 */
+			       struct module *module,  /* THIS_MODULE */
+			       struct file_operations *file_ops);
+
+/* release a block of minor numbers */
+void ieee1394_unregister_chardev(int blocknum);
+
+/* the devfs handle for /dev/ieee1394; NULL if devfs is not in use */
+extern devfs_handle_t ieee1394_devfs_handle;
+
+/* the proc_fs entry for /proc/ieee1394 */
+extern struct proc_dir_entry *ieee1394_procfs_entry;
 
 #endif /* _IEEE1394_CORE_H */
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/ieee1394_syms.c linux/drivers/ieee1394/ieee1394_syms.c
--- v2.5.2/linux/drivers/ieee1394/ieee1394_syms.c	Sun Nov 11 10:09:32 2001
+++ linux/drivers/ieee1394/ieee1394_syms.c	Wed Dec 31 16:00:00 1969
@@ -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 -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/ieee1394_transactions.c linux/drivers/ieee1394/ieee1394_transactions.c
--- v2.5.2/linux/drivers/ieee1394/ieee1394_transactions.c	Mon Oct  1 21:24:24 2001
+++ linux/drivers/ieee1394/ieee1394_transactions.c	Mon Jan 21 15:57:51 2002
@@ -246,7 +246,7 @@
                                  packet->node_id);
                         return -EAGAIN;
                 }
-                HPSB_PANIC("reached unreachable code 1 in " __FUNCTION__);
+                HPSB_PANIC("reached unreachable code 1 in %s", __FUNCTION__);
 
         case ACK_BUSY_X:
         case ACK_BUSY_A:
@@ -290,7 +290,7 @@
                 return -EAGAIN;
         }
 
-        HPSB_PANIC("reached unreachable code 2 in " __FUNCTION__);
+        HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__);
 }
 
 
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/ieee1394_types.h linux/drivers/ieee1394/ieee1394_types.h
--- v2.5.2/linux/drivers/ieee1394/ieee1394_types.h	Wed Oct 17 14:19:20 2001
+++ linux/drivers/ieee1394/ieee1394_types.h	Mon Jan 21 15:57:51 2002
@@ -6,6 +6,7 @@
 #include <linux/types.h>
 #include <linux/version.h>
 #include <linux/list.h>
+#include <linux/init.h>
 #include <asm/byteorder.h>
 
 
@@ -18,6 +19,16 @@
 
 #define INIT_TQ_LINK(tq) INIT_LIST_HEAD(&(tq).list)
 #define INIT_TQ_HEAD(tq) INIT_LIST_HEAD(&(tq))
+#endif
+
+/* The great kdev_t changeover in 2.5.x */
+#include <linux/kdev_t.h>
+#ifndef minor
+#define minor(dev) MINOR(dev)
+#endif
+
+#ifndef __devexit_p
+#define __devexit_p(x) x
 #endif
 
 /* This showed up around this time */
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/nodemgr.c linux/drivers/ieee1394/nodemgr.c
--- v2.5.2/linux/drivers/ieee1394/nodemgr.c	Wed Oct 17 14:19:20 2001
+++ linux/drivers/ieee1394/nodemgr.c	Mon Jan 21 15:57:51 2002
@@ -16,6 +16,10 @@
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kmod.h>
+#include <linux/completion.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
 
 #include "ieee1394_types.h"
 #include "ieee1394.h"
@@ -59,13 +63,200 @@
 
 struct host_info {
 	struct hpsb_host *host;
-	struct tq_struct task;
 	struct list_head list;
+	struct completion started;
+	struct completion exited;
+	wait_queue_head_t wait;
+	int pid;
 };
 
+#ifdef CONFIG_PROC_FS
+
+static int raw1394_read_proc(char *buffer, char **start, off_t offset,
+			     int size, int *eof, void *data )
+{
+	struct list_head *lh;
+	struct node_entry *ne;
+	int disp_size = 0;
+	char display_str[1024];
+
+#define PUTF(fmt, args...) disp_size += sprintf(display_str, fmt, ## args); strcat(buffer,display_str)
+	buffer[0] = '\0';
+	list_for_each(lh, &node_list) {
+		ne = list_entry(lh, struct node_entry, list);
+		if (!ne)
+			continue;
+		PUTF("Node[" NODE_BUS_FMT "]  GUID[%016Lx]:\n",
+		     NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid);
+		if (ne->host != NULL && ne->host->node_id == ne->nodeid) {
+			PUTF("\tNodes connected : %d\n", ne->host->node_count);
+			PUTF("\tSelfIDs received: %d\n", ne->host->selfid_count);
+			PUTF("\tOwn ID          : 0x%08x\n",ne->host->node_id);
+			PUTF("\tIrm ID          : 0x%08x\n",ne->host->irm_id);
+			PUTF("\tBusMgr ID       : 0x%08x\n",ne->host->busmgr_id);
+			PUTF("\tBR IR IC II IB\n");
+			PUTF("\t%02d %02d %02d %02d %02d\n",
+			     ne->host->in_bus_reset, ne->host->is_root,
+			     ne->host->is_cycmst, ne->host->is_irm,
+			     ne->host->is_busmgr);
+		}
+		PUTF("\tVendor ID: %s [0x%06x]\n",
+		     ne->vendor_name ?: "Unknown", ne->vendor_id);
+		PUTF("\tCapabilities: 0x%06x\n", ne->capabilities);
+		PUTF("\tirmc=%d cmc=%d isc=%d bmc=%d pmc=%d cyc_clk_acc=%d max_rec=%d gen=%d lspd=%d\n",
+		     ne->busopt.irmc, ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
+		     ne->busopt.pmc, ne->busopt.cyc_clk_acc, ne->busopt.max_rec,
+		     ne->busopt.generation, ne->busopt.lnkspd);
+	}
+#undef PUTF
+    return disp_size;
+}
+#endif /* CONFIG_PROC_FS */
+
 static void nodemgr_process_config_rom(struct node_entry *ne, 
 				       quadlet_t busoptions);
 
+static int nodemgr_read_quadlet(struct hpsb_host *host,
+				nodeid_t nodeid, octlet_t address,
+				quadlet_t *quad)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < 3; i++) {
+		ret = hpsb_read(host, nodeid, address, quad, 4);
+		if (ret != -EAGAIN)
+			break;
+	}
+	*quad = be32_to_cpu(*quad);
+
+	return ret;
+}
+
+static int nodemgr_size_text_leaf(struct hpsb_host *host,
+				  nodeid_t nodeid,
+				  octlet_t address)
+{
+	quadlet_t quad;
+	int size = 0;
+	if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+		return -1;
+	if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) {
+		/* This is the offset.  */
+		address += 4 * CONFIG_ROM_VALUE(quad); 
+		if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+			return -1;
+		/* Now we got the size of the text descriptor leaf. */
+		size = CONFIG_ROM_LEAF_LENGTH(quad);
+	}
+	return size;
+}
+
+static int nodemgr_read_text_leaf(struct hpsb_host *host,
+				  nodeid_t nodeid,
+				  octlet_t address,
+				  quadlet_t *quadp)
+{
+	quadlet_t quad;
+	int i, size, ret;
+
+	if (nodemgr_read_quadlet(host, nodeid, address, &quad)
+	    && CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF)
+		return -1;
+
+	/* This is the offset.  */
+	address += 4 * CONFIG_ROM_VALUE(quad);
+	if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+		return -1;
+
+	/* Now we got the size of the text descriptor leaf. */
+	size = CONFIG_ROM_LEAF_LENGTH(quad) - 2;
+	if (size <= 0)
+		return -1;
+
+	address += 4;
+	for (i = 0; i < 2; i++, address += 4, quadp++) {
+		if (nodemgr_read_quadlet(host, nodeid, address, quadp))
+			return -1;
+	}
+
+	/* Now read the text string.  */
+	ret = -ENXIO;
+	for (; size > 0; size--, address += 4, quadp++) {
+		for (i = 0; i < 3; i++) {
+			ret = hpsb_read(host, nodeid, address, quadp, 4);
+			if (ret != -EAGAIN)
+				break;
+		}
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static struct node_entry *nodemgr_scan_root_directory
+	(struct hpsb_host *host, nodeid_t nodeid)
+{
+	octlet_t address;
+	quadlet_t quad;
+	int length;
+	int code, size, total_size;
+	struct node_entry *ne;
+
+	address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
+	
+	if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+		return NULL;
+	address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;
+
+	if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+		return NULL;
+	length = CONFIG_ROM_ROOT_LENGTH(quad);
+	address += 4;
+
+	size = 0;
+	total_size = sizeof(struct node_entry);
+	for (; length > 0; length--, address += 4) {
+		if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+			return NULL;
+		code = CONFIG_ROM_KEY(quad);
+
+		if (code == CONFIG_ROM_VENDOR_ID) {
+			/* Check if there is a text descriptor leaf
+			   immediately after this.  */
+			length--;
+			if (length <= 0)
+				break;	
+			address += 4;
+			size = nodemgr_size_text_leaf(host, nodeid,
+						      address);
+			switch (size) {
+			case -1:
+				return NULL;
+				break;
+			case 0:
+				break;
+			default:
+				total_size += (size + 1) * sizeof (quadlet_t);
+				break;
+			}
+			break;
+		}
+	}
+	ne = kmalloc(total_size, SLAB_ATOMIC);
+	if (ne != NULL) {
+		if (size != 0) {
+			ne->vendor_name
+				= (const char *) &(ne->quadlets[2]);
+			ne->quadlets[size] = 0;
+		}
+		else {
+			ne->vendor_name = NULL;
+		}
+	}
+	return ne; 
+}
 
 static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoptions,
 					      struct hpsb_host *host, nodeid_t nodeid)
@@ -73,7 +264,7 @@
         struct node_entry *ne;
         unsigned long flags;
 
-        ne = kmalloc(sizeof(struct node_entry), SLAB_ATOMIC);
+	ne = nodemgr_scan_root_directory (host, nodeid);
         if (!ne) return NULL;
 
         INIT_LIST_HEAD(&ne->list);
@@ -89,9 +280,10 @@
 
 	nodemgr_process_config_rom (ne, busoptions);
 
-	HPSB_DEBUG("%s added: node " NODE_BUS_FMT ", GUID %016Lx",
+	HPSB_DEBUG("%s added: Node[" NODE_BUS_FMT "]  GUID[%016Lx]  [%s]",
 		   (host->node_id == nodeid) ? "Local host" : "Device",
-		   NODE_BUS_ARGS(nodeid), (unsigned long long)guid);
+		   NODE_BUS_ARGS(nodeid), (unsigned long long)guid,
+		   ne->vendor_name ?: "Unknown");
 
         return ne;
 }
@@ -122,30 +314,107 @@
 	return NULL;
 }
 
-int nodemgr_read_quadlet(struct node_entry *ne,
-			 octlet_t address, quadlet_t *quad)
+static struct unit_directory *nodemgr_scan_unit_directory
+	(struct node_entry *ne, octlet_t address)
 {
-	int i;
-	int ret = 0;
+	struct unit_directory *ud;
+	quadlet_t quad;
+	u8 flags, todo;
+	int length, size, total_size, count;
+	int vendor_name_size, model_name_size;
 
-	for (i = 0; i < 3; i++) {
-		ret = hpsb_read(ne->host, ne->nodeid, address, quad, 4);
-		if (ret != -EAGAIN)
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
+		return NULL;
+	length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ;
+	address += 4;
+
+	size = 0;
+	total_size = sizeof (struct unit_directory);
+	flags = 0;
+	count = 0;
+	vendor_name_size = 0;
+	model_name_size = 0;
+	for (; length > 0; length--, address += 4) {
+		int code;
+		quadlet_t value;
+
+retry:
+		if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
+			return NULL;
+		code = CONFIG_ROM_KEY(quad);
+		value = CONFIG_ROM_VALUE(quad);
+
+		todo = 0;
+		switch (code) {
+		case CONFIG_ROM_VENDOR_ID:
+			todo = UNIT_DIRECTORY_VENDOR_TEXT;
 			break;
-	}
-	*quad = be32_to_cpu(*quad);
 
-	return ret;
-}
+		case CONFIG_ROM_MODEL_ID:
+			todo = UNIT_DIRECTORY_MODEL_TEXT;
+			break;
+
+		case CONFIG_ROM_SPECIFIER_ID:
+		case CONFIG_ROM_UNIT_SW_VERSION:
+			break;
+
+		case CONFIG_ROM_DESCRIPTOR_LEAF:
+		case CONFIG_ROM_DESCRIPTOR_DIRECTORY:
+			/* TODO: read strings... icons? */
+			break;
+
+		default:
+			/* Which types of quadlets do we want to
+			   store?  Only count immediate values and
+			   CSR offsets for now.  */
+			code &= CONFIG_ROM_KEY_TYPE_MASK;
+			if ((code & 0x80) == 0)
+				count++;
+			break;
+		}
 
-#define CONFIG_ROM_VENDOR_ID		0x03
-#define CONFIG_ROM_MODEL_ID		0x17
-#define CONFIG_ROM_NODE_CAPABILITES	0x0C
-#define CONFIG_ROM_UNIT_DIRECTORY	0xd1
-#define CONFIG_ROM_SPECIFIER_ID		0x12 
-#define CONFIG_ROM_VERSION		0x13
-#define CONFIG_ROM_DESCRIPTOR_LEAF	0x81
-#define CONFIG_ROM_DESCRIPTOR_DIRECTORY	0xc1
+		if (todo) {
+			/* Check if there is a text descriptor leaf
+			   immediately after this.  */
+			length--;
+			if (length <= 0)
+				break;
+			address += 4;
+			size = nodemgr_size_text_leaf(ne->host,
+						      ne->nodeid,
+						      address);
+			if (todo | UNIT_DIRECTORY_VENDOR_TEXT)
+				vendor_name_size = size;
+			else
+				model_name_size = size;
+			switch (size) {
+			case -1:
+				return NULL;
+				break;
+			case 0:
+				goto retry;
+				break;
+			default:
+				flags |= todo;
+				total_size += (size + 1) * sizeof (quadlet_t);
+				break;
+			}
+		}
+	}
+	total_size += count * sizeof (quadlet_t);
+	ud = kmalloc (total_size, GFP_KERNEL);
+	if (ud != NULL) {
+		memset (ud, 0, sizeof *ud);
+		ud->flags = flags;
+		ud->count = count;
+		ud->vendor_name_size = vendor_name_size;
+		ud->model_name_size = model_name_size;
+		/* If there is no vendor name in the unit directory,
+		   use the one in the root directory.  */
+		ud->vendor_name = ne->vendor_name;
+	}
+	return ud;
+}
 
 /* This implementation currently only scans the config rom and its
  * immediate unit directories looking for software_id and
@@ -156,41 +425,75 @@
 					   octlet_t address)
 {
 	struct unit_directory *ud;
-	octlet_t a;
 	quadlet_t quad;
-	int length, i;
+	quadlet_t *infop;
+	int length;
 
-	if (!(ud = kmalloc (sizeof *ud, GFP_KERNEL)))
+	if (!(ud = nodemgr_scan_unit_directory(ne, address)))
 		goto unit_directory_error;
 
-	memset (ud, 0, sizeof *ud);
 	ud->ne = ne;
 	ud->address = address;
-	ud->arb_count = 0;
 
-	if (nodemgr_read_quadlet(ne, address, &quad))
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
 		goto unit_directory_error;
-	length = quad >> 16;
-	a = address + 4;
+	length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ;
+	address += 4;
 
-	for (i = 0; i < length; i++, a += 4) {
+	infop = (quadlet_t *) ud->quadlets;
+	for (; length > 0; length--, address += 4, infop++) {
 		int code;
 		quadlet_t value;
+		quadlet_t *quadp;
 
-		if (nodemgr_read_quadlet(ne, a, &quad))
+		if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
 			goto unit_directory_error;
-		code = quad >> 24;
-		value = quad & 0xffffff;
+		code = CONFIG_ROM_KEY(quad) ;
+		value = CONFIG_ROM_VALUE(quad);
 
 		switch (code) {
 		case CONFIG_ROM_VENDOR_ID:
 			ud->vendor_id = value;
 			ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
+			if ((ud->flags & UNIT_DIRECTORY_VENDOR_TEXT) != 0) {
+				length--;
+				address += 4;
+				quadp = &(ud->quadlets[ud->count]);
+				if (nodemgr_read_text_leaf(ne->host,
+							   ne->nodeid,
+							   address,
+							   quadp) == 0
+				    && quadp[0] == 0
+				    && quadp[1] == 0) {
+				    	/* We only support minimal
+					   ASCII and English. */
+					quadp[ud->vendor_name_size] = 0;
+					ud->vendor_name
+						= (const char *) &(quadp[2]);
+				}
+			}
 			break;
 
 		case CONFIG_ROM_MODEL_ID:
 			ud->model_id = value;
 			ud->flags |= UNIT_DIRECTORY_MODEL_ID;
+			if ((ud->flags & UNIT_DIRECTORY_MODEL_TEXT) != 0) {
+				length--;
+				address += 4;
+				quadp = &(ud->quadlets[ud->count + ud->vendor_name_size + 1]);
+				if (nodemgr_read_text_leaf(ne->host,
+							   ne->nodeid,
+							   address,
+							   quadp) == 0
+				    && quadp[0] == 0
+				    && quadp[1] == 0) {
+				    	/* We only support minimal
+					   ASCII and English. */
+					quadp[ud->model_name_size] = 0;
+					ud->model_name
+						= (const char *) &(quadp[2]);
+				}
+			}
 			break;
 
 		case CONFIG_ROM_SPECIFIER_ID:
@@ -198,7 +501,7 @@
 			ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
 			break;
 
-		case CONFIG_ROM_VERSION:
+		case CONFIG_ROM_UNIT_SW_VERSION:
 			ud->version = value;
 			ud->flags |= UNIT_DIRECTORY_VERSION;
 			break;
@@ -209,12 +512,13 @@
 			break;
 
 		default:
-			if (ud->arb_count < 16) {
-				/* Place them in the arbitrary pairs */
-				ud->arb_keys[ud->arb_count] = code;
-				ud->arb_values[ud->arb_count] = value;
-				ud->arb_count++;
-			}
+			/* Which types of quadlets do we want to
+			   store?  Only count immediate values and
+			   CSR offsets for now.  */
+			code &= CONFIG_ROM_KEY_TYPE_MASK;
+			if ((code & 0x80) == 0)
+				*infop = quad;
+			break;
 		}
 	}
 
@@ -233,53 +537,73 @@
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 	struct list_head *l;
 
-	HPSB_DEBUG("vendor_id=0x%06x, capabilities=0x%06x",
-		   ne->vendor_id, ne->capabilities);
+	HPSB_DEBUG("vendor_id=0x%06x [%s], capabilities=0x%06x",
+		   ne->vendor_id, ne->vendor_name ?: "Unknown",
+		   ne->capabilities);
 	list_for_each (l, &ne->unit_directories) {
 		struct unit_directory *ud = list_entry (l, struct unit_directory, node_list);
 		HPSB_DEBUG("unit directory:");
 		if (ud->flags & UNIT_DIRECTORY_VENDOR_ID)
-			HPSB_DEBUG("  vendor_id=0x%06x ", ud->vendor_id);
+			HPSB_DEBUG("  vendor_id=0x%06x [%s]",
+				   ud->vendor_id,
+				   ud->vendor_name ?: "Unknown");
 		if (ud->flags & UNIT_DIRECTORY_MODEL_ID)
-			HPSB_DEBUG("  model_id=0x%06x ", ud->model_id);
+			HPSB_DEBUG("  model_id=0x%06x [%s]",
+				   ud->model_id,
+				   ud->model_name ?: "Unknown");
 		if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
 			HPSB_DEBUG("  sw_specifier_id=0x%06x ", ud->specifier_id);
 		if (ud->flags & UNIT_DIRECTORY_VERSION)
 			HPSB_DEBUG("  sw_version=0x%06x ", ud->version);
 	}
-#else
-	return;
 #endif
+	return;
 }
 
 static void nodemgr_process_root_directory(struct node_entry *ne)
 {
 	octlet_t address;
 	quadlet_t quad;
-	int length, i;
+	int length;
 
 	address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
 	
-	if (nodemgr_read_quadlet(ne, address, &quad))
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
 		return;
-	address += 4 + (quad >> 24) * 4;
+	address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;
 
-	if (nodemgr_read_quadlet(ne, address, &quad))
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
 		return;
-	length = quad >> 16;
+	length = CONFIG_ROM_ROOT_LENGTH(quad);
 	address += 4;
 
-	for (i = 0; i < length; i++, address += 4) {
+	for (; length > 0; length--, address += 4) {
 		int code, value;
 
-		if (nodemgr_read_quadlet(ne, address, &quad))
+		if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
 			return;
-		code = quad >> 24;
-		value = quad & 0xffffff;
+		code = CONFIG_ROM_KEY(quad);
+		value = CONFIG_ROM_VALUE(quad);
 
 		switch (code) {
 		case CONFIG_ROM_VENDOR_ID:
 			ne->vendor_id = value;
+			/* Now check if there is a vendor name text
+			   string.  */
+			if (ne->vendor_name != NULL) {
+				length--;
+				address += 4;
+				if (nodemgr_read_text_leaf(ne->host,
+							   ne->nodeid,
+							   address,
+							   ne->quadlets)
+				    != 0
+				    || ne->quadlets [0] != 0
+				    || ne->quadlets [1] != 0)
+				    	/* We only support minimal
+					   ASCII and English. */
+					ne->vendor_name = NULL;
+			}
 			break;
 
 		case CONFIG_ROM_NODE_CAPABILITES:
@@ -359,7 +683,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 +693,8 @@
 {
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 	HPSB_DEBUG("NodeMgr: nodemgr_call_policy(): hotplug not enabled");
-#else
-	return;
 #endif
+	return;
 } 
 
 #endif /* CONFIG_HOTPLUG */
@@ -582,13 +905,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 +920,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);
@@ -613,6 +934,7 @@
 	int header_count;
 	unsigned header_size;
 	quadlet_t quad;
+	int ret;
 
 retry_configrom:
 
@@ -636,9 +958,10 @@
 	 * to work though, and we are forced to doing quadlet
 	 * sized reads.  */
 
-	if (hpsb_read(host, nodeid, base, &quad, 4)) {
-		HPSB_ERR("ConfigROM quadlet transaction error for node " NODE_BUS_FMT,
-			 NODE_BUS_ARGS(nodeid));
+	ret = hpsb_read(host, nodeid, base, &quad, 4);
+	if (ret) {
+		HPSB_ERR("ConfigROM quadlet transaction error (%d) for node " NODE_BUS_FMT,
+			 ret, NODE_BUS_ARGS(nodeid));
 		goto retry_configrom;
 	}
 	buffer[header_count++] = be32_to_cpu(quad);
@@ -652,9 +975,10 @@
 	}
 
 	while (header_count <= header_size && header_count < buffer_length) {
-		if (hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4)) {
-			HPSB_ERR("ConfigROM quadlet transaction error for " NODE_BUS_FMT,
-				 NODE_BUS_ARGS(nodeid));
+		ret = hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4);
+		if (ret) {
+			HPSB_ERR("ConfigROM quadlet transaction error (%d) for " NODE_BUS_FMT,
+				 ret, NODE_BUS_ARGS(nodeid));
 			goto retry_configrom;
 		}
 		buffer[header_count++] = be32_to_cpu(quad);
@@ -667,8 +991,10 @@
 {
 	unsigned long flags;
 
-	HPSB_DEBUG("Device removed: node " NODE_BUS_FMT ", GUID %016Lx",
-		   NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid);
+	HPSB_DEBUG("%s removed: Node[" NODE_BUS_FMT "]  GUID[%016Lx]  [%s]",
+		   (ne->host->node_id == ne->nodeid) ? "Local host" : "Device",
+		   NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid,
+		   ne->vendor_name ?: "Unknown");
 
 	write_lock_irqsave(&unit_directory_lock, flags);
 	nodemgr_free_unit_directories(ne);
@@ -681,52 +1007,47 @@
 
 /* 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(struct hpsb_host *host, nodeid_t nodeid)
 {
-	struct hpsb_host *host = (struct hpsb_host *)data;
-        struct selfid *sid = (struct selfid *)host->topology_map;
-	struct list_head *lh, *next;
 	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 (host, nodeid, buffer, sizeof(buffer) >> 2))
+		return;
 
-		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(nodeid));
+		return;
+	}
 
-		guid = ((u64)buffer[3] << 32) | buffer[4];
-		ne = hpsb_guid_get_entry(guid);
+	guid = ((u64)buffer[3] << 32) | buffer[4];
+	ne = hpsb_guid_get_entry(guid);
 
-		if (!ne)
-			nodemgr_create_node(guid, buffer[2], host, nodeid);
-		else
-			nodemgr_update_node(ne, buffer[2], host, nodeid);
-        }
+	if (!ne)
+		nodemgr_create_node(guid, buffer[2], host, nodeid);
+	else
+		nodemgr_update_node(ne, buffer[2], host, nodeid);
+
+	return;
+}
+
+static void nodemgr_node_probe_cleanup(struct hpsb_host *host)
+{
+	unsigned long flags;
+	struct list_head *lh, *next;
+	struct node_entry *ne;
 
 	/* Now check to see if we have any nodes that aren't referenced
 	 * any longer.  */
-        write_lock_irqsave(&node_lock, flags);
-	for (lh = node_list.next; lh != &node_list; lh = next) {
+	write_lock_irqsave(&node_lock, flags);
+	list_for_each_safe(lh, next, &node_list) {
 		ne = list_entry(lh, struct node_entry, list);
-		next = lh->next;
 
 		/* Only checking this host */
 		if (ne->host != host)
@@ -744,6 +1065,56 @@
 	return;
 }
 
+static void nodemgr_node_probe(struct hpsb_host *host)
+{
+	int nodecount = host->node_count;
+	struct selfid *sid = (struct selfid *)host->topology_map;
+	nodeid_t nodeid = LOCAL_BUS;
+
+	/* Scan each node on the bus */
+	for (; nodecount; nodecount--, nodeid++, sid++) {
+		while (sid->extended)
+			sid++;
+		if (!sid->link_active)
+			continue;
+
+		nodemgr_node_probe_one(host, nodeid);
+	}
+
+	/* Cleanup if needed */
+	nodemgr_node_probe_cleanup(host);
+
+	return;
+}
+
+static int nodemgr_host_thread(void *__hi)
+{
+	struct host_info *hi = (struct host_info *)__hi;
+	lock_kernel();
+
+	/* No userlevel access needed */
+	daemonize();
+
+	strcpy(current->comm, "NodeMgr");
+
+	complete(&hi->started);
+
+	/* Sit and wait for a signal to probe the nodes on the bus. This
+	 * happens when we get a bus reset.  */
+	do {
+		interruptible_sleep_on(&hi->wait);
+		if (!signal_pending(current))
+			nodemgr_node_probe(hi->host);
+	} while (!signal_pending(current));
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	HPSB_DEBUG ("NodeMgr: Exiting thread for %s", hi->host->driver->name);
+#endif
+
+	unlock_kernel();
+
+	complete_and_exit(&hi->exited, 0);
+}
 
 struct node_entry *hpsb_guid_get_entry(u64 guid)
 {
@@ -802,7 +1173,18 @@
 	 * until the first bus reset.  */
 	hi->host = host;
 	INIT_LIST_HEAD(&hi->list);
-	INIT_TQUEUE(&hi->task, nodemgr_node_probe, host);
+	init_completion(&hi->started);
+	init_completion(&hi->exited);
+	init_waitqueue_head(&hi->wait);
+
+	hi->pid = kernel_thread(nodemgr_host_thread, hi, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+
+	if (hi->pid < 0) {
+		HPSB_ERR ("NodeMgr: failed to start NodeMgr thread for %s", host->driver->name);
+		return;
+	}
+
+	wait_for_completion(&hi->started);
 
 	spin_lock_irqsave (&host_info_lock, flags);
 	list_add_tail (&hi->list, &host_info_list);
@@ -831,7 +1213,11 @@
 		goto done_reset_host;
 	}
 
-	schedule_task(&hi->task);
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	HPSB_DEBUG ("NodeMgr: Processing host reset for %s", host->driver->name);
+#endif
+
+	wake_up(&hi->wait);
 
 done_reset_host:
 	spin_unlock_irqrestore (&host_info_lock, flags);
@@ -844,40 +1230,42 @@
 	struct list_head *lh, *next;
 	struct node_entry *ne;
 	unsigned long flags;
+	struct host_info *hi = NULL;
 
-	/* Make sure we have no active scans */
-	flush_scheduled_tasks();
+	spin_lock_irqsave (&host_info_lock, flags);
+	list_for_each_safe(lh, next, &host_info_list) {
+		struct host_info *myhi = list_entry(lh, struct host_info, list);
+		if (myhi->host == host) {
+			list_del(&myhi->list);
+			hi = myhi;
+			break;
+		}
+	}
 
-	/* First remove all node entries for this host */
-	write_lock_irqsave(&node_lock, flags);
+	if (!hi)
+		HPSB_ERR ("NodeMgr: host %s does not exist, cannot remove",
+			  host->driver->name);
+	spin_unlock_irqrestore (&host_info_lock, flags);
 
-	for (lh = node_list.next; lh != &node_list; lh = next) {
+	/* Even if we fail the host_info part, remove all the node
+	 * entries.  */
+	write_lock_irqsave(&node_lock, flags);
+	list_for_each_safe(lh, next, &node_list) {
 		ne = list_entry(lh, struct node_entry, list);
-		next = lh->next;
-
-		/* Only checking this host */
-		if (ne->host != host)
-			continue;
 
+		if (ne->host == host)
 		nodemgr_remove_node(ne);
 	}
 	write_unlock_irqrestore(&node_lock, flags);
 
-	spin_lock_irqsave (&host_info_lock, flags);
-	list_for_each(lh, &host_info_list) {
-		struct host_info *hi = list_entry(lh, struct host_info, list);
-		if (hi->host == host) {
-			list_del(&hi->list);
-			kfree (hi);
-			break;
+	if (hi) {
+		if (hi->pid >= 0) {
+			kill_proc(hi->pid, SIGTERM, 1);
+			wait_for_completion(&hi->exited);
 		}
+		kfree(hi);
 	}
 
-	if (lh == host_info_list.next)
-		HPSB_ERR ("NodeMgr: could not remove non-existent host");
-
-	spin_unlock_irqrestore (&host_info_lock, flags);
-
 	return;
 }
 
@@ -889,8 +1277,14 @@
 
 static struct hpsb_highlevel *hl;
 
+#define PROC_ENTRY "devices"
+
 void init_ieee1394_nodemgr(void)
 {
+#ifdef CONFIG_PROC_FS
+	if (!create_proc_read_entry(PROC_ENTRY, 0444, ieee1394_procfs_entry, raw1394_read_proc, NULL))
+		HPSB_ERR("Can't create devices procfs entry");
+#endif
         hl = hpsb_register_highlevel("Node manager", &nodemgr_ops);
         if (!hl) {
 		HPSB_ERR("NodeMgr: out of memory during ieee1394 initialization");
@@ -900,4 +1294,7 @@
 void cleanup_ieee1394_nodemgr(void)
 {
         hpsb_unregister_highlevel(hl);
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry(PROC_ENTRY, ieee1394_procfs_entry);
+#endif
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/nodemgr.h linux/drivers/ieee1394/nodemgr.h
--- v2.5.2/linux/drivers/ieee1394/nodemgr.h	Mon Oct  1 21:24:24 2001
+++ linux/drivers/ieee1394/nodemgr.h	Mon Jan 21 15:57:51 2002
@@ -20,6 +20,44 @@
 #ifndef _IEEE1394_NODEMGR_H
 #define _IEEE1394_NODEMGR_H
 
+#define CONFIG_ROM_BUS_INFO_LENGTH(q)		((q) >> 24)
+#define CONFIG_ROM_BUS_CRC_LENGTH(q)		(((q) >> 16) & 0xff)
+#define CONFIG_ROM_BUS_CRC(q)			((q) & 0xffff)
+
+#define CONFIG_ROM_ROOT_LENGTH(q)		((q) >> 16)
+#define CONFIG_ROM_ROOT_CRC(q)			((q) & 0xffff)
+
+#define CONFIG_ROM_DIRECTORY_LENGTH(q)		((q) >> 16)
+#define CONFIG_ROM_DIRECTORY_CRC(q)		((q) & 0xffff)
+
+#define CONFIG_ROM_LEAF_LENGTH(q)		((q) >> 16)
+#define CONFIG_ROM_LEAF_CRC(q)			((q) & 0xffff)
+
+#define CONFIG_ROM_DESCRIPTOR_TYPE(q)		((q) >> 24)
+#define CONFIG_ROM_DESCRIPTOR_SPECIFIER_ID(q)	((q) & 0xffffff)
+#define CONFIG_ROM_DESCRIPTOR_WIDTH(q)		((q) >> 28)
+#define CONFIG_ROM_DESCRIPTOR_CHAR_SET(q)	(((q) >> 16) & 0xfff)
+#define CONFIG_ROM_DESCRIPTOR_LANG(q)		((q) & 0xffff)
+
+#define CONFIG_ROM_KEY_ID_MASK			0x3f
+#define CONFIG_ROM_KEY_TYPE_MASK		0xc0
+#define CONFIG_ROM_KEY_TYPE_IMMEDIATE		0x00
+#define CONFIG_ROM_KEY_TYPE_OFFSET		0x40
+#define CONFIG_ROM_KEY_TYPE_LEAF		0x80
+#define CONFIG_ROM_KEY_TYPE_DIRECTORY		0xc0
+
+#define CONFIG_ROM_KEY(q)			((q) >> 24)
+#define CONFIG_ROM_VALUE(q)			((q) & 0xffffff)
+
+#define CONFIG_ROM_VENDOR_ID			0x03
+#define CONFIG_ROM_MODEL_ID			0x17
+#define CONFIG_ROM_NODE_CAPABILITES		0x0C
+#define CONFIG_ROM_UNIT_DIRECTORY		0xd1
+#define CONFIG_ROM_SPECIFIER_ID			0x12 
+#define CONFIG_ROM_UNIT_SW_VERSION		0x13
+#define CONFIG_ROM_DESCRIPTOR_LEAF		0x81
+#define CONFIG_ROM_DESCRIPTOR_DIRECTORY		0xc1
+
 /* '1' '3' '9' '4' in ASCII */
 #define IEEE1394_BUSID_MAGIC	0x31333934
 
@@ -42,6 +80,8 @@
 #define UNIT_DIRECTORY_MODEL_ID		0x02
 #define UNIT_DIRECTORY_SPECIFIER_ID	0x04
 #define UNIT_DIRECTORY_VERSION		0x08
+#define UNIT_DIRECTORY_VENDOR_TEXT	0x10
+#define UNIT_DIRECTORY_MODEL_TEXT	0x20
 
 /*
  * A unit directory corresponds to a protocol supported by the
@@ -58,17 +98,14 @@
 	octlet_t address;	/* Address of the unit directory on the node */
 	u8 flags;		/* Indicates which entries were read */
 	quadlet_t vendor_id;
-	char *vendor_name;
+	const char *vendor_name;
+	int vendor_name_size;
 	quadlet_t model_id;
-	char *model_name;
+	const char *model_name;
+	int model_name_size;
 	quadlet_t specifier_id;
 	quadlet_t version;
 
-	/* Groupings for arbitrary key/value pairs */
-	int arb_count;			/* Number of arbitrary key/values */
-	char arb_keys[16];		/* Up to 16 keys */
-	quadlet_t arb_values[16];	/* Same for values */
-
 	struct hpsb_protocol_driver *driver;
 	void *driver_data;
 
@@ -77,6 +114,9 @@
 
 	/* For linking directories belonging to a node */
 	struct list_head node_list;
+
+	int count;		/* Number of quadlets */
+	quadlet_t quadlets[0];
 };
 
 struct node_entry {
@@ -91,6 +131,9 @@
 	u32 vendor_id;
 	u32 capabilities;	
 	struct list_head unit_directories;
+
+	const char *vendor_name;
+	quadlet_t quadlets[0];
 };
 
 static inline int hpsb_node_entry_valid(struct node_entry *ne)
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
--- v2.5.2/linux/drivers/ieee1394/ohci1394.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ieee1394/ohci1394.c	Mon Jan 21 15:57:51 2002
@@ -77,6 +77,12 @@
  *  . Config ROM generation
  */
 
+/* Issues:
+ *
+ * - devctl BUS_RESET should treat arg as reset type
+ *
+ */
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -105,16 +111,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"
@@ -139,10 +141,10 @@
 
 #ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG
 #define OHCI_DMA_ALLOC(fmt, args...) \
-	HPSB_ERR("%s("__FUNCTION__")alloc(%d): "fmt, OHCI1394_DRIVER_NAME, \
+	HPSB_ERR("%s(%s)alloc(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \
 		++global_outstanding_dmas, ## args)
 #define OHCI_DMA_FREE(fmt, args...) \
-	HPSB_ERR("%s("__FUNCTION__")free(%d): "fmt, OHCI1394_DRIVER_NAME, \
+	HPSB_ERR("%s(%s)free(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \
 		--global_outstanding_dmas, ## args)
 u32 global_outstanding_dmas = 0;
 #else
@@ -158,35 +160,23 @@
 #define PRINT(level, card, fmt, args...) \
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
-#define PCI_CLASS_FIREWIRE_OHCI     ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
-
-static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = {
-	{
-		class: 		PCI_CLASS_FIREWIRE_OHCI,
-		class_mask: 	0x00ffffff,
-		vendor:		PCI_ANY_ID,
-		device:		PCI_ANY_ID,
-		subvendor:	PCI_ANY_ID,
-		subdevice:	PCI_ANY_ID,
-	},
-	{ 0, },
-};
-MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
-
 static char version[] __devinitdata =
-	"v0.51 08/08/01 Ben Collins <bcollins@debian.org>";
+	"$Revision: 1.91 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
 MODULE_PARM_DESC(attempt_root, "Attempt to make the host root.");
 static int attempt_root = 0;
 
-static unsigned int card_id_counter = 0;
-
 static void dma_trm_tasklet(unsigned long data);
-static void remove_card(struct ti_ohci *ohci);
 static void dma_trm_reset(struct dma_trm_ctx *d);
 
+static void __devexit ohci1394_pci_remove(struct pci_dev *pdev);
+
+static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci,
+					  quadlet_t isoRecvEvent, 
+					  quadlet_t isoXmitEvent);
+
 #ifndef __LITTLE_ENDIAN
 /* Swap a series of quads inplace. */
 static __inline__ void block_swab32(quadlet_t *data, size_t size) {
@@ -314,8 +304,8 @@
 	if ((self_id_count & 0x80000000) || 
 	    ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) {
 		PRINT(KERN_ERR, ohci->id, 
-		      "Error in reception of SelfID packets [0x%08x/0x%08x]",
-		      self_id_count, q0);
+		      "Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)",
+		      self_id_count, q0, ohci->self_id_errors);
 
 		/* Tip by James Goodwin <jamesg@Filanet.com>:
 		 * We had an error, generate another bus reset in response.  */
@@ -328,6 +318,9 @@
 		}
 		return;
 	}
+
+	/* SelfID Ok, reset error counter. */
+	ohci->self_id_errors = 0;
 	
 	size = ((self_id_count & 0x00001FFC) >> 2) - 1;
 	q++;
@@ -361,7 +354,7 @@
 	return;
 }
 
-static int ohci_soft_reset(struct ti_ohci *ohci) {
+static void ohci_soft_reset(struct ti_ohci *ohci) {
 	int i;
 
 	reg_write(ohci, OHCI1394_HCControlSet, 0x00010000);
@@ -372,9 +365,13 @@
 		mdelay(1);
 	}
 
-	DBGMSG (ohci->id, "Soft reset finished");
+	/* Now reenable LPS, since that's usually what we want after a
+	 * softreset anyway. Wait 50msec to make sure we have full link
+	 * enabled.  */
+	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
+	mdelay(50);
 
-	return 0;
+	DBGMSG (ohci->id, "Soft reset finished");
 }
 
 static int run_context(struct ti_ohci *ohci, int reg, char *msg)
@@ -415,8 +412,7 @@
 	for (i=0; i<d->num_desc; i++) {
 		u32 c;
 		
-		c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-			DMA_CTL_BRANCH;
+		c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH;
 		if (generate_irq)
 			c |= DMA_CTL_IRQ;
 				
@@ -489,19 +485,14 @@
 static void ohci_init_config_rom(struct ti_ohci *ohci);
 
 /* Global initialization */
-static int ohci_initialize(struct hpsb_host *host)
+static void ohci_initialize(struct ti_ohci *ohci)
 {
-	struct ti_ohci *ohci=host->hostdata;
-	int retval, i;
+	int i;
 	quadlet_t buf;
 
 	spin_lock_init(&ohci->phy_reg_lock);
 	spin_lock_init(&ohci->event_lock);
   
-	/* Soft reset */
-	if ((retval = ohci_soft_reset(ohci)) < 0)
-		return retval;
-
 	/* Put some defaults to these undefined bus options */
 	buf = reg_read(ohci, OHCI1394_BusOptions);
 	buf |=  0x60000000; /* Enable CMC and ISC */
@@ -509,19 +500,6 @@
 	buf &= ~0x98000000; /* Disable PMC, IRMC and BMC */
 	reg_write(ohci, OHCI1394_BusOptions, buf);
 
-	/* Set Link Power Status (LPS) */
-	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
-
-	/* 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);
-	}
-
 	/* Set the bus number */
 	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
 
@@ -558,10 +536,6 @@
 	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
 
 	/* Initialize IR dma */
-	ohci->nb_iso_rcv_ctx = 
-		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
-	DBGMSG(ohci->id, "%d iso receive contexts available",
-	       ohci->nb_iso_rcv_ctx);
 	for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {
 		reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i,
 			  0xffffffff);
@@ -580,10 +554,6 @@
 	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
 
 	/* Initialize IT dma */
-	ohci->nb_iso_xmit_ctx = 
-		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
-	DBGMSG(ohci->id, "%d iso transmit contexts available",
-	       ohci->nb_iso_xmit_ctx);
 	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {
 		reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i,
 			  0xffffffff);
@@ -645,32 +615,19 @@
 		  OHCI1394_respTxComplete |
 		  OHCI1394_reqTxComplete |
 		  OHCI1394_isochRx |
-		  OHCI1394_isochTx |
-		  OHCI1394_unrecoverableError
-		);
+		  OHCI1394_isochTx);
 
 	/* Enable link */
 	reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
 
 	buf = reg_read(ohci, OHCI1394_Version);
-	PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d]  MMIO=[%lx-%lx]"
-	      "  Max Packet=[%d]", ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
+	PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d]  "
+	      "MMIO=[%lx-%lx]  Max Packet=[%d]",
+	      ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
 	      ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,
 	      pci_resource_start(ohci->dev, 0),
 	      pci_resource_start(ohci->dev, 0) + pci_resource_len(ohci->dev, 0),
 	      ohci->max_packet_size);
-
-	return 1;
-}
-
-static void ohci_remove(struct hpsb_host *host)
-{
-	struct ti_ohci *ohci;
-
-	if (host != NULL) {
-		ohci = host->hostdata;
-		remove_card(ohci);
-	}
 }
 
 /* 
@@ -692,7 +649,7 @@
 	d->prg_cpu[idx]->begin.address = 0;
 	d->prg_cpu[idx]->begin.branchAddress = 0;
 
-	if (d->ctx==1) {
+	if (d->type == DMA_CTX_ASYNC_RESP) {
 		/* 
 		 * For response packets, we need to put a timeout value in
 		 * the 16 lower bits of the status... let's try 1 sec timeout 
@@ -741,9 +698,9 @@
                         if (cross_bound((unsigned long)packet->data, 
                                         packet->data_size)>0) {
                                 /* FIXME: do something about it */
-                                PRINT(KERN_ERR, ohci->id, __FUNCTION__
-                                      ": packet data addr: %p size %Zd bytes "
-                                      "cross page boundary", 
+                                PRINT(KERN_ERR, ohci->id,
+                                      "%s: packet data addr: %p size %Zd bytes "
+                                      "cross page boundary", __FUNCTION__,
                                       packet->data, packet->data_size);
                         }
 
@@ -933,10 +890,8 @@
 	switch (cmd) {
 	case RESET_BUS:
 		DBGMSG(ohci->id, "devctl: Bus reset requested%s",
-		       ((host->attempt_root || attempt_root) ? 
-		       " and attempting to become root" : ""));
-		set_phy_reg_mask (ohci, 1, 0x40 | ((host->attempt_root || attempt_root) ?
-				  0x80 : 0));
+		       attempt_root ? " and attempting to become root" : "");
+		set_phy_reg_mask (ohci, 1, 0x40 | (attempt_root ? 0x80 : 0));
 		break;
 
 	case GET_CYCLE_COUNTER:
@@ -988,9 +943,9 @@
 		u64 mask;
 
 		if (arg<0 || arg>63) {
-			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0 listen channel %d is out of range", 
-			      arg);
+			PRINT(KERN_ERR, ohci->id,
+			      "%s: IS0 listen channel %d is out of range", 
+			      __FUNCTION__, arg);
 			return -EFAULT;
 		}
 
@@ -999,9 +954,9 @@
                 spin_lock_irqsave(&ohci->IR_channel_lock, flags);
 
 		if (ohci->ISO_channel_usage & mask) {
-			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0 listen channel %d is already used", 
-			      arg);
+			PRINT(KERN_ERR, ohci->id,
+			      "%s: IS0 listen channel %d is already used", 
+			      __FUNCTION__, arg);
 			spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
 			return -EFAULT;
 		}
@@ -1024,9 +979,9 @@
 		u64 mask;
 
 		if (arg<0 || arg>63) {
-			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0 unlisten channel %d is out of range", 
-			      arg);
+			PRINT(KERN_ERR, ohci->id,
+			      "%s: IS0 unlisten channel %d is out of range", 
+			      __FUNCTION__, arg);
 			return -EFAULT;
 		}
 
@@ -1035,9 +990,9 @@
                 spin_lock_irqsave(&ohci->IR_channel_lock, flags);
 
 		if (!(ohci->ISO_channel_usage & mask)) {
-			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0 unlisten channel %d is not used", 
-			      arg);
+			PRINT(KERN_ERR, ohci->id,
+			      "%s: IS0 unlisten channel %d is not used", 
+			      __FUNCTION__, arg);
 			spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
 			return -EFAULT;
 		}
@@ -1130,11 +1085,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;
@@ -1144,7 +1095,6 @@
 	/* Die right here an now */
 	if (event & OHCI1394_unrecoverableError) {
 		PRINT(KERN_ERR, ohci->id, "Unrecoverable error, shutting down card!");
-		remove_card(ohci);
 		return;
 	}
 
@@ -1153,16 +1103,22 @@
 		 * 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",
-			      ((host->attempt_root || attempt_root) ?
-			      " and attempting to become root" : ""));
+			      (attempt_root) ? " and attempting to become root"
+			       : "");
 
 			/* Subsystem call */
 			hpsb_bus_reset(ohci->host);
@@ -1233,9 +1189,9 @@
 			else
 				tasklet_schedule(&d->task);
 		}
-		if (ohci->video_tmpl) 
-			ohci->video_tmpl->irq_handler(ohci->id, isoRecvIntEvent,
-						      0);
+
+		ohci1394_run_irq_hooks(ohci, isoRecvIntEvent, 0);
+
 		event &= ~OHCI1394_isochRx;
 	}
 	if (event & OHCI1394_isochTx) {
@@ -1248,9 +1204,9 @@
                        DBGMSG(ohci->id, "Got isochTx interrupt "
                                "status=0x%08x isoXmitIntEvent=%08x",
                               reg_read(ohci, d->ctrlSet), isoXmitIntEvent);
-		if (ohci->video_tmpl) 
-			ohci->video_tmpl->irq_handler(ohci->id, 0,
-						      isoXmitIntEvent);
+
+		ohci1394_run_irq_hooks(ohci, 0, isoXmitIntEvent);
+		
 		if (isoXmitIntEvent & 0x1) {
 			if (reg_read(ohci, d->ctrlSet) & 0x800)
 				ohci1394_stop_context(ohci, d->ctrlClear, "isochTx");
@@ -1308,12 +1264,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;	
 	}
 
@@ -1359,7 +1313,7 @@
 {
 	int length = -1;
 
-	if (d->ctx < 2) { /* Async Receive Response/Request */
+	if (d->type == DMA_CTX_ASYNC_REQ || d->type == DMA_CTX_ASYNC_RESP) {
 		length = TCODE_SIZE[tcode];
 		if (length == 0) {
 			if (offset + 12 >= d->buf_size) {
@@ -1370,7 +1324,7 @@
 			}
 			length += 20;
 		}
-	} else if (d->ctx == 2) { /* Iso receive */
+	} else if (d->type == DMA_CTX_ISO) {
 		/* Assumption: buffer fill mode with header/trailer */
 		length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8;
 	}
@@ -1400,11 +1354,8 @@
 	offset = d->buf_offset;
 	buf_ptr = d->buf_cpu[idx] + offset/4;
 
-	dma_cache_wback_inv(&(d->prg_cpu[idx]->status), sizeof(d->prg_cpu[idx]->status));
 	rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
-
 	bytes_left = d->buf_size - rescount - offset;
-	dma_cache_wback_inv(buf_ptr, bytes_left);
 
 	while (bytes_left > 0) {
 		tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf;
@@ -1456,7 +1407,6 @@
 			insert_dma_buffer(d, idx);
 			idx = (idx+1) % d->num_desc;
 			buf_ptr = d->buf_cpu[idx];
-			dma_cache_wback_inv(buf_ptr, d->buf_size);
 			offset=0;
 
 			while (split_left >= d->buf_size) {
@@ -1466,7 +1416,6 @@
 				insert_dma_buffer(d, idx);
 				idx = (idx+1) % d->num_desc;
 				buf_ptr = d->buf_cpu[idx];
-                                dma_cache_wback_inv(buf_ptr, d->buf_size);
 			}
 
 			if (split_left > 0) {
@@ -1513,8 +1462,6 @@
 			       d->ctx);
 #endif
 
-                dma_cache_wback_inv(&(d->prg_cpu[idx]->status),
-                        sizeof(d->prg_cpu[idx]->status));
 	       	rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
 
 		bytes_left = d->buf_size - rescount - offset;
@@ -1653,6 +1600,11 @@
 	}
 	if ((*d)->spb) kfree((*d)->spb);
 
+	/* clear ISO context usage bit */
+	if ((*d)->type == DMA_CTX_ISO) {
+		clear_bit((*d)->ctx, &ohci->ir_ctx_usage);
+	}
+	       
 	kfree(*d);
 	*d = NULL;
 
@@ -1660,15 +1612,21 @@
 }
 
 static struct dma_rcv_ctx *
-alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
-		  int buf_size, int split_buf_size, 
-		  int ctrlSet, int ctrlClear, int cmdPtr)
+alloc_dma_rcv_ctx(struct ti_ohci *ohci, enum context_type type, int ctx, int num_desc,
+		  int buf_size, int split_buf_size, int context_base)
 {
-	struct dma_rcv_ctx *d=NULL;
+	struct dma_rcv_ctx *d;
 	int i;
 
-	d = (struct dma_rcv_ctx *)kmalloc(sizeof(struct dma_rcv_ctx), 
-					  GFP_KERNEL);
+	if (type == DMA_CTX_ISO) {
+		/* try to claim the ISO context usage bit */
+		if (test_and_set_bit(ctx, &ohci->ir_ctx_usage)) {
+			PRINT(KERN_ERR, ohci->id, "IR DMA context %d is not available", ctx);
+			return NULL;
+		}
+	}
+	
+	d = kmalloc(sizeof(struct dma_rcv_ctx), GFP_KERNEL);
 
 	if (d == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_rcv_ctx");
@@ -1677,21 +1635,17 @@
 
 	memset (d, 0, sizeof (struct dma_rcv_ctx));
 
-	d->ohci = (void *)ohci;
+	d->ohci = ohci;
+	d->type = type;
 	d->ctx = ctx;
 
 	d->num_desc = num_desc;
 	d->buf_size = buf_size;
 	d->split_buf_size = split_buf_size;
-	d->ctrlSet = ctrlSet;
-	d->ctrlClear = ctrlClear;
-	d->cmdPtr = cmdPtr;
-
-	d->buf_cpu = NULL;
-	d->buf_bus = NULL;
-	d->prg_cpu = NULL;
-	d->prg_bus = NULL;
-	d->spb = NULL;
+
+	d->ctrlSet = context_base + OHCI1394_ContextControlSet;
+	d->ctrlClear = context_base + OHCI1394_ContextControlClear;
+	d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
 
 	d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL);
 	d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
@@ -1790,36 +1744,47 @@
 		kfree((*d)->prg_bus);
 	}
 
+	/* clear the ISO context usage bit */
+	if ((*d)->type == DMA_CTX_ISO) {
+		clear_bit((*d)->ctx, &ohci->it_ctx_usage);
+	}
+
 	kfree(*d);
 	*d = NULL;
 	return 0;
 }
 
 static struct dma_trm_ctx *
-alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
-		  int ctrlSet, int ctrlClear, int cmdPtr)
+alloc_dma_trm_ctx(struct ti_ohci *ohci, enum context_type type, int ctx, int num_desc,
+		  int context_base)
 {
-	struct dma_trm_ctx *d=NULL;
+	struct dma_trm_ctx *d;
 	int i;
 
-	d = (struct dma_trm_ctx *)kmalloc(sizeof(struct dma_trm_ctx), 
-					  GFP_KERNEL);
+	if (type == DMA_CTX_ISO) {
+		/* try to claim the ISO context usage bit */
+		if (test_and_set_bit(ctx, &ohci->it_ctx_usage)) {
+			PRINT(KERN_ERR, ohci->id, "IT DMA context %d is not available", ctx);
+			return NULL;
+		}
+	}
+	
+	d = kmalloc(sizeof(struct dma_trm_ctx), GFP_KERNEL);
 
-	if (d==NULL) {
+	if (d == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_trm_ctx");
 		return NULL;
 	}
 
 	memset (d, 0, sizeof (struct dma_trm_ctx));
 
-	d->ohci = (void *)ohci;
+	d->ohci = ohci;
+	d->type = type;
 	d->ctx = ctx;
 	d->num_desc = num_desc;
-	d->ctrlSet = ctrlSet;
-	d->ctrlClear = ctrlClear;
-	d->cmdPtr = cmdPtr;
-	d->prg_cpu = NULL;
-	d->prg_bus = NULL;
+	d->ctrlSet = context_base + OHCI1394_ContextControlSet;
+	d->ctrlClear = context_base + OHCI1394_ContextControlClear;
+	d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
 
 	d->prg_cpu = kmalloc(d->num_desc * sizeof(struct at_dma_prg*), 
 			     GFP_KERNEL);
@@ -1833,7 +1798,7 @@
 	memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*));
 	memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
 
-	for (i=0; i<d->num_desc; i++) {
+	for (i = 0; i < d->num_desc; i++) {
                 d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, 
 						     sizeof(struct at_dma_prg),
 						     d->prg_bus+i);
@@ -1896,6 +1861,21 @@
 
 #define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32(((key) << 24) | (val)))
 
+static inline void cf_put_str(struct config_rom_ptr *cr, const char *str)
+{
+	int t;
+	char fourb[4];
+
+	while (str[0]) {
+		memset(fourb, 0, 4);
+		for (t = 0; t < 4 && str[t]; t++)
+			fourb[t] = str[t];
+		cf_put_4bytes(cr, fourb[0], fourb[1], fourb[2], fourb[3]);
+		str += strlen(str) < 4 ? strlen(str) : 4;
+	}
+	return;
+}
+
 static inline void cf_put_crc16(struct config_rom_ptr *cr, int unit)
 {
 	*cr->unitdir[unit].start =
@@ -1965,8 +1945,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);
 
@@ -1974,49 +1952,7 @@
 	cf_unit_begin(&cr, 2);
 	cf_put_keyval(&cr, 0, 0);
 	cf_put_1quad(&cr, 0);
-	cf_put_4bytes(&cr, 'L', 'i', 'n', 'u');
-	cf_put_4bytes(&cr, 'x', ' ', '1', '3');
-	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_put_str(&cr, "Linux OHCI-1394");
 	cf_unit_end(&cr);
 
 	ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;
@@ -2034,13 +1970,15 @@
 	return ohci->csr_config_rom_length * 4;
 }
 
-int ohci_compare_swap(struct ti_ohci *ohci, quadlet_t *data,
-                      quadlet_t compare, int sel)
+static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
+                                 quadlet_t data, quadlet_t compare)
 {
+	struct ti_ohci *ohci = host->hostdata;
 	int i;
-	reg_write(ohci, OHCI1394_CSRData, *data);
+
+	reg_write(ohci, OHCI1394_CSRData, data);
 	reg_write(ohci, OHCI1394_CSRCompareData, compare);
-	reg_write(ohci, OHCI1394_CSRControl, sel & 0x3);
+	reg_write(ohci, OHCI1394_CSRControl, reg & 0x3);
 
 	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
 		if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
@@ -2049,68 +1987,58 @@
 		mdelay(1);
 	}
 
-	*data = reg_read(ohci, OHCI1394_CSRData);
-	return 0;
+	return reg_read(ohci, OHCI1394_CSRData);
 }
 
-static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
-                                 quadlet_t data, quadlet_t compare)
-{
-	struct ti_ohci *ohci=host->hostdata;
-
-	ohci_compare_swap (ohci, &data, compare, reg);
-
-	return data;
-}
-
-static struct hpsb_host_template ohci_template = {
-	name:			OHCI1394_DRIVER_NAME,
-	initialize_host:	ohci_initialize,
-	release_host:		ohci_remove,
+static struct hpsb_host_operations ohci1394_ops = {
 	get_rom:		ohci_get_rom,
 	transmit_packet:	ohci_transmit,
 	devctl:			ohci_devctl,
 	hw_csr_reg:		ohci_hw_csr_reg,
 };
 
+static struct hpsb_host_driver *ohci1394_driver;
+
+
+
+/***********************************
+ * PCI Driver Interface functions  *
+ ***********************************/
 
-#define FAIL(fmt, args...)			\
+#define FAIL(err, fmt, args...)			\
 do {						\
 	PRINT_G(KERN_ERR, fmt , ## args);	\
-	remove_card(ohci);			\
-	return 1;				\
+        ohci1394_pci_remove(dev);               \
+	return err;				\
 } while(0)
 
-static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_device_id *ent)
+static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
+					const struct pci_device_id *ent)
 {
-	struct ti_ohci *ohci;	/* shortcut to currently handled device */
-	struct hpsb_host *host;
-	unsigned long ohci_base, ohci_len;
+	static unsigned int card_id_counter = 0;
 	static int version_printed = 0;
 
+	struct hpsb_host *host;
+	struct ti_ohci *ohci;	/* shortcut to currently handled device */
+	unsigned long ohci_base, ohci_len;
+	int i;
+	
 	if (version_printed++ == 0)
 		PRINT_G(KERN_INFO, "%s", version);
 
-        if (pci_enable_device(dev)) {
-		/* Skip ID's that fail */
-		PRINT_G(KERN_NOTICE, "Failed to enable OHCI hardware %d",
-			card_id_counter++);
-		return -ENXIO;
-        }
+        if (pci_enable_device(dev))
+		FAIL(-ENXIO, "Failed to enable OHCI hardware %d",
+		        card_id_counter++);
         pci_set_master(dev);
 
-	host = hpsb_get_host(&ohci_template, sizeof (struct ti_ohci));
-	if (!host) {
-		PRINT_G(KERN_ERR, "Out of memory trying to allocate host structure");
-		return -ENOMEM;
-	}
+	host = hpsb_alloc_host(ohci1394_driver, sizeof(struct ti_ohci));
+	if (!host) FAIL(-ENOMEM, "Failed to allocate host structure");
+
 	ohci = host->hostdata;
-	ohci->host = host;
-	INIT_LIST_HEAD(&ohci->list);
 	ohci->id = card_id_counter++;
 	ohci->dev = dev;
-	host->pdev = dev;
 	ohci->host = host;
+	host->pdev = dev;
 	pci_set_drvdata(dev, ohci);
 
 	/* We don't want hardware swapping */
@@ -2138,8 +2066,54 @@
 				     &ohci->csr_config_rom_bus);
 	OHCI_DMA_ALLOC("consistent csr_config_rom");
 	if (ohci->csr_config_rom_cpu == NULL)
-		FAIL("Failed to allocate buffer config rom");
+		FAIL(-ENOMEM, "Failed to allocate buffer config rom");
+
+
+	ohci_base = pci_resource_start(dev, 0);
+	ohci_len = pci_resource_len(dev, 0);
+
+	if (!request_mem_region (ohci_base, ohci_len, OHCI1394_DRIVER_NAME))
+		FAIL(-ENOMEM, "MMIO resource (0x%lx@0x%lx) unavailable, aborting.",
+		     ohci_base, ohci_len);
+
+	ohci->registers = ioremap(ohci_base, ohci_len);
+
+	if (ohci->registers == NULL)
+		FAIL(-ENXIO, "Failed to remap registers - card not accessible");
+
+	DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p", ohci->registers);
+
+
+	/* Start off with a softreset, to clear everything to a sane
+	 * state.  This will also set Link Power State (LPS), which we
+	 * need in order to start accessing most of the registers.  */
+	ohci_soft_reset(ohci);
+
+	/* determinte the number of available IR and IT contexts right away,
+	   because they need to be known for alloc_dma_*_ctx() */
+	ohci->nb_iso_rcv_ctx = 
+		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
+	DBGMSG(ohci->id, "%d iso receive contexts available",
+	       ohci->nb_iso_rcv_ctx);
+
+	ohci->ir_ctx_usage = 0;
+	
+	/* set the usage bits for non-existent contexts so they can't be allocated */
+	for(i = ohci->nb_iso_rcv_ctx; i < sizeof(ohci->ir_ctx_usage)*8; i++)
+		__set_bit(i, &ohci->ir_ctx_usage);
+	
+	ohci->nb_iso_xmit_ctx = 
+		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
+	DBGMSG(ohci->id, "%d iso transmit contexts available",
+	       ohci->nb_iso_xmit_ctx);
+
+	ohci->it_ctx_usage = 0;
+	
+	/* set the usage bits for non-existent contexts so they can't be allocated */
+	for(i = ohci->nb_iso_xmit_ctx; i < sizeof(ohci->it_ctx_usage)*8; i++)
+		__set_bit(i, &ohci->it_ctx_usage);
 
+	
 	/* 
 	 * self-id dma buffer allocation
 	 */
@@ -2148,103 +2122,101 @@
                       &ohci->selfid_buf_bus);
 	OHCI_DMA_ALLOC("consistent selfid_buf");
 	if (ohci->selfid_buf_cpu == NULL)
-		FAIL("Failed to allocate DMA buffer for self-id packets");
+		FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets");
 
 	if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff)
 		PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on "
 		      "8Kb boundary... may cause problems on some CXD3222 chip", 
 		      ohci->selfid_buf_cpu);  
 
-	ohci->it_context =
-		alloc_dma_trm_ctx(ohci, 2, IT_NUM_DESC,
-				  OHCI1394_IsoXmitContextControlSet,
-				  OHCI1394_IsoXmitContextControlClear,
-				  OHCI1394_IsoXmitCommandPtr);
-
-	if (ohci->it_context == NULL)
-		FAIL("Failed to allocate IT context");
-
-	ohci_base = pci_resource_start(dev, 0);
-	ohci_len = pci_resource_len(dev, 0);
-
-	if (!request_mem_region (ohci_base, ohci_len, host->template->name))
-		FAIL("MMIO resource (0x%lx@0x%lx) unavailable, aborting.",
-		     ohci_base, ohci_len);
-
-	ohci->registers = ioremap(ohci_base, ohci_len);
-
-	if (ohci->registers == NULL)
-		FAIL("Failed to remap registers - card not accessible");
-
-	DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p",
-	      ohci->registers);
+	/* No self-id errors at startup */
+	ohci->self_id_errors = 0;
 
+	/* AR DMA request context allocation */
 	ohci->ar_req_context = 
-		alloc_dma_rcv_ctx(ohci, 0, AR_REQ_NUM_DESC,
+		alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC,
 				  AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,
-				  OHCI1394_AsReqRcvContextControlSet,
-				  OHCI1394_AsReqRcvContextControlClear,
-				  OHCI1394_AsReqRcvCommandPtr);
+				  OHCI1394_AsReqRcvContextBase);
 
 	if (ohci->ar_req_context == NULL)
-		FAIL("Failed to allocate AR Req context");
+		FAIL(-ENOMEM, "Failed to allocate AR Req context");
 
+	/* AR DMA response context allocation */
 	ohci->ar_resp_context = 
-		alloc_dma_rcv_ctx(ohci, 1, AR_RESP_NUM_DESC,
+		alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC,
 				  AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,
-				  OHCI1394_AsRspRcvContextControlSet,
-				  OHCI1394_AsRspRcvContextControlClear,
-				  OHCI1394_AsRspRcvCommandPtr);
+				  OHCI1394_AsRspRcvContextBase);
 	
 	if (ohci->ar_resp_context == NULL)
-		FAIL("Failed to allocate AR Resp context");
+		FAIL(-ENOMEM, "Failed to allocate AR Resp context");
 
+	/* AT DMA request context */
 	ohci->at_req_context = 
-		alloc_dma_trm_ctx(ohci, 0, AT_REQ_NUM_DESC,
-				  OHCI1394_AsReqTrContextControlSet,
-				  OHCI1394_AsReqTrContextControlClear,
-				  OHCI1394_AsReqTrCommandPtr);
+		alloc_dma_trm_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC,
+				  OHCI1394_AsReqTrContextBase);
 	
 	if (ohci->at_req_context == NULL)
-		FAIL("Failed to allocate AT Req context");
+		FAIL(-ENOMEM, "Failed to allocate AT Req context");
 
+	/* AT DMA response context */
 	ohci->at_resp_context = 
-		alloc_dma_trm_ctx(ohci, 1, AT_RESP_NUM_DESC,
-				  OHCI1394_AsRspTrContextControlSet,
-				  OHCI1394_AsRspTrContextControlClear,
-				  OHCI1394_AsRspTrCommandPtr);
+		alloc_dma_trm_ctx(ohci, DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC,
+				  OHCI1394_AsRspTrContextBase);
 	
 	if (ohci->at_resp_context == NULL)
-		FAIL("Failed to allocate AT Resp context");
+		FAIL(-ENOMEM, "Failed to allocate AT Resp context");
 
+	/* IR DMA context */
 	ohci->ir_context =
-		alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC,
+		alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, 0, IR_NUM_DESC,
 				  IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
-				  OHCI1394_IsoRcvContextControlSet,
-				  OHCI1394_IsoRcvContextControlClear,
-				  OHCI1394_IsoRcvCommandPtr);
+				  OHCI1394_IsoRcvContextBase);
 
 	if (ohci->ir_context == NULL)
-		FAIL("Failed to allocate IR context");
+		FAIL(-ENOMEM, "Failed to allocate IR context");
+
+	
+	/* IT DMA context allocation */
+	ohci->it_context =
+		alloc_dma_trm_ctx(ohci, DMA_CTX_ISO, 0, IT_NUM_DESC,
+				  OHCI1394_IsoXmitContextBase);
+
+	if (ohci->it_context == NULL)
+		FAIL(-ENOMEM, "Failed to allocate IT context");
 
 	ohci->ISO_channel_usage = 0;
         spin_lock_init(&ohci->IR_channel_lock);
 
+	for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
+		ohci->irq_hooks[i].irq_handler = NULL;
+		ohci->irq_hooks[i].data = NULL;
+	}
+	
 	if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
 			 OHCI1394_DRIVER_NAME, ohci))
-		FAIL("Failed to allocate shared interrupt %d", dev->irq);
+		FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq);
+
+	ohci_initialize(ohci);
 
 	/* Tell the highlevel this host is ready */
-	highlevel_add_one_host (host);
+	hpsb_add_host(host);
 
 	return 0;
 #undef FAIL
 }
 
-static void remove_card(struct ti_ohci *ohci)
+static void __devexit ohci1394_pci_remove(struct pci_dev *pdev)
 {
+	struct ti_ohci *ohci;
 	quadlet_t buf;
 
+	ohci = pci_get_drvdata(pdev);
+	if (!ohci)
+		return;
+
+	if (ohci->host)
+		hpsb_remove_host(ohci->host);
+
 	/* Soft reset before we start */
 	ohci_soft_reset(ohci);
 
@@ -2308,15 +2280,48 @@
 
 		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 */
 
 	pci_set_drvdata(ohci->dev, NULL);
+	kfree(ohci);
 }
 
+#define PCI_CLASS_FIREWIRE_OHCI     ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
+
+static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = {
+	{
+		class: 		PCI_CLASS_FIREWIRE_OHCI,
+		class_mask: 	0x00ffffff,
+		vendor:		PCI_ANY_ID,
+		device:		PCI_ANY_ID,
+		subvendor:	PCI_ANY_ID,
+		subdevice:	PCI_ANY_ID,
+	},
+	{ 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
+
+static struct pci_driver ohci1394_pci_driver = {
+	name:		OHCI1394_DRIVER_NAME,
+	id_table:	ohci1394_pci_tbl,
+	probe:		ohci1394_pci_probe,
+	remove:		__devexit_p(ohci1394_pci_remove),
+};
+
+
+
+/***********************************
+ * OHCI1394 Video Interface        *
+ ***********************************/
+
+/* essentially the only purpose of this code is to allow another
+   module to hook into ohci's interrupt handler */
+
 void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
 {
 	int i=0;
@@ -2336,111 +2341,96 @@
 	if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg);
 }
 
-int ohci1394_register_video(struct ti_ohci *ohci,
-			    struct video_template *tmpl)
+static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci,
+					  quadlet_t isoRecvEvent, 
+					  quadlet_t isoXmitEvent)
 {
-	if (ohci->video_tmpl)
-		return -ENFILE;
-	ohci->video_tmpl = tmpl;
-	MOD_INC_USE_COUNT;
-	return 0;
+	int i;
+	for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
+		if(ohci->irq_hooks[i].irq_handler != NULL) {
+			ohci->irq_hooks[i].irq_handler(ohci->id, isoRecvEvent, isoXmitEvent,
+						       ohci->irq_hooks[i].data);
+		}
+	}
 }
-	
-void ohci1394_unregister_video(struct ti_ohci *ohci,
-			       struct video_template *tmpl)
+
+int ohci1394_hook_irq(struct ti_ohci *ohci,
+		      void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
+		      void *data)
 {
-	if (ohci->video_tmpl != tmpl) {
-		PRINT(KERN_ERR, ohci->id, 
-		      "Trying to unregister wrong video device");
-	} else {
-		ohci->video_tmpl = NULL;
-		MOD_DEC_USE_COUNT;
+	int i;
+	
+	/* find a free slot */
+	for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
+		if(ohci->irq_hooks[i].irq_handler == NULL)
+			break;
 	}
+
+	if(i >= OHCI1394_MAX_IRQ_HOOKS)
+		return -EBUSY;
+
+	ohci->irq_hooks[i].irq_handler = irq_handler;
+	ohci->irq_hooks[i].data = data;
+
+	/* ohci1394 will never be unloaded while an IRQ hook is
+	   in use, because the user must reference this symbol */
+	
+	return 0;
 }
 
-#if 0
-int ohci1394_request_channel(struct ti_ohci *ohci, int channel)
+void ohci1394_unhook_irq(struct ti_ohci *ohci,
+			 void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
+			 void *data)
 {
-	int csrSel;
-	quadlet_t chan, data1=0, data2=0;
-	int timeout = 32;
-
-	if (channel<32) {
-		chan = 1<<channel;
-		csrSel = 2;
-	}
-	else {
-		chan = 1<<(channel-32);
-		csrSel = 3;
-	}
-	if (ohci_compare_swap(ohci, &data1, 0, csrSel)<0) {
-		PRINT(KERN_INFO, ohci->id, "request_channel timeout");
-		return -1;
+	int i;
+	
+	for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
+		if( (ohci->irq_hooks[i].irq_handler == irq_handler) &&
+		    (ohci->irq_hooks[i].data == data) )
+			break;
 	}
-	while (timeout--) {
-		if (data1 & chan) {
-			PRINT(KERN_INFO, ohci->id, 
-			      "request channel %d failed", channel);
-			return -1;
-		}
-		data2 = data1;
-		data1 |= chan;
-		if (ohci_compare_swap(ohci, &data1, data2, csrSel)<0) {
-			PRINT(KERN_INFO, ohci->id, "request_channel timeout");
-			return -1;
-		}
-		if (data1==data2) {
-			PRINT(KERN_INFO, ohci->id, 
-			      "request channel %d succeded", channel);
-			return 0;
-		}
+	
+	if(i < OHCI1394_MAX_IRQ_HOOKS) {
+		ohci->irq_hooks[i].irq_handler = NULL;
+		ohci->irq_hooks[i].data = NULL;
 	}
-	PRINT(KERN_INFO, ohci->id, "request channel %d failed", channel);
-	return -1;
 }
-#endif
 
 EXPORT_SYMBOL(ohci1394_stop_context);
-EXPORT_SYMBOL(ohci1394_register_video);
-EXPORT_SYMBOL(ohci1394_unregister_video);
+EXPORT_SYMBOL(ohci1394_hook_irq);
+EXPORT_SYMBOL(ohci1394_unhook_irq);
 
-MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
-MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers");
-MODULE_LICENSE("GPL");
 
-static void __devexit ohci1394_remove_one(struct pci_dev *pdev)
-{
-	struct ti_ohci *ohci = pci_get_drvdata(pdev);
 
-	if (ohci) {
-		remove_card (ohci);
-		pci_set_drvdata(pdev, NULL);
-	}
-}
+/***********************************
+ * General module initialization   *
+ ***********************************/
 
-static struct pci_driver ohci1394_driver = {
-	name:		OHCI1394_DRIVER_NAME,
-	id_table:	ohci1394_pci_tbl,
-	probe:		ohci1394_add_one,
-	remove:		ohci1394_remove_one,
-};
+MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
+MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers");
+MODULE_LICENSE("GPL");
 
 static void __exit ohci1394_cleanup (void)
 {
-	hpsb_unregister_lowlevel(&ohci_template);
-	pci_unregister_driver(&ohci1394_driver);
+	pci_unregister_driver(&ohci1394_pci_driver);
+	hpsb_unregister_lowlevel(ohci1394_driver);
 }
 
 static int __init ohci1394_init(void)
 {
 	int ret;
-	if (hpsb_register_lowlevel(&ohci_template)) {
-		PRINT_G(KERN_ERR, "Registering failed");
-		return -ENXIO;
-	}
-	if ((ret = pci_module_init(&ohci1394_driver))) {
-		PRINT_G(KERN_ERR, "PCI module init failed");
-		hpsb_unregister_lowlevel(&ohci_template);
+
+	ohci1394_driver = hpsb_register_lowlevel(&ohci1394_ops,
+						 OHCI1394_DRIVER_NAME);
+	if (!ohci1394_driver) {
+		PRINT_G(KERN_ERR, "hpsb_register_lowlevel failed");
+		return -ENOMEM;
+	}
+
+	ret = pci_module_init(&ohci1394_pci_driver);
+	if (ret < 0) {
+		PRINT_G(KERN_ERR, "pci_module_init failed");
+		hpsb_unregister_lowlevel(ohci1394_driver);
 		return ret;
 	}
 	return ret;
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/ohci1394.h linux/drivers/ieee1394/ohci1394.h
--- v2.5.2/linux/drivers/ieee1394/ohci1394.h	Mon Oct  1 21:24:24 2001
+++ linux/drivers/ieee1394/ohci1394.h	Mon Jan 21 15:57:51 2002
@@ -76,9 +76,13 @@
 	quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
 };
 
+/* identify whether a DMA context is asynchronous or isochronous */
+enum context_type { DMA_CTX_ASYNC_REQ, DMA_CTX_ASYNC_RESP, DMA_CTX_ISO };
+
 /* DMA receive context */
 struct dma_rcv_ctx {
-	void *ohci;
+	struct ti_ohci *ohci;
+	enum context_type type;
 	int ctx;
 	unsigned int num_desc;
 
@@ -105,7 +109,8 @@
 
 /* DMA transmit context */	
 struct dma_trm_ctx {
-	void *ohci;
+	struct ti_ohci *ohci;
+	enum context_type type;
 	int ctx;
 	unsigned int num_desc;
 
@@ -133,18 +138,9 @@
 	int cmdPtr;
 };
 
-/* video device template */
-struct video_template {
-	void (*irq_handler) (int card, quadlet_t isoRecvEvent, 
-			     quadlet_t isoXmitEvent);
-};
-
-
 struct ti_ohci {
         int id; /* sequential card number */
 
-	struct list_head list;
-
         struct pci_dev *dev;
 
         u32 state;
@@ -175,11 +171,13 @@
 	struct dma_rcv_ctx *ir_context;
         spinlock_t IR_channel_lock;
 	int nb_iso_rcv_ctx;
-
+	unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */
+	
         /* iso transmit */
 	struct dma_trm_ctx *it_context;
 	int nb_iso_xmit_ctx;
-
+	unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */
+	
         u64 ISO_channel_usage;
 
         /* IEEE-1394 part follows */
@@ -192,8 +190,15 @@
 
 	int self_id_errors;
 
-	/* video device */
-	struct video_template *video_tmpl;
+	/* IRQ hooks, for video1394 and dv1394 */
+	
+#define OHCI1394_MAX_IRQ_HOOKS 4
+	
+	struct ohci1394_irq_hook {
+		void (*irq_handler) (int card, quadlet_t isoRecvEvent, 
+				     quadlet_t isoXmitEvent, void *data);
+		void *data;
+	} irq_hooks[OHCI1394_MAX_IRQ_HOOKS];
 
 	/* Swap the selfid buffer? */
 	unsigned int selfid_swap:1;
@@ -230,6 +235,12 @@
 /* 2 KiloBytes of register space */
 #define OHCI1394_REGISTER_SIZE                0x800       
 
+/* Offsets relative to context bases defined below */
+
+#define OHCI1394_ContextControlSet            0x000
+#define OHCI1394_ContextControlClear          0x004
+#define OHCI1394_ContextCommandPtr            0x00C
+
 /* register map */
 #define OHCI1394_Version                      0x000
 #define OHCI1394_GUID_ROM                     0x004
@@ -281,27 +292,37 @@
 #define OHCI1394_PhyReqFilterLoSet            0x118
 #define OHCI1394_PhyReqFilterLoClear          0x11C
 #define OHCI1394_PhyUpperBound                0x120
+
+#define OHCI1394_AsReqTrContextBase           0x180
 #define OHCI1394_AsReqTrContextControlSet     0x180
 #define OHCI1394_AsReqTrContextControlClear   0x184
 #define OHCI1394_AsReqTrCommandPtr            0x18C
+
+#define OHCI1394_AsRspTrContextBase           0x1A0
 #define OHCI1394_AsRspTrContextControlSet     0x1A0
 #define OHCI1394_AsRspTrContextControlClear   0x1A4
 #define OHCI1394_AsRspTrCommandPtr            0x1AC
+
+#define OHCI1394_AsReqRcvContextBase          0x1C0
 #define OHCI1394_AsReqRcvContextControlSet    0x1C0
 #define OHCI1394_AsReqRcvContextControlClear  0x1C4
 #define OHCI1394_AsReqRcvCommandPtr           0x1CC
+
+#define OHCI1394_AsRspRcvContextBase          0x1E0
 #define OHCI1394_AsRspRcvContextControlSet    0x1E0
 #define OHCI1394_AsRspRcvContextControlClear  0x1E4
 #define OHCI1394_AsRspRcvCommandPtr           0x1EC
 
 /* Isochronous transmit registers */
 /* Add (32 * n) for context n */
+#define OHCI1394_IsoXmitContextBase           0x200
 #define OHCI1394_IsoXmitContextControlSet     0x200
 #define OHCI1394_IsoXmitContextControlClear   0x204
 #define OHCI1394_IsoXmitCommandPtr            0x20C
 
 /* Isochronous receive registers */
 /* Add (32 * n) for context n */
+#define OHCI1394_IsoRcvContextBase            0x400
 #define OHCI1394_IsoRcvContextControlSet      0x400
 #define OHCI1394_IsoRcvContextControlClear    0x404
 #define OHCI1394_IsoRcvCommandPtr             0x40C
@@ -346,10 +367,13 @@
 
 void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
 struct ti_ohci *ohci1394_get_struct(int card_num);
-int ohci1394_register_video(struct ti_ohci *ohci,
-			    struct video_template *tmpl);
-void ohci1394_unregister_video(struct ti_ohci *ohci,
-			       struct video_template *tmpl);
 
+int ohci1394_hook_irq(struct ti_ohci *ohci,
+		      void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
+		      void *data);
+
+void ohci1394_unhook_irq(struct ti_ohci *ohci,
+			 void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
+			 void *data);
 #endif
 
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c
--- v2.5.2/linux/drivers/ieee1394/pcilynx.c	Sun Nov 11 10:20:21 2001
+++ linux/drivers/ieee1394/pcilynx.c	Mon Jan 21 15:57:51 2002
@@ -42,10 +42,6 @@
 #include "pcilynx.h"
 
 
-#if MAX_PCILYNX_CARDS > PCILYNX_MINOR_ROM_START
-#error Max number of cards is bigger than PCILYNX_MINOR_ROM_START - this does not work.
-#endif
-
 /* print general (card independent) information */
 #define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
 /* print card specific information */
@@ -60,9 +56,8 @@
 #endif
 
 
-static struct ti_lynx cards[MAX_PCILYNX_CARDS];
-static int num_of_cards = 0;
-static struct hpsb_host_template lynx_template;
+static struct hpsb_host_driver *lynx_driver;
+static unsigned int card_id;
 
 /*
  * PCL handling functions.
@@ -143,10 +138,6 @@
 #endif
 
 
-static int add_card(struct pci_dev *dev, const struct pci_device_id *devid);
-static void remove_card(struct pci_dev *dev);
-
-
 
 /***********************************
  * IEEE-1394 functionality section *
@@ -161,8 +152,9 @@
         unsigned long flags;
 
         if (addr > 15) {
-                PRINT(KERN_ERR, lynx->id, __FUNCTION__
-                      ": PHY register address %d out of range", addr);
+                PRINT(KERN_ERR, lynx->id,
+                      "%s: PHY register address %d out of range",
+		      __FUNCTION__, addr);
                 return -1;
         }
 
@@ -173,8 +165,8 @@
                 retval = reg_read(lynx, LINK_PHY);
 
                 if (i > 10000) {
-                        PRINT(KERN_ERR, lynx->id, __FUNCTION__ 
-                              ": runaway loop, aborting");
+                        PRINT(KERN_ERR, lynx->id, "%s: runaway loop, aborting",
+			      __FUNCTION__);
                         retval = -1;
                         break;
                 }
@@ -196,14 +188,14 @@
         unsigned long flags;
 
         if (addr > 15) {
-                PRINT(KERN_ERR, lynx->id, __FUNCTION__
-                      ": PHY register address %d out of range", addr);
+                PRINT(KERN_ERR, lynx->id,
+                      "%s: PHY register address %d out of range", __FUNCTION__, addr);
                 return -1;
         }
 
         if (val > 0xff) {
-                PRINT(KERN_ERR, lynx->id, __FUNCTION__
-                      ": PHY register value %d out of range", val);
+                PRINT(KERN_ERR, lynx->id,
+                      "%s: PHY register value %d out of range", __FUNCTION__, val);
                 return -1;
         }
 
@@ -222,8 +214,8 @@
         int reg;
 
         if (page > 7) {
-                PRINT(KERN_ERR, lynx->id, __FUNCTION__
-                      ": PHY page %d out of range", page);
+                PRINT(KERN_ERR, lynx->id,
+                      "%s: PHY page %d out of range", __FUNCTION__, page);
                 return -1;
         }
 
@@ -244,8 +236,8 @@
         int reg;
 
         if (port > 15) {
-                PRINT(KERN_ERR, lynx->id, __FUNCTION__
-                      ": PHY port %d out of range", port);
+                PRINT(KERN_ERR, lynx->id,
+                      "%s: PHY port %d out of range", __FUNCTION__, port);
                 return -1;
         }
 
@@ -377,7 +369,7 @@
 
         hpsb_selfid_complete(host, phyid, isroot);
 
-        if (host->in_bus_reset) return;
+        if (host->in_bus_reset) return; /* in bus reset again */
 
         if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER);
         reg_set_bits(lynx, LINK_CONTROL,
@@ -440,160 +432,7 @@
 }
 
 
-#if 0
-static int lynx_detect(struct hpsb_host_template *tmpl)
-{
-        struct hpsb_host *host;
-        int i;
-
-        init_driver();
-
-        for (i = 0; i < num_of_cards; i++) {
-                host = hpsb_get_host(tmpl, 0);
-                if (host == NULL) {
-                        /* simply don't init more after out of mem */
-                        return i;
-                }
-                host->hostdata = &cards[i];
-                cards[i].host = host;
-        }
-
-        return num_of_cards;
-}
-#endif
-
-static int lynx_initialize(struct hpsb_host *host)
-{
-        struct ti_lynx *lynx = host->hostdata;
-        struct ti_pcl pcl;
-        int i;
-        u32 *pcli;
-
-        lynx->selfid_size = -1;
-        lynx->phy_reg0 = -1;
-
-        lynx->async.queue = NULL;
-        
-        pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
-        put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
-        
-        pcl.next = PCL_NEXT_INVALID;
-        pcl.async_error_next = PCL_NEXT_INVALID;
-#ifdef __BIG_ENDIAN
-        pcl.buffer[0].control = PCL_CMD_RCV | 16;
-        pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
-#else
-        pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;
-        pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
-#endif
-        pcl.buffer[0].pointer = lynx->rcv_page_dma;
-        pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
-        put_pcl(lynx, lynx->rcv_pcl, &pcl);
-        
-        pcl.next = pcl_bus(lynx, lynx->async.pcl);
-        pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
-        put_pcl(lynx, lynx->async.pcl_start, &pcl);
-
-        pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);
-        pcl.async_error_next = PCL_NEXT_INVALID;
-        put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);
-
-        pcl.next = PCL_NEXT_INVALID;
-        pcl.async_error_next = PCL_NEXT_INVALID;
-        pcl.buffer[0].control = PCL_CMD_RCV | 4;
-#ifndef __BIG_ENDIAN
-        pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
-        pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
-
-        for (i = 0; i < NUM_ISORCV_PCL; i++) {
-                int page = i / ISORCV_PER_PAGE;
-                int sec = i % ISORCV_PER_PAGE;
-
-                pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page] 
-                        + sec * MAX_ISORCV_SIZE;
-                pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
-                put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
-        }
-
-        pcli = (u32 *)&pcl;
-        for (i = 0; i < NUM_ISORCV_PCL; i++) {
-                pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
-        }
-        put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
-
-        /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */
-        reg_write(lynx, FIFO_SIZES, 0x003030a0);
-        /* 20 byte threshold before triggering PCI transfer */
-        reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
-        /* threshold on both send FIFOs before transmitting:
-           FIFO size - cache line size - 1 */
-        i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;
-        i = 0x30 - i - 1;
-        reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);
-        
-        reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
-
-        reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
-                  | LINK_INT_PHY_REG_RCVD  | LINK_INT_PHY_BUSRESET
-                  | LINK_INT_ISO_STUCK     | LINK_INT_ASYNC_STUCK 
-                  | LINK_INT_SENT_REJECT   | LINK_INT_TX_INVALID_TC
-                  | LINK_INT_GRF_OVERFLOW  | LINK_INT_ITF_UNDERFLOW
-                  | LINK_INT_ATF_UNDERFLOW);
-        
-        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
-        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);
-        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
-        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),
-                  DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST
-                  | DMA_WORD1_CMP_MATCH_EXACT    | DMA_WORD1_CMP_MATCH_BUS_BCAST
-                  | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);
-
-        run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
-
-        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
-        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
-        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
-        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
-
-        run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
-
-        reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
-                  | LINK_CONTROL_TX_ISO_EN   | LINK_CONTROL_RX_ISO_EN
-                  | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
-                  | LINK_CONTROL_RESET_TX    | LINK_CONTROL_RESET_RX);
-
-        if (!lynx->phyic.reg_1394a) {
-                /* attempt to enable contender bit -FIXME- would this work
-                 * elsewhere? */
-                reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
-                reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1); 
-        } else {
-                /* set the contender bit in the extended PHY register
-                 * set. (Should check that bis 0,1,2 (=0xE0) is set
-                 * in register 2?)
-                 */
-                i = get_phy_reg(lynx, 4);
-                if (i != -1) set_phy_reg(lynx, 4, i | 0x40);
-        }
-
-        return 1;
-}
-
-static void lynx_release(struct hpsb_host *host)
-{
-        struct ti_lynx *lynx;
-        
-        if (host != NULL) {
-                lynx = host->hostdata;
-                remove_card(lynx->dev);
-        } else {
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-                unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
-#endif
-        }
-}
-
+/* called from subsystem core */
 static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
 {
         struct ti_lynx *lynx = host->hostdata;
@@ -642,6 +481,8 @@
         return 1;
 }
 
+
+/* called from subsystem core */
 static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
 {
         struct ti_lynx *lynx = host->hostdata;
@@ -666,9 +507,7 @@
                 arg |= (retval == -1 ? 63 : retval);
                 retval = 0;
 
-                PRINT(KERN_INFO, lynx->id, "resetting bus on request%s",
-                      (host->attempt_root ? " and attempting to become root"
-                       : ""));
+                PRINT(KERN_INFO, lynx->id, "resetting bus on request");
 
                 lynx->selfid_size = -1;
                 lynx->phy_reg0 = -1;
@@ -721,6 +560,8 @@
                 } else {
                         MOD_DEC_USE_COUNT;
                 }
+
+                retval = 1;
                 break;
 
         case ISO_LISTEN_CHANNEL:
@@ -1010,8 +851,8 @@
                 membase = md->lynx->aux_port;
                 break;
         default:
-                panic("pcilynx%d: unsupported md->type %d in " __FUNCTION__,
-                      md->lynx->id, md->type);
+                panic("pcilynx%d: unsupported md->type %d in %s",
+                      md->lynx->id, md->type, __FUNCTION__);
         }
 
         down(&md->lynx->mem_dma_mutex);
@@ -1291,6 +1132,7 @@
         }
 }
 
+
 static void iso_rcv_bh(struct ti_lynx *lynx)
 {
         unsigned int idx;
@@ -1335,44 +1177,97 @@
 }
 
 
+static void remove_card(struct pci_dev *dev)
+{
+        struct ti_lynx *lynx;
+        int i;
+
+        lynx = pci_get_drvdata(dev);
+        if (!lynx) return;
+        pci_set_drvdata(dev, NULL);
+
+        switch (lynx->state) {
+        case is_host:
+                reg_write(lynx, PCI_INT_ENABLE, 0);
+                hpsb_remove_host(lynx->host);
+        case have_intr:
+                reg_write(lynx, PCI_INT_ENABLE, 0);
+                free_irq(lynx->dev->irq, lynx);
+        case have_iomappings:
+                reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+                /* Fix buggy cards with autoboot pin not tied low: */
+                reg_write(lynx, DMA0_CHAN_CTRL, 0);
+                iounmap(lynx->registers);
+                iounmap(lynx->local_rom);
+                iounmap(lynx->local_ram);
+                iounmap(lynx->aux_port);
+        case have_1394_buffers:
+                for (i = 0; i < ISORCV_PAGES; i++) {
+                        if (lynx->iso_rcv.page[i]) {
+                                pci_free_consistent(lynx->dev, PAGE_SIZE,
+                                                    lynx->iso_rcv.page[i],
+                                                    lynx->iso_rcv.page_dma[i]);
+                        }
+                }
+                pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
+                                    lynx->rcv_page_dma);
+        case have_aux_buf:
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+                pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer,
+                                    lynx->mem_dma_buffer_dma);
+#endif
+        case have_pcl_mem:
+#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
+                pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
+                                    lynx->pcl_mem_dma);
+#endif
+        case clear:
+                /* do nothing - already freed */
+                ;
+        }
+
+	tasklet_kill(&lynx->iso_rcv.tq);
+        kfree(lynx);
+}
+
+
 static int __devinit add_card(struct pci_dev *dev,
-                              const struct pci_device_id *devid)
+                              const struct pci_device_id *devid_is_unused)
 {
 #define FAIL(fmt, args...) do { \
         PRINT_G(KERN_ERR, fmt , ## args); \
-        num_of_cards--; \
         remove_card(dev); \
-        return -1; \
+        return error; \
         } while (0)
 
+	struct hpsb_host *host;
         struct ti_lynx *lynx; /* shortcut to currently handled device */
-        unsigned int i;
+        struct ti_pcl pcl;
+        u32 *pcli;
+        int i;
+        int error;
 
-        if (num_of_cards == MAX_PCILYNX_CARDS) {
-                PRINT_G(KERN_WARNING, "cannot handle more than %d cards.  "
-                        "Adjust MAX_PCILYNX_CARDS in pcilynx.h.",
-                        MAX_PCILYNX_CARDS);
-                return -1;
-        }
 
-        lynx = &cards[num_of_cards++];
+        error = -ENXIO;
 
         if (pci_set_dma_mask(dev, 0xffffffff))
-                FAIL("DMA address limits not supported for PCILynx hardware %d",
-                     lynx->id);
+                FAIL("DMA address limits not supported for PCILynx hardware");
         if (pci_enable_device(dev))
-                FAIL("failed to enable PCILynx hardware %d", lynx->id);
+                FAIL("failed to enable PCILynx hardware");
         pci_set_master(dev);
 
-        lynx->host = hpsb_get_host(&lynx_template, 0);
-        if (!lynx->host)
-                FAIL("failed to allocate host structure");
-
-        lynx->state = have_host_struct;
-	lynx->host->hostdata = lynx;
-        lynx->id = num_of_cards-1;
+        error = -ENOMEM;
+
+	host = hpsb_alloc_host(lynx_driver, sizeof(struct ti_lynx));
+        if (!host) FAIL("failed to allocate control structure memory");
+
+        lynx = host->hostdata;
+	lynx->id = card_id++;
         lynx->dev = dev;
-	lynx->host->pdev = dev;
+        lynx->state = clear;
+	lynx->host = host;
+        host->pdev = dev;
+        pci_set_drvdata(dev, lynx);
 
         lynx->lock = SPIN_LOCK_UNLOCKED;
         lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED;
@@ -1435,7 +1330,9 @@
         }
 #endif
 
-        reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+        reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+        /* Fix buggy cards with autoboot pin not tied low: */
+        reg_write(lynx, DMA0_CHAN_CTRL, 0);
 
         if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ,
                          PCILYNX_DRIVER_NAME, lynx)) {
@@ -1502,99 +1399,121 @@
                 PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");
         }
 
-	/* Tell the highlevel this host is ready */
-	highlevel_add_one_host (lynx->host);
-
-        return 0;
-#undef FAIL
-}
+        lynx->selfid_size = -1;
+        lynx->phy_reg0 = -1;
 
-static void remove_card(struct pci_dev *dev)
-{
-        struct ti_lynx *lynx;
-        int i;
+        lynx->async.queue = NULL;
 
-        lynx = cards;
-        while (lynx->dev != dev) lynx++;
+        pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
+        put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
 
-        switch (lynx->state) {
-        case have_intr:
-                reg_write(lynx, PCI_INT_ENABLE, 0);
-                free_irq(lynx->dev->irq, lynx);
-        case have_iomappings:
-                reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
-                iounmap(lynx->registers);
-                iounmap(lynx->local_rom);
-                iounmap(lynx->local_ram);
-                iounmap(lynx->aux_port);
-        case have_1394_buffers:
-                for (i = 0; i < ISORCV_PAGES; i++) {
-                        if (lynx->iso_rcv.page[i]) {
-                                pci_free_consistent(lynx->dev, PAGE_SIZE,
-                                                    lynx->iso_rcv.page[i],
-                                                    lynx->iso_rcv.page_dma[i]);
-                        }
-                }
-                pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
-                                    lynx->rcv_page_dma);
-        case have_aux_buf:
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-                pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer,
-                                    lynx->mem_dma_buffer_dma);
+        pcl.next = PCL_NEXT_INVALID;
+        pcl.async_error_next = PCL_NEXT_INVALID;
+#ifdef __BIG_ENDIAN
+        pcl.buffer[0].control = PCL_CMD_RCV | 16;
+        pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
+#else
+        pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;
+        pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
 #endif
-        case have_pcl_mem:
-#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
-                pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
-                                    lynx->pcl_mem_dma);
+        pcl.buffer[0].pointer = lynx->rcv_page_dma;
+        pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
+        put_pcl(lynx, lynx->rcv_pcl, &pcl);
+        
+        pcl.next = pcl_bus(lynx, lynx->async.pcl);
+        pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
+        put_pcl(lynx, lynx->async.pcl_start, &pcl);
+
+        pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);
+        pcl.async_error_next = PCL_NEXT_INVALID;
+        put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);
+
+        pcl.next = PCL_NEXT_INVALID;
+        pcl.async_error_next = PCL_NEXT_INVALID;
+        pcl.buffer[0].control = PCL_CMD_RCV | 4;
+#ifndef __BIG_ENDIAN
+        pcl.buffer[0].control |= PCL_BIGENDIAN;
 #endif
-        case have_host_struct:
-                /* FIXME - verify host freeing */
-        case clear:;
-                /* do nothing - already freed */
+        pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
+
+        for (i = 0; i < NUM_ISORCV_PCL; i++) {
+                int page = i / ISORCV_PER_PAGE;
+                int sec = i % ISORCV_PER_PAGE;
+
+                pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page] 
+                        + sec * MAX_ISORCV_SIZE;
+                pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
+                put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
         }
 
-	tasklet_kill(&lynx->iso_rcv.tq);
+        pcli = (u32 *)&pcl;
+        for (i = 0; i < NUM_ISORCV_PCL; i++) {
+                pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
+        }
+        put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
 
-        lynx->state = clear;
-}
+        /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */
+        reg_write(lynx, FIFO_SIZES, 0x003030a0);
+        /* 20 byte threshold before triggering PCI transfer */
+        reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
+        /* threshold on both send FIFOs before transmitting:
+           FIFO size - cache line size - 1 */
+        i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;
+        i = 0x30 - i - 1;
+        reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);
 
-#if 0
-static int init_driver()
-{
-        struct pci_dev *dev = NULL;
-        int success = 0;
+        reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
 
-        if (num_of_cards) {
-                PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again");
-                return 0;
-        }
+        reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
+                  | LINK_INT_PHY_REG_RCVD  | LINK_INT_PHY_BUSRESET
+                  | LINK_INT_ISO_STUCK     | LINK_INT_ASYNC_STUCK 
+                  | LINK_INT_SENT_REJECT   | LINK_INT_TX_INVALID_TC
+                  | LINK_INT_GRF_OVERFLOW  | LINK_INT_ITF_UNDERFLOW
+                  | LINK_INT_ATF_UNDERFLOW);
+        
+        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
+        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);
+        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
+        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),
+                  DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST
+                  | DMA_WORD1_CMP_MATCH_EXACT    | DMA_WORD1_CMP_MATCH_BUS_BCAST
+                  | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);
 
-        PRINT_G(KERN_INFO, "looking for PCILynx cards");
+        run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
 
-        while ((dev = pci_find_device(PCI_VENDOR_ID_TI,
-                                      PCI_DEVICE_ID_TI_PCILYNX, dev)) 
-               != NULL) {
-                if (add_card(dev) == 0) {
-                        success = 1;
-                }
-        }
+        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
+        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
+        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
+        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
 
-        if (success == 0) {
-                PRINT_G(KERN_WARNING, "no operable PCILynx cards found");
-                return -ENXIO;
-        }
+        run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
 
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
-                PRINT_G(KERN_ERR, "allocation of char major number %d failed",
-                        PCILYNX_MAJOR);
-                return -EBUSY;
+        reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
+                  | LINK_CONTROL_TX_ISO_EN   | LINK_CONTROL_RX_ISO_EN
+                  | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
+                  | LINK_CONTROL_RESET_TX    | LINK_CONTROL_RESET_RX);
+
+        if (!lynx->phyic.reg_1394a) {
+                /* attempt to enable contender bit -FIXME- would this work
+                 * elsewhere? */
+                reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
+                reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1); 
+        } else {
+                /* set the contender bit in the extended PHY register
+                 * set. (Should check that bis 0,1,2 (=0xE0) is set
+                 * in register 2?)
+                 */
+                i = get_phy_reg(lynx, 4);
+                if (i != -1) set_phy_reg(lynx, 4, i | 0x40);
         }
-#endif
+
+        hpsb_add_host(host);
+        lynx->state = is_host;
 
         return 0;
+#undef FAIL
 }
-#endif
+
 
 
 static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
@@ -1603,15 +1522,6 @@
         return sizeof(lynx_csr_rom);
 }
 
-static struct hpsb_host_template lynx_template = {
-	name:             PCILYNX_DRIVER_NAME,
-	initialize_host:  lynx_initialize,
-	release_host:     lynx_release,
-	get_rom:          get_lynx_rom,
-	transmit_packet:  lynx_transmit,
-	devctl:           lynx_devctl
-};
-
 static struct pci_device_id pci_table[] __devinitdata = {
 	{
                 vendor:     PCI_VENDOR_ID_TI,
@@ -1622,11 +1532,17 @@
 	{ }			/* Terminating entry */
 };
 
-static struct pci_driver lynx_pcidriver = {
+static struct pci_driver lynx_pci_driver = {
         name:      PCILYNX_DRIVER_NAME,
         id_table:  pci_table,
         probe:     add_card,
-        remove:    remove_card,
+        remove:    __devexit_p(remove_card),
+};
+
+static struct hpsb_host_operations lynx_ops = {
+        get_rom:          get_lynx_rom,
+        transmit_packet:  lynx_transmit,
+        devctl:           lynx_devctl,
 };
 
 MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>");
@@ -1635,30 +1551,52 @@
 MODULE_SUPPORTED_DEVICE("pcilynx");
 MODULE_DEVICE_TABLE(pci, pci_table);
 
-static void __exit pcilynx_cleanup(void)
-{
-        pci_unregister_driver(&lynx_pcidriver);
-        hpsb_unregister_lowlevel(&lynx_template);
-        PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module");
-}
-
 static int __init pcilynx_init(void)
 {
         int ret;
 
-        if (hpsb_register_lowlevel(&lynx_template)) {
-                PRINT_G(KERN_ERR, "registering failed");
-                return -ENXIO;
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+        if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
+                PRINT_G(KERN_ERR, "allocation of char major number %d failed",
+                        PCILYNX_MAJOR);
+                return -EBUSY;
+        }
+#endif
+
+        lynx_driver = hpsb_register_lowlevel(&lynx_ops, PCILYNX_DRIVER_NAME);
+        if (!lynx_driver) {
+                ret = -ENOMEM;
+                goto free_char_dev;
         }
 
-        ret = pci_module_init(&lynx_pcidriver);
+        ret = pci_module_init(&lynx_pci_driver);
         if (ret < 0) {
                 PRINT_G(KERN_ERR, "PCI module init failed");
-                hpsb_unregister_lowlevel(&lynx_template);
+                goto unregister_lowlevel;
         }
 
+        return 0;
+
+ unregister_lowlevel:
+        hpsb_unregister_lowlevel(lynx_driver);
+ free_char_dev:
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+        unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
+#endif
+
         return ret;
 }
+
+static void __exit pcilynx_cleanup(void)
+{
+        pci_unregister_driver(&lynx_pci_driver);
+        hpsb_unregister_lowlevel(lynx_driver);
+
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+        unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
+#endif
+}
+
 
 module_init(pcilynx_init);
 module_exit(pcilynx_cleanup);
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/pcilynx.h linux/drivers/ieee1394/pcilynx.h
--- v2.5.2/linux/drivers/ieee1394/pcilynx.h	Sun Aug 12 12:39:02 2001
+++ linux/drivers/ieee1394/pcilynx.h	Mon Jan 21 15:57:51 2002
@@ -40,8 +40,8 @@
                 u32 product;
         } phyic;
 
-        enum { clear, have_host_struct,  have_intr, have_aux_buf, have_pcl_mem,
-               have_1394_buffers, have_iomappings } state;
+        enum { clear, have_intr, have_aux_buf, have_pcl_mem,
+               have_1394_buffers, have_iomappings, is_host } state;
         
         /* remapped memory spaces */
         void *registers;
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/raw1394.c linux/drivers/ieee1394/raw1394.c
--- v2.5.2/linux/drivers/ieee1394/raw1394.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ieee1394/raw1394.c	Mon Jan 21 15:57:51 2002
@@ -467,7 +467,7 @@
                                 hi = list_entry(lh, struct host_info, list);
 
                                 khl->nodes = hi->host->node_count;
-                                strcpy(khl->name, hi->host->template->name);
+                                strcpy(khl->name, hi->host->driver->name);
 
                                 khl++;
                         }
@@ -495,7 +495,7 @@
                                 lh = lh->next;
                         }
                         hi = list_entry(lh, struct host_info, list);
-                        hpsb_inc_host_usage(hi->host);
+                        hpsb_ref_host(hi->host);
                         list_add_tail(&fi->list, &hi->file_info_list);
                         fi->host = hi->host;
                         fi->state = connected;
@@ -915,7 +915,7 @@
 {
         struct file_info *fi;
 
-        if (MINOR(inode->i_rdev)) {
+        if (ieee1394_file_to_instance(file) > 0) {
                 return -ENXIO;
         }
 
@@ -983,7 +983,7 @@
                 list_del(&fi->list);
                 spin_unlock_irq(&host_info_lock);
 
-                hpsb_dec_host_usage(fi->host);
+                hpsb_unref_host(fi->host);
         }
 
         kfree(fi);
@@ -1017,14 +1017,18 @@
                 return -ENOMEM;
         }
 
-	devfs_handle = devfs_register(NULL, RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
-                                      RAW1394_DEVICE_MAJOR, 0,
+	devfs_handle = devfs_register(NULL,
+				      RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
+                                      IEEE1394_MAJOR,
+				      IEEE1394_MINOR_BLOCK_RAW1394 * 16,
                                       S_IFCHR | S_IRUSR | S_IWUSR, &file_ops,
                                       NULL);
 
-        if (devfs_register_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME, 
-                                  &file_ops)) {
-                HPSB_ERR("raw1394 failed to register /dev/raw1394 device");
+        if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394,
+				      THIS_MODULE, &file_ops)) {
+                HPSB_ERR("raw1394 failed to register minor device block");
+		devfs_unregister(devfs_handle);
+		hpsb_unregister_highlevel(hl_handle);
                 return -EBUSY;
         }
 	printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
@@ -1033,7 +1037,7 @@
 
 static void __exit cleanup_raw1394(void)
 {
-        devfs_unregister_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME);
+        ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
 	devfs_unregister(devfs_handle);
         hpsb_unregister_highlevel(hl_handle);
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/sbp2.c linux/drivers/ieee1394/sbp2.c
--- v2.5.2/linux/drivers/ieee1394/sbp2.c	Wed Oct 17 14:19:20 2001
+++ linux/drivers/ieee1394/sbp2.c	Mon Jan 21 15:57:51 2002
@@ -2,7 +2,7 @@
  * sbp2.c - SBP-2 protocol driver for IEEE-1394
  *
  * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
- * jamesg@filanet.com
+ * jamesg@filanet.com (JSG)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -80,7 +80,7 @@
  *
  * The SBP-2 driver is still in an early state, but supports a variety of devices.
  * I have read/written many gigabytes of data from/to SBP-2 drives, and have seen 
- * performance of more than 16 MBytes/s on individual drives (limit of the media 
+ * performance of more than 25 MBytes/s on individual drives (limit of the media 
  * transfer rate).
  *
  * Following are the devices that have been tested successfully:
@@ -91,7 +91,7 @@
  *	- LaCie IEEE-1394 hard drives (several flavors)
  *	- QPS IEEE-1394 CD-RW/DVD drives and hard drives
  *	- BusLink IEEE-1394 hard drives
- *	- Iomega IEEE-1394 Zip/Jazz drives
+ *	- Iomega IEEE-1394 Zip/Jazz/Peerless drives
  *	- ClubMac IEEE-1394 hard drives
  *	- FirePower IEEE-1394 hard drives
  *	- EzQuest IEEE-1394 hard drives and CD-RW drives
@@ -104,7 +104,6 @@
  *	- Sony IEEE-1394 CD-RW drives
  *	- Epson IEEE-1394 scanner
  *	- ADS IEEE-1394 memory stick and compact flash readers 
- *	  (e.g. "insmod sbp2 mode_sense_hack=1" for mem stick and flash readers))
  *	- SBP-2 bridge-based devices (LSI, Oxford Semiconductor, Indigita bridges)
  *	- Various other standard IEEE-1394 hard drives and enclosures
  *
@@ -130,10 +129,6 @@
  *	  add some init code to the kernel to support this... and modules are much
  *	  more flexible anyway.   ;-)
  *
- *     - The scsi stack in recent kernels pass down the data transfer
- *       direction as scsicmd->sc_data_direction, which we should use
- *       instead of the sbp2scsi_direction_table.
- *
  *
  * History:
  *
@@ -222,9 +217,37 @@
  *                 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>
+ *	01/06/02 - Misc bug fixes/enhancements:	(JSG)
+ *		   * Enable use_new_eh_code for scsi stuff.
+ *		   * Do not write all ones for NULL ORB high/low fields, but
+ *		     rather leave reserved areas zeroed (per SBP2 spec).
+ *		   * Use newer scsi transfer direction passed down instead of our
+ *		     direction table.
+ *		   * Bumped login time-out to 20 seconds, as some devices are slow.
+ *		   * Fixed a couple scsi unregister bugs on module unload
+ *	01/13/02 - Fixed compatibility with certain SBP2 devices, such as Iomega
+ *		   1394 devices (Peerless, Jazz). Also a bit of clean-up of the 
+ *		   driver, thanks to H.J.Lu (hjl@lucon.org). Removed mode_sense_hack
+ *		   module load option, as it's been fixed in the 2.4 scsi stack.
  */
-    
-
+
 
 /*
  * Includes
@@ -244,6 +267,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>
@@ -252,6 +276,16 @@
 #include <asm/io.h>
 #include <asm/scatterlist.h>
 
+#ifdef CONFIG_KBUILD_2_5
+#include <scsi.h>
+#include <hosts.h>
+#include <sd.h>
+#else
+#include "../scsi/scsi.h"
+#include "../scsi/hosts.h"
+#include "../scsi/sd.h"
+#endif
+
 #include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "ieee1394_core.h"
@@ -260,9 +294,6 @@
 #include "highlevel.h"
 #include "ieee1394_transactions.h"
 #include "ieee1394_hotplug.h"
-#include "../scsi/scsi.h"
-#include "../scsi/hosts.h"
-#include "../scsi/sd.h"
 #include "sbp2.h"
 
 /*
@@ -270,16 +301,6 @@
  */
 
 /*
- * Set mode_sense_hack to 1 if you have some sort of unusual sbp2 device,
- * like a 1394 memory stick reader, compact flash reader, or MO drive that
- * does not support mode sense. Allows you to mount the media rw instead
- * of ro.
- */
-MODULE_PARM(mode_sense_hack,"i");
-MODULE_PARM_DESC(mode_sense_hack, "Emulate mode sense for devices like 1394 memory stick readers");
-static int mode_sense_hack = 0;
-
-/*
  * Change max_speed on module load if you have a bad IEEE-1394 controller
  * that has trouble running 2KB packets at 400mb.
  *
@@ -334,7 +355,7 @@
  */
 
 #ifdef CONFIG_IEEE1394_SBP2_DEBUG_ORBS
-#define SBP2_ORB_DEBUG(fmt, args...)	HPSB_ERR("sbp2("__FUNCTION__"): "fmt, ## args)
+#define SBP2_ORB_DEBUG(fmt, args...)	HPSB_ERR("sbp2(%s): "fmt, __FUNCTION__, ## args)
 static u32 global_outstanding_command_orbs = 0;
 #define outstanding_orb_incr global_outstanding_command_orbs++
 #define outstanding_orb_decr global_outstanding_command_orbs--
@@ -346,10 +367,10 @@
 
 #ifdef CONFIG_IEEE1394_SBP2_DEBUG_DMA
 #define SBP2_DMA_ALLOC(fmt, args...) \
-	HPSB_ERR("sbp2("__FUNCTION__")alloc(%d): "fmt, \
+	HPSB_ERR("sbp2(%s)alloc(%d): "fmt, __FUNCTION__, \
 		 ++global_outstanding_dmas, ## args)
 #define SBP2_DMA_FREE(fmt, args...) \
-	HPSB_ERR("sbp2("__FUNCTION__")free(%d): "fmt, \
+	HPSB_ERR("sbp2(%s)free(%d): "fmt, __FUNCTION__, \
 		 --global_outstanding_dmas, ## args)
 static u32 global_outstanding_dmas = 0;
 #else
@@ -357,7 +378,6 @@
 #define SBP2_DMA_FREE(fmt, args...)
 #endif
 
-
 #if CONFIG_IEEE1394_SBP2_DEBUG >= 2
 #define SBP2_DEBUG(fmt, args...)	HPSB_ERR("sbp2: "fmt, ## args)
 #define SBP2_INFO(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
@@ -395,12 +415,11 @@
  * Globals
  */
 
-Scsi_Host_Template *global_scsi_tpnt = NULL;
+static Scsi_Host_Template scsi_driver_template;
 
 static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 };
 
 static LIST_HEAD(sbp2_host_info_list);
-static int sbp2_host_count = 0;
 
 static struct hpsb_highlevel *sbp2_hl_handle = NULL;
 
@@ -671,13 +690,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 */
@@ -786,14 +805,26 @@
 	hi = (struct sbp2scsi_host_info *) command->Current_SCpnt->host->hostdata[0];
 
 	if (hi == NULL) {
-		printk(KERN_ERR __FUNCTION__": hi == NULL\n");
+		printk(KERN_ERR "%s: hi == NULL\n", __FUNCTION__);
 		return;
 	}
 
 	if (command->cmd_dma) {
-		pci_unmap_single(hi->host->pdev, command->cmd_dma,
-				 command->dma_size, command->dma_dir);
-		SBP2_DMA_FREE("single bulk");
+		if (command->dma_type == CMD_DMA_SINGLE) {
+			pci_unmap_single(hi->host->pdev, command->cmd_dma,
+					 command->dma_size, command->dma_dir);
+			SBP2_DMA_FREE("single bulk");
+		} else if (command->dma_type == CMD_DMA_PAGE) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
+			pci_unmap_single(hi->host->pdev, command->cmd_dma,
+					 command->dma_size, command->dma_dir);
+#else
+			pci_unmap_page(hi->host->pdev, command->cmd_dma,
+				       command->dma_size, command->dma_dir);
+#endif /* Linux version < 2.4.13 */
+			SBP2_DMA_FREE("single page");
+		} /* XXX: Check for CMD_DMA_NONE bug */
+		command->dma_type = CMD_DMA_NONE;
 		command->cmd_dma = 0;
 	}
 
@@ -868,7 +899,6 @@
 		hpsb_unregister_highlevel(sbp2_hl_handle);
 		sbp2_hl_handle = NULL;
 	}
-	return;
 }
 
 static int sbp2_probe(struct unit_directory *ud)
@@ -889,8 +919,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 +941,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;
 		}
 	}
@@ -974,11 +1004,13 @@
 
 	sbp2_spin_lock(&sbp2_host_info_lock, flags);
 	list_add_tail(&hi->list, &sbp2_host_info_list);
-	sbp2_host_count++;
 	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;
 }
@@ -994,22 +1026,38 @@
 
 	list_for_each (lh, &sbp2_host_info_list) {
 		hi = list_entry(lh, struct sbp2scsi_host_info, list);
-		if (hi->host == host) {
+		if (hi->host == host)
 			return hi;
-		}
 	}
 
-	return(NULL);
+	return NULL;
 }
 
 /*
- * This function is called when the host is removed
+ * This function returns a host info structure for a given Scsi_Host
+ * struct.
+ */
+static struct sbp2scsi_host_info *sbp2_find_host_info_scsi(struct Scsi_Host *host)
+{
+	struct list_head *lh;
+	struct sbp2scsi_host_info *hi;
+
+	list_for_each (lh, &sbp2_host_info_list) {
+		hi = list_entry(lh, struct sbp2scsi_host_info, list);
+		if (hi->scsi_host == host)
+			return hi;
+	}
+
+	return NULL;
+}
+
+/*
+ * 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,21 +1065,7 @@
 
 	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);
 		kfree(hi);
 	}
@@ -1203,10 +1237,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 +1262,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 +1309,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);
 }
@@ -1361,9 +1393,9 @@
 
 	save_flags(flags);
 	cli();
-	/* 10 second timeout */
+	/* 20 second timeout */
 	if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma)
-		sleep_on_timeout(&scsi_id->sbp2_login_wait, 10*HZ);
+		sleep_on_timeout(&scsi_id->sbp2_login_wait, 20*HZ);
 	restore_flags(flags);
 
 	SBP2_DEBUG("sbp2_login_device: initial check");
@@ -1381,7 +1413,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)) {
@@ -1591,13 +1623,13 @@
 	ud = scsi_id->ud;
 
 	/* Handle different fields in the unit directory, based on keys */
-	for (i = 0; i < ud->arb_count; i++) {
-		switch (ud->arb_keys[i]) {
+	for (i = 0; i < ud->count; i++) {
+		switch (CONFIG_ROM_KEY(ud->quadlets[i])) {
 		case SBP2_CSR_OFFSET_KEY:
 			/* Save off the management agent address */
 			scsi_id->sbp2_management_agent_addr =
-				CONFIG_ROM_INITIAL_MEMORY_SPACE + 
-				(ud->arb_values[i] << 2);
+				CSR_REGISTER_BASE + 
+				(CONFIG_ROM_VALUE(ud->quadlets[i]) << 2);
 
 			SBP2_DEBUG("sbp2_management_agent_addr = %x",
 				   (unsigned int) scsi_id->sbp2_management_agent_addr);
@@ -1605,14 +1637,16 @@
 
 		case SBP2_COMMAND_SET_SPEC_ID_KEY:
 			/* Command spec organization */
-			scsi_id->sbp2_command_set_spec_id = ud->arb_values[i];
+			scsi_id->sbp2_command_set_spec_id
+				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			SBP2_DEBUG("sbp2_command_set_spec_id = %x",
 				   (unsigned int) scsi_id->sbp2_command_set_spec_id);
 			break;
 
 		case SBP2_COMMAND_SET_KEY:
 			/* Command set used by sbp2 device */
-			scsi_id->sbp2_command_set = ud->arb_values[i];
+			scsi_id->sbp2_command_set
+				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			SBP2_DEBUG("sbp2_command_set = %x",
 				   (unsigned int) scsi_id->sbp2_command_set);
 			break;
@@ -1622,7 +1656,8 @@
 			 * Unit characterisitcs (orb related stuff
 			 * that I'm not yet paying attention to)
 			 */
-			scsi_id->sbp2_unit_characteristics = ud->arb_values[i];
+			scsi_id->sbp2_unit_characteristics
+				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			SBP2_DEBUG("sbp2_unit_characteristics = %x",
 				   (unsigned int) scsi_id->sbp2_unit_characteristics);
 			break;
@@ -1632,7 +1667,8 @@
 			 * Device type and lun (used for
 			 * detemining type of sbp2 device)
 			 */
-			scsi_id->sbp2_device_type_and_lun = ud->arb_values[i];
+			scsi_id->sbp2_device_type_and_lun
+				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			SBP2_DEBUG("sbp2_device_type_and_lun = %x",
 				   (unsigned int) scsi_id->sbp2_device_type_and_lun);
 			break;
@@ -1645,7 +1681,8 @@
 			 * bridge with 128KB max transfer size
 			 * limitation.
 			 */
-			scsi_id->sbp2_firmware_revision = ud->arb_values[i];
+			scsi_id->sbp2_firmware_revision
+				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			if (scsi_id->sbp2_firmware_revision ==
 			    SBP2_128KB_BROKEN_FIRMWARE) {
 				SBP2_WARN("warning: Bridge chipset supports 128KB max transfer size");
@@ -1687,9 +1724,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);
 }
@@ -1747,13 +1784,15 @@
 				   unchar *scsi_cmd,
 				   unsigned int scsi_use_sg,
 				   unsigned int scsi_request_bufflen,
-				   void *scsi_request_buffer, int dma_dir)
+				   void *scsi_request_buffer, 
+				   unsigned char scsi_dir)
 {
 	struct scatterlist *sgpnt = (struct scatterlist *) scsi_request_buffer;
 	struct sbp2_command_orb *command_orb = &command->command_orb;
 	struct sbp2_unrestricted_page_table *scatter_gather_element =
 		&command->scatter_gather_element[0];
-	u32 sg_count, sg_len;
+	int dma_dir = scsi_to_pci_dma_dir (scsi_dir);
+	u32 sg_count, sg_len, orb_direction;
 	dma_addr_t sg_addr;
 	int i;
 
@@ -1765,25 +1804,49 @@
 	 * that data_size becomes the number of s/g elements, and
 	 * page_size should be zero (for unrestricted).
 	 */
-	command_orb->next_ORB_hi = 0xffffffff;
-	command_orb->next_ORB_lo = 0xffffffff;
+	command_orb->next_ORB_hi = ORB_SET_NULL_PTR(1);
+	command_orb->next_ORB_lo = 0x0;
 	command_orb->misc = ORB_SET_MAX_PAYLOAD(scsi_id->max_payload_size);
 	command_orb->misc |= ORB_SET_SPEED(scsi_id->speed_code);
 	command_orb->misc |= ORB_SET_NOTIFY(1);		/* Notify us when complete */
 
 	/*
+	 * Get the direction of the transfer. If the direction is unknown, then use our
+	 * goofy table as a back-up.
+	 */
+	switch (scsi_dir) {
+		case SCSI_DATA_NONE:
+			orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
+			break;
+		case SCSI_DATA_WRITE:
+			orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA;
+			break;
+		case SCSI_DATA_READ:
+			orb_direction = ORB_DIRECTION_READ_FROM_MEDIA;
+			break;
+		case SCSI_DATA_UNKNOWN:
+		default:
+			SBP2_ERR("SCSI data transfer direction not specified. "
+				 "Update the SBP2 direction table in sbp2.h if " 
+				 "necessary for your application");
+			print_command (scsi_cmd);
+			orb_direction = sbp2scsi_direction_table[*scsi_cmd];
+			break;
+	}
+
+	/*
 	 * Set-up our pagetable stuff... unfortunately, this has become
 	 * messier than I'd like. Need to clean this up a bit.   ;-)
 	 */
-	if (sbp2scsi_direction_table[*scsi_cmd] == ORB_DIRECTION_NO_DATA_TRANSFER) {
+	if (orb_direction == ORB_DIRECTION_NO_DATA_TRANSFER) {
 
 		SBP2_DEBUG("No data transfer");
 
 		/*
 		 * Handle no data transfer
 		 */
-		command_orb->data_descriptor_hi = 0xffffffff;
-		command_orb->data_descriptor_lo = 0xffffffff;
+		command_orb->data_descriptor_hi = 0x0;
+		command_orb->data_descriptor_lo = 0x0;
 		command_orb->misc |= ORB_SET_DIRECTION(1);
 
 	} else if (scsi_use_sg) {
@@ -1798,15 +1861,24 @@
 			SBP2_DEBUG("Only one s/g element");
 			command->dma_dir = dma_dir;
 			command->dma_size = sgpnt[0].length;
+			command->dma_type = CMD_DMA_PAGE;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
 			command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address,
 							   command->dma_size,
 							   command->dma_dir);
-			SBP2_DMA_ALLOC("single scatter element");
+#else
+			command->cmd_dma = pci_map_page(hi->host->pdev,
+							sgpnt[0].page,
+							sgpnt[0].offset,
+							command->dma_size,
+							command->dma_dir);
+#endif /* Linux version < 2.4.13 */
+			SBP2_DMA_ALLOC("single page scatter element");
 
 			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
 			command_orb->data_descriptor_lo = command->cmd_dma;
 			command_orb->misc |= ORB_SET_DATA_SIZE(command->dma_size);
-			command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
+			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
 
 		} else {
 			int count = pci_map_sg(hi->host->pdev, sgpnt, scsi_use_sg, dma_dir);
@@ -1818,7 +1890,7 @@
 
 			/* use page tables (s/g) */
 			command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
-			command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
+			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
 			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
 			command_orb->data_descriptor_lo = command->sge_dma;
 
@@ -1863,6 +1935,7 @@
 
 		command->dma_dir = dma_dir;
 		command->dma_size = scsi_request_bufflen;
+		command->dma_type = CMD_DMA_SINGLE;
 		command->cmd_dma = pci_map_single (hi->host->pdev, scsi_request_buffer,
 						   command->dma_size,
 						   command->dma_dir);
@@ -1877,15 +1950,15 @@
 			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
 			command_orb->data_descriptor_lo = command->cmd_dma;
 			command_orb->misc |= ORB_SET_DATA_SIZE(scsi_request_bufflen);
-			command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
+			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
 
 			/*
 			 * Sanity, in case our direction table is not
 			 * up-to-date
 			 */
 			if (!scsi_request_bufflen) {
-				command_orb->data_descriptor_hi = 0xffffffff;
-				command_orb->data_descriptor_lo = 0xffffffff;
+				command_orb->data_descriptor_hi = 0x0;
+				command_orb->data_descriptor_lo = 0x0;
 				command_orb->misc |= ORB_SET_DIRECTION(1);
 			}
 
@@ -1899,7 +1972,7 @@
 
 			/* Use page tables (s/g) */
 			command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
-			command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
+			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
 
 			/*
 			 * fill out our sbp-2 page tables (and split up
@@ -1964,6 +2037,12 @@
 	SBP2_ORB_DEBUG("sending command orb %p, linked = %x, total orbs = %x",
 			command_orb, command->linked, global_outstanding_command_orbs);
 
+	pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
+			    sizeof(struct sbp2_command_orb),
+			    PCI_DMA_BIDIRECTIONAL);
+	pci_dma_sync_single(hi->host->pdev, command->sge_dma,
+			    sizeof(command->scatter_gather_element),
+			    PCI_DMA_BIDIRECTIONAL);
 	/*
 	 * Check to see if there are any previous orbs to use
 	 */
@@ -2000,6 +2079,7 @@
 		}
 
 		scsi_id->last_orb = command_orb;
+		scsi_id->last_orb_dma = command->command_orb_dma;
 
 	} else {
 
@@ -2014,6 +2094,9 @@
 			cpu_to_be32(command->command_orb_dma);
 		/* Tells hardware that this pointer is valid */
 		scsi_id->last_orb->next_ORB_hi = 0x0;
+		pci_dma_sync_single(hi->host->pdev, scsi_id->last_orb_dma,
+				    sizeof(struct sbp2_command_orb),
+				    PCI_DMA_BIDIRECTIONAL);
 
 		/*
 		 * Only ring the doorbell if we need to (first parts of
@@ -2041,6 +2124,7 @@
 		}
 
 		scsi_id->last_orb = command_orb;
+		scsi_id->last_orb_dma = command->command_orb_dma;
 
 	}
        	return(0);
@@ -2053,12 +2137,17 @@
 			     Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
 	unchar *cmd = (unchar *) SCpnt->cmnd;
-	u32 device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16;
+	unsigned int request_bufflen = SCpnt->request_bufflen;
+	u8 device_type
+		= SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
 	struct sbp2_command_info *command;
 
 	SBP2_DEBUG("sbp2_send_command");
-	SBP2_DEBUG("SCSI command = %02x", *cmd);
-	SBP2_DEBUG("SCSI transfer size = %x", SCpnt->request_bufflen);
+	SBP2_DEBUG("SCSI command:");
+#if CONFIG_IEEE1394_SBP2_DEBUG >= 2
+	print_command (cmd);
+#endif
+	SBP2_DEBUG("SCSI transfer size = %x", request_bufflen);
 	SBP2_DEBUG("SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg);
 
 	/*
@@ -2069,7 +2158,7 @@
 	    (SCpnt->request_bufflen > SBP2_BROKEN_FIRMWARE_MAX_TRANSFER) && 
 	    (device_type == TYPE_DISK) &&
 	    (SCpnt->use_sg) &&
-	    (*cmd == 0x28 || *cmd == 0x2a || *cmd == 0x0a || *cmd == 0x08)) {
+	    (*cmd == READ_6 || *cmd == READ_10 || *cmd == WRITE_6 || *cmd == WRITE_10)) {
 
 		/*
 		 * Darn, a broken device. We'll need to split up the
@@ -2088,14 +2177,24 @@
 	}
 
 	/*
+	 * The scsi stack sends down a request_bufflen which does not match the
+	 * length field in the scsi cdb. This causes some sbp2 devices to 
+	 * reject this inquiry command. Fix is to fix request_bufflen to match
+	 * the value in the cdb.
+	 */
+	if (*cmd == INQUIRY) {
+		request_bufflen = cmd[4];
+	}
+
+	/*
 	 * Now actually fill in the comamnd orb and sbp2 s/g list
 	 */
 	sbp2_create_command_orb(hi, scsi_id, command, cmd, SCpnt->use_sg,
-			SCpnt->request_bufflen, SCpnt->request_buffer,
-			scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); 
+				request_bufflen, SCpnt->request_buffer,
+				SCpnt->sc_data_direction); 
 	/*
 	 * Update our cdb if necessary (to handle sbp2 RBC command set
-	 * differences).  This is where the command set hacks go!   =)
+	 * differences). This is where the command set hacks go!   =)
 	 */
 	if ((device_type == TYPE_DISK) ||
 	    (device_type == TYPE_SDAD) ||
@@ -2185,7 +2284,7 @@
 
 			sbp2_create_command_orb(hi, scsi_id, command, new_cmd, total_sg, 
 						total_transfer, &sgpnt[current_sg],
-						scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+						SCpnt->sc_data_direction);
 
 			/*
 			 * Link up the orb, and ring the doorbell if needed
@@ -2219,7 +2318,7 @@
 
 	sbp2_create_command_orb(hi, scsi_id, command, new_cmd, total_sg, 
 				total_transfer, &sgpnt[current_sg],
-				scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+				SCpnt->sc_data_direction);
 
 	/*
 	 * Link up the orb, and ring the doorbell if needed
@@ -2361,15 +2460,20 @@
 				     Scsi_Cmnd *SCpnt)
 {
 	u8 *scsi_buf = SCpnt->request_buffer;
-	u32 device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16;
-        
+	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
+
 	SBP2_DEBUG("sbp2_check_sbp2_response");
 
 	switch (SCpnt->cmnd[0]) {
 		
 		case INQUIRY:
 
-			SBP2_DEBUG("Check Inquiry data");
+			/*
+			 * Make sure data length is ok. Minimum length is 36 bytes
+			 */
+			if (scsi_buf[4] == 0) {
+				scsi_buf[4] = 36 - 5;
+			}
 
 			/*
 			 * Check for Simple Direct Access Device and change it to TYPE_DISK
@@ -2485,6 +2589,12 @@
 	if (command) {
 
 		SBP2_DEBUG("Found status for command ORB");
+		pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
+				    sizeof(struct sbp2_command_orb),
+				    PCI_DMA_BIDIRECTIONAL);
+		pci_dma_sync_single(hi->host->pdev, command->sge_dma,
+				    sizeof(command->scatter_gather_element),
+				    PCI_DMA_BIDIRECTIONAL);
 
 		SBP2_ORB_DEBUG("matched command orb %p", &command->command_orb);
 		outstanding_orb_decr;
@@ -2498,22 +2608,27 @@
 		if (SCpnt && !command->linked) {
 
 			/*
-			 * Handle check conditions
+			 * See if the target stored any scsi status information
 			 */
-			if (STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
-
-				SBP2_DEBUG("CHECK CONDITION");
-
+			if (length > 8) {
 				/*
 				 * Translate SBP-2 status to SCSI sense data
 				 */
 				scsi_status = sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer);
+			}
 
+			/*
+			 * Handle check conditions. If there is either SBP status or SCSI status
+			 * then we'll do a fetch agent reset and note that a check condition
+			 * occured.
+			 */
+			if (STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc) ||
+			    scsi_status) {
 				/*
 				 * Initiate a fetch agent reset. 
 				 */
+				SBP2_DEBUG("CHECK CONDITION");
 				sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT);
-
 			}
 
 			SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb);
@@ -2647,6 +2762,12 @@
 		SBP2_DEBUG("Found pending command to complete");
 		lh = scsi_id->sbp2_command_orb_inuse.next;
 		command = list_entry(lh, struct sbp2_command_info, list);
+		pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
+				    sizeof(struct sbp2_command_orb),
+				    PCI_DMA_BIDIRECTIONAL);
+		pci_dma_sync_single(hi->host->pdev, command->sge_dma,
+				    sizeof(command->scatter_gather_element),
+				    PCI_DMA_BIDIRECTIONAL);
 		sbp2util_mark_command_completed(scsi_id, command);
 		if (command->Current_SCpnt && !command->linked) {
 			void (*done)(Scsi_Cmnd *) = command->Current_done;
@@ -2704,13 +2825,17 @@
 			/*
 			 * Debug stuff
 			 */
+#if CONFIG_IEEE1394_SBP2_DEBUG >= 1
+			print_command (SCpnt->cmnd);
 			print_sense("bh", SCpnt);
+#endif
 
 			break;
 
 		case SBP2_SCSI_STATUS_SELECTION_TIMEOUT:
 			SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT");
 			SCpnt->result = DID_NO_CONNECT << 16;
+			print_command (SCpnt->cmnd);
 			break;
 
 		case SBP2_SCSI_STATUS_CONDITION_MET:
@@ -2718,6 +2843,7 @@
 		case SBP2_SCSI_STATUS_COMMAND_TERMINATED:
 			SBP2_ERR("Bad SCSI status = %x", scsi_status);
 			SCpnt->result = DID_ERROR << 16;
+			print_command (SCpnt->cmnd);
 			break;
 
 		default:
@@ -2733,19 +2859,6 @@
 	}
 
 	/*
-	 * One more quick hack (not enabled by default). Some sbp2 devices
-	 * do not support mode sense. Turn-on this hack to allow the
-	 * device to pass the sd driver's write-protect test (so that you
-	 * can mount the device rw).
-	 */
-	if (mode_sense_hack && SCpnt->result != DID_OK && SCpnt->cmnd[0] == MODE_SENSE) {
-		SBP2_INFO("Returning success to mode sense command");
-		SCpnt->result = DID_OK;
-		SCpnt->sense_buffer[0] = 0;
-		memset (SCpnt->request_buffer, 0, 8);
-	}
-
-	/*
 	 * If a bus reset is in progress and there was an error, complete
 	 * the command as busy so that it will get retried.
 	 */
@@ -2784,7 +2897,8 @@
 	unsigned long flags;
 
 	SBP2_ERR("aborting sbp2 command");
-
+	print_command (SCpnt->cmnd);
+        
 	if (scsi_id) {
 
 		/*
@@ -2797,6 +2911,14 @@
 			command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
 			if (command) {
 				SBP2_DEBUG("Found command to abort");
+				pci_dma_sync_single(hi->host->pdev,
+						    command->command_orb_dma,
+						    sizeof(struct sbp2_command_orb),
+						    PCI_DMA_BIDIRECTIONAL);
+				pci_dma_sync_single(hi->host->pdev,
+						    command->sge_dma,
+						    sizeof(command->scatter_gather_element),
+						    PCI_DMA_BIDIRECTIONAL);
 				sbp2util_mark_command_completed(scsi_id, command);
 				if (command->Current_SCpnt && !command->linked) {
 					void (*done)(Scsi_Cmnd *) = command->Current_done;
@@ -2814,13 +2936,13 @@
 		sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
 	}
 
-	return(SCSI_ABORT_SUCCESS);
+	return(SUCCESS);
 }
 
 /*
  * Called by scsi stack when something has really gone wrong.
  */
-static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) 
+static int sbp2scsi_reset (Scsi_Cmnd *SCpnt) 
 {
 	struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0];
 
@@ -2831,7 +2953,7 @@
 		hpsb_reset_bus(hi->host, LONG_RESET);
 	}
 
-	return(SCSI_RESET_SUCCESS);
+	return(SUCCESS);
 }
 
 /*
@@ -2861,126 +2983,146 @@
 }
 
 /*
- * This routine is called at setup (init) and does nothing. Not used here.   =)
+ * Called by scsi stack after scsi driver is registered
  */
-void sbp2scsi_setup( char *str, int *ints) 
+static int sbp2scsi_detect (Scsi_Host_Template *tpnt) 
 {
-	SBP2_DEBUG("sbp2scsi_setup");
-	return;
+	SBP2_DEBUG("sbp2scsi_detect");
+
+	/*
+	 * 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 scsi_driver_template.present;
 }
 
+
 /*
- * This is our detection routine, and is where we init everything.
+ * Called for contents of procfs
  */
-static int sbp2scsi_detect (Scsi_Host_Template *tpnt) 
+static const char *sbp2scsi_info (struct Scsi_Host *host)
 {
-	SBP2_DEBUG("sbp2scsi_detect");
+	struct sbp2scsi_host_info *hi = sbp2_find_host_info_scsi(host);
+	static char info[1024];
 
-	global_scsi_tpnt = tpnt;
+	if (!hi) /* shouldn't happen, but... */
+        	return "IEEE-1394 SBP-2 protocol driver";
+
+	sprintf(info, "IEEE-1394 SBP-2 protocol driver\nHost Driver: %s\nSerial I/O: %s",
+		hi->host->driver->name, serialize_io ? "yes" : "no");
+
+	return info;
+}
+
+
+MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>");
+MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
+MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
+MODULE_LICENSE("GPL");
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,26)
+#define PROC_SCSI_SBP2 PROC_SCSI_NOT_PRESENT /* What should I use? */
+static struct proc_dir_entry proc_scsi_sbp2scsi = {
+	low_ino:	PROC_SCSI_SBP2,
+	namelen:	SBP2_DEVICE_NAME_SIZE,
+	name:		SBP2_DEVICE_NAME,
+	mode:		S_IFDIR | S_IRUGO | S_IXUGO,
+	nlink:		2
+};
+#endif
+
+/* SCSI host template */
+static Scsi_Host_Template scsi_driver_template = {
+	name:			"IEEE-1394 SBP-2 protocol driver",
+	info:			sbp2scsi_info,
+	detect:			sbp2scsi_detect,
+	queuecommand:		sbp2scsi_queuecommand,
+	eh_abort_handler:	sbp2scsi_abort,
+	eh_device_reset_handler:sbp2scsi_reset,
+	eh_bus_reset_handler:	sbp2scsi_reset,
+	eh_host_reset_handler:	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,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	use_new_eh_code:	TRUE,
+#endif
+	emulated:		1,
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,26)
-	global_scsi_tpnt->proc_name = SBP2_DEVICE_NAME;
+	proc_name:	SBP2_DEVICE_NAME,
+#else
+	proc_dir:	&proc_scsi_sbp2scsi,
 #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.
+	 */
+	scsi_driver_template.module = THIS_MODULE;
+	if (SCSI_REGISTER_HOST(&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";
-}
 
-MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>");
-MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
-MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
-MODULE_LICENSE("GPL");
+	if (SCSI_UNREGISTER_HOST(&scsi_driver_template))
+		SBP2_ERR("sbp2_module_exit: couldn't unregister scsi driver");
 
-/* 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 -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/sbp2.h linux/drivers/ieee1394/sbp2.h
--- v2.5.2/linux/drivers/ieee1394/sbp2.h	Wed Oct 17 14:19:20 2001
+++ linux/drivers/ieee1394/sbp2.h	Mon Jan 21 15:57:51 2002
@@ -22,6 +22,15 @@
 #ifndef SBP2_H
 #define SBP2_H
 
+/* Some compatibility code */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#define SCSI_REGISTER_HOST(tmpl)	scsi_register_module(MODULE_SCSI_HA, tmpl)
+#define SCSI_UNREGISTER_HOST(tmpl)	scsi_unregister_module(MODULE_SCSI_HA, tmpl)
+#else
+#define SCSI_REGISTER_HOST(tmpl)	scsi_register_host(tmpl)
+#define SCSI_UNREGISTER_HOST(tmpl)	scsi_unregister_host(tmpl)
+#endif
+
 #define SBP2_DEVICE_NAME		"sbp2"
 #define SBP2_DEVICE_NAME_SIZE		4
 
@@ -36,6 +45,7 @@
 #define ORB_DIRECTION_READ_FROM_MEDIA   0x1
 #define ORB_DIRECTION_NO_DATA_TRANSFER  0x2
 
+#define ORB_SET_NULL_PTR(value)			((value & 0x1) << 31)
 #define ORB_SET_NOTIFY(value)                   ((value & 0x1) << 31)
 #define ORB_SET_RQ_FMT(value)                   ((value & 0x3) << 29)
 #define ORB_SET_NODE_ID(value)			((value & 0xffff) << 16)
@@ -199,6 +209,9 @@
 #define SBP2_DEVICE_TYPE_AND_LUN_KEY				0x14
 #define SBP2_FIRMWARE_REVISION_KEY				0x3c
 
+#define SBP2_DEVICE_TYPE(q)			(((q) >> 16) & 0x1f)
+#define SBP2_DEVICE_LUN(q)			((q) & 0xffff)
+
 #define SBP2_AGENT_STATE_OFFSET					0x00ULL
 #define SBP2_AGENT_RESET_OFFSET					0x04ULL
 #define SBP2_ORB_POINTER_OFFSET					0x08ULL
@@ -218,15 +231,6 @@
 #define SBP2_UNIT_SPEC_ID_ENTRY					0x0000609e
 #define SBP2_SW_VERSION_ENTRY					0x00010483
 
-/*
- * Miscellaneous general config rom related defines
- */
-
-#define CONFIG_ROM_INITIAL_MEMORY_SPACE 			0xfffff0000000ULL
-
-#define CONFIG_ROM_BASE_ADDRESS					0xfffff0000400ULL
-#define CONFIG_ROM_ROOT_DIR_BASE				0xfffff0000414ULL
-#define CONFIG_ROM_UNIT_DIRECTORY_OFFSET			0xfffff0000424ULL
 
 #define SBP2_128KB_BROKEN_FIRMWARE				0xa0b800
 #define SBP2_BROKEN_FIRMWARE_MAX_TRANSFER			0x20000
@@ -252,7 +256,8 @@
 #endif
 
 /*
- * SCSI direction table... since the scsi stack doesn't specify direction...   =(
+ * SCSI direction table... 
+ * (now used as a back-up in case the direction passed down from above is "unknown")
  *
  * DIN = IN data direction
  * DOU = OUT data direction
@@ -306,21 +311,27 @@
 
 };
 
+
+/* This is the two dma types we use for cmd_dma below */
+#define CMD_DMA_NONE   0x0
+#define CMD_DMA_PAGE   0x1
+#define CMD_DMA_SINGLE 0x2
+
 /* 
  * Encapsulates all the info necessary for an outstanding command. 
  */
 struct sbp2_command_info {
 
 	struct list_head list;
-	struct sbp2_command_orb command_orb;
-	dma_addr_t command_orb_dma;
+	struct sbp2_command_orb command_orb ____cacheline_aligned;
+	dma_addr_t command_orb_dma ____cacheline_aligned;
 	Scsi_Cmnd *Current_SCpnt;
 	void (*Current_done)(Scsi_Cmnd *);
 	unsigned int linked;
 
 	/* Also need s/g structure for each sbp2 command */
-	struct sbp2_unrestricted_page_table scatter_gather_element[SBP2_MAX_SG_ELEMENTS];
-	dma_addr_t sge_dma;
+	struct sbp2_unrestricted_page_table scatter_gather_element[SBP2_MAX_SG_ELEMENTS] ____cacheline_aligned;
+	dma_addr_t sge_dma ____cacheline_aligned;
 	void *sge_buffer;
 	dma_addr_t cmd_dma;
 	int dma_type;
@@ -340,6 +351,7 @@
 	 * Various sbp2 specific structures
 	 */
 	struct sbp2_command_orb *last_orb;
+	dma_addr_t last_orb_dma;
 	struct sbp2_login_orb *login_orb;
 	dma_addr_t login_orb_dma;
 	struct sbp2_login_response *login_response;
@@ -403,6 +415,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
@@ -480,7 +499,8 @@
 				   unchar *scsi_cmd,
 				   unsigned int scsi_use_sg,
 				   unsigned int scsi_request_bufflen,
-				   void *scsi_request_buffer, int dma_dir);
+				   void *scsi_request_buffer, 
+				   unsigned char scsi_dir);
 static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
 				 struct sbp2_command_info *command);
 static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
@@ -498,17 +518,16 @@
 /*
  * Scsi interface related prototypes
  */
-static const char *sbp2scsi_info (struct Scsi_Host *host);
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt);
+static const char *sbp2scsi_info (struct Scsi_Host *host);
 void sbp2scsi_setup(char *str, int *ints);
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]);
 static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); 
-static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags); 
+static int sbp2scsi_reset (Scsi_Cmnd *SCpnt); 
 static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
 static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, 
 					   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 -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c
--- v2.5.2/linux/drivers/ieee1394/video1394.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ieee1394/video1394.c	Thu Jan 24 22:06:39 2002
@@ -43,9 +43,12 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
+#include <asm/segment.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/vmalloc.h>
+#include <linux/timex.h>
+#include <linux/mm.h>
 
 #include "ieee1394.h"
 #include "ieee1394_types.h"
@@ -56,7 +59,6 @@
 
 #include "ohci1394.h"
 
-#define VIDEO1394_MAJOR 172
 #define ISO_CHANNELS 64
 #define ISO_RECEIVE 0
 #define ISO_TRANSMIT 1
@@ -78,6 +80,7 @@
 
 struct dma_iso_ctx {
 	struct ti_ohci *ohci;
+	int type; /* ISO_TRANSMIT or ISO_RECEIVE */
 	int ctx;
 	int channel;
 	int last_buffer;
@@ -94,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;
@@ -101,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;
 };
 
@@ -141,7 +145,7 @@
 printk(level "video1394_%d: " fmt "\n" , card , ## args)
 
 static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
-		 quadlet_t isoXmitIntEvent);
+			quadlet_t isoXmitIntEvent, void *data);
 
 static LIST_HEAD(video1394_cards);
 static spinlock_t video1394_cards_lock = SPIN_LOCK_UNLOCKED;
@@ -149,8 +153,6 @@
 static devfs_handle_t devfs_handle;
 static struct hpsb_highlevel *hl_handle = NULL;
 
-static struct video_template video_tmpl = { irq_handler };
-
 /* Code taken from bttv.c */
 
 /*******************************/
@@ -277,6 +279,7 @@
 {
 	int i;
 	struct ti_ohci *ohci;
+	unsigned long *usage;
 	
 	if ((*d)==NULL) return -1;
 
@@ -303,11 +306,19 @@
 
 	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)
 		kfree((*d)->next_buffer);
 
+	usage = ((*d)->type == ISO_RECEIVE) ? &ohci->ir_ctx_usage :
+		&ohci->it_ctx_usage;
+       
+	/* clear the ISO context usage bit */
+	clear_bit((*d)->ctx, usage);
+	
 	kfree(*d);
 	*d = NULL;
 
@@ -315,12 +326,28 @@
 }
 
 static struct dma_iso_ctx *
-alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int ctx, int num_desc,
+alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
 		  int buf_size, int channel, unsigned int packet_size)
 {
 	struct dma_iso_ctx *d=NULL;
 	int i;
 
+	unsigned long *usage = (type == ISO_RECEIVE) ? &ohci->ir_ctx_usage :
+		                                       &ohci->it_ctx_usage;
+
+	/* try to claim the ISO context usage bit */
+	for (i = 0; i < ohci->nb_iso_rcv_ctx; i++) {
+		if (!test_and_set_bit(i, usage)) {
+			PRINT(KERN_ERR, ohci->id, "Free iso ctx %d found", i);
+			break;
+		}
+	}
+
+	if (i == ohci->nb_iso_rcv_ctx) {
+		PRINT(KERN_ERR, ohci->id, "No DMA contexts available");
+		return NULL;
+	}
+	
 	d = (struct dma_iso_ctx *)kmalloc(sizeof(struct dma_iso_ctx), 
 					  GFP_KERNEL);
 	if (d==NULL) {
@@ -331,7 +358,8 @@
 	memset(d, 0, sizeof(struct dma_iso_ctx));
 
 	d->ohci = (void *)ohci;
-	d->ctx = ctx;
+	d->type = type;
+	d->ctx = i;
 	d->channel = channel;
 	d->num_desc = num_desc;
 	d->frame_size = buf_size;
@@ -436,6 +464,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),
@@ -446,6 +476,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);
@@ -457,6 +492,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));
 	
@@ -554,38 +590,38 @@
 }
 
 /* find which context is listening to this channel */
-int ir_ctx_listening(struct video_card *video, int channel)
+static struct dma_iso_ctx **
+ir_ctx_listening(struct video_card *video, int channel)
 {
 	int i;
 	struct ti_ohci *ohci = video->ohci;
 
-	for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++) 
-		if (video->ir_context[i]) {
-			if (video->ir_context[i]->channel==channel)
-				return i;
-		}
+	for (i = 0; i < ohci->nb_iso_rcv_ctx-1; i++) 
+		if (video->ir_context[i] &&
+		    video->ir_context[i]->channel == channel)
+			return &video->ir_context[i];
 		
 	PRINT(KERN_ERR, ohci->id, "No iso context is listening to channel %d",
 	      channel);
 
-	return -1;
+	return NULL;
 }
 
-int it_ctx_talking(struct video_card *video, int channel)
+static struct dma_iso_ctx **
+it_ctx_talking(struct video_card *video, int channel)
 {
 	int i;
 	struct ti_ohci *ohci = video->ohci;
 
-	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) 
-		if (video->it_context[i]) {
-			if (video->it_context[i]->channel==channel)
-				return i;
-		}
+	for (i = 0; i < ohci->nb_iso_xmit_ctx; i++) 
+		if (video->it_context[i] &&
+		    video->it_context[i]->channel==channel)
+			return &video->ir_context[i];
 		
 	PRINT(KERN_ERR, ohci->id, "No iso context is talking to channel %d",
 	      channel);
 
-	return -1;
+	return NULL;
 }
 
 int wakeup_dma_ir_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) 
@@ -603,6 +639,7 @@
 		if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) {
 			reset_ir_status(d, i);
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
+			do_gettimeofday(&d->buffer_time[i]);
 		}
 	}
 	spin_unlock(&d->lock);
@@ -807,7 +844,7 @@
 	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
 }
 
-static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d, 
+static int do_iso_mmap(struct vm_area_struct *vma, struct ti_ohci *ohci, struct dma_iso_ctx *d, 
 		       const char *adr, unsigned long size)
 {
         unsigned long start=(unsigned long) adr;
@@ -828,7 +865,7 @@
         pos=(unsigned long) d->buf;
         while (size > 0) {
                 page = kvirt_to_pa(pos);
-                if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+                if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
                         return -EAGAIN;
                 start+=PAGE_SIZE;
                 pos+=PAGE_SIZE;
@@ -850,7 +887,7 @@
 		struct video_card *p;
 		list_for_each(lh, &video1394_cards) {
 			p = list_entry(lh, struct video_card, list);
-			if (p->id == MINOR(inode->i_rdev)) {
+			if (p->id == ieee1394_file_to_instance(file)) {
 				video = p;
 				ohci = video->ohci;
 				break;
@@ -860,7 +897,8 @@
 	spin_unlock_irqrestore(&video1394_cards_lock, flags);
 
 	if (video == NULL) {
-		PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d", MINOR(inode->i_rdev));
+		PRINT_G(KERN_ERR, "%s: Unknown video card for minor %d",
+			__FUNCTION__, ieee1394_file_to_instance(file));
 		return -EFAULT;
 	}
 
@@ -875,9 +913,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", 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;
@@ -923,7 +975,7 @@
 			}
 
 			video->ir_context[i] = 
-				alloc_dma_iso_ctx(ohci, ISO_RECEIVE, i+1, 
+				alloc_dma_iso_ctx(ohci, ISO_RECEIVE,
 						  v.nb_buffers, v.buf_size, 
 						  v.channel, 0);
 
@@ -940,8 +992,8 @@
 			v.buf_size = video->ir_context[i]->buf_size;
 
 			PRINT(KERN_INFO, ohci->id, 
-			      "iso context %d listen on channel %d", i+1, 
-			      v.channel);
+			      "iso context %d listen on channel %d",
+			      video->current_ctx->ctx, v.channel);
 		}
 		else {
 			/* find a free iso transmit context */
@@ -955,7 +1007,7 @@
 			}
 			
 			video->it_context[i] = 
-				alloc_dma_iso_ctx(ohci, ISO_TRANSMIT, i, 
+				alloc_dma_iso_ctx(ohci, ISO_TRANSMIT,
 						  v.nb_buffers, v.buf_size, 
 						  v.channel, v.packet_size);
 
@@ -986,7 +1038,6 @@
 	{
 		int channel;
 		u64 mask;
-		int i;
 
 		if(copy_from_user(&channel, (void *)arg, sizeof(int)))
 			return -EFAULT;
@@ -1005,24 +1056,23 @@
 		ohci->ISO_channel_usage &= ~mask;
 
 		if (cmd == VIDEO1394_UNLISTEN_CHANNEL) {
-			i = ir_ctx_listening(video, channel);
-			if (i<0) return -EFAULT;
-
-			free_dma_iso_ctx(&video->ir_context[i]);
-
+			struct dma_iso_ctx **d;
+			d = ir_ctx_listening(video, channel);
+			if (d == NULL) return -EFAULT;
 			PRINT(KERN_INFO, ohci->id, 
 			      "Iso context %d stop listening on channel %d", 
-			      i+1, channel);
+			      (*d)->ctx, channel);
+			free_dma_iso_ctx(d);
 		}
 		else {
-			i = it_ctx_talking(video, channel);
-			if (i<0) return -EFAULT;
-
-			free_dma_iso_ctx(&video->it_context[i]);
-
+			struct dma_iso_ctx **d;
+			d = it_ctx_talking(video, channel);
+			if (d == NULL) return -EFAULT;
 			PRINT(KERN_INFO, ohci->id, 
 			      "Iso context %d stop talking on channel %d", 
-			      i, channel);
+			      (*d)->ctx, channel);
+			free_dma_iso_ctx(d);
+
 		}
 		
 		return 0;
@@ -1030,15 +1080,14 @@
 	case VIDEO1394_LISTEN_QUEUE_BUFFER:
 	{
 		struct video1394_wait v;
-		struct dma_iso_ctx *d;
-		int i;
+		struct dma_iso_ctx *d, **dd;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		i = ir_ctx_listening(video, v.channel);
-		if (i<0) return -EFAULT;
-		d = video->ir_context[i];
+		dd = ir_ctx_listening(video, v.channel);
+		if (dd == NULL) return -EFAULT;
+		d = *dd;
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1091,17 +1140,18 @@
 		
 	}
 	case VIDEO1394_LISTEN_WAIT_BUFFER:
+	case VIDEO1394_LISTEN_POLL_BUFFER:
 	{
 		struct video1394_wait v;
-		struct dma_iso_ctx *d;
+		struct dma_iso_ctx *d, **dd;
 		int i;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		i = ir_ctx_listening(video, v.channel);
-		if (i<0) return -EFAULT;
-		d = video->ir_context[i];
+		dd = ir_ctx_listening(video, v.channel);
+		if (dd==NULL) return -EFAULT;
+		d = *dd;
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1119,6 +1169,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) {
@@ -1146,6 +1202,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
 		 */
@@ -1167,15 +1227,14 @@
 	{
 		struct video1394_wait v;
 		struct video1394_queue_variable qv;
-		struct dma_iso_ctx *d;
-		int i;
+		struct dma_iso_ctx *d, **dd;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		i = it_ctx_talking(video, v.channel);
-		if (i<0) return -EFAULT;
-		d = video->it_context[i];
+		dd = it_ctx_talking(video, v.channel);
+		if (dd == NULL) return -EFAULT;
+		d = *dd;
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1259,15 +1318,14 @@
 	case VIDEO1394_TALK_WAIT_BUFFER:
 	{
 		struct video1394_wait v;
-		struct dma_iso_ctx *d;
-		int i;
+		struct dma_iso_ctx *d, **dd;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		i = it_ctx_talking(video, v.channel);
-		if (i<0) return -EFAULT;
-		d = video->it_context[i];
+		dd = it_ctx_talking(video, v.channel);
+		if (dd == NULL) return -EFAULT;
+		d = *dd;
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1328,7 +1386,7 @@
 		struct video_card *p;
 		list_for_each(lh, &video1394_cards) {
 			p = list_entry(lh, struct video_card, list);
-			if (p->id == MINOR(file->f_dentry->d_inode->i_rdev)) {
+			if (p->id == ieee1394_file_to_instance(file)) {
 				video = p;
 				break;
 			}
@@ -1337,8 +1395,8 @@
         spin_unlock_irqrestore(&video1394_cards_lock, flags);
 
 	if (video == NULL) {
-		PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d",
-			MINOR(file->f_dentry->d_inode->i_rdev));
+		PRINT_G(KERN_ERR, "%s: Unknown video card for minor %d",
+			__FUNCTION__, ieee1394_file_to_instance(file));
 		return -EFAULT;
 	}
 
@@ -1357,7 +1415,7 @@
 
 static int video1394_open(struct inode *inode, struct file *file)
 {
-	int i = MINOR(inode->i_rdev);
+	int i = ieee1394_file_to_instance(file);
 	unsigned long flags;
 	struct video_card *video = NULL;
 	struct list_head *lh;
@@ -1397,7 +1455,7 @@
 		struct video_card *p;
 		list_for_each(lh, &video1394_cards) {
 			p = list_entry(lh, struct video_card, list);
-			if (p->id == MINOR(inode->i_rdev)) {
+			if (p->id == ieee1394_file_to_instance(file)) {
 				video = p;
 				break;
 			}
@@ -1406,8 +1464,8 @@
         spin_unlock_irqrestore(&video1394_cards_lock, flags);
 
 	if (video == NULL) {
-		PRINT_G(KERN_ERR, __FUNCTION__": Unknown device for minor %d",
-				MINOR(inode->i_rdev));
+		PRINT_G(KERN_ERR, "%s: Unknown device for minor %d",
+			__FUNCTION__, ieee1394_file_to_instance(file));
 		return 1;
 	}
 
@@ -1419,13 +1477,13 @@
 			mask = (u64)0x1<<video->ir_context[i]->channel;
 			if (!(ohci->ISO_channel_usage & mask))
 				PRINT(KERN_ERR, ohci->id, 
-				      "Channel %d is not being used", 
+				      "On release: Channel %d is not being used", 
 				      video->ir_context[i]->channel);
 			else
 				ohci->ISO_channel_usage &= ~mask;
 			PRINT(KERN_INFO, ohci->id, 
 			      "Iso receive context %d stop listening "
-			      "on channel %d", i+1, 
+			      "on channel %d", video->ir_context[i]->ctx,
 			      video->ir_context[i]->channel);
 			free_dma_iso_ctx(&video->ir_context[i]);
 		}
@@ -1441,7 +1499,7 @@
 				ohci->ISO_channel_usage &= ~mask;
 			PRINT(KERN_INFO, ohci->id, 
 			      "Iso transmit context %d stop talking "
-			      "on channel %d", i+1, 
+			      "on channel %d", video->it_context[i]->ctx,
 			      video->it_context[i]->channel);
 			free_dma_iso_ctx(&video->it_context[i]);
 		}
@@ -1453,44 +1511,29 @@
 }
 
 static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
-		 quadlet_t isoXmitIntEvent)
+			quadlet_t isoXmitIntEvent, void *data)
 {
 	int i;
-	unsigned long flags;
-	struct video_card *video = NULL;
-	struct list_head *lh;
-
-	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->id == card) {
-				video = p;
-				break;
-			}
-                }
-        }
-        spin_unlock_irqrestore(&video1394_cards_lock, flags);
+	struct video_card *video = (struct video_card*) data;
 
 	if (video == NULL) {
-		PRINT_G(KERN_ERR, __FUNCTION__": Unknown card number %d!!",
-				card);
+		PRINT_G(KERN_ERR, "%s: Unknown card number %d",
+			__FUNCTION__, card);
 		return;
 	}
 	
 	DBGMSG(card, "Iso event Recv: %08x Xmit: %08x",
 	       isoRecvIntEvent, isoXmitIntEvent);
 
-	for (i=0;i<video->ohci->nb_iso_rcv_ctx-1;i++)
-		if (isoRecvIntEvent & (1<<(i+1))) 
-			wakeup_dma_ir_ctx(video->ohci,
-					  video->ir_context[i]);
-
-	for (i=0;i<video->ohci->nb_iso_xmit_ctx;i++)
-		if (isoXmitIntEvent & (1<<i)) 
-			wakeup_dma_it_ctx(video->ohci,
-					  video->it_context[i]);
+	for (i = 0; i < video->ohci->nb_iso_rcv_ctx-1; i++)
+		if (video->ir_context[i] != NULL &&
+		    isoRecvIntEvent & (1<<(video->ir_context[i]->ctx)))
+			wakeup_dma_ir_ctx(video->ohci, video->ir_context[i]);
+
+	for (i = 0; i < video->ohci->nb_iso_xmit_ctx; i++)
+		if (video->it_context[i] != NULL &&
+		    isoXmitIntEvent & (1<<(video->it_context[i]->ctx)))
+			wakeup_dma_it_ctx(video->ohci, video->it_context[i]);
 }
 
 static struct file_operations video1394_fops=
@@ -1520,8 +1563,8 @@
 	list_add_tail(&video->list, &video1394_cards);
 	spin_unlock_irqrestore(&video1394_cards_lock, flags);
 
-	if (ohci1394_register_video(ohci, &video_tmpl)<0) {
-		PRINT(KERN_ERR, ohci->id, "Register_video failed");
+	if (ohci1394_hook_irq(ohci, irq_handler, (void*) video) != 0) {
+		PRINT(KERN_ERR, ohci->id, "ohci1394_hook_irq() failed");
 		return -1;
 	}
 
@@ -1555,7 +1598,8 @@
 	sprintf(name, "%d", video->id);
 	video->devfs = devfs_register(devfs_handle, name,
 				      DEVFS_FL_AUTO_OWNER,
-				      VIDEO1394_MAJOR, 0,
+				      IEEE1394_MAJOR,
+				      IEEE1394_MINOR_BLOCK_VIDEO1394*16+video->id,
 				      S_IFCHR | S_IRUSR | S_IWUSR,
 				      &video1394_fops, NULL);
 
@@ -1567,7 +1611,7 @@
 {
 	int i;
 
-	ohci1394_unregister_video(video->ohci, &video_tmpl);
+	ohci1394_unhook_irq(video->ohci, irq_handler, (void*) video);
 
 	devfs_unregister(video->devfs);
 
@@ -1595,23 +1639,21 @@
 {
 	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))
+	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
 		return;
 
 	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);
@@ -1624,7 +1666,7 @@
 	struct ti_ohci *ohci;
 
 	/* We only work with the OHCI-1394 driver */
-	if (strcmp(host->template->name, OHCI1394_DRIVER_NAME))
+	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
 		return;
 
 	ohci = (struct ti_ohci *)host->hostdata;
@@ -1649,19 +1691,19 @@
 	hpsb_unregister_highlevel (hl_handle);
 
 	devfs_unregister(devfs_handle);
-	devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME);
-
-	PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module\n");
+	ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
+	
+	PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
 }
 
 static int __init video1394_init_module (void)
 {
-	if (devfs_register_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME,
-				&video1394_fops)) {
-		PRINT_G(KERN_ERR, "video1394: unable to get major %d\n",
-				VIDEO1394_MAJOR);
-		return -EIO;
-	}
+	if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394,
+				      THIS_MODULE, &video1394_fops)) {
+		PRINT_G(KERN_ERR, "video1394: unable to get minor device block");
+ 		return -EIO;
+ 	}
+	
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 	devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME,
 			strlen(VIDEO1394_DRIVER_NAME), NULL);
@@ -1673,10 +1715,11 @@
 	if (hl_handle == NULL) {
 		PRINT_G(KERN_ERR, "No more memory for driver\n");
 		devfs_unregister(devfs_handle);
-		devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME);
+		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
 		return -ENOMEM;
 	}
 
+	PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module");
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/video1394.h linux/drivers/ieee1394/video1394.h
--- v2.5.2/linux/drivers/ieee1394/video1394.h	Sun Aug 12 12:39:02 2001
+++ linux/drivers/ieee1394/video1394.h	Mon Jan 21 15:57:51 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/drivers/input/Config.help linux/drivers/input/Config.help
--- v2.5.2/linux/drivers/input/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/input/Config.help	Fri Jan 25 16:03:52 2002
@@ -0,0 +1,59 @@
+CONFIG_INPUT
+  Say Y here if you want to enable any of the following options for
+  USB Human Interface Device (HID) support.
+
+  Say Y here if you want to enable any of the USB HID options in the
+  USB support section which require Input core support.
+
+  Otherwise, say N.
+
+CONFIG_INPUT_KEYBDEV
+  Say Y here if you want your USB HID keyboard (or an ADB keyboard
+  handled by the input layer) to be able to serve as a system
+  keyboard.
+
+  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 keybdev.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_MOUSEDEV
+  Say Y here if you want your USB HID mouse (or ADB mouse handled by
+  the input layer) to be accessible as char devices 13:32+ -
+  /dev/input/mouseX and 13:63 - /dev/input/mice as an emulated ImPS/2
+  mouse.  That way, all user space programs will be able to use your
+  mouse.
+
+  If unsure, say Y.
+
+  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 mousedev.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_MOUSEDEV_SCREEN_X
+  If you're using a digitizer, or a graphic tablet, and want to use
+  it as a mouse then the mousedev driver needs to know the X window
+  screen resolution you are using to correctly scale the data. If
+  you're not using a digitizer, this value is ignored.
+
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y
+  If you're using a digitizer, or a graphic tablet, and want to use
+  it as a mouse then the mousedev driver needs to know the X window
+  screen resolution you are using to correctly scale the data. If
+  you're not using a digitizer, this value is ignored.
+
+CONFIG_INPUT_JOYDEV
+  Say Y here if you want your USB HID joystick or gamepad to be
+  accessible as char device 13:0+ - /dev/input/jsX device.
+
+  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 joydev.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_EVDEV
+  Say Y here if you want your USB or ADB HID device events be
+  accessible under char device 13:64+ - /dev/input/eventX in a generic
+  way.  This is the future ...
+
diff -u --recursive --new-file v2.5.2/linux/drivers/input/evdev.c linux/drivers/input/evdev.c
--- v2.5.2/linux/drivers/input/evdev.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/input/evdev.c	Wed Jan 23 15:28:39 2002
@@ -67,7 +67,7 @@
 
 	while (list) {
 
-		get_fast_time(&list->buffer[list->head].time);
+		do_gettimeofday(&list->buffer[list->head].time);
 		list->buffer[list->head].type = type;
 		list->buffer[list->head].code = code;
 		list->buffer[list->head].value = value;
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/Config.help linux/drivers/isdn/Config.help
--- v2.5.2/linux/drivers/isdn/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/Config.help	Sun Jan 27 11:33:38 2002
@@ -0,0 +1,532 @@
+CONFIG_ISDN
+  ISDN ("Integrated Services Digital Networks", called RNIS in France)
+  is a special type of fully digital telephone service; it's mostly
+  used to connect to your Internet service provider (with SLIP or
+  PPP).  The main advantage is that the speed is higher than ordinary
+  modem/telephone connections, and that you can have voice
+  conversations while downloading stuff.  It only works if your
+  computer is equipped with an ISDN card and both you and your service
+  provider purchased an ISDN line from the phone company.  For
+  details, read <http://alumni.caltech.edu/~dank/isdn/> on the WWW.
+
+  This driver allows you to use an ISDN-card for networking
+  connections and as dialin/out device.  The isdn-tty's have a built
+  in AT-compatible modem emulator.  Network devices support autodial,
+  channel-bundling, callback and caller-authentication without having
+  a daemon running.  A reduced T.70 protocol is supported with tty's
+  suitable for German BTX.  On D-Channel, the protocols EDSS1
+  (Euro-ISDN) and 1TR6 (German style) are supported.  See
+  <file:Documentation/isdn/README> for more information.
+
+  If you want to compile the ISDN code 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 isdn.o. If unsure, say N.
+
+CONFIG_ISDN_PPP
+  Over digital connections such as ISDN, there is no need to
+  synchronize sender and recipient's clocks with start and stop bits
+  as is done over analog telephone lines. Instead, one can use
+  "synchronous PPP". Saying Y here will include this protocol. This
+  protocol is used by Cisco and Sun for example. So you want to say Y
+  here if the other end of your ISDN connection supports it. You will
+  need a special version of pppd (called ipppd) for using this
+  feature. See <file:Documentation/isdn/README.syncppp> and
+  <file:Documentation/isdn/syncPPP.FAQ> for more information.
+
+CONFIG_ISDN_MPP
+  With synchronous PPP enabled, it is possible to increase throughput
+  by bundling several ISDN-connections, using this protocol. See
+  <file:Documentation/isdn/README.syncppp> for more information.
+
+CONFIG_ISDN_PPP_VJ
+  This enables Van Jacobson header compression for synchronous PPP.
+  Say Y if the other end of the connection supports it.
+
+CONFIG_ISDN_PPP_BSDCOMP
+  Support for the BSD-Compress compression method for PPP, which uses
+  the LZW compression method to compress each PPP packet before it is
+  sent over the wire. The machine at the other end of the PPP link
+  (usually your ISP) has to support the BSD-Compress compression
+  method as well for this to be useful. Even if they don't support it,
+  it is safe to say Y here.
+
+CONFIG_ISDN_AUDIO
+  If you say Y here, the modem-emulator will support a subset of the
+  EIA Class 8 Voice commands. Using a getty with voice-support
+  (mgetty+sendfax by gert@greenie.muc.de with an extension, available
+  with the ISDN utility package for example), you will be able to use
+  your Linux box as an ISDN-answering machine. Of course, this must be
+  supported by the lowlevel driver also. Currently, the HiSax driver
+  is the only voice-supporting driver. See
+  <file:Documentation/isdn/README.audio> for more information.
+
+CONFIG_ISDN_X25
+  This feature provides the X.25 protocol over ISDN connections.
+  See <file:Documentation/isdn/README.x25> for more information
+  if you are thinking about using this.
+
+CONFIG_ISDN_DIVERSION
+  This option allows you to use some supplementary diversion
+  services in conjunction with the HiSax driver on an EURO/DSS1
+  line.
+
+  Supported options are CD (call deflection), CFU (Call forward
+  unconditional), CFB (Call forward when busy) and CFNR (call forward
+  not reachable). Additionally the actual CFU, CFB and CFNR state may
+  be interrogated.
+
+  The use of CFU, CFB, CFNR and interrogation may be limited to some
+  countries. The keypad protocol is still not implemented. CD should
+  work in all countries if the service has been subscribed to.
+
+  Please read the file <file:Documentation/isdn/README.diversion>.
+
+CONFIG_ISDN_DRV_ICN
+  This enables support for two kinds of ISDN-cards made by a German
+  company called ICN.  2B is the standard version for a single ISDN
+  line with two B-channels, 4B supports two ISDN lines.  For running
+  this card, additional firmware is necessary, which has to be
+  downloaded into the card using a utility which is distributed
+  separately.  See <file:Documentation/isdn/README> and
+  <file:Documentation/isdn/README.icn> for more
+  information.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called icn.o.
+
+CONFIG_ISDN_DRV_LOOP
+  This driver provides a virtual ISDN card. Its primary purpose is
+  testing of linklevel features or configuration without getting
+  charged by your service-provider for lots of phone calls.
+  You need will need the loopctrl utility from the latest isdn4k-utils
+  package to set up this driver.
+
+CONFIG_ISDN_DRV_HISAX
+  This is a driver supporting the Siemens chipset on various
+  ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, Teles
+  S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many
+  compatibles).
+
+  HiSax is just the name of this driver, not the name of any hardware.
+
+  If you have a card with such a chipset, you should say Y here and
+  also to the configuration option of the driver for your particular
+  card, below.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called hisax.o.  See <file:Documentation/isdn/README.HiSax>
+  for more information on using this driver.
+
+CONFIG_HISAX_EURO
+  Say Y or N according to the D-channel protocol which your local
+  telephone service company provides.
+
+  The call control protocol E-DSS1 is used in most European countries.
+  If unsure, say Y.
+
+CONFIG_DE_AOC
+  If you want that the HiSax hardware driver sends messages to the
+  upper level of the isdn code on each AOCD (Advice Of Charge, During
+  the call -- transmission of the fee information during a call) and
+  on each AOCE (Advice Of Charge, at the End of the call --
+  transmission of fee information at the end of the call), say Y here.
+  This works only in Germany.
+
+CONFIG_HISAX_NO_SENDCOMPLETE
+  If you have trouble with some ugly exchanges or you live in
+  Australia select this option.
+
+CONFIG_HISAX_NO_LLC
+  If you have trouble with some ugly exchanges try to select this
+  option.
+
+CONFIG_HISAX_NO_KEYPAD
+  If you like to send special dial strings including * or # without
+  using the keypad protocol, select this option.
+
+CONFIG_HISAX_1TR6
+  Say Y or N according to the D-channel protocol which your local
+  telephone service company provides.
+
+  1TR6 is an old call control protocol which was used in Germany
+  before E-DSS1 was established. Nowadays, all new lines in Germany
+  use E-DSS1.
+
+CONFIG_HISAX_NI1
+  Enable this if you like to use ISDN in US on a NI1 basic rate
+  interface.
+
+CONFIG_HISAX_16_0
+  This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8
+  and many compatibles.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using the different cards, a different D-channel protocol, or
+  non-standard IRQ/port/shmem settings.
+
+CONFIG_HISAX_16_3
+  This enables HiSax support for the Teles ISDN-cards S0-16.3 the
+  Teles/Creatix PnP and the Teles PCMCIA.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using the different cards, a different D-channel protocol, or
+  non-standard IRQ/port settings.
+
+CONFIG_HISAX_TELESPCI
+  This enables HiSax support for the Teles PCI.
+  See <file:Documentation/isdn/README.HiSax> on how to configure it.
+
+CONFIG_HISAX_S0BOX
+  This enables HiSax support for the Teles/Creatix parallel port
+  S0BOX.  See <file:Documentation/isdn/README.HiSax> on how to
+  configure it.
+
+CONFIG_HISAX_AVM_A1
+  This enables HiSax support for the AVM A1 (aka "Fritz").
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using the different cards, a different D-channel protocol, or
+  non-standard IRQ/port settings.
+
+CONFIG_HISAX_FRITZPCI
+  This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI".
+  See <file:Documentation/isdn/README.HiSax> on how to configure it.
+
+CONFIG_HISAX_AVM_A1_PCMCIA
+  This enables HiSax support for the AVM A1 "Fritz!PCMCIA").
+  See <file:Documentation/isdn/README.HiSax> on how to configure it.
+
+CONFIG_HISAX_ELSA
+  This enables HiSax support for the Elsa Mircolink ISA cards, for the
+  Elsa Quickstep series cards and Elsa PCMCIA.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using the different cards, a different D-channel protocol, or
+  non-standard IRQ/port settings.
+
+CONFIG_HISAX_IX1MICROR2
+  This enables HiSax support for the ITK ix1-micro Revision 2 card.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using the different cards, a different D-channel protocol, or
+  non-standard IRQ/port settings.
+
+CONFIG_HISAX_DIEHLDIVA
+  This enables HiSax support for the Eicon.Diehl Diva none PRO
+  versions passive ISDN cards.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using the different cards, a different D-channel protocol, or
+  non-standard IRQ/port settings.
+
+CONFIG_HISAX_ASUSCOM
+  This enables HiSax support for the AsusCom and their OEM versions
+  passive ISDN ISA cards.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using the different cards, a different D-channel protocol, or
+  non-standard IRQ/port settings.
+
+CONFIG_HISAX_TELEINT
+  This enables HiSax support for the TELEINT SA1 semiactiv ISDN card.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using the different cards, a different D-channel protocol, or
+  non-standard IRQ/port settings.
+
+CONFIG_HISAX_HFCS
+  This enables HiSax support for the HFC-S 2BDS0 based cards, like
+  teles 16.3c.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using the different cards, a different D-channel protocol, or
+  non-standard IRQ/port settings.
+
+CONFIG_HISAX_SEDLBAUER
+  This enables HiSax support for the Sedlbauer passive ISDN cards.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using the different cards, a different D-channel protocol, or
+  non-standard IRQ/port settings.
+
+CONFIG_HISAX_SPORTSTER
+  This enables HiSax support for the USR Sportster internal TA card.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using a different D-channel protocol, or non-standard IRQ/port
+  settings.
+
+CONFIG_HISAX_MIC
+  This enables HiSax support for the ITH MIC card.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using a different D-channel protocol, or non-standard IRQ/port
+  settings.
+
+CONFIG_HISAX_NETJET
+  This enables HiSax support for the NetJet from Traverse
+  Technologies.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using a different D-channel protocol, or non-standard IRQ/port
+  settings.
+
+CONFIG_HISAX_NETJET_U
+  This enables HiSax support for the Netspider U interface ISDN card
+  from Traverse Technologies.
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using a different D-channel protocol, or non-standard IRQ/port
+  settings.
+
+CONFIG_HISAX_NICCY
+  This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using a different D-channel protocol, or non-standard IRQ/port
+  settings.
+
+CONFIG_HISAX_ISURF
+  This enables HiSax support for the Siemens I-Talk/I-Surf card with
+  ISAR chip.
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using a different D-channel protocol, or non-standard IRQ/port
+  settings.
+
+CONFIG_HISAX_HSTSAPHIR
+  This enables HiSax support for the HST Saphir card.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using a different D-channel protocol, or non-standard IRQ/port
+  settings.
+
+CONFIG_HISAX_BKM_A4T
+  This enables HiSax support for the Telekom A4T card.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using a different D-channel protocol, or non-standard IRQ/port
+  settings.
+
+CONFIG_HISAX_SCT_QUADRO
+  This enables HiSax support for the Scitel Quadro card.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using a different D-channel protocol, or non-standard IRQ/port
+  settings.
+
+CONFIG_HISAX_GAZEL
+  This enables HiSax support for the Gazel cards.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using a different D-channel protocol, or non-standard IRQ/port
+  settings.
+
+CONFIG_HISAX_HFC_PCI
+  This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
+
+  For more informations see under
+  <file:Documentation/isdn/README.hfc-pci>.
+
+CONFIG_HISAX_W6692
+  This enables HiSax support for Winbond W6692 based PCI ISDN cards.
+
+  See <file:Documentation/isdn/README.HiSax> on how to configure it
+  using a different D-channel protocol, or non-standard IRQ/port
+  settings.
+
+CONFIG_HISAX_HFC_SX
+  This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA
+  cards. This code is not finished yet.
+
+CONFIG_HISAX_AMD7930
+  This enables HiSax support for the AMD7930 chips on some SPARCs.
+  This code is not finished yet.
+
+CONFIG_HISAX_DEBUG
+  This enables debugging code in the new-style HiSax drivers, i.e.
+  the ST5481 USB driver currently. 
+  If in doubt, say yes.
+
+CONFIG_HISAX_ELSA_CS
+  This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink
+  card.
+
+CONFIG_HISAX_SEDLBAUER_CS
+  This enables the PCMCIA client driver for the Sedlbauer Speed Star
+  and Speed Star II cards.
+
+CONFIG_HISAX_ST5481
+  This enables the driver for ST5481 based USB ISDN adapters,
+  e.g. the BeWan Gazel 128 USB
+
+CONFIG_HISAX_FRITZ_PCIPNP
+  This enables the driver for the AVM Fritz!Card PCI, Fritz!Card PCI v2 
+  and Fritz!Card PnP.
+  (the latter also needs you to select "ISA Plug and Play support"
+  from the menu "Plug and Play configuration")
+
+CONFIG_HISAX_FRITZ_CLASSIC
+  This enables the driver for the AVM Fritz!Card classic, formerly
+  known as AVM A1.
+
+CONFIG_ISDN_DRV_PCBIT
+  This enables support for the PCBIT ISDN-card.  This card is
+  manufactured in Portugal by Octal.  For running this card,
+  additional firmware is necessary, which has to be downloaded into
+  the card using a utility which is distributed separately.  See
+  <file:Documentation/isdn/README> and
+  <file:Documentation/isdn/README.pcbit> for more information.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called pcbit.o.
+
+CONFIG_ISDN_DRV_SC
+  This enables support for the Spellcaster BRI ISDN boards.  This
+  driver currently builds only in a modularized version ( = code which
+  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.
+
+CONFIG_ISDN_DRV_EICON
+  Say Y here if you have an Eicon active ISDN card. In order to use
+  this card, additional firmware is necessary, which has to be loaded
+  into the card using the eiconctrl utility which is part of the
+  latest isdn4k-utils package. Please read the file
+  <file:Documentation/isdn/README.eicon> for more information.
+
+CONFIG_ISDN_DRV_EICON_OLD
+  Say Y here to use your Eicon active ISDN card with ISDN4Linux
+  isdn module.
+
+CONFIG_ISDN_DRV_EICON_PCI
+  Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN
+  card.  Please read <file:Documentation/isdn/README.eicon> for more
+  information.
+
+CONFIG_ISDN_DRV_EICON_ISA
+  Say Y here if you have an old-type Eicon active ISDN card. In order
+  to use this card, additional firmware is necessary, which has to be
+  loaded into the card using the eiconctrl utility which is part of
+  the latest isdn4k-utils package. Please read the file
+  <file:Documentation/isdn/README.eicon> for more information.
+
+CONFIG_ISDN_DRV_EICON_DIVAS
+  Enable this option if you want the eicon driver as standalone
+  version with no interface to the ISDN4Linux isdn module. If you
+  say Y here, the eicon module only supports the Diva Server PCI
+  cards and will provide its own IDI interface. You should say N
+  here.
+
+CONFIG_ISDN_TTY_FAX
+  If you say Y here, the modem-emulator will support a subset of the
+  Fax Class 1 and 2 commands. Using a getty with fax-support
+  (mgetty+sendfax, hylafax), you will be able to use your Linux box as
+  an ISDN-fax-machine. This must be supported by the lowlevel driver
+  also. See <file:Documentation/isdn/README.fax> for more information.
+
+CONFIG_ISDN_CAPI
+  This provides the CAPI (Common ISDN Application Programming
+  Interface, a standard making it easy for programs to access ISDN
+  hardware, see <http://www.capi.org/>.  This is needed for AVM's set
+  of active ISDN controllers like B1, T1, M1.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The modules will be called capi.o and kernelcapi.o. If you want to
+  compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+CONFIG_ISDN_CAPI_CAPI20
+  This option will provide the CAPI 2.0 interface to userspace
+  applications via /dev/capi20. Applications should use the
+  standardized libcapi20 to access this functionality.  You should say
+  Y/M here.
+
+CONFIG_ISDN_CAPI_MIDDLEWARE
+  This option will enhance the capabilities of the /dev/capi20
+  interface.  It will provide a means of moving a data connection,
+  established via the usual /dev/capi20 interface to a special tty
+  device.  If you want to use pppd with pppdcapiplugin to dial up to
+  your ISP, say Y here.
+
+CONFIG_ISDN_CAPI_CAPIFS
+  This option provides a special file system, similar to /dev/pts with
+  device nodes for the special ttys established by using the
+  middleware extension above. If you want to use pppd with
+  pppdcapiplugin to dial up to your ISP, say Y here.
+
+CONFIG_ISDN_CAPI_CAPIDRV
+  This option provides the glue code to hook up CAPI driven cards to
+  the legacy isdn4linux link layer.  If you have a card which is
+  supported by a CAPI driver, but still want to use old features like
+  ippp interfaces or ttyI emulation, say Y/M here.
+
+CONFIG_ISDN_DRV_AVMB1_B1ISA
+  Enable support for the ISA version of the AVM B1 card.
+
+CONFIG_ISDN_DRV_AVMB1_B1PCI
+  Enable support for the PCI version of the AVM B1 card.
+
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+  Enable support for the V4 version of AVM B1 PCI card.
+
+CONFIG_ISDN_DRV_AVMB1_T1ISA
+  Enable support for the AVM T1 T1B card.
+  Note: This is a PRI card and handle 30 B-channels.
+
+CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+  Enable support for the PCMCIA version of the AVM B1 card.
+
+CONFIG_ISDN_DRV_AVMB1_AVM_CS
+  Enable the PCMCIA client driver for the AVM B1/M1/M2
+  PCMCIA cards.
+
+CONFIG_ISDN_DRV_AVMB1_T1PCI
+  Enable support for the AVM T1 T1B card.
+  Note: This is a PRI card and handle 30 B-channels.
+
+CONFIG_ISDN_DRV_AVMB1_C4
+  Enable support for the AVM C4/C2 PCI cards.
+  These cards handle 4/2 BRI ISDN lines (8/4 channels).
+
+CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+  If you say Y here, the AVM B1 driver will give verbose reasons for
+  disconnecting. This will increase the size of the kernel by 7 KB. If
+  unsure, say Y.
+
+CONFIG_ISDN_DRV_ACT2000
+  Say Y here if you have an IBM Active 2000 ISDN card. In order to use
+  this card, additional firmware is necessary, which has to be loaded
+  into the card using a utility which is part of the latest
+  isdn4k-utils package. Please read the file
+  <file:Documentation/isdn/README.act2000> for more information.
+
+CONFIG_ISDN_DRV_TPAM
+  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/>.
+
+  Please redirect all support questions to support@auvertech.fr.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called tpam.o.
+
+CONFIG_HYSDN
+  Say Y here if you have one of Hypercope's active PCI ISDN cards
+  Champ, Ergo and Metro. You will then get a module called hysdn.o.
+  Please read the file <file:Documentation/isdn/README.hysdn> for more
+  information.
+
+CONFIG_HYSDN_CAPI
+  Say Y here if you like to use Hypercope's CAPI 2.0 interface.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in
--- v2.5.2/linux/drivers/isdn/Config.in	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/Config.in	Mon Jan 21 15:45:15 2002
@@ -83,6 +83,7 @@
    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 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL
+   dep_tristate 'AVM Fritz!Card classic support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_CLASSIC $CONFIG_HISAX $CONFIG_EXPERIMENTAL
 fi
 endmenu
 
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c
--- v2.5.2/linux/drivers/isdn/avmb1/b1pci.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/avmb1/b1pci.c	Thu Jan 17 14:04:15 2002
@@ -67,26 +67,6 @@
 
 	card->interrupt = 0;
 }
-/* ------------------------------------------------------------- */
-
-static void b1pci_remove_ctr(struct capi_ctr *ctrl)
-{
-	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-	avmcard *card = cinfo->card;
-	unsigned int port = card->port;
-
-	b1_reset(port);
-	b1_reset(port);
-
-	di->detach_ctr(ctrl);
-	free_irq(card->irq, card);
-	release_region(card->port, AVMB1_PORTLEN);
-	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
-	kfree(card);
-
-	MOD_DEC_USE_COUNT;
-}
 
 /* ------------------------------------------------------------- */
 
@@ -118,20 +98,18 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	retval = -ENOMEM;
+	card = kmalloc(sizeof(avmcard), GFP_KERNEL);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err;
 	}
 	memset(card, 0, sizeof(avmcard));
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+
+        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_kfree;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info));
 	card->ctrlinfo = cinfo;
@@ -140,51 +118,38 @@
 	card->port = p->port;
 	card->irq = p->irq;
 	card->cardtype = avm_b1pci;
-
-	if (check_region(card->port, AVMB1_PORTLEN)) {
+	
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		goto err_kfree_ctrlinfo;
 	}
 	b1_reset(card->port);
-	if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
+	retval = b1_detect(card->port, card->cardtype);
+	if (retval) {
 		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
-					driver->name, card->port, retval);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		       driver->name, card->port, retval);
+		retval = -EIO;
+		goto err_release_region;
 	}
 	b1_reset(card->port);
 	b1_getrevision(card);
-
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
+	
 	retval = request_irq(card->irq, b1pci_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
-				driver->name, card->irq);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		       driver->name, card->irq);
+		retval = -EBUSY;
+		goto err_release_region;
 	}
-
+	
 	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n",
-				driver->name);
-		free_irq(card->irq, card);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		       driver->name);
+		retval = -EBUSY;
+		goto err_free_irq;
 	}
 
 	if (card->revision >= 4) {
@@ -198,6 +163,37 @@
 	}
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+	kfree(card->ctrlinfo);
+ err_kfree:
+	kfree(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+static void b1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	unsigned int port = card->port;
+
+	b1_reset(port);
+	b1_reset(port);
+
+	di->detach_ctr(ctrl);
+	free_irq(card->irq, card);
+	release_region(card->port, AVMB1_PORTLEN);
+	ctrl->driverdata = 0;
+	kfree(card->ctrlinfo);
+	kfree(card);
+
+	MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
@@ -226,25 +222,6 @@
 
 /* ------------------------------------------------------------- */
 
-static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
-{
-	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-	avmcard *card = cinfo->card;
-
- 	b1dma_reset(card);
-
-	div4->detach_ctr(ctrl);
-	free_irq(card->irq, card);
-	iounmap(card->mbase);
-	release_region(card->port, AVMB1_PORTLEN);
-	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
-        avmcard_dma_free(card->dma);
-	kfree(card);
-
-	MOD_DEC_USE_COUNT;
-}
-
 static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -274,28 +251,23 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	retval = -ENOMEM;
+	card = kmalloc(sizeof(avmcard), GFP_KERNEL);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err;
 	}
 	memset(card, 0, sizeof(avmcard));
+
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: dma alloc.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_kfree;
 	}
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_dma_free;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info));
 	card->ctrlinfo = cinfo;
@@ -306,69 +278,47 @@
 	card->membase = p->membase;
 	card->cardtype = avm_b1pci;
 
-	if (check_region(card->port, AVMB1_PORTLEN)) {
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_kfree_ctrlinfo;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 64);
 	if (!card->mbase) {
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_release_region;
 	}
 
 	b1dma_reset(card);
 
-	if ((retval = b1pciv4_detect(card)) != 0) {
+	retval = b1pciv4_detect(card);
+	if (retval) {
 		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
 					driver->name, card->port, retval);
-                iounmap(card->mbase);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_unmap;
 	}
 	b1dma_reset(card);
 	b1_getrevision(card);
 
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
 	retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 				driver->name, card->irq);
-                iounmap(card->mbase);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_unmap;
 	}
 
 	cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
-                iounmap(card->mbase);
-		free_irq(card->irq, card);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_free_irq;
 	}
 	card->cardnr = cinfo->capi_ctrl->cnr;
 
@@ -378,6 +328,42 @@
 		card->membase, card->revision);
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_unmap:
+	iounmap(card->mbase);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+	kfree(card->ctrlinfo);
+ err_dma_free:
+	avmcard_dma_free(card->dma);
+ err_kfree:
+	kfree(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
+
+}
+
+static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+
+ 	b1dma_reset(card);
+
+	div4->detach_ctr(ctrl);
+	free_irq(card->irq, card);
+	iounmap(card->mbase);
+	release_region(card->port, AVMB1_PORTLEN);
+	ctrl->driverdata = 0;
+	kfree(card->ctrlinfo);
+        avmcard_dma_free(card->dma);
+	kfree(card);
+
+	MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
@@ -402,8 +388,6 @@
 
 #endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
 
-static int ncards = 0;
-
 static int __devinit b1pci_probe(struct pci_dev *dev,
 				 const struct pci_device_id *ent)
 {
@@ -470,6 +454,7 @@
 	struct capi_driver *driverv4 = &b1pciv4_driver;
 #endif
 	char *p;
+	int ncards;
 
 	MOD_INC_USE_COUNT;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- v2.5.2/linux/drivers/isdn/avmb1/c4.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/avmb1/c4.c	Thu Jan 17 14:04:15 2002
@@ -1133,28 +1133,23 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	retval = -ENOMEM;
+	card = kmalloc(sizeof(avmcard), GFP_ATOMIC);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err;
 	}
 	memset(card, 0, sizeof(avmcard));
+
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_kfree;
 	}
         cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_dma_free;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info)*4);
 	card->ctrlinfo = cinfo;
@@ -1168,53 +1163,37 @@
 	card->membase = p->membase;
 	card->cardtype = nr == 4 ? avm_c4 : avm_c2;
 
-	if (check_region(card->port, AVMB1_PORTLEN)) {
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_kfree_ctrlinfo;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 128);
 	if (card->mbase == 0) {
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_release_region;
 	}
 
-	if ((retval = c4_detect(card)) != 0) {
+	retval = c4_detect(card);
+	if (retval != 0) {
 		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
 					driver->name, card->port, retval);
-                iounmap(card->mbase);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_unmap;
 	}
 	c4_reset(card);
 
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
 	retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 				driver->name, card->irq);
-                iounmap(card->mbase);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_unmap;
 	}
 
 	for (i=0; i < nr ; i++) {
@@ -1228,14 +1207,7 @@
 				cinfo = &card->ctrlinfo[i];
 				di->detach_ctr(cinfo->capi_ctrl);
 			}
-                	iounmap(card->mbase);
-			free_irq(card->irq, card);
-			release_region(card->port, AVMB1_PORTLEN);
-                        avmcard_dma_free(card->dma);
-	        	kfree(card->ctrlinfo);
-			kfree(card);
-	        	MOD_DEC_USE_COUNT;
-			return -EBUSY;
+			goto err_free_irq;
 		}
 		if (i == 0)
 			card->cardnr = cinfo->capi_ctrl->cnr;
@@ -1246,6 +1218,22 @@
 		driver->name, nr, card->port, card->irq, card->membase);
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_unmap:
+	iounmap(card->mbase);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+	kfree(card->ctrlinfo);
+ err_dma_free:
+	avmcard_dma_free(card->dma);
+ err_kfree:
+	kfree(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
 }
 
 /* ------------------------------------------------------------- */
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c
--- v2.5.2/linux/drivers/isdn/avmb1/t1pci.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/avmb1/t1pci.c	Thu Jan 17 14:04:15 2002
@@ -49,27 +49,6 @@
 
 /* ------------------------------------------------------------- */
 
-static void t1pci_remove_ctr(struct capi_ctr *ctrl)
-{
-	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-	avmcard *card = cinfo->card;
-
- 	b1dma_reset(card);
-
-	di->detach_ctr(ctrl);
-	free_irq(card->irq, card);
-	iounmap(card->mbase);
-	release_region(card->port, AVMB1_PORTLEN);
-	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
-	avmcard_dma_free(card->dma);
-	kfree(card);
-
-	MOD_DEC_USE_COUNT;
-}
-
-/* ------------------------------------------------------------- */
-
 static int t1pci_add_card(struct capi_driver *driver,
                           struct capicardparams *p,
 	                  struct pci_dev *dev)
@@ -80,28 +59,22 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	retval = -ENOMEM;
+	card = kmalloc(sizeof(avmcard), GFP_KERNEL);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err;
 	}
 	memset(card, 0, sizeof(avmcard));
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_kfree;
 	}
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_dma_free;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info));
 	card->ctrlinfo = cinfo;
@@ -112,72 +85,50 @@
 	card->membase = p->membase;
 	card->cardtype = avm_t1pci;
 
-	if (check_region(card->port, AVMB1_PORTLEN)) {
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_kfree_ctrlinfo;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 64);
 	if (!card->mbase) {
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_release_region;
 	}
 
 	b1dma_reset(card);
 
-	if ((retval = t1pci_detect(card)) != 0) {
+	retval = t1pci_detect(card);
+	if (retval != 0) {
 		if (retval < 6)
 			printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
 					driver->name, card->port, retval);
 		else
 			printk(KERN_NOTICE "%s: card at 0x%x, but cabel not connected or T1 has no power (%d)\n",
 					driver->name, card->port, retval);
-                iounmap(card->mbase);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_unmap;
 	}
 	b1dma_reset(card);
 
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
 	retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 				driver->name, card->irq);
-                iounmap(card->mbase);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_unmap;
 	}
 
 	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
-                iounmap(card->mbase);
-		free_irq(card->irq, card);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_free_irq;
 	}
 	card->cardnr = cinfo->capi_ctrl->cnr;
 
@@ -186,6 +137,43 @@
 		driver->name, card->port, card->irq, card->membase);
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_unmap:
+	iounmap(card->mbase);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+	kfree(card->ctrlinfo);
+ err_dma_free:
+	avmcard_dma_free(card->dma);
+ err_kfree:
+	kfree(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+
+ 	b1dma_reset(card);
+
+	di->detach_ctr(ctrl);
+	free_irq(card->irq, card);
+	iounmap(card->mbase);
+	release_region(card->port, AVMB1_PORTLEN);
+	ctrl->driverdata = 0;
+	kfree(card->ctrlinfo);
+	avmcard_dma_free(card->dma);
+	kfree(card);
+
+	MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile
--- v2.5.2/linux/drivers/isdn/hisax/Makefile	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/hisax/Makefile	Mon Jan 21 15:45:15 2002
@@ -10,7 +10,7 @@
 
 # Objects that export symbols.
 
-export-objs	  := config.o fsm.o hisax_isac.o
+export-objs	  := config.o fsm.o hisax_isac.o hisax_hscx.o
 
 # Multipart objects.
 
@@ -63,6 +63,7 @@
 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
+obj-$(CONFIG_HISAX_FRITZ_CLASSIC)       += hisax_isac.o hisax_hscx.o hisax_fcclassic.o
 
 CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
 CFLAGS_cert.o := -DCERTIFICATION=$(CERT)
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/avm_pci.c linux/drivers/isdn/hisax/avm_pci.c
--- v2.5.2/linux/drivers/isdn/hisax/avm_pci.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/avm_pci.c	Mon Jan 21 15:45:15 2002
@@ -561,7 +561,7 @@
 		case (PH_PULL | REQUEST):
 			if (!st->l1.bcs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -577,7 +577,7 @@
 			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
 			modehdlc(st->l1.bcs, 0, st->l1.bc);
-			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -640,7 +640,7 @@
 	if (open_hdlcstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l2.l2l1 = hdlc_l2l1;
+	st->l1.l2l1 = hdlc_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c
--- v2.5.2/linux/drivers/isdn/hisax/callc.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/callc.c	Mon Jan 21 15:45:15 2002
@@ -250,7 +250,6 @@
 	}
 }
 
-
 /*
  * Dial out
  */
@@ -264,7 +263,7 @@
 		link_debug(chanp, 0, "STAT_DCONN");
 	HL_LL(chanp, ISDN_STAT_DCONN);
 	init_b_st(chanp, 0);
-	chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
+	L4L3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
 }
 
 static void
@@ -281,7 +280,7 @@
 		lli_init_bchan_out(fi, event, arg);
 	} else {
 		FsmChangeState(fi, ST_OUT_DIAL);
-		chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp);
+		L4L3(chanp->d_st, CC_SETUP | REQUEST, chanp);
 	}
 }
 
@@ -299,7 +298,7 @@
 		lli_init_bchan_out(fi, event, arg);
 	} else {
 		FsmChangeState(fi, ST_OUT_DIAL);
-		chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp);
+		L4L3(chanp->d_st, CC_RESUME | REQUEST, chanp);
 	}
 }
 
@@ -366,33 +365,33 @@
 			case 1:	/* OK, someone likes this call */
 				FsmDelTimer(&chanp->drel_timer, 61);
 				FsmChangeState(fi, ST_IN_ALERT_SENT);
-				chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+				L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
 				break;
 			case 5: /* direct redirect */
 			case 4: /* Proceeding desired */
 				FsmDelTimer(&chanp->drel_timer, 61);
 				FsmChangeState(fi, ST_IN_PROCEED_SEND);
-				chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
+				L4L3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
 				if (ret == 5) {
 					memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm));
-					chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
+					L4L3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
 				}
 				break;
 			case 2:	/* Rejecting Call */
 				break;
 			case 3:	/* incomplete number */
 				FsmDelTimer(&chanp->drel_timer, 61);
-				chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc);
+				L4L3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc);
 				break;
 			case 0:	/* OK, nobody likes this call */
 			default:	/* statcallb problems */
-				chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
+				L4L3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
 				chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
 				FsmChangeState(fi, ST_NULL);
 				break;
 		}
 	} else {
-		chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
+		L4L3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
 		chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
 	}
 }
@@ -403,7 +402,7 @@
 	struct Channel *chanp = fi->userdata;
 
 	FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
-	chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
+	L4L3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
 }
 
 static void
@@ -412,7 +411,7 @@
 	struct Channel *chanp = fi->userdata;
 
 	FsmChangeState(fi, ST_IN_ALERT_SENT);
-	chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+	L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
 }
 
 static void
@@ -420,7 +419,7 @@
 {
 	struct Channel *chanp = fi->userdata;
 
-	chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
+	L4L3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
 }
 
 static void
@@ -435,7 +434,7 @@
 	chanp->l2_active_protocol = chanp->l2_protocol;
 	chanp->incoming = !0;
 	init_b_st(chanp, !0);
-	chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
+	L4L3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
 }
 
 static void
@@ -448,9 +447,9 @@
 	} else {
 		FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
 #ifdef WANT_ALERT
-		chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+		L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
 #endif
-		chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
+		L4L3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
 	}
 }
 
@@ -461,7 +460,7 @@
 {
 	struct Channel *chanp = fi->userdata;
 
-	chanp->d_st->lli.l4l3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc);
+	L4L3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc);
 }
 
 /* Call clearing */
@@ -493,8 +492,7 @@
 		FsmChangeState(fi, ST_WAIT_DRELEASE);
 		if (chanp->proc)
 			chanp->proc->para.cause = 0x10;	/* Normal Call Clearing */
-		chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
-			chanp->proc);
+		L4L3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
 	}
 }
 
@@ -509,8 +507,7 @@
 		FsmChangeState(fi, ST_WAIT_DRELEASE);
 		if (chanp->proc)
 			chanp->proc->para.cause = 0x15;	/* Call Rejected */
-		chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
-			chanp->proc);
+		L4L3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
 	}
 }
 
@@ -542,12 +539,12 @@
 #ifndef ALERT_REJECT
 	if (chanp->proc)
 		chanp->proc->para.cause = 0x15;	/* Call Rejected */
-	chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
+	L4L3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
 	lli_dhup_close(fi, event, arg);
 #else
 	FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63);
 	FsmChangeState(fi, ST_IN_ALERT_SENT);
-	chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+	L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
 #endif
 }
 
@@ -558,7 +555,7 @@
 
 	chanp->data_open = 0;
 	FsmChangeState(fi, ST_WAIT_BRELEASE);
-	chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+	L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
 }
 
 static void
@@ -613,7 +610,7 @@
 
 	chanp->data_open = 0;
 	FsmChangeState(fi, ST_WAIT_BREL_DISC);
-	chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+	L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
 }
 
 
@@ -643,7 +640,7 @@
 	struct Channel *chanp = fi->userdata;
 
 	chanp->data_open = 0;
-	chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+	L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
 	lli_bhup_dhup(fi, event, arg);
 }
  
@@ -656,8 +653,7 @@
 		lli_leased_hup(fi, chanp);
 	} else {
 		FsmChangeState(fi, ST_WAIT_D_REL_CNF);
-		chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST,
-			chanp->proc);
+		L4L3(chanp->d_st, CC_RELEASE | REQUEST,	chanp->proc);
 	}
 }
 
@@ -768,7 +764,7 @@
 	struct Channel *chanp = fi->userdata;
 
 	chanp->data_open = 0;
-	chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+	L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
 	lli_bhup_fail(fi, event, arg);
 }
 
@@ -942,7 +938,7 @@
 	if (pr == (CC_SETUP | INDICATION)) {
 		if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) {
 			pc->para.cause = 0x11;	/* User busy */
-			pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc);
+			L4L3(pc->st, CC_REJECT | REQUEST, pc);
 		} else {
 			chanp->proc = pc;
 			pc->chan = chanp;
@@ -1025,16 +1021,16 @@
 	if (!*stp)
 		return -ENOMEM;
 	(*stp)->next = NULL;
-	(*stp)->l1.l1l2 = dummy_pstack;
 	(*stp)->l1.l1hw = dummy_pstack;
 	(*stp)->l1.l1tei = dummy_pstack;
+	(*stp)->l1.l2l1 = dummy_pstack;
+	(*stp)->l2.l1l2 = dummy_pstack;
 	(*stp)->l2.l2tei = dummy_pstack;
-	(*stp)->l2.l2l1 = dummy_pstack;
-	(*stp)->l2.l2l3 = dummy_pstack;
-	(*stp)->l3.l3l2 = dummy_pstack;
+	(*stp)->l2.l3l2 = dummy_pstack;
+	(*stp)->l3.l2l3 = dummy_pstack;
 	(*stp)->l3.l3ml3 = dummy_pstack;
-	(*stp)->l3.l3l4 = dummy_pstack;
-	(*stp)->lli.l4l3 = dummy_pstack;
+	(*stp)->l3.l4l3 = dummy_pstack;
+	(*stp)->lli.l3l4 = dummy_pstack;
 	(*stp)->ma.layer = dummy_pstack;
 	return 0;
 }
@@ -1073,7 +1069,7 @@
 	setstack_l3dc(st, chanp);
 	st->lli.userdata = chanp;
 	st->lli.l2writewakeup = NULL;
-	st->l3.l3l4 = dchan_l3l4;
+	st->lli.l3l4 = dchan_l3l4;
 
 	return 0;
 }
@@ -1147,8 +1143,7 @@
 	printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n");
 	if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) {
 		printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
-		csta->channel->d_st->lli.l4l3(csta->channel->d_st,
-			DL_ESTABLISH | REQUEST, NULL);
+		L4L3(csta->channel->d_st, DL_ESTABLISH | REQUEST, NULL);
 	}
 	return (0);
 }
@@ -1317,7 +1312,7 @@
 			sprintf(tmp, "Ch%d X.75", chanp->chan);
 			setstack_isdnl2(st, tmp);
 			setstack_l3bc(st, chanp);
-			st->l2.l2l3 = lldata_handler;
+			st->l3.l2l3 = lldata_handler;
 			st->lli.userdata = chanp;
 			st->lli.l1writewakeup = NULL;
 			st->lli.l2writewakeup = ll_writewakeup;
@@ -1329,7 +1324,7 @@
 		case (ISDN_PROTO_L2_TRANS):
 		case (ISDN_PROTO_L2_MODEM):
 		case (ISDN_PROTO_L2_FAX):
-			st->l1.l1l2 = lltrans_handler;
+			st->l2.l1l2 = lltrans_handler;
 			st->lli.userdata = chanp;
 			st->lli.l1writewakeup = ll_writewakeup;
 			setstack_transl2(st);
@@ -1352,7 +1347,7 @@
 			dev_kfree_skb(skb);
 			break;
 		case (DL_ESTABLISH | REQUEST):
-			st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
+			L2L1(st, PH_ACTIVATE | REQUEST, NULL);
 			break;
 		case (DL_RELEASE | REQUEST):
 			break;
@@ -1650,16 +1645,15 @@
 						HiSax_putstatus(csta, "Card",
 							"%d channel %d set leased mode\n",
 							csta->cardnr + 1, num + 1);
-						chanp->d_st->l1.l1l2 = leased_l1l2;
-						chanp->d_st->lli.l4l3 = leased_l4l3;
-						chanp->d_st->lli.l4l3(chanp->d_st,
-							DL_ESTABLISH | REQUEST, NULL);
+						chanp->d_st->l2.l1l2 = leased_l1l2;
+						chanp->d_st->l3.l4l3 = leased_l4l3;
+						L4L3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL);
 					}
 					break;
 				case (6):	/* set B-channel test loop */
 					num = *(unsigned int *) ic->parm.num;
 					if (csta->stlist)
-						csta->stlist->l2.l2l1(csta->stlist,
+						csta->stlist->l1.l2l1(csta->stlist,
 							PH_TESTLOOP | REQUEST, (void *) (long)num);
 					break;
 				case (7):	/* set card in PTP mode */
@@ -1673,8 +1667,7 @@
 						HiSax_putstatus(csta, "set card ", "in PTP mode");
 						printk(KERN_DEBUG "HiSax: set card in PTP mode\n");
 						printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
-						csta->channel[0].d_st->lli.l4l3(csta->channel[0].d_st,
-							DL_ESTABLISH | REQUEST, NULL);
+						L4L3(csta->channel[0].d_st, DL_ESTABLISH | REQUEST, NULL);
 					} else {
 						test_and_clear_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag);
 						test_and_clear_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag);
@@ -1698,8 +1691,7 @@
 						printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n",
 							num);
 					}
-					chanp->d_st->lli.l4l3(chanp->d_st,
-						DL_ESTABLISH | REQUEST, NULL);
+					L4L3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL);
 					break;
 #ifdef MODULE
 				case (55):
@@ -1764,7 +1756,7 @@
 		case (ISDN_CMD_PROT_IO):
 			for (st = csta->stlist; st; st = st->next)
 				if (st->protocol == (ic->arg & 0xFF))
-					return(st->lli.l4l3_proto(st, ic));
+					return(st->l3.l4l3_proto(st, ic));
 			return(-EINVAL);
 			break;
 		default:
@@ -1820,10 +1812,10 @@
 			if (!ack)
 				nskb->pkt_type = PACKET_NOACK;
 			if (chanp->l2_active_protocol == ISDN_PROTO_L2_X75I)
-				st->l3.l3l2(st, DL_DATA | REQUEST, nskb);
+				L3L2(st, DL_DATA | REQUEST, nskb);
 			else {
 				chanp->bcs->tx_cnt += len;
-				st->l2.l2l1(st, PH_DATA | REQUEST, nskb);
+				st->l1.l2l1(st, PH_DATA | REQUEST, nskb);
 			}
 			dev_kfree_skb(skb);
 		} else
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
--- v2.5.2/linux/drivers/isdn/hisax/config.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/hisax/config.c	Mon Jan 21 15:45:15 2002
@@ -1776,7 +1776,7 @@
 	cs->hw.hisax_d_if = hisax_d_if;
 	cs->cardmsg = hisax_cardmsg;
 	cs->tqueue.routine = (void *) (void *) hisax_bh;
-	cs->channel[0].d_st->l2.l2l1 = hisax_d_l2l1;
+	cs->channel[0].d_st->l1.l2l1 = hisax_d_l2l1;
 	for (i = 0; i < 2; i++) {
 		cs->bcs[i].BC_SetStack = hisax_bc_setstack;
 		cs->bcs[i].BC_Close = hisax_bc_close;
@@ -1823,7 +1823,7 @@
 		else
 			pr = PH_DEACTIVATE | INDICATION;
 		for (st = cs->stlist; st; st = st->next)
-			st->l1.l1l2(st, pr, NULL);
+			L1L2(st, pr, NULL);
 		
 	}
 }
@@ -1876,7 +1876,7 @@
 		clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 		for (st = cs->stlist; st; st = st->next) {
 			if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) {
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 				break;
 			}
 		}
@@ -1901,10 +1901,10 @@
 	// FIXME use isdnl1?
 	switch (pr) {
 	case PH_ACTIVATE | INDICATION:
-		st->l1.l1l2(st, pr, NULL);
+		L1L2(st, pr, NULL);
 		break;
 	case PH_DEACTIVATE | INDICATION:
-		st->l1.l1l2(st, pr, NULL);
+		L1L2(st, pr, NULL);
 		bcs->hw.b_if = NULL;
 		break;
 	case PH_DATA | INDICATION:
@@ -1922,7 +1922,7 @@
 		}
 		clear_bit(BC_FLG_BUSY, &bcs->Flag);
 		if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) {
-			st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			L1L2(st, PH_PULL | CONFIRM, NULL);
 		}
 		break;
 	default:
@@ -1953,7 +1953,7 @@
 		break;
 	case PH_PULL | REQUEST:
 		if (!test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-			st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			L1L2(st, PH_PULL | CONFIRM, NULL);
 		else
 			set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 		break;
@@ -1988,7 +1988,7 @@
 		break;
 	case PH_PULL | REQUEST:
 		if (!test_bit(BC_FLG_BUSY, &bcs->Flag))
-			st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			L1L2(st, PH_PULL | CONFIRM, NULL);
 		else
 			set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 		break;
@@ -2009,7 +2009,7 @@
 	hisax_d_if->b_if[st->l1.bc]->bcs = bcs;
 
 	st->l1.bcs = bcs;
-	st->l2.l2l1 = hisax_b_l2l1;
+	st->l1.l2l1 = hisax_b_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/elsa_ser.c linux/drivers/isdn/hisax/elsa_ser.c
--- v2.5.2/linux/drivers/isdn/hisax/elsa_ser.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/elsa_ser.c	Mon Jan 21 15:45:15 2002
@@ -591,7 +591,7 @@
 		}
 	} else if (pr == (PH_ACTIVATE | REQUEST)) {
 		test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-		st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+		L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
 		set_arcofi(st->l1.bcs->cs, st->l1.bc);
 		mstartup(st->l1.bcs->cs);
 		modem_set_dial(st->l1.bcs->cs, test_bit(FLG_ORIG, &st->l2.flag));
@@ -617,7 +617,7 @@
 		case L1_MODE_TRANS:
 			if (open_hscxstate(st->l1.hardware, bcs))
 				return (-1);
-			st->l2.l2l1 = hscx_l2l1;
+			st->l1.l2l1 = hscx_l2l1;
 			break;
 		case L1_MODE_MODEM:
 			bcs->mode = L1_MODE_MODEM;
@@ -632,7 +632,7 @@
 			bcs->hw.hscx.rcvidx = 0;
 			bcs->tx_cnt = 0;
 			bcs->cs->hw.elsa.bcs = bcs;
-			st->l2.l2l1 = modem_l2l1;
+			st->l1.l2l1 = modem_l2l1;
 			break;
 	}
 	st->l1.bcs = bcs;
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c
--- v2.5.2/linux/drivers/isdn/hisax/hfc_2bds0.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/hfc_2bds0.c	Mon Jan 21 15:45:15 2002
@@ -545,7 +545,7 @@
 		case (PH_PULL | REQUEST):
 			if (!st->l1.bcs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -561,7 +561,7 @@
 			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
 			mode_2bs0(st->l1.bcs, 0, st->l1.bc);
-			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -602,7 +602,7 @@
 	if (open_hfcstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l2.l2l1 = hfc_l2l1;
+	st->l1.l2l1 = hfc_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
@@ -1066,7 +1066,7 @@
 #endif
 			if (!cs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c
--- v2.5.2/linux/drivers/isdn/hisax/hfc_2bs0.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/hfc_2bs0.c	Mon Jan 21 15:45:15 2002
@@ -507,7 +507,7 @@
 		case (PH_PULL | REQUEST):
 			if (!st->l1.bcs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -523,7 +523,7 @@
 			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
 			mode_hfc(st->l1.bcs, 0, st->l1.bc);
-			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -566,7 +566,7 @@
 	if (open_hfcstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l2.l2l1 = hfc_l2l1;
+	st->l1.l2l1 = hfc_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c
--- v2.5.2/linux/drivers/isdn/hisax/hfc_pci.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/hfc_pci.c	Mon Jan 21 15:45:15 2002
@@ -776,7 +776,7 @@
 			st->l1.l1hw(st, pr, arg);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+			L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
 			break;
 		case (PH_TESTLOOP | REQUEST):
 			if (1 & (long) arg)
@@ -821,7 +821,7 @@
 		cs->dc.hfcpci.ph_state = 1;
 		cs->hw.hfcpci.nt_mode = 1;
 		cs->hw.hfcpci.nt_timer = 0;
-		cs->stlist->l2.l2l1 = dch_nt_l2l1;
+		cs->stlist->l1.l2l1 = dch_nt_l2l1;
 		restore_flags(flags);
 		debugl1(cs, "NT mode activated");
 		return (0);
@@ -1211,7 +1211,7 @@
 #endif
 			if (!cs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -1462,7 +1462,7 @@
 		case (PH_PULL | REQUEST):
 			if (!st->l1.bcs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -1478,7 +1478,7 @@
 			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
 			mode_hfcpci(st->l1.bcs, 0, st->l1.bc);
-			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -1528,7 +1528,7 @@
 	if (open_hfcpcistate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l2.l2l1 = hfcpci_l2l1;
+	st->l1.l2l1 = hfcpci_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/hfc_sx.c linux/drivers/isdn/hisax/hfc_sx.c
--- v2.5.2/linux/drivers/isdn/hisax/hfc_sx.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/hfc_sx.c	Mon Jan 21 15:45:15 2002
@@ -632,7 +632,7 @@
 			st->l1.l1hw(st, pr, arg);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+			L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
 			break;
 		case (PH_TESTLOOP | REQUEST):
 			if (1 & (long) arg)
@@ -676,7 +676,7 @@
 		cs->dc.hfcsx.ph_state = 1;
 		cs->hw.hfcsx.nt_mode = 1;
 		cs->hw.hfcsx.nt_timer = 0;
-		cs->stlist->l2.l2l1 = dch_nt_l2l1;
+		cs->stlist->l1.l2l1 = dch_nt_l2l1;
 		restore_flags(flags);
 		debugl1(cs, "NT mode activated");
 		return (0);
@@ -1008,7 +1008,7 @@
 #endif
 			if (!cs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -1248,7 +1248,7 @@
 		case (PH_PULL | REQUEST):
 			if (!st->l1.bcs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -1264,7 +1264,7 @@
 			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
 			mode_hfcsx(st->l1.bcs, 0, st->l1.bc);
-			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -1314,7 +1314,7 @@
 	if (open_hfcsxstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l2.l2l1 = hfcsx_l2l1;
+	st->l1.l2l1 = hfcsx_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h
--- v2.5.2/linux/drivers/isdn/hisax/hisax.h	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/hisax/hisax.h	Mon Jan 21 15:45:15 2002
@@ -203,9 +203,9 @@
 	long Flags;
 	struct FsmInst l1m;
 	struct FsmTimer	timer;
-	void (*l1l2) (struct PStack *, int, void *);
 	void (*l1hw) (struct PStack *, int, void *);
 	void (*l1tei) (struct PStack *, int, void *);
+	void (*l2l1) (struct PStack *, int, void *);
 	int mode, bc;
 	int delay;
 };
@@ -247,8 +247,8 @@
 	struct sk_buff *windowar[MAX_WINDOW];
 	struct sk_buff_head i_queue;
 	struct sk_buff_head ui_queue;
-	void (*l2l1) (struct PStack *, int, void *);
-	void (*l2l3) (struct PStack *, int, void *);
+	void (*l3l2) (struct PStack *, int, void *);
+	void (*l1l2) (struct PStack *, int, void *);
 	void (*l2tei) (struct PStack *, int, void *);
 	struct FsmInst l2m;
 	struct FsmTimer t200, t203;
@@ -258,9 +258,10 @@
 };
 
 struct Layer3 {
-	void (*l3l4) (struct PStack *, int, void *);
+	void (*l4l3) (struct PStack *, int, void *);
+        int  (*l4l3_proto) (struct PStack *, isdn_ctrl *);
         void (*l3ml3) (struct PStack *, int, void *);
-	void (*l3l2) (struct PStack *, int, void *);
+	void (*l2l3) (struct PStack *, int, void *);
 	struct FsmInst l3m;
         struct FsmTimer l3m_timer;
 	struct sk_buff_head squeue;
@@ -272,8 +273,7 @@
 };
 
 struct LLInterface {
-	void (*l4l3) (struct PStack *, int, void *);
-        int  (*l4l3_proto) (struct PStack *, isdn_ctrl *);
+	void (*l3l4) (struct PStack *, int, void *);
 	void *userdata;
 	void (*l1writewakeup) (struct PStack *, int);
 	void (*l2writewakeup) (struct PStack *, int);
@@ -1348,3 +1348,40 @@
 int TeiNew(void);
 void TeiFree(void);
 int certification_check(int output);
+
+static inline void
+L2L1(struct PStack *st, int pr, void *arg)
+{
+	st->l1.l2l1(st, pr, arg);
+}
+
+static inline void
+L1L2(struct PStack *st, int pr, void *arg)
+{
+	st->l2.l1l2(st, pr, arg);
+}
+
+static inline void
+L3L2(struct PStack *st, int pr, void *arg)
+{
+	st->l2.l3l2(st, pr, arg);
+}
+
+static inline void
+L2L3(struct PStack *st, int pr, void *arg)
+{
+	st->l3.l2l3(st, pr, arg);
+}
+
+static inline void
+L3L4(struct PStack *st, int pr, void *arg)
+{
+	st->lli.l3l4(st, pr, arg);
+}
+
+static inline void
+L4L3(struct PStack *st, int pr, void *arg)
+{
+	st->l3.l4l3(st, pr, arg);
+}
+
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/hisax_fcclassic.c linux/drivers/isdn/hisax/hisax_fcclassic.c
--- v2.5.2/linux/drivers/isdn/hisax/hisax_fcclassic.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/hisax/hisax_fcclassic.c	Mon Jan 21 15:45:15 2002
@@ -0,0 +1,384 @@
+/*
+ * Driver for AVM Fritz!classic (ISA) ISDN card
+ *
+ * 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_a1.c driver
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+
+#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_fcclassic.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!Card classic ISDN driver");
+
+static int protocol = 2;       /* EURO-ISDN Default */
+MODULE_PARM(protocol, "i");
+
+// ----------------------------------------------------------------------
+
+#define	 AVM_A1_STAT_ISAC	0x01
+#define	 AVM_A1_STAT_HSCX	0x02
+#define	 AVM_A1_STAT_TIMER	0x04
+
+// ----------------------------------------------------------------------
+
+static unsigned char
+fcclassic_read_isac(struct isac *isac, unsigned char offset)
+{
+	struct fritz_adapter *adapter = isac->priv;
+	unsigned char val;
+
+	val = inb(adapter->isac_base + offset);
+	DBG(0x1000, " port %#x, value %#x",
+	    offset, val);
+	return val;
+}
+
+static void
+fcclassic_write_isac(struct isac *isac, unsigned char offset,
+		     unsigned char value)
+{
+	struct fritz_adapter *adapter = isac->priv;
+
+	DBG(0x1000, " port %#x, value %#x",
+	    offset, value);
+	outb(value, adapter->isac_base + offset);
+}
+
+static void
+fcclassic_read_isac_fifo(struct isac *isac, unsigned char * data, int size)
+{
+	struct fritz_adapter *adapter = isac->priv;
+
+	insb(adapter->isac_fifo, data, size);
+}
+
+static void
+fcclassic_write_isac_fifo(struct isac *isac, unsigned char * data, int size)
+{
+	struct fritz_adapter *adapter = isac->priv;
+
+	outsb(adapter->isac_fifo, data, size);
+}
+
+static u_char
+fcclassic_read_hscx(struct hscx *hscx, u_char offset)
+{
+	struct fritz_adapter *adapter = hscx->priv;
+
+	return inb(adapter->hscx_base[hscx->channel] + offset);
+}
+
+static void
+fcclassic_write_hscx(struct hscx *hscx, u_char offset, u_char value)
+{
+	struct fritz_adapter *adapter = hscx->priv;
+
+	outb(value, adapter->hscx_base[hscx->channel] + offset);
+}
+
+static void
+fcclassic_read_hscx_fifo(struct hscx *hscx, unsigned char * data, int size)
+{
+	struct fritz_adapter *adapter = hscx->priv;
+
+	insb(adapter->hscx_fifo[hscx->channel], data, size);
+}
+
+static void
+fcclassic_write_hscx_fifo(struct hscx *hscx, unsigned char * data, int size)
+{
+	struct fritz_adapter *adapter = hscx->priv;
+
+	outsb(adapter->hscx_fifo[hscx->channel], data, size);
+}
+
+// ----------------------------------------------------------------------
+
+static void
+fcclassic_irq(int intno, void *dev, struct pt_regs *regs)
+{
+	struct fritz_adapter *adapter = dev;
+	unsigned char sval;
+
+	DBG(2, "");
+	while ((sval = inb(adapter->cfg_reg) & 0xf) != 0x7) {
+		DBG(2, "sval %#x", sval);
+		if (!(sval & AVM_A1_STAT_TIMER)) {
+			outb(0x1e, adapter->cfg_reg);
+		}
+		if (!(sval & AVM_A1_STAT_HSCX)) {
+			hscx_irq(adapter->hscx);
+		}
+		if (!(sval & AVM_A1_STAT_ISAC)) {
+			isac_irq(&adapter->isac);
+		}
+	}
+}
+
+// ----------------------------------------------------------------------
+
+static int __init
+fcclassic_setup(struct fritz_adapter *adapter)
+{
+	u32 val = 0;
+	int i;
+	int retval;
+
+	DBG(1,"");
+
+	isac_init(&adapter->isac); // FIXME is this okay now
+
+	adapter->cfg_reg      = adapter->io + 0x1800;
+	adapter->isac_base    = adapter->io + 0x1400 - 0x20;
+	adapter->isac_fifo    = adapter->io + 0x1000;
+	adapter->hscx_base[0] = adapter->io + 0x0400 - 0x20;
+	adapter->hscx_fifo[0] = adapter->io;
+	adapter->hscx_base[1] = adapter->io + 0x0c00 - 0x20;
+	adapter->hscx_fifo[1] = adapter->io + 0x0800;
+
+	retval = -EBUSY;
+	if (!request_region(adapter->cfg_reg            ,  8,
+			    "fcclassic cfg"))
+		goto err;
+	if (!request_region(adapter->isac_base + 0x20   , 32,
+			    "fcclassic isac"))
+		goto err_cfg_reg;
+	if (!request_region(adapter->isac_fifo          ,  1,
+			    "fcclassic isac fifo"))
+		goto err_isac_base;
+	if (!request_region(adapter->hscx_base[0] + 0x20, 32,
+			    "fcclassic hscx"))
+		goto err_isac_fifo;
+	if (!request_region(adapter->hscx_fifo[0]       ,  1,
+			    "fcclassic hscx fifo"))
+		goto err_hscx_base_0;
+	if (!request_region(adapter->hscx_base[1] + 0x20, 32,
+			    "fcclassic hscx"))
+		goto err_hscx_fifo_0;
+	if (!request_region(adapter->hscx_fifo[1]       ,  1,
+			    "fcclassic hscx fifo"))
+		goto err_hscx_base_1;
+	retval = request_irq(adapter->irq, fcclassic_irq,  0,
+			     "fcclassic", adapter);
+	if (retval)
+		goto err_hscx_fifo_1;
+
+	// Reset
+	outb(0x00, adapter->cfg_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(200 * HZ / 1000); // 200 msec
+	outb(0x01, adapter->cfg_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(200 * HZ / 1000); // 200 msec
+	outb(0x00, adapter->cfg_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(200 * HZ / 1000); // 200 msec
+
+	val = adapter->irq;
+	if (val == 9)
+		val = 2;
+	outb(val, adapter->cfg_reg + 1);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(200 * HZ / 1000); // 200 msec
+	outb(0x00, adapter->cfg_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(200 * HZ / 1000); // 200 msec
+
+	val = inb(adapter->cfg_reg);
+	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+	       adapter->cfg_reg, val);
+	val = inb(adapter->cfg_reg + 3);
+	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+	       adapter->cfg_reg + 3, val);
+	val = inb(adapter->cfg_reg + 2);
+	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+	       adapter->cfg_reg + 2, val);
+	val = inb(adapter->cfg_reg);
+	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+	       adapter->cfg_reg, val);
+
+	outb(0x16, adapter->cfg_reg);
+	outb(0x1e, adapter->cfg_reg);
+
+	adapter->isac.priv            = adapter;
+	adapter->isac.read_isac       = &fcclassic_read_isac;
+	adapter->isac.write_isac      = &fcclassic_write_isac;
+	adapter->isac.read_isac_fifo  = &fcclassic_read_isac_fifo;
+	adapter->isac.write_isac_fifo = &fcclassic_write_isac_fifo;
+	isac_setup(&adapter->isac);
+	for (i = 0; i < 2; i++) {
+		hscx_init(&adapter->hscx[i]);
+		adapter->hscx[i].priv            = adapter;
+		adapter->hscx[i].read_hscx       = &fcclassic_read_hscx;
+		adapter->hscx[i].write_hscx      = &fcclassic_write_hscx;
+		adapter->hscx[i].read_hscx_fifo  = &fcclassic_read_hscx_fifo;
+		adapter->hscx[i].write_hscx_fifo = &fcclassic_write_hscx_fifo;
+		hscx_setup(&adapter->hscx[i]);
+	}
+
+	return 0;
+
+ err_hscx_fifo_1:
+	release_region(adapter->hscx_fifo[1]       ,  1);
+ err_hscx_base_1:
+	release_region(adapter->hscx_base[1] + 0x20, 32);
+ err_hscx_fifo_0:
+	release_region(adapter->hscx_fifo[0]       ,  1);
+ err_hscx_base_0:
+	release_region(adapter->hscx_base[0] + 0x20, 32);
+ err_isac_fifo:
+	release_region(adapter->isac_fifo          ,  1);
+ err_isac_base:
+	release_region(adapter->isac_base    + 0x20, 32);
+ err_cfg_reg:
+	release_region(adapter->cfg_reg            ,  8);
+ err:
+	return retval;
+}
+
+static void __exit fcclassic_release(struct fritz_adapter *adapter)
+{
+	DBG(1,"");
+
+//	outb(0, adapter->io + AVM_STATUS0);
+	free_irq(adapter->irq, adapter);
+	release_region(adapter->hscx_fifo[1]       ,  1);
+	release_region(adapter->hscx_base[1] + 0x20, 32);
+	release_region(adapter->hscx_fifo[0]       ,  1);
+	release_region(adapter->hscx_base[0] + 0x20, 32);
+	release_region(adapter->isac_fifo          ,  1);
+	release_region(adapter->isac_base    + 0x20, 32);
+	release_region(adapter->cfg_reg            ,  8);
+}
+
+// ----------------------------------------------------------------------
+
+static struct fritz_adapter * __init 
+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->hscx[i].adapter = adapter;
+		adapter->hscx[i].channel = i;
+		adapter->hscx[i].b_if.ifc.priv = &adapter->hscx[i];
+		adapter->hscx[i].b_if.ifc.l2l1 = hscx_b_l2l1;
+	}
+	pci_set_drvdata(pdev, adapter);
+
+	for (i = 0; i < 2; i++)
+		b_if[i] = &adapter->hscx[i].b_if;
+
+	hisax_register(&adapter->isac.hisax_d_if, b_if, "fcclassic", protocol);
+
+	return adapter;
+}
+
+static void
+delete_adapter(struct fritz_adapter *adapter)
+{
+	hisax_unregister(&adapter->isac.hisax_d_if);
+	kfree(adapter);
+}
+
+static int __init
+fcclassic_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->io = pdev->resource[0].start;
+	adapter->irq = pdev->irq_resource[0].start;
+
+	printk(KERN_INFO "hisax_fcclassic: found Fritz!Card classic at IO %#x irq %d\n",
+	       adapter->io, adapter->irq);
+
+	retval = fcclassic_setup(adapter);
+	if (retval)
+		goto err_free;
+
+	return 0;
+	
+ err_free:
+	delete_adapter(adapter);
+ err:
+	return retval;
+}
+
+static int __exit 
+fcclassic_remove(struct pci_dev *pdev)
+{
+	struct fritz_adapter *adapter = pci_get_drvdata(pdev);
+
+	fcclassic_release(adapter);
+	delete_adapter(adapter);
+
+	return 0;
+}
+
+static struct pci_dev isa_dev[4];
+
+static int __init
+hisax_fcclassic_init(void)
+{
+	printk(KERN_INFO "hisax_fcclassic: Fritz!Card classic ISDN driver v0.0.1\n");
+
+	isa_dev[0].resource[0].start = 0x300;
+	isa_dev[0].irq_resource[0].start = 7;
+
+	fcclassic_probe(isa_dev, NULL);
+
+	return 0;
+}
+
+static void __exit
+hisax_fcclassic_exit(void)
+{
+	fcclassic_remove(isa_dev);
+}
+
+module_init(hisax_fcclassic_init);
+module_exit(hisax_fcclassic_exit);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/hisax_fcclassic.h linux/drivers/isdn/hisax/hisax_fcclassic.h
--- v2.5.2/linux/drivers/isdn/hisax/hisax_fcclassic.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/hisax/hisax_fcclassic.h	Mon Jan 21 15:45:15 2002
@@ -0,0 +1,18 @@
+#include "hisax_if.h"
+#include "hisax_isac.h"
+#include "hisax_hscx.h"
+
+#include <linux/pci.h>
+
+struct fritz_adapter {
+	unsigned int io;
+	unsigned int irq;
+	unsigned int cfg_reg;
+	unsigned int isac_base;
+	unsigned int isac_fifo;
+	unsigned int hscx_base[2];
+	unsigned int hscx_fifo[2];
+	struct isac isac;
+
+	struct hscx hscx[2];
+};
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/hisax_hscx.c linux/drivers/isdn/hisax/hisax_hscx.c
--- v2.5.2/linux/drivers/isdn/hisax/hisax_hscx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/hisax/hisax_hscx.c	Mon Jan 21 15:45:15 2002
@@ -0,0 +1,421 @@
+/*
+ * Driver for HSCX
+ * High-Level Serial Communcation Controller Extended
+ *
+ * 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.
+ */
+
+/* TODO:
+ * comments in .h
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include "hisax_hscx.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 *HSCXVer[] =
+{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
+ "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
+#endif
+
+MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
+MODULE_DESCRIPTION("HSCX 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
+
+#define HSCX_ISTA      0x20
+#define HSCX_ISTA_EXB  0x01
+#define HSCX_ISTA_EXA  0x02
+#define HSCX_ISTA_ICA  0x04
+#define HSCX_ISTA_TIN  0x08
+#define HSCX_ISTA_XPR  0x10
+#define HSCX_ISTA_RSC  0x20
+#define HSCX_ISTA_RPF  0x40
+#define HSCX_ISTA_RME  0x80
+
+#define HSCX_CMDR      0x21
+#define HSCX_CMDR_RMC  0x80
+#define HSCX_CMDR_RHR  0x40
+#define HSCX_CMDR_RNR  0x20
+#define HSCX_CMDR_STI  0x10
+#define HSCX_CMDR_XTF  0x08
+#define HSCX_CMDR_XIF  0x04
+#define HSCX_CMDR_XME  0x02
+#define HSCX_CMDR_XRES 0x01
+
+#define HSCX_EXIR      0x24
+#define HSCX_EXIR_XDU  0x40
+
+#define HSCX_RSTA      0x27
+#define HSCX_RSTA_VFR  0x80
+#define HSCX_RSTA_RDO  0x40
+#define HSCX_RSTA_CRC  0x20
+#define HSCX_RSTA_RAB  0x10
+
+#define HSCX_CCR1 0x2f
+#define HSCX_CCR2 0x2c
+#define HSCX_TSAR 0x31
+#define HSCX_TSAX 0x30
+#define HSCX_XCCR 0x32
+#define HSCX_RCCR 0x33
+#define HSCX_MODE 0x22
+
+#define HSCX_XAD1 0x24
+#define HSCX_XAD2 0x25
+#define HSCX_RAH2 0x27
+#define HSCX_TIMR 0x23
+#define HSCX_STAR 0x21
+#define HSCX_RBCL 0x25
+#define HSCX_XBCH 0x2d
+#define HSCX_VSTR 0x2e
+#define HSCX_RLCR 0x2e
+#define HSCX_MASK 0x20
+
+static inline void B_L1L2(struct hscx *hscx, int pr, void *arg)
+{
+	struct hisax_if *ifc = (struct hisax_if *) &hscx->b_if;
+
+	DBG(0x10, "pr %#x", pr);
+	ifc->l1l2(ifc, pr, arg);
+}
+
+static void hscx_version(struct hscx *hscx)
+{
+	int val;
+
+	val = hscx->read_hscx(hscx, HSCX_VSTR) & 0xf;
+	DBG(1, "HSCX version (%x): %s", val, HSCXVer[val]);
+}
+
+static void hscx_empty_fifo(struct hscx *hscx, int count)
+{
+	u_char *ptr;
+
+	DBG(DBG_IRQ, "count %d", count);
+
+	if ((hscx->rcvidx + count) >= HSCX_BUFMAX) {
+		DBG(DBG_WARN, "overrun %d", hscx->rcvidx + count);
+		hscx->write_hscx(hscx, HSCX_CMDR, HSCX_CMDR_RMC);
+		hscx->rcvidx = 0;
+		return;
+	}
+	ptr = hscx->rcvbuf + hscx->rcvidx;
+	hscx->rcvidx += count;
+	hscx->read_hscx_fifo(hscx, ptr, count);
+	hscx->write_hscx(hscx, HSCX_CMDR, HSCX_CMDR_RMC);
+	DBG_PACKET(DBG_RFIFO, ptr, count);
+}
+
+static void hscx_fill_fifo(struct hscx *hscx)
+{
+	int count;
+	unsigned char cmd;
+	int fifo_size = test_bit(HSCX_IPAC, &hscx->flags)? 64: 32;
+	unsigned char *ptr;
+
+	if (!hscx->tx_skb)
+		BUG();
+
+	count = hscx->tx_skb->len;
+	if (count <= 0)
+		BUG();
+
+	DBG(DBG_IRQ, "count %d", count);
+
+	if (count > fifo_size || hscx->mode == L1_MODE_TRANS) {
+		count = fifo_size;
+		cmd = 0x8;
+	} else {
+		cmd = 0xa;
+	}
+
+	ptr = hscx->tx_skb->data;
+	skb_pull(hscx->tx_skb, count);
+	hscx->tx_cnt += count;
+	DBG_PACKET(DBG_XFIFO, ptr, count);
+	hscx->write_hscx_fifo(hscx, ptr, count);
+	hscx->write_hscx(hscx, HSCX_CMDR, cmd);
+}
+
+static void hscx_retransmit(struct hscx *hscx)
+{
+	if (!hscx->tx_skb) {
+		DBG(DBG_WARN, "no skb");
+		return;
+	}
+	skb_push(hscx->tx_skb, hscx->tx_cnt);
+	hscx->tx_cnt = 0;
+	hscx->write_hscx(hscx, HSCX_CMDR, 0x01);
+}
+
+static inline void hscx_rme_interrupt(struct hscx *hscx)
+{
+	unsigned char val;
+	int count;
+	struct sk_buff *skb;
+	int fifo_size = test_bit(HSCX_IPAC, &hscx->flags)? 64: 32;
+	
+	val = hscx->read_hscx(hscx, HSCX_RSTA);
+	if ((val & (HSCX_RSTA_VFR | HSCX_RSTA_RDO | HSCX_RSTA_CRC | HSCX_RSTA_RAB) )
+	     != (HSCX_RSTA_VFR | HSCX_RSTA_CRC)) {
+		DBG(DBG_WARN, "RSTA %#x, dropped", val);
+		hscx->write_hscx(hscx, HSCX_CMDR, HSCX_CMDR_RMC);
+		goto out;
+	}
+	
+	count = hscx->read_hscx(hscx, HSCX_RBCL) & (fifo_size-1);
+	DBG(DBG_IRQ, "RBCL %#x", count);
+	if (count == 0)
+		count = fifo_size;
+
+	hscx_empty_fifo(hscx, count);
+
+	count = hscx->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), hscx->rcvbuf, count);
+	DBG_SKB(DBG_RPACKET, skb);
+	B_L1L2(hscx, PH_DATA | INDICATION, skb);
+ out:
+	hscx->rcvidx = 0;
+}
+
+static inline void hscx_xpr_interrupt(struct hscx *hscx)
+{
+	struct sk_buff *skb;
+
+	skb = hscx->tx_skb;
+	if (!skb)
+		return;
+
+	if (skb->len > 0) {
+		hscx_fill_fifo(hscx);
+		return;
+	}
+	hscx->tx_cnt = 0;
+	hscx->tx_skb = NULL;
+	B_L1L2(hscx, PH_DATA | CONFIRM, (void *) skb->truesize);
+	dev_kfree_skb_irq(skb);
+}
+
+static inline void hscx_exi_interrupt(struct hscx *hscx)
+{
+	unsigned char val;
+
+	val = hscx->read_hscx(hscx, HSCX_EXIR);
+	DBG(2, "EXIR %#x", val);
+
+	if (val & HSCX_EXIR_XDU) {
+		DBG(DBG_WARN, "HSCX XDU");
+		if (hscx->mode == L1_MODE_TRANS) {
+			hscx_fill_fifo(hscx);
+		} else {
+			hscx_retransmit(hscx);
+		}
+	}
+}
+
+static void hscx_reg_interrupt(struct hscx *hscx, unsigned char val)
+{
+	struct sk_buff *skb;
+
+	if (val & HSCX_ISTA_XPR) {
+		DBG(DBG_IRQ, "XPR");
+		hscx_xpr_interrupt(hscx);
+	}
+	if (val & HSCX_ISTA_RME) {
+		DBG(DBG_IRQ, "RME");
+		hscx_rme_interrupt(hscx);
+	}
+	if (val & HSCX_ISTA_RPF) {
+		int fifo_size = test_bit(HSCX_IPAC, &hscx->flags)? 64: 32;
+
+		DBG(DBG_IRQ, "RPF");
+		hscx_empty_fifo(hscx, fifo_size);
+		if (hscx->mode == L1_MODE_TRANS) {
+			skb = dev_alloc_skb(fifo_size);
+			if (!skb) {
+				DBG(DBG_WARN, "no memory, dropping\n");
+				goto out;
+			}
+			memcpy(skb_put(skb, fifo_size), hscx->rcvbuf, fifo_size);
+			DBG_SKB(DBG_RPACKET, skb);
+			B_L1L2(hscx, PH_DATA | INDICATION, skb);
+		out:
+			hscx->rcvidx = 0;
+		}
+	}
+}
+
+void hscx_irq(struct hscx *hscx_a)
+{
+	struct hscx *hscx_b = hscx_a + 1;
+	unsigned char val;
+
+	val = hscx_b->read_hscx(hscx_b, HSCX_ISTA);
+	DBG(DBG_IRQ, "ISTA B %#x", val);
+
+	if (val & HSCX_ISTA_EXB) {
+		DBG(DBG_IRQ, "EXI B");
+		hscx_exi_interrupt(hscx_b);
+	}
+	if (val & HSCX_ISTA_EXA) {
+		DBG(DBG_IRQ, "EXI A");
+		hscx_exi_interrupt(hscx_a);
+	}
+	if (val & 0xf8) {
+		hscx_reg_interrupt(hscx_b, val);
+	}
+	if (val & HSCX_ISTA_ICA) {
+		val = hscx_a->read_hscx(hscx_a, HSCX_ISTA);
+		DBG(DBG_IRQ, "ISTA A %#x", val);
+		hscx_reg_interrupt(hscx_a, val);
+		hscx_a->write_hscx(hscx_a, HSCX_MASK, 0xff);
+		hscx_a->write_hscx(hscx_a, HSCX_MASK, 0x00);
+	}
+	hscx_b->write_hscx(hscx_b, HSCX_MASK, 0xff);
+	hscx_b->write_hscx(hscx_b, HSCX_MASK, 0x00);
+}
+
+static void modehscx(struct hscx *hscx, int mode)
+{
+	int bc = hscx->channel;
+
+	DBG(0x40, "hscx %c mode %d --> %d",
+	    'A' + hscx->channel, hscx->mode, mode);
+
+	hscx->mode = mode;
+	hscx->write_hscx(hscx, HSCX_XAD1, 0xFF);
+	hscx->write_hscx(hscx, HSCX_XAD2, 0xFF);
+	hscx->write_hscx(hscx, HSCX_RAH2, 0xFF);
+	hscx->write_hscx(hscx, HSCX_XBCH, 0x0);
+	hscx->write_hscx(hscx, HSCX_RLCR, 0x0);
+	hscx->write_hscx(hscx, HSCX_CCR1, 
+			 test_bit(HSCX_IPAC, &hscx->flags) ? 0x82 : 0x85);
+	hscx->write_hscx(hscx, HSCX_CCR2, 0x30);
+	hscx->write_hscx(hscx, HSCX_XCCR, 7);
+	hscx->write_hscx(hscx, HSCX_RCCR, 7);
+
+	/* Switch IOM 1 SSI */
+	if (test_bit(HSCX_IOM1, &hscx->flags))
+		bc = 1;
+
+	hscx->write_hscx(hscx, HSCX_TSAX, hscx->tsaxr);
+	hscx->write_hscx(hscx, HSCX_TSAR, hscx->tsaxr);
+
+	switch (mode) {
+		case (L1_MODE_NULL):
+			hscx->write_hscx(hscx, HSCX_TSAX, 0x1f);
+			hscx->write_hscx(hscx, HSCX_TSAR, 0x1f);
+			hscx->write_hscx(hscx, HSCX_MODE, 0x84);
+			break;
+		case (L1_MODE_TRANS):
+			hscx->write_hscx(hscx, HSCX_MODE, 0xe4);
+			break;
+		case (L1_MODE_HDLC):
+			hscx->write_hscx(hscx, HSCX_CCR1, test_bit(HSCX_IPAC, &hscx->flags) ? 0x8a : 0x8d);
+			hscx->write_hscx(hscx, HSCX_MODE, 0x8c);
+			break;
+	}
+	if (mode)
+		hscx->write_hscx(hscx, HSCX_CMDR, 0x41);
+
+	hscx->write_hscx(hscx, HSCX_ISTA, 0x00);
+}
+
+void hscx_init(struct hscx *hscx)
+{
+	if (hscx->channel)
+		hscx->tsaxr = 0x03;
+	else
+		hscx->tsaxr = 0x2f;
+}
+
+void hscx_setup(struct hscx *hscx)
+{
+	hscx_version(hscx);
+	hscx->mode = -1;
+	modehscx(hscx, L1_MODE_NULL);
+}
+
+void hscx_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
+{
+	struct hscx *hscx = ifc->priv;
+	struct sk_buff *skb = arg;
+	int mode;
+
+	DBG(0x10, "pr %#x", pr);
+
+	switch (pr) {
+	case PH_DATA | REQUEST:
+		if (hscx->tx_skb)
+			BUG();
+		
+		hscx->tx_skb = skb;
+		DBG_SKB(1, skb);
+		hscx_fill_fifo(hscx);
+		break;
+	case PH_ACTIVATE | REQUEST:
+		mode = (int) arg;
+		DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", hscx->channel + 1, mode);
+		modehscx(hscx, mode);
+		B_L1L2(hscx, PH_ACTIVATE | INDICATION, NULL);
+		break;
+	case PH_DEACTIVATE | REQUEST:
+		DBG(4,"B%d,PH_DEACTIVATE_REQUEST", hscx->channel + 1);
+		modehscx(hscx, L1_MODE_NULL);
+		B_L1L2(hscx, PH_DEACTIVATE | INDICATION, NULL);
+		break;
+	}
+}
+
+static int __init hisax_hscx_init(void)
+{
+	printk(KERN_INFO "hisax_hscx: HSCX ISDN driver v0.1.0\n");
+	return 0;
+}
+
+static void __exit hisax_hscx_exit(void)
+{
+}
+
+EXPORT_SYMBOL(hscx_init);
+EXPORT_SYMBOL(hscx_b_l2l1);
+
+EXPORT_SYMBOL(hscx_setup);
+EXPORT_SYMBOL(hscx_irq);
+
+module_init(hisax_hscx_init);
+module_exit(hisax_hscx_exit);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/hisax_hscx.h linux/drivers/isdn/hisax/hisax_hscx.h
--- v2.5.2/linux/drivers/isdn/hisax/hisax_hscx.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/hisax/hisax_hscx.h	Mon Jan 21 15:45:15 2002
@@ -0,0 +1,37 @@
+#ifndef __HISAX_HSCX_H__
+#define __HISAX_HSCX_H__
+
+#include <linux/kernel.h>
+#include "fsm.h"
+#include "hisax_if.h"
+
+#define HSCX_BUFMAX	4096
+
+#define HSCX_IOM1 0
+#define HSCX_IPAC 1
+
+struct hscx {
+	void *priv;
+	u_long flags;
+	struct hisax_b_if b_if;
+	int mode;
+	int channel;
+	u_char tsaxr;
+	struct sk_buff *tx_skb;
+	int tx_cnt;
+	u_char rcvbuf[HSCX_BUFMAX];
+	int rcvidx;
+
+	u_char (*read_hscx)      (struct hscx *, u_char);
+	void   (*write_hscx)     (struct hscx *, u_char, u_char);
+	void   (*read_hscx_fifo) (struct hscx *, u_char *, int);
+	void   (*write_hscx_fifo)(struct hscx *, u_char *, int);
+};
+
+void hscx_init(struct hscx *hscx);
+void hscx_b_l2l1(struct hisax_if *hisax_b_if, int pr, void *arg);
+
+void hscx_setup(struct hscx *hscx);
+void hscx_irq(struct hscx *hscx);
+
+#endif
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/hscx.c linux/drivers/isdn/hisax/hscx.c
--- v2.5.2/linux/drivers/isdn/hisax/hscx.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/hscx.c	Mon Jan 21 15:45:15 2002
@@ -134,7 +134,7 @@
 		case (PH_PULL | REQUEST):
 			if (!st->l1.bcs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -150,7 +150,7 @@
 			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
 			modehscx(st->l1.bcs, 0, st->l1.bc);
-			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -214,7 +214,7 @@
 	if (open_hscxstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l2.l2l1 = hscx_l2l1;
+	st->l1.l2l1 = hscx_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/icc.c linux/drivers/isdn/hisax/icc.c
--- v2.5.2/linux/drivers/isdn/hisax/icc.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/icc.c	Mon Jan 21 15:45:15 2002
@@ -89,7 +89,7 @@
 			debugl1(cs, "D-Channel Busy cleared");
 		stptr = cs->stlist;
 		while (stptr != NULL) {
-			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
+			L1L2(stptr, PH_PAUSE | CONFIRM, NULL);
 			stptr = stptr->next;
 		}
 	}
@@ -506,7 +506,7 @@
 #endif
 			if (!cs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -603,7 +603,7 @@
 			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 			stptr = cs->stlist;
 			while (stptr != NULL) {
-				stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+				L1L2(stptr, PH_PAUSE | INDICATION, NULL);
 				stptr = stptr->next;
 			}
 		} else {
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/isac.c linux/drivers/isdn/hisax/isac.c
--- v2.5.2/linux/drivers/isdn/hisax/isac.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/isac.c	Mon Jan 21 15:45:15 2002
@@ -93,7 +93,7 @@
 			debugl1(cs, "D-Channel Busy cleared");
 		stptr = cs->stlist;
 		while (stptr != NULL) {
-			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
+			L1L2(stptr, PH_PAUSE | CONFIRM, NULL);
 			stptr = stptr->next;
 		}
 	}
@@ -510,7 +510,7 @@
 #endif
 			if (!cs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -605,7 +605,7 @@
 			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 			stptr = cs->stlist;
 			while (stptr != NULL) {
-				stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+				L1L2(stptr, PH_PAUSE | INDICATION, NULL);
 				stptr = stptr->next;
 			}
 		} else {
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c
--- v2.5.2/linux/drivers/isdn/hisax/isar.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/hisax/isar.c	Mon Jan 21 15:45:15 2002
@@ -1602,7 +1602,7 @@
 		case (PH_PULL | REQUEST):
 			if (!st->l1.bcs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -1637,7 +1637,7 @@
 			if (st->l1.bcs->cs->debug & L1_DEB_HSCX)
 				debugl1(st->l1.bcs->cs, "PDAC clear BC_FLG_BUSY");
 			modeisar(st->l1.bcs, 0, st->l1.bc);
-			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -1696,7 +1696,7 @@
 	if (open_isarstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l2.l2l1 = isar_l2l1;
+	st->l1.l2l1 = isar_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c
--- v2.5.2/linux/drivers/isdn/hisax/isdnl1.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/isdnl1.c	Mon Jan 21 15:45:15 2002
@@ -160,9 +160,9 @@
 	st = cs->stlist;
 	while (st) {
 		if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
-			st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+			L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
 		else
-			st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL);
+			L1L2(st, PH_ACTIVATE | INDICATION, NULL);
 		st = st->next;
 	}
 }
@@ -175,8 +175,8 @@
 	st = cs->stlist;
 	while (st) {
 		if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-			st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL);
-		st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, NULL);
+			L1L2(st, PH_PAUSE | CONFIRM, NULL);
+		L1L2(st, PH_DEACTIVATE | INDICATION, NULL);
 		st = st->next;
 	}
 	test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
@@ -193,7 +193,7 @@
 	stptr = cs->stlist;
 	while (stptr != NULL)
 		if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) {
-			stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL);
+			L1L2(stptr, PH_PULL | CONFIRM, NULL);
 			break;
 		} else
 			stptr = stptr->next;
@@ -235,7 +235,7 @@
 			if (sapi == CTRL_SAPI) { /* sapi 0 */
 				while (stptr != NULL) {
 					if ((nskb = skb_clone(skb, GFP_ATOMIC)))
-						stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb);
+						L1L2(stptr, PH_DATA | INDICATION, nskb);
 					else
 						printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
 					stptr = stptr->next;
@@ -254,7 +254,7 @@
 			found = 0;
 			while (stptr != NULL)
 				if (tei == stptr->l2.tei) {
-					stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb);
+					L1L2(stptr, PH_DATA | INDICATION, skb);
 					found = !0;
 					break;
 				} else
@@ -277,10 +277,10 @@
 	}
 
 	if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags))
-		st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+		L1L2(st, PH_PULL | CONFIRM, NULL);
 	if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) {
 		if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) {
-			st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
+			L2L1(st, PH_DEACTIVATE | CONFIRM, NULL);
 		}
 	}
 }
@@ -295,7 +295,7 @@
 		FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL);
 	}
 	while ((skb = skb_dequeue(&bcs->rqueue))) {
-		bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb);
+		L1L2(bcs->st, PH_DATA | INDICATION, skb);
 	}
 }
 
@@ -717,7 +717,7 @@
 	struct PStack *st = fi->userdata;
 
 	FsmChangeState(fi, ST_L1_ACTIV);
-	st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+	L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
 }
 
 static void
@@ -726,7 +726,7 @@
 	struct PStack *st = fi->userdata;
 
 	FsmChangeState(fi, ST_L1_NULL);
-	st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
+	L2L1(st, PH_DEACTIVATE | CONFIRM, NULL);
 }
 
 static struct FsmNode L1BFnList[] __initdata =
@@ -801,7 +801,7 @@
 				debugl1(cs, "PH_ACTIVATE_REQ %s",
 					st->l1.l1m.fsm->strState[st->l1.l1m.state]);
 			if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags))
-				st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+				L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
 			else {
 				test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
 				FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg);
@@ -897,7 +897,7 @@
 	setstack_tei(st);
 	setstack_manager(st);
 	st->l1.stlistp = &(cs->stlist);
-	st->l2.l2l1  = dch_l2l1;
+	st->l1.l2l1  = dch_l2l1;
 	if (cs->setstack_d)
 		cs->setstack_d(st, cs);
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c
--- v2.5.2/linux/drivers/isdn/hisax/isdnl2.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/isdnl2.c	Mon Jan 21 15:45:15 2002
@@ -27,14 +27,14 @@
 static struct Fsm l2fsm;
 
 enum {
-	ST_L2_1,
-	ST_L2_2,
-	ST_L2_3,
-	ST_L2_4,
-	ST_L2_5,
-	ST_L2_6,
-	ST_L2_7,
-	ST_L2_8,
+	ST_L2_1, /* TEI unassigned */
+	ST_L2_2, /* Assign awaiting TEI */
+	ST_L2_3, /* Establish awaiting TEI */
+	ST_L2_4, /* TEI assigned */
+	ST_L2_5, /* Awaiting establishment */
+	ST_L2_6, /* Awaiting release */
+	ST_L2_7, /* Multiple frame established */
+	ST_L2_8, /* Timer recovery */
 };
 
 #define L2_STATE_COUNT (ST_L2_8+1)
@@ -219,7 +219,7 @@
 {
 	if (test_bit(FLG_LAPB, &st->l2.flag))
 		st->l1.bcs->tx_cnt += skb->len;
-	st->l2.l2l1(st, PH_DATA | REQUEST, skb);
+	L2L1(st, PH_DATA | REQUEST, skb);
 }
 
 #define enqueue_ui(a, b) enqueue_super(a, b)
@@ -494,15 +494,15 @@
 		else
 			pr = DL_RELEASE | INDICATION;
 
-		st->l2.l2l3(st, pr, NULL);
+		L2L3(st, pr, NULL);
 }
 
 inline void
 lapb_dl_release_l2l3(struct PStack *st, int f)
 {
 		if (test_bit(FLG_LAPB, &st->l2.flag))
-			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
-		st->l2.l2l3(st, DL_RELEASE | f, NULL);
+			L2L1(st, PH_DEACTIVATE | REQUEST, NULL);
+		L2L3(st, DL_RELEASE | f, NULL);
 }
 
 static void
@@ -631,7 +631,7 @@
 	struct sk_buff *skb = arg;
 
 	skb_pull(skb, l2headersize(&st->l2, 1));
-	st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb);
+	L2L3(st, DL_UNIT_DATA | INDICATION, skb);
 /*	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  *		in states 1-3 for broadcast
  */
@@ -673,7 +673,7 @@
 {
 	struct PStack *st = fi->userdata;
 
-	st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+	L2L3(st, DL_RELEASE | CONFIRM, NULL);
 }
 
 static void
@@ -714,7 +714,7 @@
 	FsmChangeState(fi, ST_L2_7);
 	FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
 
-	st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
+	L2L3(st, DL_ESTABLISH | INDICATION, NULL);
 }
 
 static void
@@ -763,11 +763,11 @@
 	FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
 
 	if (est)
-		st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
+		L2L3(st, DL_ESTABLISH | INDICATION, NULL);
 
 	if ((ST_L2_7==state) || (ST_L2_8 == state))
 		if (skb_queue_len(&st->l2.i_queue) && cansend(st))
-			st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+			L2L1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -820,10 +820,10 @@
 	FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4);
 
 	if (pr != -1)
-		st->l2.l2l3(st, pr, NULL);
+		L2L3(st, pr, NULL);
 
 	if (skb_queue_len(&st->l2.i_queue) && cansend(st))
-		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+		L2L1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -866,7 +866,7 @@
 	 	if (!test_bit(FLG_L3_INIT, &st->l2.flag))
 			skb_queue_purge(&st->l2.i_queue);
 		if (test_bit(FLG_LAPB, &st->l2.flag))
-			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+			L2L1(st, PH_DEACTIVATE | REQUEST, NULL);
 		st5_dl_release_l2l3(st);
 		FsmChangeState(fi, ST_L2_4);
 	}
@@ -962,7 +962,7 @@
 			skb_queue_head(&l2->i_queue, l2->windowar[p1]);
 			l2->windowar[p1] = NULL;
 		}
-		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+		L2L1(st, PH_PULL | REQUEST, NULL);
 	}
 }
 
@@ -1022,7 +1022,7 @@
 			restart_t200(st, 12);
 		}
 		if (skb_queue_len(&st->l2.i_queue) && (typ == RR))
-			st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+			L2L1(st, PH_PULL | REQUEST, NULL);
 	} else
 		nrerrorrecovery(fi);
 }
@@ -1050,7 +1050,7 @@
 	if (test_bit(FLG_LAPB, &st->l2.flag))
 		st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
 	skb_queue_tail(&st->l2.i_queue, skb);
-	st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+	L2L1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -1099,7 +1099,7 @@
 		else
 			test_and_set_bit(FLG_ACK_PEND, &l2->flag);
 		skb_pull(skb, l2headersize(l2, 0));
-		st->l2.l2l3(st, DL_DATA | INDICATION, skb);
+		L2L3(st, DL_DATA | INDICATION, skb);
 	} else {
 		/* n(s)!=v(r) */
 		FreeSkb(skb);
@@ -1128,7 +1128,7 @@
 	}
 
 	if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7))
-		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+		L2L1(st, PH_PULL | REQUEST, NULL);
 	if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag))
 		enquiry_cr(st, RR, RSP, 0);
 }
@@ -1163,7 +1163,7 @@
 		skb_queue_purge(&st->l2.i_queue);
 		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G');
 		if (test_bit(FLG_LAPB, &st->l2.flag))
-			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+			L2L1(st, PH_DEACTIVATE | REQUEST, NULL);
 		st5_dl_release_l2l3(st);
 	} else {
 		st->l2.rc++;
@@ -1304,14 +1304,14 @@
 		memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len);
 		FreeSkb(oskb);
 	}
-	st->l2.l2l1(st, PH_PULL | INDICATION, skb);
+	L2L1(st, PH_PULL | INDICATION, skb);
 	test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
 	if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
 		FsmDelTimer(&st->l2.t203, 13);
 		FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11);
 	}
 	if (skb_queue_len(&l2->i_queue) && cansend(st))
-		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+		L2L1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -1357,7 +1357,7 @@
 			invoke_retransmission(st, nr);
 			FsmChangeState(fi, ST_L2_7);
 			if (skb_queue_len(&l2->i_queue) && cansend(st))
-				st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+				L2L1(st, PH_PULL | REQUEST, NULL);
 		} else
 			nrerrorrecovery(fi);
 	} else {
@@ -1404,7 +1404,7 @@
 
 	skb_queue_purge(&st->l2.ui_queue);
 	st->l2.tei = -1;
-	st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+	L2L3(st, DL_RELEASE | INDICATION, NULL);
 	FsmChangeState(fi, ST_L2_1);
 }
 
@@ -1430,7 +1430,7 @@
 	skb_queue_purge(&st->l2.ui_queue);
 	st->l2.tei = -1;
 	stop_t200(st, 18);
-	st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+	L2L3(st, DL_RELEASE | CONFIRM, NULL);
 	FsmChangeState(fi, ST_L2_1);
 }
 
@@ -1445,7 +1445,7 @@
 	st->l2.tei = -1;
 	stop_t200(st, 17);
 	FsmDelTimer(&st->l2.t203, 19);
-	st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+	L2L3(st, DL_RELEASE | INDICATION, NULL);
 	FsmChangeState(fi, ST_L2_1);
 }
 
@@ -1457,7 +1457,7 @@
 	skb_queue_purge(&st->l2.i_queue);
 	skb_queue_purge(&st->l2.ui_queue);
 	if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
-		st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+		L2L3(st, DL_RELEASE | INDICATION, NULL);
 }
 
 static void
@@ -1480,7 +1480,7 @@
 
 	skb_queue_purge(&st->l2.ui_queue);
 	stop_t200(st, 20);
-	st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+	L2L3(st, DL_RELEASE | CONFIRM, NULL);
 	FsmChangeState(fi, ST_L2_4);
 }
 
@@ -1494,7 +1494,7 @@
 	freewin(st);
 	stop_t200(st, 19);
 	FsmDelTimer(&st->l2.t203, 19);
-	st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+	L2L3(st, DL_RELEASE | INDICATION, NULL);
 	FsmChangeState(fi, ST_L2_4);
 }
 
@@ -1739,12 +1739,12 @@
 					test_bit(FLG_ORIG, &st->l2.flag)) {
 					test_and_set_bit(FLG_ESTAB_PEND, &st->l2.flag);
 				}
-				st->l2.l2l1(st, PH_ACTIVATE, NULL);
+				L2L1(st, PH_ACTIVATE, NULL);
 			}
 			break;
 		case (DL_RELEASE | REQUEST):
 			if (test_bit(FLG_LAPB, &st->l2.flag)) {
-				st->l2.l2l1(st, PH_DEACTIVATE, NULL);
+				L2L1(st, PH_DEACTIVATE, NULL);
 			}
 			FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE_REQ, arg);
 			break;
@@ -1784,8 +1784,8 @@
 void
 setstack_isdnl2(struct PStack *st, char *debug_id)
 {
-	st->l1.l1l2 = isdnl2_l1l2;
-	st->l3.l3l2 = isdnl2_l3l2;
+	st->l2.l1l2 = isdnl2_l1l2;
+	st->l2.l3l2 = isdnl2_l3l2;
 
 	skb_queue_head_init(&st->l2.i_queue);
 	skb_queue_head_init(&st->l2.ui_queue);
@@ -1813,13 +1813,13 @@
 	switch (pr) {
 		case (DL_DATA | REQUEST):
 		case (DL_UNIT_DATA | REQUEST):
-			st->l2.l2l1(st, PH_DATA | REQUEST, arg);
+			L2L1(st, PH_DATA | REQUEST, arg);
 			break;
 		case (DL_ESTABLISH | REQUEST):
-			st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
+			L2L1(st, PH_ACTIVATE | REQUEST, NULL);
 			break;
 		case (DL_RELEASE | REQUEST):
-			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+			L2L1(st, PH_DEACTIVATE | REQUEST, NULL);
 			break;
 	}
 }
@@ -1827,7 +1827,7 @@
 void
 setstack_transl2(struct PStack *st)
 {
-	st->l3.l3l2 = transl2_l3l2;
+	st->l2.l3l2 = transl2_l3l2;
 }
 
 void
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/isdnl2.h linux/drivers/isdn/hisax/isdnl2.h
--- v2.5.2/linux/drivers/isdn/hisax/isdnl2.h	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/isdnl2.h	Mon Jan 21 15:45:15 2002
@@ -23,3 +23,4 @@
 #define RSP    1
 
 #define LC_FLUSH_WAIT 1
+
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c
--- v2.5.2/linux/drivers/isdn/hisax/isdnl3.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/isdnl3.c	Mon Jan 21 15:45:15 2002
@@ -163,7 +163,7 @@
 static void
 L3ExpireTimer(struct L3Timer *t)
 {
-	t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc);
+	t->pc->st->l3.l4l3(t->pc->st, t->event, t->pc);
 }
 
 void
@@ -355,7 +355,7 @@
 	st->l3.l3m.printdebug = l3m_debug;
         FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer);
 	strcpy(st->l3.debug_id, "L3DC ");
-	st->lli.l4l3_proto = no_l3_proto_spec;
+	st->l3.l4l3_proto = no_l3_proto_spec;
 
 #ifdef	CONFIG_HISAX_EURO
 	if (st->protocol == ISDN_PTYPE_EURO) {
@@ -373,13 +373,13 @@
 	} else
 #endif
 	if (st->protocol == ISDN_PTYPE_LEASED) {
-		st->lli.l4l3 = no_l3_proto;
-		st->l2.l2l3 = no_l3_proto;
+		st->l3.l4l3 = no_l3_proto;
+		st->l3.l2l3 = no_l3_proto;
                 st->l3.l3ml3 = no_l3_proto;
 		printk(KERN_INFO "HiSax: Leased line mode\n");
 	} else {
-		st->lli.l4l3 = no_l3_proto;
-		st->l2.l2l3 = no_l3_proto;
+		st->l3.l4l3 = no_l3_proto;
+		st->l3.l2l3 = no_l3_proto;
                 st->l3.l3ml3 = no_l3_proto;
 		sprintf(tmp, "protocol %s not supported",
 			(st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
@@ -393,7 +393,7 @@
 
 void
 isdnl3_trans(struct PStack *st, int pr, void *arg) {
-	st->l3.l3l2(st, pr, arg);
+	L3L2(st, pr, arg);
 }
 
 void
@@ -424,7 +424,7 @@
 	st->l3.l3m.userint = 0;
 	st->l3.l3m.printdebug = l3m_debug;
 	strcpy(st->l3.debug_id, "L3BC ");
-	st->lli.l4l3 = isdnl3_trans;
+	st->l3.l4l3 = isdnl3_trans;
 }
 
 #define DREL_TIMER_VALUE 40000
@@ -435,7 +435,7 @@
 	struct PStack *st = fi->userdata;
 
 	FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
-	st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL);
+	L3L2(st, DL_ESTABLISH | REQUEST, NULL);
 }
 
 static void
@@ -447,7 +447,7 @@
 
 	FsmChangeState(fi, ST_L3_LC_ESTAB);
 	while ((skb = skb_dequeue(&st->l3.squeue))) {
-		st->l3.l3l2(st, DL_DATA | REQUEST, skb);
+		L3L2(st, DL_DATA | REQUEST, skb);
 		dequeued++;
 	}
 	if ((!st->l3.proc) &&  dequeued) {
@@ -468,7 +468,7 @@
 	FsmDelTimer(&st->l3.l3m_timer, 51);
 	FsmChangeState(fi, ST_L3_LC_ESTAB);
 	while ((skb = skb_dequeue(&st->l3.squeue))) {
-		st->l3.l3l2(st, DL_DATA | REQUEST, skb);
+		L3L2(st, DL_DATA | REQUEST, skb);
 		dequeued++;
 	}
 	if ((!st->l3.proc) &&  dequeued) {
@@ -512,7 +512,7 @@
 		FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
 	} else {
 		FsmChangeState(fi, ST_L3_LC_REL_WAIT);
-		st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
+		L3L2(st, DL_RELEASE | REQUEST, NULL);
 	}
 }
 
@@ -565,7 +565,7 @@
 	switch (pr) {
 		case (DL_DATA | REQUEST):
 			if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
-				st->l3.l3l2(st, pr, arg);
+				L3L2(st, pr, arg);
 			} else {
 				struct sk_buff *skb = arg;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/jade.c linux/drivers/isdn/hisax/jade.c
--- v2.5.2/linux/drivers/isdn/hisax/jade.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/jade.c	Mon Jan 21 15:45:15 2002
@@ -177,7 +177,7 @@
 	case (PH_PULL | REQUEST):
 		if (!st->l1.bcs->tx_skb) {
 		    test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-		    st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+		    L1L2(st, PH_PULL | CONFIRM, NULL);
 		} else
 		    test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 		break;
@@ -193,7 +193,7 @@
 		test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 		test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
 		modejade(st->l1.bcs, 0, st->l1.bc);
-		st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+		L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
 		break;
     }
 }
@@ -258,7 +258,7 @@
 	if (open_jadestate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l2.l2l1 = jade_l2l1;
+	st->l1.l2l1 = jade_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/l3_1tr6.c linux/drivers/isdn/hisax/l3_1tr6.c
--- v2.5.2/linux/drivers/isdn/hisax/l3_1tr6.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/l3_1tr6.c	Mon Jan 21 15:45:15 2002
@@ -223,7 +223,7 @@
 			l3_debug(pc->st, tmp);
 		}
 		newl3state(pc, 6);
-		pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
+		L3L4(pc->st, CC_SETUP | INDICATION, pc);
 	} else
 		release_l3_process(pc);
 }
@@ -253,7 +253,7 @@
 	}
 	dev_kfree_skb(skb);
 	L3AddTimer(&pc->timer, T304, CC_T304);
-	pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+	L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
 }
 
 static void
@@ -285,7 +285,7 @@
 	dev_kfree_skb(skb);
 	L3AddTimer(&pc->timer, T310, CC_T310);
 	newl3state(pc, 3);
-	pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
+	L3L4(pc->st, CC_PROCEEDING | INDICATION, pc);
 }
 
 static void
@@ -296,7 +296,7 @@
 	dev_kfree_skb(skb);
 	L3DelTimer(&pc->timer);	/* T304 */
 	newl3state(pc, 4);
-	pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
+	L3L4(pc->st, CC_ALERTING | INDICATION, pc);
 }
 
 static void
@@ -316,7 +316,7 @@
 		}
 		if (tmpcharge > pc->para.chargeinfo) {
 			pc->para.chargeinfo = tmpcharge;
-			pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
+			L3L4(pc->st, CC_CHARGE | INDICATION, pc);
 		}
 		if (pc->st->l3.debug & L3_DEB_CHARGE) {
 			sprintf(tmp, "charging info %d", pc->para.chargeinfo);
@@ -349,7 +349,7 @@
 	newl3state(pc, 10);
 	dev_kfree_skb(skb);
 	pc->para.chargeinfo = 0;
-	pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
+	L3L4(pc->st, CC_SETUP | CONFIRM, pc);
 }
 
 static void
@@ -379,7 +379,7 @@
 	StopAllL3Timer(pc);
 	newl3state(pc, 0);
 	l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1);
-	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
 	release_l3_process(pc);
 }
 
@@ -392,7 +392,7 @@
 	StopAllL3Timer(pc);
 	newl3state(pc, 0);
 	pc->para.cause = NO_CAUSE;
-	pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
+	L3L4(pc->st, CC_RELEASE | CONFIRM, pc);
 	release_l3_process(pc);
 }
 
@@ -414,7 +414,7 @@
 		}
 		if (tmpcharge > pc->para.chargeinfo) {
 			pc->para.chargeinfo = tmpcharge;
-			pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
+			L3L4(pc->st, CC_CHARGE | INDICATION, pc);
 		}
 		if (pc->st->l3.debug & L3_DEB_CHARGE) {
 			sprintf(tmp, "charging info %d", pc->para.chargeinfo);
@@ -447,7 +447,7 @@
 	}
 	dev_kfree_skb(skb);
 	newl3state(pc, 12);
-	pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
+	L3L4(pc->st, CC_DISCONNECT | INDICATION, pc);
 }
 
 
@@ -464,7 +464,7 @@
 	newl3state(pc, 10);
 	pc->para.chargeinfo = 0;
 	L3DelTimer(&pc->timer);
-	pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+	L3L4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
 }
 
 static void
@@ -573,7 +573,7 @@
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 0xE6;
 	l3_1tr6_disconnect_req(pc, pr, NULL);
-	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+	L3L4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
@@ -618,7 +618,7 @@
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 0xE6;
 	l3_1tr6_disconnect_req(pc, pr, NULL);
-	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+	L3L4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
@@ -627,7 +627,7 @@
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 0xE6;
 	l3_1tr6_disconnect_req(pc, pr, NULL);
-	pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
+	L3L4(pc->st, CC_CONNECT_ERR, pc);
 }
 
 static void
@@ -643,7 +643,7 @@
 l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
-	pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
+	L3L4(pc->st, CC_RELEASE_ERR, pc);
 	release_l3_process(pc);
 }
 
@@ -652,7 +652,7 @@
 {
         pc->para.cause = CAUSE_LocalProcErr;
         l3_1tr6_disconnect_req(pc, pr, NULL);
-        pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+        L3L4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
@@ -661,7 +661,7 @@
         newl3state(pc, 0);
         pc->para.cause = 0x1b;          /* Destination out of order */
         pc->para.loc = 0;
-        pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+        L3L4(pc->st, CC_RELEASE | INDICATION, pc);
         release_l3_process(pc);
 }
 
@@ -946,8 +946,8 @@
 {
 	char tmp[64];
 
-	st->lli.l4l3 = down1tr6;
-	st->l2.l2l3 = up1tr6;
+	st->l3.l4l3 = down1tr6;
+	st->l3.l2l3 = up1tr6;
 	st->l3.l3ml3 = man1tr6;
 	st->l3.N303 = 0;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c
--- v2.5.2/linux/drivers/isdn/hisax/l3dss1.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/l3dss1.c	Mon Jan 21 15:45:15 2002
@@ -449,7 +449,7 @@
                             pc->prot.dss1.remote_result = 0; /* success */     
                             pc->prot.dss1.invoke_id = 0;
                             pc->redir_result = pc->prot.dss1.remote_result; 
-                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successful */
+                            L3L4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successful */
                         else
                           l3_debug(st,"return error unknown identifier");
 			break;
@@ -494,7 +494,7 @@
                             pc->prot.dss1.remote_result = err_ret; /* result */
                             pc->prot.dss1.invoke_id = 0; 
                             pc->redir_result = pc->prot.dss1.remote_result; 
-                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);  
+                            L3L4(st, CC_REDIR | INDICATION, pc);  
                           } /* Deflection error */
                         else
                           l3_debug(st,"return result unknown identifier");
@@ -983,7 +983,7 @@
 		pc->para.cause = NO_CAUSE;
 	StopAllL3Timer(pc);
 	newl3state(pc, 0);
-	pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
+	L3L4(pc->st, CC_RELEASE | CONFIRM, pc);
 	dss1_release_l3_process(pc);
 }
 
@@ -1473,7 +1473,7 @@
 	L3AddTimer(&pc->timer, T310, CC_T310);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3dss1_std_ie_err(pc, ret);
-	pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
+	L3L4(pc->st, CC_PROCEEDING | INDICATION, pc);
 }
 
 static void
@@ -1512,7 +1512,7 @@
 	L3AddTimer(&pc->timer, T304, CC_T304);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3dss1_std_ie_err(pc, ret);
-	pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+	L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
 }
 
 static void
@@ -1544,7 +1544,7 @@
 	if (cause)
 		newl3state(pc, 19);
        	if (11 != ret)
-		pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
+		L3L4(pc->st, CC_DISCONNECT | INDICATION, pc);
        	else if (!cause)
 		   l3dss1_release_req(pc, pr, NULL);
 	if (cause) {
@@ -1570,7 +1570,7 @@
 	/* here should inserted COLP handling KKe */
 	if (ret)
 		l3dss1_std_ie_err(pc, ret);
-	pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
+	L3L4(pc->st, CC_SETUP | CONFIRM, pc);
 }
 
 static void
@@ -1588,7 +1588,7 @@
 	newl3state(pc, 4);
 	if (ret)
 		l3dss1_std_ie_err(pc, ret);
-	pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
+	L3L4(pc->st, CC_ALERTING | INDICATION, pc);
 }
 
 static void
@@ -1754,7 +1754,7 @@
 	newl3state(pc, 6);
 	if (err) /* STATUS for none mandatory IE errors after actions are taken */
 		l3dss1_std_ie_err(pc, err);
-	pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
+	L3L4(pc->st, CC_SETUP | INDICATION, pc);
 }
 
 static void
@@ -1833,7 +1833,7 @@
 	L3DelTimer(&pc->timer);
 	if (ret)
 		l3dss1_std_ie_err(pc, ret);
-	pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+	L3L4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
 }
 
 static void
@@ -1860,7 +1860,7 @@
 		return;
 	memcpy(skb_put(skb, l), tmp, l);
 	l3_msg(pc->st, DL_DATA | REQUEST, skb);
-	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
 	newl3state(pc, 0);
 	dss1_release_l3_process(pc);
 }
@@ -1894,7 +1894,7 @@
 		l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
 	else
 		l3dss1_message(pc, MT_RELEASE_COMPLETE);
-	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
 	newl3state(pc, 0);
 	dss1_release_l3_process(pc);
 }
@@ -1916,7 +1916,7 @@
 {
 	newl3state(pc, 9);
 	l3dss1_message(pc, MT_CALL_PROCEEDING);
-	pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); 
+	L3L4(pc->st, CC_PROCEED_SEND | INDICATION, pc); 
 }
 
 static void
@@ -2009,7 +2009,7 @@
 	if (err)
 		l3dss1_std_ie_err(pc, err);
 	if (ERR_IE_COMPREHENSION != err)
-		pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
+		L3L4(pc->st, CC_PROGRESS | INDICATION, pc);
 }
 
 static void
@@ -2050,7 +2050,7 @@
 	if (err)
 		l3dss1_std_ie_err(pc, err);
 	if (ERR_IE_COMPREHENSION != err)
-		pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
+		L3L4(pc->st, CC_NOTIFY | INDICATION, pc);
 }
 
 static void
@@ -2082,7 +2082,7 @@
 		if ((p = findie(p, skb->len, 0x70, 0))) {
 			iecpy(tmp, p, 1);
 			strcat(pc->para.setup.eazmsn, tmp);
-			pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+			L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
 		}
 		L3AddTimer(&pc->timer, T302, CC_T302);
 	}
@@ -2297,11 +2297,11 @@
 		/* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
 		 * set down layer 3 without sending any message
 		 */
-		pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+		L3L4(pc->st, CC_RELEASE | INDICATION, pc);
 		newl3state(pc, 0);
 		dss1_release_l3_process(pc);
 	} else {
-		pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
+		L3L4(pc->st, CC_IGNORE | INDICATION, pc);
 	}
 }
 
@@ -2317,7 +2317,7 @@
 	pc->para.loc = 0;
 	pc->para.cause = 28; /* invalid number */
 	l3dss1_disconnect_req(pc, pr, NULL);
-	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+	L3L4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
@@ -2330,7 +2330,7 @@
 	} else {
 		L3DelTimer(&pc->timer);
 		l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
-		pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
+		L3L4(pc->st, CC_NOSETUP_RSP, pc);
 		dss1_release_l3_process(pc);
 	}
 }
@@ -2342,7 +2342,7 @@
 	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3dss1_disconnect_req(pc, pr, NULL);
-	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+	L3L4(pc->st, CC_SETUP_ERR, pc);
 
 }
 
@@ -2382,7 +2382,7 @@
 	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3dss1_disconnect_req(pc, pr, NULL);
-	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+	L3L4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
@@ -2392,7 +2392,7 @@
 	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3dss1_disconnect_req(pc, pr, NULL);
-	pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
+	L3L4(pc->st, CC_CONNECT_ERR, pc);
 }
 
 static void
@@ -2408,7 +2408,7 @@
 l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
-	pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
+	L3L4(pc->st, CC_RELEASE_ERR, pc);
 	dss1_release_l3_process(pc);
 }
 
@@ -2418,7 +2418,7 @@
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 102;	/* Timer expiry */
 	pc->para.loc = 0;	/* local */
-	pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+	L3L4(pc->st, CC_RESUME_ERR, pc);
 	newl3state(pc, 19);
 	l3dss1_message(pc, MT_RELEASE);
 	L3AddTimer(&pc->timer, T308, CC_T308_1);
@@ -2430,7 +2430,7 @@
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 102;	/* Timer expiry */
 	pc->para.loc = 0;	/* local */
-	pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+	L3L4(pc->st, CC_SUSPEND_ERR, pc);
 	newl3state(pc, 10);
 }
 
@@ -2438,7 +2438,7 @@
 l3dss1_restart(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
-	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
 	dss1_release_l3_process(pc);
 }
 
@@ -2494,7 +2494,7 @@
 		 * if received MT_STATUS with cause == 111 and call
 		 * state == 0, then we must set down layer 3
 		 */
-		pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+		L3L4(pc->st, CC_RELEASE | INDICATION, pc);
 		newl3state(pc, 0);
 		dss1_release_l3_process(pc);
 	}
@@ -2553,7 +2553,7 @@
 	L3DelTimer(&pc->timer);
 	newl3state(pc, 0);
 	pc->para.cause = NO_CAUSE;
-	pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
+	L3L4(pc->st, CC_SUSPEND | CONFIRM, pc);
 	/* We don't handle suspend_ack for IE errors now */
 	if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
 		if (pc->debug & L3_DEB_WARN)
@@ -2583,7 +2583,7 @@
 		return;
 	}
 	L3DelTimer(&pc->timer);
-	pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+	L3L4(pc->st, CC_SUSPEND_ERR, pc);
 	newl3state(pc, 10);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3dss1_std_ie_err(pc, ret);
@@ -2647,7 +2647,7 @@
 		return;
 	}
 	L3DelTimer(&pc->timer);
-	pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
+	L3L4(pc->st, CC_RESUME | CONFIRM, pc);
 	newl3state(pc, 10);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3dss1_std_ie_err(pc, ret);
@@ -2675,7 +2675,7 @@
 		return;
 	}
 	L3DelTimer(&pc->timer);
-	pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+	L3L4(pc->st, CC_RESUME_ERR, pc);
 	newl3state(pc, 0);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3dss1_std_ie_err(pc, ret);
@@ -2713,9 +2713,9 @@
 	up = pc->st->l3.proc;
 	while (up) {
 		if ((ri & 7) == 7)
-			up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+			L4L3(up->st, CC_RESTART | REQUEST, up);
 		else if (up->para.bchannel == chan)
-			up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+			L4L3(up->st, CC_RESTART | REQUEST, up);
 		up = up->next;
 	}
 	p = tmp;
@@ -2742,7 +2742,7 @@
         pc->para.cause = 0x29;          /* Temporary failure */
         pc->para.loc = 0;
         l3dss1_disconnect_req(pc, pr, NULL);
-        pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+        L3L4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
@@ -2751,7 +2751,7 @@
         newl3state(pc, 0);
         pc->para.cause = 0x1b;          /* Destination out of order */
         pc->para.loc = 0;
-        pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+        L3L4(pc->st, CC_RELEASE | INDICATION, pc);
         release_l3_process(pc);
 }
 
@@ -3219,9 +3219,9 @@
 	char tmp[64];
 	int i;
 
-	st->lli.l4l3 = dss1down;
-	st->lli.l4l3_proto = l3dss1_cmd_global;
-	st->l2.l2l3 = dss1up;
+	st->l3.l4l3 = dss1down;
+	st->l3.l4l3_proto = l3dss1_cmd_global;
+	st->l3.l2l3 = dss1up;
 	st->l3.l3ml3 = dss1man;
 	st->l3.N303 = 1;
 	st->prot.dss1.last_invoke_id = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/l3ni1.c linux/drivers/isdn/hisax/l3ni1.c
--- v2.5.2/linux/drivers/isdn/hisax/l3ni1.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/l3ni1.c	Mon Jan 21 15:45:15 2002
@@ -377,7 +377,7 @@
                             pc->prot.ni1.remote_result = 0; /* success */     
                             pc->prot.ni1.invoke_id = 0;
                             pc->redir_result = pc->prot.ni1.remote_result; 
-                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successful */
+                            L3L4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successful */
                         else
                           l3_debug(st,"return error unknown identifier");
 			break;
@@ -422,7 +422,7 @@
                             pc->prot.ni1.remote_result = err_ret; /* result */
                             pc->prot.ni1.invoke_id = 0; 
                             pc->redir_result = pc->prot.ni1.remote_result; 
-                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);  
+                            L3L4(st, CC_REDIR | INDICATION, pc);  
                           } /* Deflection error */
                         else
                           l3_debug(st,"return result unknown identifier");
@@ -932,7 +932,7 @@
 		pc->para.cause = NO_CAUSE;
 	StopAllL3Timer(pc);
 	newl3state(pc, 0);
-	pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
+	L3L4(pc->st, CC_RELEASE | CONFIRM, pc);
 	ni1_release_l3_process(pc);
 }
 
@@ -1326,7 +1326,7 @@
 	L3AddTimer(&pc->timer, T310, CC_T310);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3ni1_std_ie_err(pc, ret);
-	pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
+	L3L4(pc->st, CC_PROCEEDING | INDICATION, pc);
 }
 
 static void
@@ -1365,7 +1365,7 @@
 	L3AddTimer(&pc->timer, T304, CC_T304);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3ni1_std_ie_err(pc, ret);
-	pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+	L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
 }
 
 static void
@@ -1397,7 +1397,7 @@
 	if (cause)
 		newl3state(pc, 19);
        	if (11 != ret)
-		pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
+		L3L4(pc->st, CC_DISCONNECT | INDICATION, pc);
        	else if (!cause)
 		   l3ni1_release_req(pc, pr, NULL);
 	if (cause) {
@@ -1423,7 +1423,7 @@
 	/* here should inserted COLP handling KKe */
 	if (ret)
 		l3ni1_std_ie_err(pc, ret);
-	pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
+	L3L4(pc->st, CC_SETUP | CONFIRM, pc);
 }
 
 static void
@@ -1441,7 +1441,7 @@
 	newl3state(pc, 4);
 	if (ret)
 		l3ni1_std_ie_err(pc, ret);
-	pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
+	L3L4(pc->st, CC_ALERTING | INDICATION, pc);
 }
 
 static void
@@ -1607,7 +1607,7 @@
 	newl3state(pc, 6);
 	if (err) /* STATUS for none mandatory IE errors after actions are taken */
 		l3ni1_std_ie_err(pc, err);
-	pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
+	L3L4(pc->st, CC_SETUP | INDICATION, pc);
 }
 
 static void
@@ -1688,7 +1688,7 @@
 	L3DelTimer(&pc->timer);
 	if (ret)
 		l3ni1_std_ie_err(pc, ret);
-	pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+	L3L4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
 }
 
 static void
@@ -1715,7 +1715,7 @@
 		return;
 	memcpy(skb_put(skb, l), tmp, l);
 	l3_msg(pc->st, DL_DATA | REQUEST, skb);
-	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
 	newl3state(pc, 0);
 	ni1_release_l3_process(pc);
 }
@@ -1749,7 +1749,7 @@
 		l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
 	else
 		l3ni1_message(pc, MT_RELEASE_COMPLETE);
-	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
 	newl3state(pc, 0);
 	ni1_release_l3_process(pc);
 }
@@ -1771,7 +1771,7 @@
 {
 	newl3state(pc, 9);
 	l3ni1_message(pc, MT_CALL_PROCEEDING);
-	pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); 
+	L3L4(pc->st, CC_PROCEED_SEND | INDICATION, pc); 
 }
 
 static void
@@ -1864,7 +1864,7 @@
 	if (err)
 		l3ni1_std_ie_err(pc, err);
 	if (ERR_IE_COMPREHENSION != err)
-		pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
+		L3L4(pc->st, CC_PROGRESS | INDICATION, pc);
 }
 
 static void
@@ -1905,7 +1905,7 @@
 	if (err)
 		l3ni1_std_ie_err(pc, err);
 	if (ERR_IE_COMPREHENSION != err)
-		pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
+		L3L4(pc->st, CC_NOTIFY | INDICATION, pc);
 }
 
 static void
@@ -1937,7 +1937,7 @@
 		if ((p = findie(p, skb->len, 0x70, 0))) {
 			iecpy(tmp, p, 1);
 			strcat(pc->para.setup.eazmsn, tmp);
-			pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+			L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
 		}
 		L3AddTimer(&pc->timer, T302, CC_T302);
 	}
@@ -2152,11 +2152,11 @@
 		/* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
 		 * set down layer 3 without sending any message
 		 */
-		pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+		L3L4(pc->st, CC_RELEASE | INDICATION, pc);
 		newl3state(pc, 0);
 		ni1_release_l3_process(pc);
 	} else {
-		pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
+		L3L4(pc->st, CC_IGNORE | INDICATION, pc);
 	}
 }
 
@@ -2172,7 +2172,7 @@
 	pc->para.loc = 0;
 	pc->para.cause = 28; /* invalid number */
 	l3ni1_disconnect_req(pc, pr, NULL);
-	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+	L3L4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
@@ -2185,7 +2185,7 @@
 	} else {
 		L3DelTimer(&pc->timer);
 		l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
-		pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
+		L3L4(pc->st, CC_NOSETUP_RSP, pc);
 		ni1_release_l3_process(pc);
 	}
 }
@@ -2197,7 +2197,7 @@
 	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3ni1_disconnect_req(pc, pr, NULL);
-	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+	L3L4(pc->st, CC_SETUP_ERR, pc);
 
 }
 
@@ -2237,7 +2237,7 @@
 	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3ni1_disconnect_req(pc, pr, NULL);
-	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+	L3L4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
@@ -2247,7 +2247,7 @@
 	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3ni1_disconnect_req(pc, pr, NULL);
-	pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
+	L3L4(pc->st, CC_CONNECT_ERR, pc);
 }
 
 static void
@@ -2263,7 +2263,7 @@
 l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
-	pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
+	L3L4(pc->st, CC_RELEASE_ERR, pc);
 	ni1_release_l3_process(pc);
 }
 
@@ -2273,7 +2273,7 @@
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 102;	/* Timer expiry */
 	pc->para.loc = 0;	/* local */
-	pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+	L3L4(pc->st, CC_RESUME_ERR, pc);
 	newl3state(pc, 19);
 	l3ni1_message(pc, MT_RELEASE);
 	L3AddTimer(&pc->timer, T308, CC_T308_1);
@@ -2285,7 +2285,7 @@
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 102;	/* Timer expiry */
 	pc->para.loc = 0;	/* local */
-	pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+	L3L4(pc->st, CC_SUSPEND_ERR, pc);
 	newl3state(pc, 10);
 }
 
@@ -2293,7 +2293,7 @@
 l3ni1_restart(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
-	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
 	ni1_release_l3_process(pc);
 }
 
@@ -2349,7 +2349,7 @@
 		 * if received MT_STATUS with cause == 111 and call
 		 * state == 0, then we must set down layer 3
 		 */
-		pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+		L3L4(pc->st, CC_RELEASE | INDICATION, pc);
 		newl3state(pc, 0);
 		ni1_release_l3_process(pc);
 	}
@@ -2408,7 +2408,7 @@
 	L3DelTimer(&pc->timer);
 	newl3state(pc, 0);
 	pc->para.cause = NO_CAUSE;
-	pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
+	L3L4(pc->st, CC_SUSPEND | CONFIRM, pc);
 	/* We don't handle suspend_ack for IE errors now */
 	if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
 		if (pc->debug & L3_DEB_WARN)
@@ -2438,7 +2438,7 @@
 		return;
 	}
 	L3DelTimer(&pc->timer);
-	pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+	L3L4(pc->st, CC_SUSPEND_ERR, pc);
 	newl3state(pc, 10);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3ni1_std_ie_err(pc, ret);
@@ -2502,7 +2502,7 @@
 		return;
 	}
 	L3DelTimer(&pc->timer);
-	pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
+	L3L4(pc->st, CC_RESUME | CONFIRM, pc);
 	newl3state(pc, 10);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3ni1_std_ie_err(pc, ret);
@@ -2530,7 +2530,7 @@
 		return;
 	}
 	L3DelTimer(&pc->timer);
-	pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+	L3L4(pc->st, CC_RESUME_ERR, pc);
 	newl3state(pc, 0);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3ni1_std_ie_err(pc, ret);
@@ -2568,9 +2568,9 @@
 	up = pc->st->l3.proc;
 	while (up) {
 		if ((ri & 7) == 7)
-			up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+			L4L3(up->st, CC_RESTART | REQUEST, up);
 		else if (up->para.bchannel == chan)
-			up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+			L4L3(up->st, CC_RESTART | REQUEST, up);
 		
 		up = up->next;
 	}
@@ -2598,7 +2598,7 @@
         pc->para.cause = 0x29;          /* Temporary failure */
         pc->para.loc = 0;
         l3ni1_disconnect_req(pc, pr, NULL);
-        pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+        L3L4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
@@ -2607,7 +2607,7 @@
         newl3state(pc, 0);
         pc->para.cause = 0x1b;          /* Destination out of order */
         pc->para.loc = 0;
-        pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+        L3L4(pc->st, CC_RELEASE | INDICATION, pc);
         release_l3_process(pc);
 }
 
@@ -2642,7 +2642,7 @@
 	{
 		printk( KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn );
 		newl3state( pc, 0 );
-		pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL );
+		L3L2( pc->st, DL_RELEASE | REQUEST, NULL );
 		return;
 	}
 
@@ -2667,7 +2667,7 @@
 	L3DelTimer( &pc->timer );
 	L3AddTimer( &pc->timer, TSPID, CC_TSPID );
 
-	pc->st->l3.l3l2( pc->st, DL_DATA | REQUEST, skb );
+	L3L2( pc->st, DL_DATA | REQUEST, skb );
 }
 
 static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg )
@@ -2700,7 +2700,7 @@
 
 		printk( KERN_ERR "SPID not accepted\n" );
 		newl3state( pc, 0 );
-		pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL );
+		L3L2( pc->st, DL_RELEASE | REQUEST, NULL );
 	}
 }
 
@@ -3170,9 +3170,9 @@
 	char tmp[64];
 	int i;
 
-	st->lli.l4l3 = ni1down;
-	st->lli.l4l3_proto = l3ni1_cmd_global;
-	st->l2.l2l3 = ni1up;
+	st->l3.l4l3 = ni1down;
+	st->l3.l4l3_proto = l3ni1_cmd_global;
+	st->l3.l2l3 = ni1up;
 	st->l3.l3ml3 = ni1man;
 	st->l3.N303 = 1;
 	st->prot.ni1.last_invoke_id = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c
--- v2.5.2/linux/drivers/isdn/hisax/netjet.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/hisax/netjet.c	Mon Jan 21 15:45:15 2002
@@ -847,7 +847,7 @@
 		case (PH_PULL | REQUEST):
 			if (!st->l1.bcs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -863,7 +863,7 @@
 			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
 			mode_tiger(st->l1.bcs, 0, st->l1.bc);
-			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -924,7 +924,7 @@
 	if (open_tigerstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l2.l2l1 = tiger_l2l1;
+	st->l1.l2l1 = tiger_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/st5481.h linux/drivers/isdn/hisax/st5481.h
--- v2.5.2/linux/drivers/isdn/hisax/st5481.h	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/hisax/st5481.h	Mon Jan 21 15:44:21 2002
@@ -478,7 +478,7 @@
   if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb)
 
 static void __attribute__((unused))
-dump_iso_packet(const char *name,urb_t *urb)
+dump_iso_packet(const char *name, struct urb *urb)
 {
 	int i,j;
 	int len,ofs;
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/st5481_d.c linux/drivers/isdn/hisax/st5481_d.c
--- v2.5.2/linux/drivers/isdn/hisax/st5481_d.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/isdn/hisax/st5481_d.c	Mon Jan 21 15:44:21 2002
@@ -297,7 +297,7 @@
 	unsigned int num_packets, packet_offset;
 	int len, buf_size, bytes_sent;
 	struct sk_buff *skb;
-	iso_packet_descriptor_t *desc;
+	struct usb_iso_packet_descriptor *desc;
 
 	if (d_out->fsm.state != ST_DOUT_NORMAL)
 		return;
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/st5481_usb.c linux/drivers/isdn/hisax/st5481_usb.c
--- v2.5.2/linux/drivers/isdn/hisax/st5481_usb.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/hisax/st5481_usb.c	Mon Jan 21 15:44:21 2002
@@ -235,7 +235,7 @@
 	struct usb_interface_descriptor *altsetting;
 	struct usb_endpoint_descriptor *endpoint;
 	int status;
-	urb_t *urb;
+	struct urb *urb;
 	u_char *buf;
 	
 	DBG(1,"");
@@ -560,7 +560,7 @@
  */
 int st5481_isoc_flatten(struct urb *urb)
 {
-	iso_packet_descriptor_t *pipd,*pend;
+	struct usb_iso_packet_descriptor *pipd,*pend;
 	unsigned char *src,*dst;
 	unsigned int len;
 	
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/tei.c linux/drivers/isdn/hisax/tei.c
--- v2.5.2/linux/drivers/isdn/hisax/tei.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/hisax/tei.c	Mon Jan 21 15:45:15 2002
@@ -120,7 +120,7 @@
 	bp[2] = ri & 0xff;
 	bp[3] = m_id;
 	bp[4] = (tei << 1) | 1;
-	st->l2.l2l1(st, PH_DATA | REQUEST, skb);
+	L2L1(st, PH_DATA | REQUEST, skb);
 }
 
 static void
@@ -166,7 +166,7 @@
 	} else if (ri == st->ma.ri) {
 		FsmDelTimer(&st->ma.t202, 1);
 		FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
-		st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei);
+		L3L2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei);
 		cs = (struct IsdnCardState *) st->l1.hardware;
 		cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
 	}
@@ -240,7 +240,7 @@
 	if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
 		FsmDelTimer(&st->ma.t202, 5);
 		FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
-		st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0);
+		L3L2(st, MDL_REMOVE | REQUEST, 0);
 		cs = (struct IsdnCardState *) st->l1.hardware;
 		cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
 	}
@@ -276,7 +276,7 @@
 		FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3);
 	} else {
 		st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed");
-		st->l3.l3l2(st, MDL_ERROR | RESPONSE, 0);
+		L3L2(st, MDL_ERROR | RESPONSE, 0);
 		cs = (struct IsdnCardState *) st->l1.hardware;
 		cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
 		FsmChangeState(fi, ST_TEI_NOP);
@@ -299,7 +299,7 @@
 	} else {
 		st->ma.tei_m.printdebug(&st->ma.tei_m,
 			"verify req for tei %d failed", st->l2.tei);
-		st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0);
+		L3L2(st, MDL_REMOVE | REQUEST, 0);
 		cs = (struct IsdnCardState *) st->l1.hardware;
 		cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
 		FsmChangeState(fi, ST_TEI_NOP);
@@ -372,7 +372,7 @@
 			if (st->ma.debug)
 				st->ma.tei_m.printdebug(&st->ma.tei_m,
 					"fixed assign tei %d", st->l2.tei);
-			st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei);
+			L3L2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei);
 			cs = (struct IsdnCardState *) st->l1.hardware;
 			cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/hisax/w6692.c linux/drivers/isdn/hisax/w6692.c
--- v2.5.2/linux/drivers/isdn/hisax/w6692.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/hisax/w6692.c	Mon Jan 21 15:45:15 2002
@@ -108,7 +108,7 @@
 			debugl1(cs, "D-Channel Busy cleared");
 		stptr = cs->stlist;
 		while (stptr != NULL) {
-			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
+			L1L2(stptr, PH_PAUSE | CONFIRM, NULL);
 			stptr = stptr->next;
 		}
 	}
@@ -614,7 +614,7 @@
 #endif
 			if (!cs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -687,7 +687,7 @@
 			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 			stptr = cs->stlist;
 			while (stptr != NULL) {
-				stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+				L1L2(stptr, PH_PAUSE | INDICATION, NULL);
 				stptr = stptr->next;
 			}
 		} else {
@@ -772,7 +772,7 @@
 		case (PH_PULL | REQUEST):
 			if (!st->l1.bcs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+				L1L2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
@@ -788,7 +788,7 @@
 			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
 			W6692Bmode(st->l1.bcs, 0, st->l1.bc);
-			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -852,7 +852,7 @@
 	if (open_w6692state(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l2.l2l1 = W6692_l2l1;
+	st->l1.l2l1 = W6692_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- v2.5.2/linux/drivers/isdn/isdn_common.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/isdn_common.c	Sun Jan 27 11:33:38 2002
@@ -65,7 +65,6 @@
 #endif /* CONFIG_ISDN_DIVERSION */
 
 
-static int isdn_writebuf_stub(int, int, const u_char *, int, int);
 static void set_global_features(void);
 static void isdn_register_devfs(int);
 static void isdn_unregister_devfs(int);
@@ -946,7 +945,9 @@
 	return istatbuf;
 }
 
-/* Module interface-code */
+/* 
+ * /dev/isdninfo
+ */
 
 void
 isdn_info_update(void)
@@ -960,234 +961,321 @@
 	wake_up_interruptible(&(dev->info_waitq));
 }
 
+static int
+isdn_status_open(struct inode *ino, struct file *filep)
+{
+	infostruct *p;
+	
+	p = kmalloc(sizeof(infostruct), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	p->next = (char *) dev->infochain;
+	p->private = (char *) &(filep->private_data);
+	dev->infochain = p;
+	/* At opening we allow a single update */
+	filep->private_data = (char *) 1;
+
+	return 0;
+}
+
+static int
+isdn_status_release(struct inode *ino, struct file *filep)
+{
+	infostruct *p = dev->infochain;
+	infostruct *q = NULL;
+	
+	lock_kernel();
+
+	while (p) {
+		if (p->private == (char *) &(filep->private_data)) {
+			if (q)
+				q->next = p->next;
+			else
+				dev->infochain = (infostruct *) (p->next);
+			kfree(p);
+			goto out;
+		}
+		q = p;
+		p = (infostruct *) (p->next);
+	}
+	printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
+
+ out:
+	unlock_kernel();
+	return 0;
+}
+
 static ssize_t
-isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
+isdn_status_read(struct file *file, char *buf, size_t count, loff_t * off)
 {
-	uint minor = minor(file->f_dentry->d_inode->i_rdev);
-	int len = 0;
-	ulong flags;
-	int drvidx;
-	int chidx;
 	int retval;
+	int len = 0;
 	char *p;
 
 	if (off != &file->f_pos)
 		return -ESPIPE;
 
 	lock_kernel();
-	if (minor == ISDN_MINOR_STATUS) {
-		if (!file->private_data) {
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				goto out;
-			}
-			interruptible_sleep_on(&(dev->info_waitq));
-		}
-		p = isdn_statstr();
-		file->private_data = 0;
-		if ((len = strlen(p)) <= count) {
-			if (copy_to_user(buf, p, len)) {
-				retval = -EFAULT;
-				goto out;
-			}
-			*off += len;
-			retval = len;
+	if (!file->private_data) {
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
 			goto out;
 		}
-		retval = 0;
-		goto out;
-	}
-	if (!dev->drivers) {
-		retval = -ENODEV;
-		goto out;
-	}
-	if (minor <= ISDN_MINOR_BMAX) {
-		printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
-		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0) {
-			retval = -ENODEV;
-			goto out;
-		}
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
-			retval = -ENODEV;
-			goto out;
-		}
-		chidx = isdn_minor2chan(minor);
-		if (!(p = kmalloc(count, GFP_KERNEL))) {
-			retval = -ENOMEM;
-			goto out;
-		}
-		save_flags(flags);
-		cli();
-		len = isdn_readbchan(drvidx, chidx, p, 0, count,
-				     &dev->drv[drvidx]->rcv_waitq[chidx]);
-		*off += len;
-		restore_flags(flags);
-		if (copy_to_user(buf,p,len)) 
-			len = -EFAULT;
-		kfree(p);
-		retval = len;
-		goto out;
+		interruptible_sleep_on(&(dev->info_waitq));
 	}
-	if (minor <= ISDN_MINOR_CTRLMAX) {
-		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0) {
-			retval = -ENODEV;
+	p = isdn_statstr();
+	file->private_data = 0;
+	if ((len = strlen(p)) <= count) {
+		if (copy_to_user(buf, p, len)) {
+			retval = -EFAULT;
 			goto out;
 		}
-		if (!dev->drv[drvidx]->stavail) {
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				goto out;
-			}
-			interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
-		}
-		if (dev->drv[drvidx]->interface->readstat) {
-			if (count > dev->drv[drvidx]->stavail)
-				count = dev->drv[drvidx]->stavail;
-			len = dev->drv[drvidx]->interface->
-				readstat(buf, count, 1, drvidx,
-					 isdn_minor2chan(minor));
-		} else {
-			len = 0;
-		}
-		save_flags(flags);
-		cli();
-		if (len)
-			dev->drv[drvidx]->stavail -= len;
-		else
-			dev->drv[drvidx]->stavail = 0;
-		restore_flags(flags);
 		*off += len;
 		retval = len;
 		goto out;
 	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX) {
-		retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
-		goto out;
-	}
-#endif
-	retval = -ENODEV;
+	retval = 0;
+	goto out;
+
  out:
 	unlock_kernel();
 	return retval;
 }
 
 static ssize_t
-isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
+isdn_status_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+	return -EPERM;
+}
+
+static unsigned int
+isdn_status_poll(struct file *file, poll_table *wait)
+{
+	unsigned int mask = 0;
+
+	lock_kernel();
+
+	poll_wait(file, &(dev->info_waitq), wait);
+	if (file->private_data)
+		mask |= POLLIN | POLLRDNORM;
+
+	unlock_kernel();
+	return mask;
+}
+
+static int
+isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+	int ret;
+	union iocpar {
+		char name[10];
+		char bname[22];
+		isdn_ioctl_struct iocts;
+		isdn_net_ioctl_phone phone;
+		isdn_net_ioctl_cfg cfg;
+	} iocpar;
+
+#define name  iocpar.name
+#define bname iocpar.bname
+#define iocts iocpar.iocts
+#define phone iocpar.phone
+#define cfg   iocpar.cfg
+
+	switch (cmd) {
+	case IIOCGETDVR:
+		return (TTY_DV +
+			(NET_DV << 8) +
+			(INF_DV << 16));
+	case IIOCGETCPS:
+		if (arg) {
+			ulong *p = (ulong *) arg;
+			int i;
+			if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					       sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
+				return ret;
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+				put_user(dev->ibytes[i], p++);
+				put_user(dev->obytes[i], p++);
+			}
+			return 0;
+		} else
+			return -EINVAL;
+		break;
+#ifdef CONFIG_NETDEVICES
+	case IIOCNETGPN:
+		/* Get peer phone number of a connected 
+		 * isdn network interface */
+		if (arg) {
+			if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+				return -EFAULT;
+			return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
+		} else
+			return -EINVAL;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+#undef name
+#undef bname
+#undef iocts
+#undef phone
+#undef cfg
+}
+
+static struct file_operations isdn_status_fops =
+{
+	owner:		THIS_MODULE,
+	llseek:		no_llseek,
+	read:		isdn_status_read,
+	write:		isdn_status_write,
+	poll:		isdn_status_poll,
+	ioctl:		isdn_status_ioctl,
+	open:		isdn_status_open,
+	release:	isdn_status_release,
+};
+
+/*
+ * /dev/isdnctrlX
+ */
+
+static int
+isdn_ctrl_open(struct inode *ino, struct file *filep)
+{
+	uint minor = minor(ino->i_rdev);
+	int drvidx;
+
+	drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	if (drvidx < 0)
+		return -ENODEV;
+
+	isdn_lock_drivers();
+	return 0;
+}
+
+static int
+isdn_ctrl_release(struct inode *ino, struct file *filep)
+{
+	lock_kernel();
+
+	if (dev->profd == current)
+		dev->profd = NULL;
+
+	isdn_unlock_drivers();
+
+	unlock_kernel();
+	return 0;
+}
+
+static ssize_t
+isdn_ctrl_read(struct file *file, char *buf, size_t count, loff_t * off)
 {
 	uint minor = minor(file->f_dentry->d_inode->i_rdev);
+	ulong flags;
+	int len = 0;
 	int drvidx;
-	int chidx;
 	int retval;
 
 	if (off != &file->f_pos)
 		return -ESPIPE;
 
-	if (minor == ISDN_MINOR_STATUS)
-		return -EPERM;
-	if (!dev->drivers)
-		return -ENODEV;
-
 	lock_kernel();
-	if (minor <= ISDN_MINOR_BMAX) {
-		printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
-		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0) {
-			retval = -ENODEV;
-			goto out;
-		}
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
-			retval = -ENODEV;
-			goto out;
-		}
-		chidx = isdn_minor2chan(minor);
-		while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
-			interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
-		retval = count;
+
+	drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	if (drvidx < 0) {
+		retval = -ENODEV;
 		goto out;
 	}
-	if (minor <= ISDN_MINOR_CTRLMAX) {
-		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0) {
-			retval = -ENODEV;
+	if (!dev->drv[drvidx]->stavail) {
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
 			goto out;
 		}
-		/*
-		 * We want to use the isdnctrl device to load the firmware
-		 *
-		 if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-		 return -ENODEV;
-		 */
-		if (dev->drv[drvidx]->interface->writecmd)
-			retval = dev->drv[drvidx]->interface->
-				writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor));
-		else
-			retval = count;
-		goto out;
+		interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
 	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX) {
-		retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
-		goto out;
+	if (dev->drv[drvidx]->interface->readstat) {
+		if (count > dev->drv[drvidx]->stavail)
+			count = dev->drv[drvidx]->stavail;
+		len = dev->drv[drvidx]->interface->
+			readstat(buf, count, 1, drvidx,
+				 isdn_minor2chan(minor));
+	} else {
+		len = 0;
 	}
-#endif
-	retval = -ENODEV;
+	save_flags(flags);
+	cli();
+	if (len)
+		dev->drv[drvidx]->stavail -= len;
+	else
+		dev->drv[drvidx]->stavail = 0;
+	restore_flags(flags);
+	*off += len;
+	retval = len;
+	
  out:
 	unlock_kernel();
 	return retval;
 }
 
-static unsigned int
-isdn_poll(struct file *file, poll_table * wait)
+static ssize_t
+isdn_ctrl_write(struct file *file, const char *buf, size_t count, loff_t *off)
 {
-	unsigned int mask = 0;
-	unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
-	int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	uint minor = minor(file->f_dentry->d_inode->i_rdev);
+	int drvidx;
+	int retval;
+
+	if (off != &file->f_pos)
+		return -ESPIPE;
 
 	lock_kernel();
-	if (minor == ISDN_MINOR_STATUS) {
-		poll_wait(file, &(dev->info_waitq), wait);
-		/* mask = POLLOUT | POLLWRNORM; */
-		if (file->private_data) {
-			mask |= POLLIN | POLLRDNORM;
-		}
+
+	drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	if (drvidx < 0) {
+		retval = -ENODEV;
 		goto out;
 	}
-	if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
-		if (drvidx < 0) {
-			/* driver deregistered while file open */
-			mask = POLLHUP;
-			goto out;
-		}
-		poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
-		mask = POLLOUT | POLLWRNORM;
-		if (dev->drv[drvidx]->stavail) {
-			mask |= POLLIN | POLLRDNORM;
-		}
+	if (!dev->drv[drvidx]->interface->writecmd) {
+		retval = -EINVAL;
 		goto out;
 	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX) {
-		mask = isdn_ppp_poll(file, wait);
-		goto out;
-	}
-#endif
-	mask = POLLERR;
+	retval = dev->drv[drvidx]->interface->
+		writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL));
+
  out:
 	unlock_kernel();
+	return retval;
+}
+
+static unsigned int
+isdn_ctrl_poll(struct file *file, poll_table *wait)
+{
+	unsigned int mask = 0;
+	unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
+	int drvidx;
+
+	drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	if (drvidx < 0)
+		/* driver deregistered while file open */
+		return POLLHUP;
+
+	lock_kernel();
+
+	poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
+	mask = POLLOUT | POLLWRNORM;
+	if (dev->drv[drvidx]->stavail)
+		mask |= POLLIN | POLLRDNORM;
+
+	unlock_kernel();
 	return mask;
 }
 
 
 static int
-isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 {
-	uint minor = minor(inode->i_rdev);
 	isdn_ctrl c;
 	int drvidx;
-	int chidx;
 	int ret;
 	int i;
 	char *p;
@@ -1205,55 +1293,6 @@
 #define iocts iocpar.iocts
 #define phone iocpar.phone
 #define cfg   iocpar.cfg
-
-	if (minor == ISDN_MINOR_STATUS) {
-		switch (cmd) {
-			case IIOCGETDVR:
-				return (TTY_DV +
-					(NET_DV << 8) +
-					(INF_DV << 16));
-			case IIOCGETCPS:
-				if (arg) {
-					ulong *p = (ulong *) arg;
-					int i;
-					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-							       sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
-						return ret;
-					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-						put_user(dev->ibytes[i], p++);
-						put_user(dev->obytes[i], p++);
-					}
-					return 0;
-				} else
-					return -EINVAL;
-				break;
-#ifdef CONFIG_NETDEVICES
-			case IIOCNETGPN:
-				/* Get peer phone number of a connected 
-				 * isdn network interface */
-				if (arg) {
-					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-						return -EFAULT;
-					return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
-				} else
-					return -EINVAL;
-#endif
-			default:
-				return -EINVAL;
-		}
-	}
-	if (!dev->drivers)
-		return -ENODEV;
-	if (minor <= ISDN_MINOR_BMAX) {
-		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0)
-			return -ENODEV;
-		chidx = isdn_minor2chan(minor);
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-			return -ENODEV;
-		return 0;
-	}
-	if (minor <= ISDN_MINOR_CTRLMAX) {
 /*
  * isdn net devices manage lots of configuration variables as linked lists.
  * Those lists must only be manipulated from user space. Some of the ioctl's
@@ -1261,366 +1300,360 @@
  * manipulating the lists and ioctl's sleeping while accessing the lists
  * are serialized by means of a semaphore.
  */
-		switch (cmd) {
-			case IIOCNETDWRSET:
-				printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
-				return(-EINVAL);
-			case IIOCNETLCR:
-				printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
-				return -ENODEV;
+	switch (cmd) {
+	case IIOCNETDWRSET:
+		printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
+		return(-EINVAL);
+	case IIOCNETLCR:
+		printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
+		return -ENODEV;
 #ifdef CONFIG_NETDEVICES
-			case IIOCNETAIF:
-				/* Add a network-interface */
-				if (arg) {
-					if (copy_from_user(name, (char *) arg, sizeof(name)))
-						return -EFAULT;
-					s = name;
-				} else {
-					s = NULL;
-				}
-				ret = down_interruptible(&dev->sem);
-				if( ret ) return ret;
-				if ((s = isdn_net_new(s, NULL))) {
-					if (copy_to_user((char *) arg, s, strlen(s) + 1)){
-						ret = -EFAULT;
-					} else {
-						ret = 0;
+	case IIOCNETAIF:
+		/* Add a network-interface */
+		if (arg) {
+			if (copy_from_user(name, (char *) arg, sizeof(name)))
+				return -EFAULT;
+			s = name;
+		} else {
+			s = NULL;
+		}
+		ret = down_interruptible(&dev->sem);
+		if( ret ) return ret;
+		if ((s = isdn_net_new(s, NULL))) {
+			if (copy_to_user((char *) arg, s, strlen(s) + 1)){
+				ret = -EFAULT;
+			} else {
+				ret = 0;
+			}
+		} else
+			ret = -ENODEV;
+		up(&dev->sem);
+		return ret;
+	case IIOCNETASL:
+		/* Add a slave to a network-interface */
+		if (arg) {
+			if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
+				return -EFAULT;
+		} else
+			return -EINVAL;
+		ret = down_interruptible(&dev->sem);
+		if( ret ) return ret;
+		if ((s = isdn_net_newslave(bname))) {
+			if (copy_to_user((char *) arg, s, strlen(s) + 1)){
+				ret = -EFAULT;
+			} else {
+				ret = 0;
+			}
+		} else
+			ret = -ENODEV;
+		up(&dev->sem);
+		return ret;
+	case IIOCNETDIF:
+		/* Delete a network-interface */
+		if (arg) {
+			if (copy_from_user(name, (char *) arg, sizeof(name)))
+				return -EFAULT;
+			ret = down_interruptible(&dev->sem);
+			if( ret ) return ret;
+			ret = isdn_net_rm(name);
+			up(&dev->sem);
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETSCF:
+		/* Set configurable parameters of a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+				return -EFAULT;
+			return isdn_net_setcfg(&cfg);
+		} else
+			return -EINVAL;
+	case IIOCNETGCF:
+		/* Get configurable parameters of a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+				return -EFAULT;
+			if (!(ret = isdn_net_getcfg(&cfg))) {
+				if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
+					return -EFAULT;
+			}
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETANM:
+		/* Add a phone-number to a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+				return -EFAULT;
+			ret = down_interruptible(&dev->sem);
+			if( ret ) return ret;
+			ret = isdn_net_addphone(&phone);
+			up(&dev->sem);
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETGNM:
+		/* Get list of phone-numbers of a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+				return -EFAULT;
+			ret = down_interruptible(&dev->sem);
+			if( ret ) return ret;
+			ret = isdn_net_getphones(&phone, (char *) arg);
+			up(&dev->sem);
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETDNM:
+		/* Delete a phone-number of a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+				return -EFAULT;
+			ret = down_interruptible(&dev->sem);
+			if( ret ) return ret;
+			ret = isdn_net_delphone(&phone);
+			up(&dev->sem);
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETDIL:
+		/* Force dialing of a network-interface */
+		if (arg) {
+			if (copy_from_user(name, (char *) arg, sizeof(name)))
+				return -EFAULT;
+			return isdn_net_force_dial(name);
+		} else
+			return -EINVAL;
+#ifdef CONFIG_ISDN_PPP
+	case IIOCNETALN:
+		if (!arg)
+			return -EINVAL;
+		if (copy_from_user(name, (char *) arg, sizeof(name)))
+			return -EFAULT;
+		return isdn_ppp_dial_slave(name);
+	case IIOCNETDLN:
+		if (!arg)
+			return -EINVAL;
+		if (copy_from_user(name, (char *) arg, sizeof(name)))
+			return -EFAULT;
+		return isdn_ppp_hangup_slave(name);
+#endif
+	case IIOCNETHUP:
+		/* Force hangup of a network-interface */
+		if (!arg)
+			return -EINVAL;
+		if (copy_from_user(name, (char *) arg, sizeof(name)))
+			return -EFAULT;
+		return isdn_net_force_hangup(name);
+		break;
+#endif                          /* CONFIG_NETDEVICES */
+	case IIOCSETVER:
+		dev->net_verbose = arg;
+		printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
+		return 0;
+	case IIOCSETGST:
+		if (arg)
+			dev->global_flags |= ISDN_GLOBAL_STOPPED;
+		else
+			dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
+		printk(KERN_INFO "isdn: Global Mode %s\n",
+		       (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
+		return 0;
+	case IIOCSETBRJ:
+		drvidx = -1;
+		if (arg) {
+			int i;
+			char *p;
+			if (copy_from_user((char *) &iocts, (char *) arg,
+					   sizeof(isdn_ioctl_struct)))
+				return -EFAULT;
+			if (strlen(iocts.drvid)) {
+				if ((p = strchr(iocts.drvid, ',')))
+					*p = 0;
+				drvidx = -1;
+				for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+					if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+						drvidx = i;
+						break;
 					}
-				} else
-					ret = -ENODEV;
-				up(&dev->sem);
+			}
+		}
+		if (drvidx == -1)
+			return -ENODEV;
+		if (iocts.arg)
+			dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
+		else
+			dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
+		return 0;
+	case IIOCSIGPRF:
+		dev->profd = current;
+		return 0;
+		break;
+	case IIOCGETPRF:
+		/* Get all Modem-Profiles */
+		if (arg) {
+			char *p = (char *) arg;
+			int i;
+
+			if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					       (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+					       * ISDN_MAX_CHANNELS)))
 				return ret;
-			case IIOCNETASL:
-				/* Add a slave to a network-interface */
-				if (arg) {
-					if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
-						return -EFAULT;
-				} else
-					return -EINVAL;
-				ret = down_interruptible(&dev->sem);
-				if( ret ) return ret;
-				if ((s = isdn_net_newslave(bname))) {
-					if (copy_to_user((char *) arg, s, strlen(s) + 1)){
-						ret = -EFAULT;
-					} else {
-						ret = 0;
-					}
-				} else
-					ret = -ENODEV;
-				up(&dev->sem);
+
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+				if (copy_to_user(p, dev->mdm.info[i].emu.profile,
+						 ISDN_MODEM_NUMREG))
+					return -EFAULT;
+				p += ISDN_MODEM_NUMREG;
+				if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
+					return -EFAULT;
+				p += ISDN_MSNLEN;
+				if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
+					return -EFAULT;
+				p += ISDN_LMSNLEN;
+			}
+			return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
+		} else
+			return -EINVAL;
+		break;
+	case IIOCSETPRF:
+		/* Set all Modem-Profiles */
+		if (arg) {
+			char *p = (char *) arg;
+			int i;
+
+			if ((ret = verify_area(VERIFY_READ, (void *) arg,
+					       (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+					       * ISDN_MAX_CHANNELS)))
 				return ret;
-			case IIOCNETDIF:
-				/* Delete a network-interface */
-				if (arg) {
-					if (copy_from_user(name, (char *) arg, sizeof(name)))
-						return -EFAULT;
-					ret = down_interruptible(&dev->sem);
-					if( ret ) return ret;
-					ret = isdn_net_rm(name);
-					up(&dev->sem);
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETSCF:
-				/* Set configurable parameters of a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
-						return -EFAULT;
-					return isdn_net_setcfg(&cfg);
-				} else
-					return -EINVAL;
-			case IIOCNETGCF:
-				/* Get configurable parameters of a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
-						return -EFAULT;
-					if (!(ret = isdn_net_getcfg(&cfg))) {
-						if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
-							return -EFAULT;
-					}
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETANM:
-				/* Add a phone-number to a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-						return -EFAULT;
-					ret = down_interruptible(&dev->sem);
-					if( ret ) return ret;
-					ret = isdn_net_addphone(&phone);
-					up(&dev->sem);
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETGNM:
-				/* Get list of phone-numbers of a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-						return -EFAULT;
-					ret = down_interruptible(&dev->sem);
-					if( ret ) return ret;
-					ret = isdn_net_getphones(&phone, (char *) arg);
-					up(&dev->sem);
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETDNM:
-				/* Delete a phone-number of a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-						return -EFAULT;
-					ret = down_interruptible(&dev->sem);
-					if( ret ) return ret;
-					ret = isdn_net_delphone(&phone);
-					up(&dev->sem);
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETDIL:
-				/* Force dialing of a network-interface */
-				if (arg) {
-					if (copy_from_user(name, (char *) arg, sizeof(name)))
-						return -EFAULT;
-					return isdn_net_force_dial(name);
-				} else
-					return -EINVAL;
-#ifdef CONFIG_ISDN_PPP
-			case IIOCNETALN:
-				if (!arg)
-					return -EINVAL;
-				if (copy_from_user(name, (char *) arg, sizeof(name)))
+
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+				if (copy_from_user(dev->mdm.info[i].emu.profile, p,
+						   ISDN_MODEM_NUMREG))
 					return -EFAULT;
-				return isdn_ppp_dial_slave(name);
-			case IIOCNETDLN:
-				if (!arg)
-					return -EINVAL;
-				if (copy_from_user(name, (char *) arg, sizeof(name)))
+				p += ISDN_MODEM_NUMREG;
+				if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
 					return -EFAULT;
-				return isdn_ppp_hangup_slave(name);
-#endif
-			case IIOCNETHUP:
-				/* Force hangup of a network-interface */
-				if (!arg)
-					return -EINVAL;
-				if (copy_from_user(name, (char *) arg, sizeof(name)))
+				p += ISDN_LMSNLEN;
+				if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
 					return -EFAULT;
-				return isdn_net_force_hangup(name);
-				break;
-#endif                          /* CONFIG_NETDEVICES */
-			case IIOCSETVER:
-				dev->net_verbose = arg;
-				printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
-				return 0;
-			case IIOCSETGST:
-				if (arg)
-					dev->global_flags |= ISDN_GLOBAL_STOPPED;
-				else
-					dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
-				printk(KERN_INFO "isdn: Global Mode %s\n",
-				       (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
-				return 0;
-			case IIOCSETBRJ:
+				p += ISDN_MSNLEN;
+			}
+			return 0;
+		} else
+			return -EINVAL;
+		break;
+	case IIOCSETMAP:
+	case IIOCGETMAP:
+		/* Set/Get MSN->EAZ-Mapping for a driver */
+		if (arg) {
+
+			if (copy_from_user((char *) &iocts,
+					   (char *) arg,
+					   sizeof(isdn_ioctl_struct)))
+				return -EFAULT;
+			if (strlen(iocts.drvid)) {
 				drvidx = -1;
-				if (arg) {
-					int i;
-					char *p;
-					if (copy_from_user((char *) &iocts, (char *) arg,
-					     sizeof(isdn_ioctl_struct)))
-						return -EFAULT;
-					if (strlen(iocts.drvid)) {
-						if ((p = strchr(iocts.drvid, ',')))
-							*p = 0;
-						drvidx = -1;
-						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-								drvidx = i;
-								break;
-							}
-					}
-				}
-				if (drvidx == -1)
-					return -ENODEV;
-				if (iocts.arg)
-					dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
-				else
-					dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
-				return 0;
-			case IIOCSIGPRF:
-				dev->profd = current;
-				return 0;
-				break;
-			case IIOCGETPRF:
-				/* Get all Modem-Profiles */
-				if (arg) {
-					char *p = (char *) arg;
-					int i;
-
-					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-					(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
-						   * ISDN_MAX_CHANNELS)))
-						return ret;
-
-					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-						if (copy_to_user(p, dev->mdm.info[i].emu.profile,
-						      ISDN_MODEM_NUMREG))
-							return -EFAULT;
-						p += ISDN_MODEM_NUMREG;
-						if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
-							return -EFAULT;
-						p += ISDN_MSNLEN;
-						if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
-							return -EFAULT;
-						p += ISDN_LMSNLEN;
-					}
-					return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
-				} else
-					return -EINVAL;
-				break;
-			case IIOCSETPRF:
-				/* Set all Modem-Profiles */
-				if (arg) {
-					char *p = (char *) arg;
-					int i;
-
-					if ((ret = verify_area(VERIFY_READ, (void *) arg,
-					(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
-						   * ISDN_MAX_CHANNELS)))
-						return ret;
-
-					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-						if (copy_from_user(dev->mdm.info[i].emu.profile, p,
-						     ISDN_MODEM_NUMREG))
-							return -EFAULT;
-						p += ISDN_MODEM_NUMREG;
-						if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
-							return -EFAULT;
-						p += ISDN_LMSNLEN;
-						if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
-							return -EFAULT;
-						p += ISDN_MSNLEN;
+				for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+					if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+						drvidx = i;
+						break;
 					}
-					return 0;
-				} else
-					return -EINVAL;
-				break;
-			case IIOCSETMAP:
-			case IIOCGETMAP:
-				/* Set/Get MSN->EAZ-Mapping for a driver */
-				if (arg) {
-
-					if (copy_from_user((char *) &iocts,
-							    (char *) arg,
-					     sizeof(isdn_ioctl_struct)))
-						return -EFAULT;
-					if (strlen(iocts.drvid)) {
-						drvidx = -1;
-						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-								drvidx = i;
-								break;
-							}
-					} else
-						drvidx = 0;
-					if (drvidx == -1)
-						return -ENODEV;
-					if (cmd == IIOCSETMAP) {
-						int loop = 1;
-
-						p = (char *) iocts.arg;
-						i = 0;
-						while (loop) {
-							int j = 0;
-
-							while (1) {
-								if ((ret = verify_area(VERIFY_READ, p, 1)))
-									return ret;
-								get_user(bname[j], p++);
-								switch (bname[j]) {
-									case '\0':
-										loop = 0;
-										/* Fall through */
-									case ',':
-										bname[j] = '\0';
-										strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
-										j = ISDN_MSNLEN;
-										break;
-									default:
-										j++;
-								}
-								if (j >= ISDN_MSNLEN)
-									break;
-							}
-							if (++i > 9)
-								break;
-						}
-					} else {
-						p = (char *) iocts.arg;
-						for (i = 0; i < 10; i++) {
-							sprintf(bname, "%s%s",
-								strlen(dev->drv[drvidx]->msn2eaz[i]) ?
-								dev->drv[drvidx]->msn2eaz[i] : "_",
-								(i < 9) ? "," : "\0");
-							if (copy_to_user(p, bname, strlen(bname) + 1))
-								return -EFAULT;
-							p += strlen(bname);
+			} else
+				drvidx = 0;
+			if (drvidx == -1)
+				return -ENODEV;
+			if (cmd == IIOCSETMAP) {
+				int loop = 1;
+
+				p = (char *) iocts.arg;
+				i = 0;
+				while (loop) {
+					int j = 0;
+
+					while (1) {
+						if ((ret = verify_area(VERIFY_READ, p, 1)))
+							return ret;
+						get_user(bname[j], p++);
+						switch (bname[j]) {
+						case '\0':
+							loop = 0;
+							/* Fall through */
+						case ',':
+							bname[j] = '\0';
+							strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
+							j = ISDN_MSNLEN;
+							break;
+						default:
+							j++;
 						}
+						if (j >= ISDN_MSNLEN)
+							break;
 					}
-					return 0;
-				} else
-					return -EINVAL;
-			case IIOCDBGVAR:
-				if (arg) {
-					if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))
-						return -EFAULT;
-					return 0;
-				} else
-					return -EINVAL;
-				break;
-			default:
-				if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
-					cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
-				else
-					return -EINVAL;
-				if (arg) {
-					int i;
-					char *p;
-					if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
-						return -EFAULT;
-					if (strlen(iocts.drvid)) {
-						if ((p = strchr(iocts.drvid, ',')))
-							*p = 0;
-						drvidx = -1;
-						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-								drvidx = i;
-								break;
-							}
-					} else
-						drvidx = 0;
-					if (drvidx == -1)
-						return -ENODEV;
-					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-					     sizeof(isdn_ioctl_struct))))
-						return ret;
-					c.driver = drvidx;
-					c.command = ISDN_CMD_IOCTL;
-					c.arg = cmd;
-					memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
-					ret = isdn_command(&c);
-					memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
-					if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
+					if (++i > 9)
+						break;
+				}
+			} else {
+				p = (char *) iocts.arg;
+				for (i = 0; i < 10; i++) {
+					sprintf(bname, "%s%s",
+						strlen(dev->drv[drvidx]->msn2eaz[i]) ?
+						dev->drv[drvidx]->msn2eaz[i] : "_",
+						(i < 9) ? "," : "\0");
+					if (copy_to_user(p, bname, strlen(bname) + 1))
 						return -EFAULT;
-					return ret;
-				} else
-					return -EINVAL;
-		}
+					p += strlen(bname);
+				}
+			}
+			return 0;
+		} else
+			return -EINVAL;
+	case IIOCDBGVAR:
+		if (arg) {
+			if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EINVAL;
+		break;
+	default:
+		if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
+			cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
+		else
+			return -EINVAL;
+		if (arg) {
+			int i;
+			char *p;
+			if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
+				return -EFAULT;
+			if (strlen(iocts.drvid)) {
+				if ((p = strchr(iocts.drvid, ',')))
+					*p = 0;
+				drvidx = -1;
+				for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+					if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+						drvidx = i;
+						break;
+					}
+			} else
+				drvidx = 0;
+			if (drvidx == -1)
+				return -ENODEV;
+			if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					       sizeof(isdn_ioctl_struct))))
+				return ret;
+			c.driver = drvidx;
+			c.command = ISDN_CMD_IOCTL;
+			c.arg = cmd;
+			memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
+			ret = isdn_command(&c);
+			memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
+			if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
+				return -EFAULT;
+			return ret;
+		} else
+			return -EINVAL;
 	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX)
-		return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
-#endif
-	return -ENODEV;
 
 #undef name
 #undef bname
@@ -1629,123 +1662,62 @@
 #undef cfg
 }
 
+static struct file_operations isdn_ctrl_fops =
+{
+	owner:		THIS_MODULE,
+	llseek:		no_llseek,
+	read:		isdn_ctrl_read,
+	write:		isdn_ctrl_write,
+	poll:		isdn_ctrl_poll,
+	ioctl:		isdn_ctrl_ioctl,
+	open:		isdn_ctrl_open,
+	release:	isdn_ctrl_release,
+};
+
 /*
- * Open the device code.
+ * file_operations for major 43, /dev/isdn*
+ * stolen from drivers/char/misc.c
  */
+
 static int
-isdn_open(struct inode *ino, struct file *filep)
+isdn_open(struct inode * inode, struct file * file)
 {
-	uint minor = minor(ino->i_rdev);
-	int drvidx;
-	int chidx;
-	int retval = -ENODEV;
-
-
-	if (minor == ISDN_MINOR_STATUS) {
-		infostruct *p;
-
-		if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) {
-			p->next = (char *) dev->infochain;
-			p->private = (char *) &(filep->private_data);
-			dev->infochain = p;
-			/* At opening we allow a single update */
-			filep->private_data = (char *) 1;
-			retval = 0;
-			goto out;
-		} else {
-			retval = -ENOMEM;
-			goto out;
-		}
-	}
-	if (!dev->channels)
-		goto out;
-	if (minor <= ISDN_MINOR_BMAX) {
-		printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
-		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0)
-			goto out;
-		chidx = isdn_minor2chan(minor);
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-			goto out;
-		if (!(dev->drv[drvidx]->online & (1 << chidx)))
-			goto out;
-		isdn_lock_drivers();
-		retval = 0;
-		goto out;
-	}
-	if (minor <= ISDN_MINOR_CTRLMAX) {
-		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0)
-			goto out;
-		isdn_lock_drivers();
-		retval = 0;
-		goto out;
-	}
+	int minor = minor(inode->i_rdev);
+	int err = -ENODEV;
+	struct file_operations *old_fops, *new_fops = NULL;
+	
+	if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX)
+		new_fops = fops_get(&isdn_ctrl_fops);
 #ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX) {
-		retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
-		if (retval == 0)
-			isdn_lock_drivers();
-		goto out;
-	}
+	else if (minor >= ISDN_MINOR_PPP && minor <= ISDN_MINOR_PPPMAX)
+		new_fops = fops_get(&isdn_ppp_fops);
 #endif
- out:
-	return retval;
-}
+	else if (minor == ISDN_MINOR_STATUS)
+		new_fops = fops_get(&isdn_status_fops);
 
-static int
-isdn_close(struct inode *ino, struct file *filep)
-{
-	uint minor = minor(ino->i_rdev);
+	if (!new_fops)
+		goto out;
 
-	lock_kernel();
-	if (minor == ISDN_MINOR_STATUS) {
-		infostruct *p = dev->infochain;
-		infostruct *q = NULL;
-
-		while (p) {
-			if (p->private == (char *) &(filep->private_data)) {
-				if (q)
-					q->next = p->next;
-				else
-					dev->infochain = (infostruct *) (p->next);
-				kfree(p);
-				goto out;
-			}
-			q = p;
-			p = (infostruct *) (p->next);
+	err = 0;
+	old_fops = file->f_op;
+	file->f_op = new_fops;
+	if (file->f_op->open) {
+		err = file->f_op->open(inode,file);
+		if (err) {
+			fops_put(file->f_op);
+			file->f_op = fops_get(old_fops);
 		}
-		printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
-		goto out;
 	}
-	isdn_unlock_drivers();
-	if (minor <= ISDN_MINOR_BMAX)
-		goto out;
-	if (minor <= ISDN_MINOR_CTRLMAX) {
-		if (dev->profd == current)
-			dev->profd = NULL;
-		goto out;
-	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX)
-		isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
-#endif
-
+	fops_put(old_fops);
+	
  out:
-	unlock_kernel();
-	return 0;
+	return err;
 }
 
 static struct file_operations isdn_fops =
 {
 	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		isdn_read,
-	write:		isdn_write,
-	poll:		isdn_poll,
-	ioctl:		isdn_ioctl,
 	open:		isdn_open,
-	release:	isdn_close,
 };
 
 char *
@@ -1878,32 +1850,6 @@
 }
 
 /*
- *  writebuf replacement for SKB_ABLE drivers
- */
-static int
-isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
-		   int user)
-{
-	int ret;
-	int hl = dev->drv[drvidx]->interface->hl_hdrlen;
-	struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
-
-	if (!skb)
-		return 0;
-	skb_reserve(skb, hl);
-	if (user)
-		copy_from_user(skb_put(skb, len), buf, len);
-	else
-		memcpy(skb_put(skb, len), buf, len);
-	ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
-	if (ret <= 0)
-		dev_kfree_skb(skb);
-	if (ret > 0)
-		dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
-	return ret;
-}
-
-/*
  * Return: length of data on success, -ERRcode on failure.
  */
 int
@@ -2223,11 +2169,6 @@
 {
 	char buf[11];
 
-	sprintf (buf, "isdn%d", k);
-	dev->devfs_handle_isdnX[k] =
-	    devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT,
-			    ISDN_MAJOR, ISDN_MINOR_B + k,0600 | S_IFCHR,
-			    &isdn_fops, NULL);
 	sprintf (buf, "isdnctrl%d", k);
 	dev->devfs_handle_isdnctrlX[k] =
 	    devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT,
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h
--- v2.5.2/linux/drivers/isdn/isdn_common.h	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/isdn_common.h	Thu Jan 17 14:04:15 2002
@@ -27,6 +27,8 @@
 /* Prototypes */
 extern void isdn_MOD_INC_USE_COUNT(void);
 extern void isdn_MOD_DEC_USE_COUNT(void);
+extern void isdn_lock_drivers(void);
+extern void isdn_unlock_drivers(void);
 extern void isdn_free_channel(int di, int ch, int usage);
 extern void isdn_all_eaz(int di, int ch);
 extern int isdn_command(isdn_ctrl *);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- v2.5.2/linux/drivers/isdn/isdn_ppp.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/isdn_ppp.c	Mon Jan 21 15:45:15 2002
@@ -9,8 +9,9 @@
  *
  */
 
-#include <linux/config.h>
+#include <linux/module.h>
 #include <linux/isdn.h>
+#include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/ppp-comp.h>
 
@@ -268,22 +269,20 @@
  * isdn_ppp_open
  */
 
-int
-isdn_ppp_open(int min, struct file *file)
+static int
+isdn_ppp_open(struct inode *ino, struct file *file)
 {
+	uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
 	int slot;
 	struct ippp_struct *is;
 
-	if (min < 0 || min > ISDN_MAX_CHANNELS)
-		return -ENODEV;
-
 	slot = isdn_ppp_get_slot();
 	if (slot < 0) {
 		return -EBUSY;
 	}
 	is = file->private_data = ippp_table[slot];
 
-		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
+		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state);
 
 	/* compression stuff */
 	is->link_compressor   = is->compressor = NULL;
@@ -306,7 +305,7 @@
 	init_waitqueue_head(&is->wq);
 	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */
 	is->last = is->rq;
-	is->minor = min;
+	is->minor = minor;
 #ifdef CONFIG_ISDN_PPP_VJ
 	/*
 	 * VJ header compression init
@@ -315,6 +314,7 @@
 #endif
 
 	is->state = IPPP_OPEN;
+	isdn_lock_drivers();
 
 	return 0;
 }
@@ -322,18 +322,19 @@
 /*
  * release ippp device
  */
-void
-isdn_ppp_release(int min, struct file *file)
+static int
+isdn_ppp_release(struct inode *ino, struct file *file)
 {
+	uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
 	int i;
 	struct ippp_struct *is;
 
-	if (min < 0 || min >= ISDN_MAX_CHANNELS)
-		return;
+	lock_kernel();
+
 	is = file->private_data;
 
 	if (is->debug & 0x1)
-		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
+		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) is->lp);
 
 	if (is->lp) {           /* a lp address says: this link is still up */
 		isdn_net_dev *p = is->lp->netdev;
@@ -381,6 +382,11 @@
 
 	/* this slot is ready for new connections */
 	is->state = 0;
+
+	isdn_unlock_drivers();
+	
+	unlock_kernel();
+	return 0;
 }
 
 /*
@@ -412,8 +418,8 @@
 /*
  * ippp device ioctl
  */
-int
-isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
+static int
+isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	unsigned long val;
 	int r,i,j;
@@ -425,7 +431,7 @@
 	lp = is->lp;
 
 	if (is->debug & 0x1)
-		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
+		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", is->minor, cmd, is->state);
 
 	if (!(is->state & IPPP_OPEN))
 		return -EINVAL;
@@ -438,7 +444,7 @@
 			if ((r = get_arg((void *) arg, &val, sizeof(val) )))
 				return r;
 			printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
-			       (int) min, (int) is->unit, (int) val);
+			       (int) is->minor, (int) is->unit, (int) val);
 			return isdn_ppp_bundle(is, val);
 #else
 			return -1;
@@ -573,7 +579,7 @@
 	return 0;
 }
 
-unsigned int
+static unsigned int
 isdn_ppp_poll(struct file *file, poll_table * wait)
 {
 	unsigned int mask;
@@ -582,6 +588,7 @@
 	unsigned long flags;
 	struct ippp_struct *is;
 
+	lock_kernel();
 	is = file->private_data;
 
 	if (is->debug & 0x2)
@@ -592,10 +599,13 @@
 	poll_wait(file, &is->wq, wait);
 
 	if (!(is->state & IPPP_OPEN)) {
-		if(is->state == IPPP_CLOSEWAIT)
-			return POLLHUP;
+		if(is->state == IPPP_CLOSEWAIT) {
+			mask = POLLHUP;
+			goto out;
+		}
 		printk(KERN_DEBUG "isdn_ppp: device not open\n");
-		return POLLERR;
+		mask = POLLERR;
+		goto out;
 	}
 	/* we're always ready to send .. */
 	mask = POLLOUT | POLLWRNORM;
@@ -612,6 +622,9 @@
 		mask |= POLLIN | POLLRDNORM;
 	}
 	restore_flags(flags);
+
+ out:
+	unlock_kernel();
 	return mask;
 }
 
@@ -677,22 +690,29 @@
  *           reports, that there is data
  */
 
-int
-isdn_ppp_read(int min, struct file *file, char *buf, int count)
+static int
+isdn_ppp_read(struct file *file, char *buf, size_t count, loff_t *off)
 {
 	struct ippp_struct *is;
 	struct ippp_buf_queue *b;
-	int r;
 	unsigned long flags;
 	unsigned char *save_buf;
+	int retval;
 
-	is = file->private_data;
+	if (off != &file->f_pos)
+		return -ESPIPE;
+	
+	lock_kernel();
 
-	if (!(is->state & IPPP_OPEN))
-		return 0;
+	is = file->private_data;
 
-	if ((r = verify_area(VERIFY_WRITE, (void *) buf, count)))
-		return r;
+	if (!(is->state & IPPP_OPEN)) {
+		retval = 0;
+		goto out;
+	}
+	retval = verify_area(VERIFY_WRITE, (void *) buf, count);
+	if (retval)
+		goto out;
 
 	save_flags(flags);
 	cli();
@@ -701,7 +721,8 @@
 	save_buf = b->buf;
 	if (!save_buf) {
 		restore_flags(flags);
-		return -EAGAIN;
+		retval = -EAGAIN;
+		goto out;
 	}
 	if (b->len < count)
 		count = b->len;
@@ -713,25 +734,37 @@
 	copy_to_user(buf, save_buf, count);
 	kfree(save_buf);
 
-	return count;
+	retval = count;
+
+ out:
+	unlock_kernel();
+	return retval;
 }
 
 /*
  * ipppd wanna write a packet to the card .. non-blocking
  */
 
-int
-isdn_ppp_write(int min, struct file *file, const char *buf, int count)
+static int
+isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off)
 {
 	isdn_net_local *lp;
 	struct ippp_struct *is;
 	int proto;
 	unsigned char protobuf[4];
+	int retval;
+
+	if (off != &file->f_pos)
+		return -ESPIPE;
+
+	lock_kernel();
 
 	is = file->private_data;
 
-	if (!(is->state & IPPP_CONNECT))
-		return 0;
+	if (!(is->state & IPPP_CONNECT)) {
+		retval = 0;
+		goto out;
+	}
 
 	lp = is->lp;
 
@@ -744,15 +777,18 @@
 		 * Don't reset huptimer for
 		 * LCP packets. (Echo requests).
 		 */
-		if (copy_from_user(protobuf, buf, 4))
-			return -EFAULT;
+		if (copy_from_user(protobuf, buf, 4)) {
+			retval = -EFAULT;
+			goto out;
+		}
 		proto = PPP_PROTOCOL(protobuf);
 		if (proto != PPP_LCP)
 			lp->huptimer = 0;
 
-		if (lp->isdn_device < 0 || lp->isdn_channel < 0)
-			return 0;
-
+		if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
+			retval = 0;
+			goto out;
+		}
 		if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
 			lp->dialstate == 0 &&
 		    (lp->flags & ISDN_NET_CONNECTED)) {
@@ -767,13 +803,15 @@
 			skb = alloc_skb(hl+count, GFP_ATOMIC);
 			if (!skb) {
 				printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
-				return count;
+				retval = count;
+				goto out;
 			}
 			skb_reserve(skb, hl);
 			if (copy_from_user(skb_put(skb, count), buf, count))
 			{
 				kfree_skb(skb);
-				return -EFAULT;
+				retval = -EFAULT;
+				goto out;
 			}
 			if (is->debug & 0x40) {
 				printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
@@ -785,8 +823,24 @@
 			isdn_net_write_super(lp, skb);
 		}
 	}
-	return count;
+	retval = count;
+	
+ out:
+	unlock_kernel();
+	return retval;
 }
+
+struct file_operations isdn_ppp_fops =
+{
+	owner:		THIS_MODULE,
+	llseek:		no_llseek,
+	read:		isdn_ppp_read,
+	write:		isdn_ppp_write,
+	poll:		isdn_ppp_poll,
+	ioctl:		isdn_ppp_ioctl,
+	open:		isdn_ppp_open,
+	release:	isdn_ppp_release,
+};
 
 /*
  * init memory, structures etc.
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h
--- v2.5.2/linux/drivers/isdn/isdn_ppp.h	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/isdn_ppp.h	Mon Jan 21 15:45:15 2002
@@ -12,9 +12,8 @@
 #include <linux/ppp_defs.h>     /* for PPP_PROTOCOL */
 #include <linux/isdn_ppp.h>	/* for isdn_ppp info */
 
-extern int isdn_ppp_read(int, struct file *, char *, int);
-extern int isdn_ppp_write(int, struct file *, const char *, int);
-extern int isdn_ppp_open(int, struct file *);
+extern struct file_operations isdn_ppp_fops;
+
 extern int isdn_ppp_init(void);
 extern void isdn_ppp_cleanup(void);
 extern int isdn_ppp_free(isdn_net_local *);
@@ -22,9 +21,6 @@
 extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
 extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
 extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
-extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
-extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
-extern void isdn_ppp_release(int, struct file *);
 extern int isdn_ppp_dial_slave(char *);
 extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
 
diff -u --recursive --new-file v2.5.2/linux/drivers/md/Config.help linux/drivers/md/Config.help
--- v2.5.2/linux/drivers/md/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/md/Config.help	Fri Jan 25 16:03:19 2002
@@ -0,0 +1,124 @@
+CONFIG_BLK_DEV_LVM
+  This driver lets you combine several hard disks, hard disk
+  partitions, multiple devices or even loop devices (for evaluation
+  purposes) into a volume group.  Imagine a volume group as a kind of
+  virtual disk. Logical volumes, which can be thought of as virtual
+  partitions, can be created in the volume group.  You can resize
+  volume groups and logical volumes after creation time, corresponding
+  to new capacity needs.  Logical volumes are accessed as block
+  devices named /dev/VolumeGroupName/LogicalVolumeName.
+
+  For details see <file:Documentation/LVM-HOWTO>.  You will need
+  supporting user space software; location is in
+  <file:Documentation/Changes>.
+
+  If you want to compile this 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 lvm-mod.o.
+
+CONFIG_MD
+  Support multiple physical spindles through a single logical device.
+  Required for RAID and logical volume management (LVM).
+
+CONFIG_BLK_DEV_MD
+  This driver lets you combine several hard disk partitions into one
+  logical block device. This can be used to simply append one
+  partition to another one or to combine several redundant hard disks
+  into a RAID1/4/5 device so as to provide protection against hard
+  disk failures. This is called "Software RAID" since the combining of
+  the partitions is done by the kernel. "Hardware RAID" means that the
+  combining is done by a dedicated controller; if you have such a
+  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.
+
+  If unsure, say N.
+
+CONFIG_MD_LINEAR
+  If you say Y here, then your multiple devices driver will be able to
+  use the so-called linear mode, i.e. it will combine the hard disk
+  partitions by simply appending one to the other.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called linear.o.
+
+  If unsure, say Y.
+
+CONFIG_MD_RAID0
+  If you say Y here, then your multiple devices driver will be able to
+  use the so-called raid0 mode, i.e. it will combine the hard disk
+  partitions into one logical device in such a fashion as to fill them
+  up evenly, one chunk here and one chunk there. This will increase
+  the throughput rate if the partitions reside on distinct disks.
+
+  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.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called raid0.o.
+
+  If unsure, say Y.
+
+CONFIG_MD_RAID1
+  A RAID-1 set consists of several disk drives which are exact copies
+  of each other.  In the event of a mirror failure, the RAID driver
+  will continue to use the operational mirrors in the set, providing
+  an error free MD (multiple device) to the higher levels of the
+  kernel.  In a set with N drives, the available space is the capacity
+  of a single drive, and the set protects against a failure of (N - 1)
+  drives.
+
+  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.
+
+  If you want to use such a RAID-1 set, say Y. This code is also
+  available as a module called raid1.o ( = 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>.
+
+  If unsure, say Y.
+
+CONFIG_MD_RAID5
+  A RAID-5 set of N drives with a capacity of C MB per drive provides
+  the capacity of C * (N - 1) MB, and protects against a failure
+  of a single drive. For a given sector (row) number, (N - 1) drives
+  contain data sectors, and one drive contains the parity protection.
+  For a RAID-4 set, the parity blocks are present on a single drive,
+  while a RAID-5 set distributes the parity across the drives in one
+  of the available parity distribution methods.
+
+  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.
+
+  If you want to use such a RAID-4/RAID-5 set, say Y. This code is
+  also available as a module called raid5.o ( = 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>.
+
+  If unsure, say Y.
+
+CONFIG_MD_MULTIPATH
+  Multipath-IO is the ability of certain devices to address the same
+  physical disk over multiple 'IO paths'. The code ensures that such
+  paths can be defined and handled at runtime, and ensures that a
+  transparent failover to the backup path(s) happens if a IO errors
+  arrives on the primary path.
+
+  If unsure, say N.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/md/md.c linux/drivers/md/md.c
--- v2.5.2/linux/drivers/md/md.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/md/md.c	Tue Jan 15 13:53:51 2002
@@ -3458,8 +3458,7 @@
 		 * about not overloading the IO subsystem. (things like an
 		 * e2fsck being done on the RAID array should execute fast)
 		 */
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/media/Config.help linux/drivers/media/Config.help
--- v2.5.2/linux/drivers/media/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/Config.help	Fri Jan 25 16:04:16 2002
@@ -0,0 +1,15 @@
+CONFIG_VIDEO_DEV
+  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/>.
+
+  If you are interested in writing a driver for such an audio/video
+  device or user software interacting with such a driver, please read
+  the file <file:Documentation/video4linux/API.html>.
+
+  This driver is also available as a module called videodev.o ( = 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>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/media/radio/Config.help linux/drivers/media/radio/Config.help
--- v2.5.2/linux/drivers/media/radio/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/radio/Config.help	Fri Jan 25 16:04:17 2002
@@ -0,0 +1,274 @@
+CONFIG_RADIO_RTRACK
+  Choose Y here if you have one of these FM radio cards, and then fill
+  in the port address below.
+
+  Note that newer AIMSlab RadioTrack cards have a different chipset
+  and are not supported by this driver.  For these cards, use the
+  RadioTrack II driver below.
+
+  If you have a GemTeks combined (PnP) sound- and radio card you must
+  use this driver as a module and setup the card with isapnptools.
+  You must also pass the module a suitable io parameter, 0x248 has
+  been reported to be used by these cards.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video For Linux API.  Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.  More
+  information is contained in the file
+  <file:Documentation/video4linux/radiotrack.txt>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-aimslab.o.
+
+CONFIG_RADIO_RTRACK_PORT
+  Enter either 0x30f or 0x20f here.  The card default is 0x30f, if you
+  haven't changed the jumper setting on the card.
+
+CONFIG_RADIO_RTRACK2
+  Choose Y here if you have this FM radio card, and then fill in the
+  port address below.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video For Linux API.  Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-rtrack2.o.
+
+CONFIG_RADIO_RTRACK2_PORT
+  Enter either 0x30c or 0x20c here.  The card default is 0x30c, if you
+  haven't changed the jumper setting on the card.
+
+CONFIG_RADIO_AZTECH
+  Choose Y here if you have one of these FM radio cards, and then fill
+  in the port address below.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video For Linux API.  Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-aztech.o.
+
+CONFIG_RADIO_AZTECH_PORT
+  Enter either 0x350 or 0x358 here.  The card default is 0x350, if you
+  haven't changed the setting of jumper JP3 on the card.  Removing the
+  jumper sets the card to 0x358.
+
+CONFIG_RADIO_CADET
+  Choose Y here if you have one of these AM/FM radio cards, and then
+  fill in the port address below.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video For Linux API.  Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  Further documentation on this driver can be found on the WWW at
+  <http://linux.blackhawke.net/cadet.html>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-cadet.o.
+
+CONFIG_RADIO_SF16FMI
+  Choose Y here if you have one of these FM radio cards.  If you
+  compile the driver into the kernel and your card is not PnP one, you
+  have to add "sf16fm=<io>" to the kernel command line (I/O address is
+  0x284 or 0x384).
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video For Linux API.  Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-sf16fmi.o.
+
+CONFIG_RADIO_TYPHOON
+  Choose Y here if you have one of these FM radio cards, and then fill
+  in the port address and the frequency used for muting below.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video For Linux API.  Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-typhoon.o.
+
+CONFIG_RADIO_TYPHOON_PROC_FS
+  Say Y here if you want the typhoon radio card driver to write
+  status information (frequency, volume, muted, mute frequency,
+  base address) to /proc/radio-typhoon. The file can be viewed with
+  your favorite pager (i.e. use "more /proc/radio-typhoon" or "less
+  /proc/radio-typhoon" or simply "cat /proc/radio-typhoon").
+
+CONFIG_RADIO_TYPHOON_PORT
+  Enter the I/O port of your Typhoon or EcoRadio radio card.
+
+CONFIG_RADIO_TYPHOON_MUTEFREQ
+  Enter the frequency used for muting the radio. The device is never
+  completely silent. If the volume is just turned down, you can still
+  hear silent voices and music. For that reason, the frequency of the
+  radio device is set to the frequency you can enter here whenever
+  the device is muted. There should be no local radio station at that
+  frequency.
+
+CONFIG_RADIO_ZOLTRIX
+  Choose Y here if you have one of these FM radio cards, and then fill
+  in the port address below.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video For Linux API.  Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-zoltrix.o.
+
+CONFIG_RADIO_ZOLTRIX_PORT
+  Enter the I/O port of your Zoltrix radio card.
+
+CONFIG_RADIO_MIROPCM20
+  Choose Y here if you have this FM radio card. You also need to say Y
+  to "ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio)" (in "Sound")
+  for this to work.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video For Linux API.  Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called miropcm20.o.
+
+CONFIG_RADIO_MIROPCM20_RDS
+  Choose Y here if you want to see RDS/RBDS information like
+  RadioText, Programme Service name, Clock Time and date, Programme
+  TYpe and Traffic Announcement/Programme identification.  You also
+  need to say Y to "miroSOUND PCM20 radio" and devfs!
+
+  It's not possible to read the raw RDS packets from the device, so
+  the driver cant provide an V4L interface for this.  But the
+  availability of RDS is reported over V4L by the basic driver
+  already.  Here RDS can be read from files in /dev/v4l/rds.
+
+  As module the driver will be called miropcm20-rds.o.
+
+CONFIG_RADIO_MAESTRO
+  Say Y here to directly support the on-board radio tuner on the
+  Maestro 2 or 2E sound card.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video For Linux API.  Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-maestro.o.
+
+CONFIG_RADIO_MAXIRADIO
+  Choose Y here if you have this radio card.  This card may also be
+  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
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-maxiradio.o.
+
+CONFIG_RADIO_GEMTEK
+  Choose Y here if you have this FM radio card, and then fill in the
+  port address below.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video For Linux API.  Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-gemtek.o.
+
+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
+  port is 0x28c.
+
+CONFIG_RADIO_GEMTEK_PCI
+  Choose Y here if you have this PCI FM radio card.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video for Linux API.  Information on 
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-gemtek-pci.o.
+
+CONFIG_RADIO_TERRATEC
+  Choose Y here if you have this FM radio card, and then fill in the
+  port address below. (TODO)
+
+  Note: This driver is in its early stages.  Right now volume and
+  frequency control and muting works at least for me, but
+  unfortunately I have not found anybody who wants to use this card
+  with Linux.  So if it is this what YOU are trying to do right now,
+  PLEASE DROP ME A NOTE!!  Rolf Offermanns (rolf@offermanns.de)
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video For Linux API.  Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-terratec.o.
+
+CONFIG_RADIO_TERRATEC_PORT
+  Fill in the I/O port of your TerraTec FM radio card. If unsure, go
+  with the default.
+
+CONFIG_RADIO_TRUST
+  This is a driver for the Trust FM radio cards. Say Y if you have
+  such a card and want to use it under Linux.
+
+  This driver is also available as a module called radio-trust.o ( =
+  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>.
+
+CONFIG_RADIO_TRUST_PORT
+  Enter the I/O port of your Trust FM radio card. If unsure, try the
+  values "0x350" or "0x358".
+
diff -u --recursive --new-file v2.5.2/linux/drivers/media/radio/radio-sf16fmi.c linux/drivers/media/radio/radio-sf16fmi.c
--- v2.5.2/linux/drivers/media/radio/radio-sf16fmi.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/media/radio/radio-sf16fmi.c	Tue Jan 15 13:53:51 2002
@@ -94,8 +94,7 @@
 	for(i=0; i< 100; i++)
 	{
 		udelay(1400);
-		if(current->need_resched)
-			schedule();
+		cond_resched();
 	}
 /* If this becomes allowed use it ... 	
 	current->state = TASK_UNINTERRUPTIBLE;
@@ -121,8 +120,7 @@
 	for(i=0; i< 100; i++)
 	{
 		udelay(1400);
-		if(current->need_resched)
-			schedule();
+		cond_resched();
 	}
 /* If this becomes allowed use it ... 	
 	current->state = TASK_UNINTERRUPTIBLE;
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/Config.help linux/drivers/media/video/Config.help
--- v2.5.2/linux/drivers/media/video/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/video/Config.help	Fri Jan 25 16:04:19 2002
@@ -0,0 +1,153 @@
+CONFIG_VIDEO_PROC_FS
+  If you say Y here, you are able to access video device information
+  in /proc/video.
+
+  To use this option, you have to check, that the "/proc file system
+  support" (CONFIG_PROC_FS) is enabled too.
+
+CONFIG_I2C_PARPORT
+  I2C is a simple serial bus system used in many micro controller
+  applications.  Saying Y here will allow you to use your parallel
+  port as an I2C interface.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called i2c-parport.o.
+
+CONFIG_VIDEO_PLANB
+  PlanB is the V4L driver for the PowerMac 7x00/8x00 series video
+  input hardware. If you want to experiment with this, say Y.
+  Otherwise, or if you don't understand a word, say N.
+  See <http://www.cpu.lu/~mlan/planb.html> for more info.
+
+  Saying M will compile this driver as a module (planb.o).
+
+CONFIG_VIDEO_BT848
+  Support for BT848 based frame grabber/overlay boards. This includes
+  the Miro, Hauppauge and STB boards. Please read the material in
+  <file:Documentation/video4linux/bttv> for more information.
+
+  If you say Y or M here, you need to say Y or M to "I2C support" and
+  "I2C bit-banging interfaces" in the character device section.
+
+  This driver is available as a module called bttv.o ( = 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>.
+
+CONFIG_VIDEO_VINO
+  Say Y here to build in support for the Vino video input system found
+  on SGI Indy machines.
+
+CONFIG_VIDEO_STRADIS
+  Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
+  driver for PCI.  There is a product page at
+  <http://www.stradis.com/decoder.html>.
+
+CONFIG_VIDEO_ZORAN
+  Say Y here to include support for video cards based on the Zoran
+  ZR36057/36060 encoder/decoder chip (including the Iomega Buz and the
+  Miro DC10 and DC30 video capture cards).
+
+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/>.
+
+CONFIG_VIDEO_ZR36120
+  Support for ZR36120/ZR36125 based frame grabber/overlay boards.
+  This includes the Victor II, WaveWatcher, Video Wonder, Maxi-TV,
+  and Buster boards. Please read the material in
+  <file:Documentation/video4linux/zr36120.txt> for more information.
+
+  This driver is also available as a module called zr36120.o ( = 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>.
+
+CONFIG_VIDEO_SAA5249
+  Support for I2C bus based teletext using the SAA5249 chip. At the
+  moment this is only useful on some European WinTV cards.
+
+  This driver is also available as a module called saa5249.o ( = 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>.
+
+CONFIG_VIDEO_BWQCAM
+  Say Y have if you the black and white version of the QuickCam
+  camera. See the next option for the color version.
+
+  This driver is also available as a module called bw-qcam.o ( = 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>.
+
+CONFIG_VIDEO_CQCAM
+  This is the video4linux driver for the colour version of the
+  Connectix QuickCam.  If you have one of these cameras, say Y here,
+  otherwise say N.  This driver does not work with the original
+  monochrome QuickCam, QuickCam VC or QuickClip.  It is also available
+  as a module (c-qcam.o).
+  Read <file:Documentation/video4linux/CQcam.txt> for more information.
+
+CONFIG_VIDEO_W9966
+  Video4linux driver for Winbond's w9966 based Webcams.
+  Currently tested with the LifeView FlyCam Supra.
+  If you have one of these cameras, say Y here
+  otherwise say N.
+  This driver is also available as a module (w9966.o).
+
+  Check out <file:Documentation/video4linux/w9966.txt> for more
+  information.
+
+CONFIG_VIDEO_CPIA
+  This is the video4linux driver for cameras based on Vision's CPiA
+  (Colour Processor Interface ASIC), such as the Creative Labs Video
+  Blaster Webcam II. If you have one of these cameras, say Y here
+  and select parallel port and/or USB lowlevel support below,
+  otherwise say N. This will not work with the Creative Webcam III.
+
+  Please read <file:Documentation/video4linux/README.cpia> for more
+  information.
+
+  This driver is also available as a module (cpia.o).
+
+CONFIG_VIDEO_CPIA_PP
+  This is the lowlevel parallel port support for cameras based on
+  Vision's CPiA (Colour Processor Interface ASIC), such as the
+  Creative Webcam II. If you have the parallel port version of one
+  of these cameras, say Y here, otherwise say N. It is also available
+  as a module (cpia_pp.o).
+
+CONFIG_VIDEO_CPIA_USB
+  This is the lowlevel USB support for cameras based on Vision's CPiA
+  (Colour Processor Interface ASIC), such as the Creative Webcam II.
+  If you have the USB version of one of these cameras, say Y here,
+  otherwise say N. This will not work with the Creative Webcam III.
+  It is also available as a module (cpia_usb.o).
+
+CONFIG_VIDEO_PMS
+  Say Y if you have such a thing.  This driver is also available as a
+  module called pms.o ( = 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>.
+
+CONFIG_VIDEO_MEYE
+  This is the video4linux driver for the Motion Eye camera found
+  in the Vaio Picturebook laptops. Please read the material in
+  <file:Documentation/video4linux/meye.txt> for more information.
+
+  If you say Y or M here, you need to say Y or M to "Sony Programmable
+  I/O Control Device" in the character device section.
+
+  This driver is available as a module called meye.o ( = 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>.
+
+CONFIG_TUNER_3036
+  Say Y here to include support for Philips SAB3036 compatible tuners.
+  If in doubt, say N.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- v2.5.2/linux/drivers/media/video/bttv-driver.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/media/video/bttv-driver.c	Tue Jan 15 10:56:35 2002
@@ -2037,7 +2037,7 @@
  *    But e.g. pte_alloc() does not work in modules ... :-(
  */
 
-static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size)
+static int do_bttv_mmap(struct vm_area_struct *vma, struct bttv *btv, const char *adr, unsigned long size)
 {
         unsigned long start=(unsigned long) adr;
         unsigned long page,pos;
@@ -2051,7 +2051,7 @@
         pos=(unsigned long) btv->fbuffer;
         while (size > 0) {
                 page = kvirt_to_pa(pos);
-                if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+                if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
                         return -EAGAIN;
                 start+=PAGE_SIZE;
                 pos+=PAGE_SIZE;
@@ -2060,13 +2060,13 @@
         return 0;
 }
 
-static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size)
+static int bttv_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
 {
         struct bttv *btv=(struct bttv *)dev;
         int r;
 
         down(&btv->lock);
-        r=do_bttv_mmap(btv, adr, size);
+        r=do_bttv_mmap(vma, btv, adr, size);
         up(&btv->lock);
         return r;
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/c-qcam.c linux/drivers/media/video/c-qcam.c
--- v2.5.2/linux/drivers/media/video/c-qcam.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/media/video/c-qcam.c	Tue Jan 15 13:53:51 2002
@@ -425,8 +425,7 @@
 		wantlen -= t;
 		if (t < s)
 			break;
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 	}
 
 	len = outptr;
@@ -445,8 +444,7 @@
 		int l;
 		do {
 			l = qcam_read_bytes(q, tmpbuf, 3);
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 		} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
 		if (force_rgb) {
 			if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
@@ -478,8 +476,7 @@
 		int l;
 		do {
 			l = qcam_read_bytes(q, tmpbuf, 1);
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 		} while (l && tmpbuf[0] == 0x7e);
 		l = qcam_read_bytes(q, tmpbuf+1, 2);
 		if (force_rgb) {
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c
--- v2.5.2/linux/drivers/media/video/cpia.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/media/video/cpia.c	Tue Jan 15 13:53:51 2002
@@ -2147,8 +2147,7 @@
 			/* loop until image ready */
 			do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
 			while (cam->params.status.streamState != STREAM_READY) {
-				if (current->need_resched)
-					schedule();
+				cond_resched();
 
 				current->state = TASK_INTERRUPTIBLE;
 
@@ -2163,8 +2162,7 @@
 		}
 
 		/* grab image from camera */
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		oldjif = jiffies;
 		image_size = cam->ops->streamRead(cam->lowlevel_data,
@@ -2189,8 +2187,7 @@
 		/* decompress and convert image to by copying it from
 		 * raw_image to decompressed_frame
 		 */
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		cam->image_size = parse_picture(cam, image_size);
 		if (cam->image_size <= 0)
@@ -2972,7 +2969,7 @@
 } 
 
 /* FIXME */
-static int cpia_mmap(struct video_device *dev, const char *adr,
+static int cpia_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr,
                      unsigned long size)
 {
 	unsigned long start = (unsigned long)adr;
@@ -3005,7 +3002,7 @@
 	pos = (unsigned long)(cam->frame_buf);
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up(&cam->busy_lock);
 			return -EAGAIN;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/cpia_pp.c linux/drivers/media/video/cpia_pp.c
--- v2.5.2/linux/drivers/media/video/cpia_pp.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/media/video/cpia_pp.c	Tue Jan 15 13:53:51 2002
@@ -392,7 +392,7 @@
 	endseen = 0;
 	block_size = PARPORT_CHUNK_SIZE;
 	while( !cam->image_complete ) {
-		if(current->need_resched)  schedule();
+		cond_resched();
 		
 		new_bytes = cpia_pp_read(cam->port, buffer, block_size );
 		if( new_bytes <= 0 ) {
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/cpia_usb.c linux/drivers/media/video/cpia_usb.c
--- v2.5.2/linux/drivers/media/video/cpia_usb.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/media/video/cpia_usb.c	Mon Jan 21 15:44:21 2002
@@ -46,7 +46,7 @@
 
 struct cpia_sbuf {
 	char *data;
-	urb_t *urb;
+	struct urb *urb;
 };
 
 #define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
@@ -168,7 +168,7 @@
 static int cpia_usb_open(void *privdata)
 {
 	struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
-	urb_t *urb;
+	struct urb *urb;
 	int ret, retval = 0, fx, err;
   
 	if (!ucpia)
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/meye.c linux/drivers/media/video/meye.c
--- v2.5.2/linux/drivers/media/video/meye.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/media/video/meye.c	Tue Jan 15 10:56:35 2002
@@ -1240,7 +1240,7 @@
 	return 0;
 }
 
-static int meye_mmap(struct video_device *dev, const char *adr, 
+static int meye_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, 
 		     unsigned long size) {
 	unsigned long start=(unsigned long) adr;
 	unsigned long page,pos;
@@ -1263,7 +1263,7 @@
 
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up(&meye.lock);
 			return -EAGAIN;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/planb.c linux/drivers/media/video/planb.c
--- v2.5.2/linux/drivers/media/video/planb.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/media/video/planb.c	Tue Jan 15 10:56:35 2002
@@ -1994,7 +1994,7 @@
 	return 0;
 }
 
-static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size)
+static int planb_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
 {
 	int i;
 	struct planb *pb = (struct planb *)dev;
@@ -2008,7 +2008,7 @@
 			return err;
 	}
 	for (i = 0; i < pb->rawbuf_size; i++) {
-		if (remap_page_range(start, virt_to_phys((void *)pb->rawbuf[i]),
+		if (remap_page_range(vma, start, virt_to_phys((void *)pb->rawbuf[i]),
 						PAGE_SIZE, PAGE_SHARED))
 			return -EAGAIN;
 		start += PAGE_SIZE;
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/saa5249.c linux/drivers/media/video/saa5249.c
--- v2.5.2/linux/drivers/media/video/saa5249.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/media/video/saa5249.c	Tue Jan 15 13:53:51 2002
@@ -127,11 +127,7 @@
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 #endif
 
-#define RESCHED \
-        do { \
-          if (current->need_resched) \
-            schedule(); \
-        } while (0)
+#define RESCHED do { cond_resched(); } while(0)
 
 static struct video_device saa_template;	/* Declared near bottom */
 
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/videodev.c linux/drivers/media/video/videodev.c
--- v2.5.2/linux/drivers/media/video/videodev.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/media/video/videodev.c	Tue Jan 15 10:56:35 2002
@@ -206,7 +206,7 @@
 	struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
 	if(vfl->mmap) {
 		lock_kernel();
-		ret = vfl->mmap(vfl, (char *)vma->vm_start, 
+		ret = vfl->mmap(vma, vfl, (char *)vma->vm_start, 
 				(unsigned long)(vma->vm_end-vma->vm_start));
 		unlock_kernel();
 	}
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/zr36067.c linux/drivers/media/video/zr36067.c
--- v2.5.2/linux/drivers/media/video/zr36067.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/media/video/zr36067.c	Wed Jan 23 15:28:39 2002
@@ -2608,7 +2608,7 @@
 		}
 		frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
 		gbuf = &zr->jpg_gbuf[frame];
-		get_fast_time(&gbuf->bs.timestamp);
+		do_gettimeofday(&gbuf->bs.timestamp);
 
 		if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
 			gbuf->bs.length = (stat_com & 0x7fffff) >> 1;
@@ -4274,7 +4274,7 @@
  *
  */
 
-static int do_zoran_mmap(struct zoran *zr, const char *adr,
+static int do_zoran_mmap(struct vm_area_struct *vma, struct zoran *zr, const char *adr,
 		      unsigned long size)
 {
 	unsigned long start = (unsigned long) adr;
@@ -4321,7 +4321,7 @@
 				    frag_tab[2 * j];
 				page = virt_to_phys(bus_to_virt(pos));	/* should just be pos on i386 */
 				if (remap_page_range
-				    (start, page, todo, PAGE_SHARED)) {
+				    (vma, start, page, todo, PAGE_SHARED)) {
 					printk(KERN_ERR
 					       "%s: zoran_mmap(V4L): remap_page_range failed\n",
 					       zr->name);
@@ -4362,7 +4362,7 @@
 			       ("V4L remap page range %d 0x%lx %ld to 0x%lx\n",
 				i, page, todo, start));
 			if (remap_page_range
-			    (start, page, todo, PAGE_SHARED)) {
+			    (vma, start, page, todo, PAGE_SHARED)) {
 				printk(KERN_ERR
 				       "%s: zoran_mmap(V4L): remap_page_range failed\n",
 				       zr->name);
@@ -4377,14 +4377,14 @@
 	return 0;
 }
 
-static int zoran_mmap(struct video_device *dev, const char *adr,
+static int zoran_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr,
 		      unsigned long size)
 {
 	int err;
 	struct zoran *zr = (struct zoran *) dev;
 	
 	down(&zr->sem);
-	err = do_zoran_mmap(zr, adr, size);
+	err = do_zoran_mmap(vma, zr, adr, size);
 	up(&zr->sem);
 		
 	return err;
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c
--- v2.5.2/linux/drivers/media/video/zr36120.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/media/video/zr36120.c	Tue Jan 15 10:56:35 2002
@@ -1467,7 +1467,7 @@
 }
 
 static
-int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size)
+int zoran_mmap(struct vm_area_struct *vma, struct video_device* dev, const char* adr, unsigned long size)
 {
 	struct zoran* ztv = (struct zoran*)dev;
 	unsigned long start = (unsigned long)adr;
@@ -1483,7 +1483,7 @@
 	pos = (unsigned long)ztv->fbuffer;
 	while (size>0) {
 		unsigned long page = virt_to_phys((void*)pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
 			return -EAGAIN;
 		start += PAGE_SIZE;
 		pos += PAGE_SIZE;
diff -u --recursive --new-file v2.5.2/linux/drivers/message/fusion/Config.help linux/drivers/message/fusion/Config.help
--- v2.5.2/linux/drivers/message/fusion/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/Config.help	Fri Jan 25 16:03:43 2002
@@ -0,0 +1,120 @@
+CONFIG_FUSION
+  LSI Logic Fusion(TM) Message Passing Technology (MPT) device support
+  provides high performance SCSI host initiator, and LAN [1] interface
+  services to a host system.  The Fusion architecture is capable of
+  duplexing these protocols on high-speed Fibre Channel
+  (up to 2 GHz x 2 ports = 4 GHz) and parallel SCSI (up to Ultra-320)
+  physical medium.
+
+          [1] LAN is not supported on parallel SCSI medium.
+
+  These drivers require a Fusion MPT compatible PCI adapter installed
+  in the host system.  MPT adapters contain specialized I/O processors
+  to handle I/O workload, and more importantly to offload this work
+  from the host CPU(s).
+
+  If you have Fusion MPT hardware and want to use it, you can say
+  Y or M here to add MPT (base + ScsiHost) drivers.
+    <Y> = build lib (fusion.o), and link [static] into the kernel [2]
+          proper
+    <M> = compiled as [dynamic] modules [3] named: (mptbase.o,
+          mptscsih.o)
+
+          [2] In order enable capability to boot the linux kernel
+              natively from a Fusion MPT target device, you MUST
+               answer Y here! (currently requires CONFIG_BLK_DEV_SD)
+          [3] This support is also available as a module ( = code
+              which can be inserted in and removed from the running
+              kernel whenever you want).  If you want to compile as
+              modules, say M here and read
+              <file:Documentation/modules.txt>.
+
+  If unsure, say N.
+
+  If you say Y or M here you will get a choice of these
+  additional protocol and support module options:         Module Name:
+    <M>   Enhanced SCSI error reporting                     (isense.o)
+    <M>   Fusion MPT misc device (ioctl) driver             (mptctl.o)
+    <M>   Fusion MPT LAN driver                             (mptlan.o)
+
+  ---
+  Fusion MPT is trademark of LSI Logic Corporation, and its
+  architecture is based on LSI Logic's Message Passing Interface (MPI)
+  specification.
+
+CONFIG_FUSION_ISENSE
+  The isense module (roughly stands for Interpret SENSE data) is
+  completely optional.  It simply provides extra English readable
+  strings in SCSI Error Report(s) that might be generated from the
+  Fusion MPT SCSI Host driver, for example when a target device
+  returns a SCSI check condition on a I/O.  Without this module
+  loaded you might see:
+
+    SCSI Error Report =-=-= (ioc0,scsi5:0)
+      SCSI_Status=02h (CHECK_CONDITION)
+      Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00
+      SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00
+      SenseKey=2h (NOT READY); FRU=02h
+      ASC/ASCQ=29h/00h
+
+  Where otherwise, if this module had been loaded, you would see:
+
+    SCSI Error Report =-=-= (ioc0,scsi5:0)
+      SCSI_Status=02h (CHECK_CONDITION)
+      Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 - "WRITE(10)"
+      SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00
+      SenseKey=2h (NOT READY); FRU=02h
+      ASC/ASCQ=29h/00h "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED"
+
+  Say M for "Enhanced SCSI error reporting" to compile this optional module,
+  creating a driver named: isense.o.
+
+  NOTE: Support for building this feature into the kernel is not
+  available, due to kernel size considerations.
+
+CONFIG_FUSION_CTL
+  The Fusion MPT misc device driver provides specialized control
+  of MPT adapters via system ioctl calls.  Use of ioctl calls to
+  the MPT driver requires that you create and use a misc device
+  node ala:
+    mknod /dev/mptctl c 10 240
+
+  One use of this ioctl interface is to perform an upgrade (reflash)
+  of the MPT adapter firmware.  Refer to readme file(s) distributed
+  with the Fusion MPT linux driver for additional details.
+
+  If enabled by saying M to this, a driver named: mptctl.o
+  will be compiled.
+
+  If unsure whether you really want or need this, say N.
+
+CONFIG_FUSION_LAN
+  This module supports LAN IP traffic over Fibre Channel port(s)
+  on Fusion MPT compatible hardware (LSIFC9xx chips).
+  The physical interface used is defined in RFC 2625.
+  Please refer to that document for details.
+
+  Installing this driver requires the knowledge to configure and
+  activate a new network interface, "fc0", using standard Linux tools.
+
+  If enabled by saying M to this, a driver named: mptlan.o
+  will be compiled.
+
+  If unsure whether you really want or need this, say N.
+
+  NOTES: This feature is NOT available nor supported for linux-2.2.x
+  kernels.  You must be building a linux-2.3.x or linux-2.4.x kernel
+  in order to configure this option.
+  Support for building this feature into the linux kernel is not
+  yet available.
+
+CONFIG_NET_FC
+  Fibre Channel is a high speed serial protocol mainly used to connect
+  large storage devices to the computer; it is compatible with and
+  intended to replace SCSI.
+
+  If you intend to use Fibre Channel, you need to have a Fibre channel
+  adaptor card in your computer; say Y here and to the driver for your
+  adaptor below. You also should have said Y to "SCSI support" and
+  "SCSI generic support".
+
diff -u --recursive --new-file v2.5.2/linux/drivers/message/fusion/mptscsih.c linux/drivers/message/fusion/mptscsih.c
--- v2.5.2/linux/drivers/message/fusion/mptscsih.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/message/fusion/mptscsih.c	Tue Jan 15 10:52:11 2002
@@ -246,9 +246,9 @@
 		mf_chk = search_taskQ(1,sc,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
 		if (mf_chk != NULL) {
 			sc->result = DID_ABORT << 16;
-			spin_lock_irqsave(&sc->host->host_lock, flags);
+			spin_lock_irqsave(sc->host->host_lock, flags);
 			sc->scsi_done(sc);
-			spin_unlock_irqrestore(&sc->host->host_lock, flags);
+			spin_unlock_irqrestore(sc->host->host_lock, flags);
 			return 1;
 		}
 	}
@@ -426,9 +426,9 @@
 					 scsi_to_pci_dma_dir(sc->sc_data_direction));
 		}
 
-		spin_lock_irqsave(&sc->host->host_lock, flags);
+		spin_lock_irqsave(sc->host->host_lock, flags);
 		sc->scsi_done(sc);
-		spin_unlock_irqrestore(&sc->host->host_lock, flags);
+		spin_unlock_irqrestore(sc->host->host_lock, flags);
 	}
 
 	return 1;
@@ -928,9 +928,9 @@
 			}
 			SCpnt->resid = SCpnt->request_bufflen - mpt_sdev->sense_sz;
 			SCpnt->result = 0;
-/*			spin_lock(&SCpnt->host->host_lock);	*/
+/*			spin_lock(SCpnt->host->host_lock);	*/
 			SCpnt->scsi_done(SCpnt);
-/*			spin_unlock(&SCpnt->host->host_lock);	*/
+/*			spin_unlock(SCpnt->host->host_lock);	*/
 			return 0;
 		}
 	}
@@ -1333,9 +1333,9 @@
 	if (ctx2abort == -1) {
 		printk(KERN_ERR MYNAM ": ERROR - ScsiLookup fail(#2) for SCpnt=%p\n", SCpnt);
 		SCpnt->result = DID_SOFT_ERROR << 16;
-		spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+		spin_lock_irqsave(SCpnt->host->host_lock, flags);
 		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+		spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 		mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 	} else {
 		dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort));
@@ -1352,9 +1352,9 @@
 					": WARNING[2] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n",
 					i, mf, SCpnt);
 			SCpnt->result = DID_SOFT_ERROR << 16;
-			spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+			spin_lock_irqsave(SCpnt->host->host_lock, flags);
 			SCpnt->scsi_done(SCpnt);
-			spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+			spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 			mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 		}
 	}
@@ -1428,9 +1428,9 @@
 				": WARNING[3] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n",
 				i, mf, SCpnt);
 		SCpnt->result = DID_SOFT_ERROR << 16;
-		spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+		spin_lock_irqsave(SCpnt->host->host_lock, flags);
 		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+		spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 		mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 	}
 
@@ -1502,9 +1502,9 @@
 				": WARNING[4] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n",
 				i, mf, SCpnt);
 		SCpnt->result = DID_SOFT_ERROR << 16;
-		spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+		spin_lock_irqsave(SCpnt->host->host_lock, flags);
 		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+		spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 		mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 	}
 
@@ -1748,9 +1748,9 @@
 			if (ctx2abort == -1) {
 				printk(KERN_ERR MYNAM ": ERROR - ScsiLookup fail(#1) for SCpnt=%p\n", SCpnt);
 				SCpnt->result = DID_SOFT_ERROR << 16;
-				spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+				spin_lock_irqsave(SCpnt->host->host_lock, flags);
 				SCpnt->scsi_done(SCpnt);
-				spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+				spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 				mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 				continue;
 			}
@@ -1797,9 +1797,9 @@
 		    != 0) {
 			printk(KERN_WARNING MYNAM ": WARNING[1] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n", i, mf, SCpnt);
 			SCpnt->result = DID_SOFT_ERROR << 16;
-			spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+			spin_lock_irqsave(SCpnt->host->host_lock, flags);
 			SCpnt->scsi_done(SCpnt);
-			spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+			spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 			mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 		} else {
 			/* Spin-Wait for TaskMgmt complete!!! */
diff -u --recursive --new-file v2.5.2/linux/drivers/message/i2o/Config.help linux/drivers/message/i2o/Config.help
--- v2.5.2/linux/drivers/message/i2o/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/i2o/Config.help	Fri Jan 25 16:03:25 2002
@@ -0,0 +1,71 @@
+CONFIG_I2O
+  The Intelligent Input/Output (I2O) architecture allows hardware
+  drivers to be split into two parts: an operating system specific
+  module called the OSM and an hardware specific module called the
+  HDM. The OSM can talk to a whole range of HDM's, and ideally the
+  HDM's are not OS dependent. This allows for the same HDM driver to
+  be used under different operating systems if the relevant OSM is in
+  place. In order for this to work, you need to have an I2O interface
+  adapter card in your computer. This card contains a special I/O
+  processor (IOP), thus allowing high speeds since the CPU does not
+  have to deal with I/O.
+
+  If you say Y here, you will get a choice of interface adapter
+  drivers and OSM's with the following questions.
+
+  This support is also available 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>.  You will get modules called
+  i2o_core.o and i2o_config.o.
+
+  If unsure, say N.
+
+CONFIG_I2O_PCI
+  Say Y for support of PCI bus I2O interface adapters. Currently this
+  is the only variety supported, so you should say Y.
+
+  This support is also available as a module called i2o_pci.o ( = 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>.
+
+CONFIG_I2O_BLOCK
+  Include support for the I2O Block OSM. The Block OSM presents disk
+  and other structured block devices to the operating system.
+
+  This support is also available as a module called i2o_block.o ( =
+  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>.
+
+CONFIG_I2O_LAN
+  Include support for the LAN OSM. You will also need to include
+  support for token ring or FDDI if you wish to use token ring or FDDI
+  I2O cards with this driver.
+
+  This support is also available as a module called i2o_lan.o ( = 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>.
+
+CONFIG_I2O_SCSI
+  Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel
+  I2O controller. You can use both the SCSI and Block OSM together if
+  you wish.
+
+  This support is also available as a module called i2o_scsi.o ( =
+  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>.
+
+CONFIG_I2O_PROC
+  If you say Y here and to "/proc file system support", you will be
+  able to read I2O related information from the virtual directory
+  /proc/i2o.
+
+  This support is also available as a module called i2o_proc.o ( =
+  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>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/Config.help linux/drivers/mtd/Config.help
--- v2.5.2/linux/drivers/mtd/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/Config.help	Fri Jan 25 16:03:49 2002
@@ -0,0 +1,134 @@
+CONFIG_MTD
+  Memory Technology Devices are flash, RAM and similar chips, often
+  used for solid state file systems on embedded devices. This option
+  will provide the generic support for MTD drivers to register
+  themselves with the kernel and for potential users of MTD devices
+  to enumerate the devices which are present and obtain a handle on
+  them. It will also allow you to select individual drivers for 
+  particular hardware and users of MTD devices. If unsure, say N.
+
+CONFIG_MTD_DEBUG
+  This turns on low-level debugging for the entire MTD sub-system.
+  Normally, you should say 'N'.
+
+CONFIG_MTD_PARTITIONS
+  If you have a device which needs to divide its flash chip(s) up
+  into multiple 'partitions', each of which appears to the user as
+  a separate MTD device, you require this option to be enabled. If
+  unsure, say 'Y'.
+
+  Note, however, that you don't need this option for the DiskOnChip
+  devices. Partitioning on NFTL 'devices' is a different - that's the
+  'normal' form of partitioning used on a block device.
+
+CONFIG_MTD_REDBOOT_PARTS
+  RedBoot is a ROM monitor and bootloader which deals with multiple
+  'images' in flash devices by putting a table in the last erase block
+  of the device, similar to a partition table, which gives the
+  offsets, lengths and names of all the images stored in the flash.
+
+  If you need code which can detect and parse this table, and register
+  MTD 'partitions' corresponding to each image in the table, enable
+  this option.
+
+  You will still need the parsing functions to be called by the driver
+  for your particular device. It won't happen automatically. The
+  SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
+  example.
+
+CONFIG_MTD_BOOTLDR_PARTS
+  The Compaq bootldr deals with multiple 'images' in flash devices
+  by putting a table in one of the first erase blocks of the device,
+  similar to a partition table, which gives the offsets, lengths and
+  names of all the images stored in the flash.
+
+  If you need code which can detect and parse this table, and register
+  MTD 'partitions' corresponding to each image in the table, enable
+  this option.
+
+  You will still need the parsing functions to be called by the driver
+  for your particular device. It won't happen automatically. The 
+  SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for 
+  example.
+
+CONFIG_MTD_AFS_PARTS
+  The ARM Firmware Suite allows the user to divide flash devices into
+  multiple 'images'. Each such image has a header containing its name
+  and offset/size etc.
+
+  If you need code which can detect and parse these tables, and
+  register MTD 'partitions' corresponding to each image detected,
+  enable this option.
+
+  You will still need the parsing functions to be called by the driver
+  for your particular device.  It won't happen automatically.  The 
+  'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
+
+CONFIG_MTD_DEBUG_VERBOSE
+  Determines the verbosity level of the MTD debugging messages.
+
+CONFIG_MTD_CHAR
+  This provides a character device for each MTD device present in
+  the system, allowing the user to read and write directly to the
+  memory chips, and also use ioctl() to obtain information about
+  the device, or to erase parts of it.
+
+CONFIG_MTD_BLOCK
+  Although most flash chips have an erase size too large to be useful
+  as block devices, it is possible to use MTD devices which are based
+  on RAM chips in this manner. This block device is a user of MTD
+  devices performing that function.
+
+  At the moment, it is also required for the Journalling Flash File
+  System(s) to obtain a handle on the MTD device when it's mounted
+  (although JFFS and JFFS2 don't actually use any of the functionality
+  of the mtdblock device).
+
+  Later, it may be extended to perform read/erase/modify/write cycles
+  on flash chips to emulate a smaller block size. Needless to say,
+  this is very unsafe, but could be useful for file systems which are
+  almost never written to.
+
+  You do not need this option for use with the DiskOnChip devices. For
+  those, enable NFTL support (CONFIG_NFTL) instead.
+
+CONFIG_MTD_BLOCK_RO
+  This allows you to mount read-only file systems (such as cramfs)
+  from an MTD device, without the overhead (and danger) of the caching
+  driver.
+
+  You do not need this option for use with the DiskOnChip devices. For
+  those, enable NFTL support (CONFIG_NFTL) instead.
+
+CONFIG_FTL
+  This provides support for the original Flash Translation Layer which
+  is part of the PCMCIA specification. It uses a kind of pseudo-
+  file system on a flash device to emulate a block device with
+  512-byte sectors, on top of which you put a 'normal' file system.
+
+  You may find that the algorithms used in this code are patented
+  unless you live in the Free World where software patents aren't
+  legal - in the USA you are only permitted to use this on PCMCIA
+  hardware, although under the terms of the GPL you're obviously
+  permitted to copy, modify and distribute the code as you wish. Just
+  not use it.
+
+CONFIG_NFTL
+  This provides support for the NAND Flash Translation Layer which is
+  used on M-Systems' DiskOnChip devices. It uses a kind of pseudo-
+  file system on a flash device to emulate a block device with
+  512-byte sectors, on top of which you put a 'normal' file system.
+
+  You may find that the algorithms used in this code are patented
+  unless you live in the Free World where software patents aren't
+  legal - in the USA you are only permitted to use this on DiskOnChip
+  hardware, although under the terms of the GPL you're obviously
+  permitted to copy, modify and distribute the code as you wish. Just
+  not use it.
+
+CONFIG_NFTL_RW
+  If you're lucky, this will actually work. Don't whinge if it
+  doesn't.  Send mail to the MTD mailing list
+  <linux-mtd@lists.infradead.org> if you want to help to make it more
+  reliable.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/chips/Config.help linux/drivers/mtd/chips/Config.help
--- v2.5.2/linux/drivers/mtd/chips/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/chips/Config.help	Fri Jan 25 16:03:52 2002
@@ -0,0 +1,130 @@
+CONFIG_MTD_CFI
+  The Common Flash Interface specification was developed by Intel,
+  AMD and other flash manufactures that provides a universal method
+  for probing the capabilities of flash devices. If you wish to
+  support any device that is CFI-compliant, you need to enable this
+  option. Visit <http://www.amd.com/products/nvd/overview/cfi.html>
+  for more information on CFI.
+
+CONFIG_MTD_CFI_ADV_OPTIONS
+  If you need to specify a specific endianness for access to flash
+  chips, or if you wish to reduce the size of the kernel by including
+  support for only specific arrangements of flash chips, say 'Y'. This
+  option does not directly affect the code, but will enable other 
+  configuration options which allow you to do so.
+
+  If unsure, say 'N'.
+
+CONFIG_MTD_CFI_GEOMETRY
+  This option does not affect the code directly, but will enable 
+  some other configuration options which would allow you to reduce
+  the size of the kernel by including support for only certain 
+  arrangements of CFI chips. If unsure, say 'N' and all options 
+  which are supported by the current code will be enabled.
+
+CONFIG_MTD_CFI_B1
+  If you wish to support CFI devices on a physical bus which is
+  8 bits wide, say 'Y'.
+
+CONFIG_MTD_CFI_B2
+  If you wish to support CFI devices on a physical bus which is
+  16 bits wide, say 'Y'.
+
+CONFIG_MTD_CFI_B4
+  If you wish to support CFI devices on a physical bus which is
+  32 bits wide, say 'Y'.
+
+CONFIG_MTD_CFI_I1
+  If your flash chips are not interleaved - i.e. you only have one
+  flash chip addressed by each bus cycle, then say 'Y'.
+
+CONFIG_MTD_CFI_I2
+  If your flash chips are interleaved in pairs - i.e. you have two
+  flash chips addressed by each bus cycle, then say 'Y'.
+
+CONFIG_MTD_CFI_I4
+  If your flash chips are interleaved in fours - i.e. you have four
+  flash chips addressed by each bus cycle, then say 'Y'.
+
+CONFIG_MTD_CFI_NOSWAP
+  This option defines the way in which the CPU attempts to arrange
+  data bits when writing the 'magic' commands to the chips. Saying
+  'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't
+  enabled, means that the CPU will not do any swapping; the chips
+  are expected to be wired to the CPU in 'host-endian' form. 
+  Specific arrangements are possible with the BIG_ENDIAN_BYTE and
+  LITTLE_ENDIAN_BYTE, if the bytes are reversed.
+
+  If you have a LART, on which the data (and address) lines were
+  connected in a fashion which ensured that the nets were as short
+  as possible, resulting in a bit-shuffling which seems utterly
+  random to the untrained eye, you need the LART_ENDIAN_BYTE option.
+
+  Yes, there really exists something sicker than PDP-endian :)
+
+CONFIG_MTD_CFI_INTELEXT
+  The Common Flash Interface defines a number of different command
+  sets which a CFI-compliant chip may claim to implement. This code
+  provides support for one of those command sets, used on Intel
+  StrataFlash and other parts.
+
+CONFIG_MTD_CFI_AMDSTD
+  The Common Flash Interface defines a number of different command
+  sets which a CFI-compliant chip may claim to implement. This code
+  provides support for one of those command sets, used on chips 
+  chips including the AMD Am29LV320.
+
+CONFIG_MTD_SHARP
+  This option enables support for flash chips using Sharp-compatible
+  commands, including some which are not CFI-compatible and hence 
+  cannot be used with the CONFIG_MTD_CFI_INTELxxx options.
+
+CONFIG_MTD_AMDSTD
+  This option enables support for flash chips using AMD-compatible
+  commands, including some which are not CFI-compatible and hence 
+  cannot be used with the CONFIG_MTD_CFI_AMDSTD option.
+
+  It also works on AMD compatible chips that do conform to CFI.
+
+CONFIG_MTD_RAM
+  This option enables basic support for RAM chips accessed through 
+  a bus mapping driver.
+
+CONFIG_MTD_ROM
+  This option enables basic support for ROM chips accessed through 
+  a bus mapping driver.
+
+CONFIG_MTD_JEDEC
+  Enable older older JEDEC flash interface devices for self
+  programming flash.  It is commonly used in older AMD chips.  It is
+  only called JEDEC because the JEDEC association
+  <http://www.jedec.org/> distributes the identification codes for the
+  chips. WARNING!!!! This code does not compile and is incomplete as
+  are the specific JEDEC devices drivers.
+
+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.
+
+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)
+
+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>
+
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/chips/amd_flash.c linux/drivers/mtd/chips/amd_flash.c
--- v2.5.2/linux/drivers/mtd/chips/amd_flash.c	Thu Oct  4 15:14:59 2001
+++ linux/drivers/mtd/chips/amd_flash.c	Tue Jan 15 13:53:51 2002
@@ -889,7 +889,7 @@
 
 	times_left = 500000;
 	while (times_left-- && flash_is_busy(map, adr, private->interleave)) { 
-		if (current->need_resched) {
+		if (need_resched()) {
 			spin_unlock_bh(chip->mutex);
 			schedule();
 			spin_lock_bh(chip->mutex);
@@ -1126,7 +1126,7 @@
 		/* Latency issues. Drop the lock, wait a while and retry */
 		spin_unlock_bh(chip->mutex);
 
-		if (current->need_resched)
+		if (need_resched())
 			schedule();
 		else
 			udelay(1);
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/devices/Config.help linux/drivers/mtd/devices/Config.help
--- v2.5.2/linux/drivers/mtd/devices/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/devices/Config.help	Fri Jan 25 16:03:52 2002
@@ -0,0 +1,137 @@
+CONFIG_MTD_DOC1000
+  This provides an MTD device driver for the M-Systems DiskOnChip
+  1000 devices, which are obsolete so you probably want to say 'N'.
+
+CONFIG_MTD_DOC2000
+  This provides an MTD device driver for the M-Systems DiskOnChip
+  2000 and Millennium devices.  Originally designed for the DiskOnChip
+  2000, it also now includes support for the DiskOnChip Millennium.
+  If you have problems with this driver and the DiskOnChip Millennium,
+  you may wish to try the alternative Millennium driver below. To use
+  the alternative driver, you will need to undefine DOC_SINGLE_DRIVER
+  in the <file:drivers/mtd/devices/docprobe.c> source code.
+
+  If you use this device, you probably also want to enable the NFTL
+  'NAND Flash Translation Layer' option below, which is used to
+  emulate a block device by using a kind of file system on the flash
+  chips.
+
+CONFIG_MTD_DOC2001
+  This provides an alternative MTD device driver for the M-Systems 
+  DiskOnChip Millennium devices.  Use this if you have problems with
+  the combined DiskOnChip 2000 and Millennium driver above.  To get
+  the DiskOnChip probe code to load and use this driver instead of
+  the other one, you will need to undefine DOC_SINGLE_DRIVER near
+  the beginning of <file:drivers/mtd/devices/docprobe.c>.
+
+  If you use this device, you probably also want to enable the NFTL
+  'NAND Flash Translation Layer' option below, which is used to
+  emulate a block device by using a kind of file system on the flash
+  chips.
+
+CONFIG_MTD_DOCPROBE
+  This isn't a real config option, it's derived.
+
+CONFIG_MTD_DOCPROBE_ADVANCED
+  This option allows you to specify nonstandard address at which to
+  probe for a DiskOnChip, or to change the detection options.  You
+  are unlikely to need any of this unless you are using LinuxBIOS.
+  Say 'N'.
+
+CONFIG_MTD_DOCPROBE_55AA
+  Check for the 0x55 0xAA signature of a DiskOnChip, and do not
+  continue with probing if it is absent.  The signature will always be
+  present for a DiskOnChip 2000 or a normal DiskOnChip Millennium.
+  Only if you have overwritten the first block of a DiskOnChip
+  Millennium will it be  absent.  Enable this option if you are using
+  LinuxBIOS or if you need to recover a DiskOnChip Millennium on which
+  you have managed to wipe the first block.
+
+CONFIG_MTD_DOCPROBE_ADDRESS
+  By default, the probe for DiskOnChip devices will look for a
+  DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
+  This option allows you to specify a single address at which to probe
+  for the device, which is useful if you have other devices in that
+  range which get upset when they are probed.
+
+  (Note that on PowerPC, the normal probe will only check at
+  0xE4000000.)
+
+  Normally, you should leave this set to zero, to allow the probe at
+  the normal addresses.
+
+CONFIG_MTD_DOCPROBE_HIGH
+  By default, the probe for DiskOnChip devices will look for a
+  DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
+  This option changes to make it probe between 0xFFFC8000 and
+  0xFFFEE000.  Unless you are using LinuxBIOS, this is unlikely to be
+  useful to you.  Say 'N'.
+
+CONFIG_MTD_PMC551
+  This provides a MTD device driver for the Ramix PMC551 RAM PCI card
+  from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>.
+  These devices come in memory configurations from 32M - 1G.  If you
+  have one, you probably want to enable this.
+
+  If this driver is compiled as a module you get the ability to select
+  the size of the aperture window pointing into the devices memory.
+  What this means is that if you have a 1G card, normally the kernel
+  will use a 1G memory map as its view of the device.  As a module,
+  you can select a 1M window into the memory and the driver will
+  "slide" the window around the PMC551's memory.  This was
+  particularly useful on the 2.2 kernels on PPC architectures as there
+  was limited kernel space to deal with.
+
+CONFIG_MTD_PMC551_BUGFIX
+  Some of Ramix's PMC551 boards with 256M configurations have invalid
+  column and row mux values.  This option will fix them, but will
+  break other memory configurations.  If unsure say N.
+
+CONFIG_MTD_PMC551_DEBUG
+  This option makes the PMC551 more verbose during its operation and
+  is only really useful if you are developing on this driver or
+  suspect a possible hardware or driver bug.  If unsure say N.
+
+CONFIG_MTD_SLRAM
+  If your CPU cannot cache all of the physical memory in your machine,
+  you can still use it for storage or swap by using this driver to
+  present it to the system as a Memory Technology Device.
+
+CONFIG_MTD_MTDRAM
+  This enables a test MTD device driver which uses vmalloc() to
+  provide storage.  You probably want to say 'N' unless you're
+  testing stuff.
+
+CONFIG_MTDRAM_ERASE_SIZE
+  This allows you to configure the size of the erase blocks in the
+  device emulated by the MTDRAM driver.  If the MTDRAM driver is built
+  as a module, it is also possible to specify this as a parameter when
+  loading the module.
+
+CONFIG_MTDRAM_TOTAL_SIZE
+  This allows you to configure the total size of the MTD device
+  emulated by the MTDRAM driver.  If the MTDRAM driver is built
+  as a module, it is also possible to specify this as a parameter when
+  loading the module.
+
+CONFIG_MTDRAM_ABS_POS
+  If you have system RAM accessible by the CPU but not used by Linux
+  in normal operation, you can give the physical address at which the
+  available RAM starts, and the MTDRAM driver will use it instead of
+  allocating space from Linux's available memory. Otherwise, leave 
+  this set to zero. Most people will want to leave this as zero.
+
+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).
+
+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 (:
+
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/devices/blkmtd.c linux/drivers/mtd/devices/blkmtd.c
--- v2.5.2/linux/drivers/mtd/devices/blkmtd.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/mtd/devices/blkmtd.c	Mon Jan 14 21:49:42 2002
@@ -265,7 +265,6 @@
   sigfillset(&tsk->blocked);
   recalc_sigpending(tsk);
   spin_unlock_irq(&tsk->sigmask_lock);
-  exit_sighand(tsk);
 
   if(alloc_kiovec(1, &iobuf))
     return 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/devices/doc2000.c linux/drivers/mtd/devices/doc2000.c
--- v2.5.2/linux/drivers/mtd/devices/doc2000.c	Thu Oct  4 15:14:59 2001
+++ linux/drivers/mtd/devices/doc2000.c	Tue Jan 15 13:53:51 2002
@@ -97,7 +97,7 @@
 			DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
 			return -EIO;
 		}
-		if (current->need_resched) {
+		if (need_resched()) {
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout(1);
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/maps/Config.help linux/drivers/mtd/maps/Config.help
--- v2.5.2/linux/drivers/mtd/maps/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/maps/Config.help	Fri Jan 25 16:03:52 2002
@@ -0,0 +1,171 @@
+CONFIG_MTD_SA1100
+  This enables access to the flash chips on most platforms based on
+  the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.
+  If you have such a board, say 'Y'.
+
+CONFIG_MTD_PHYSMAP
+  This provides a 'mapping' driver which allows the CFI probe and
+  command set driver code to communicate with flash chips which
+  are mapped physically into the CPU's memory. You will need to
+  configure the physical address and size of the flash chips on
+  your particular board as well as the bus width.
+
+CONFIG_MTD_PHYSMAP_START
+  This is the physical memory location at which the flash chips
+  are mapped on your particular target board. Refer to the
+  memory map which should hopefully be in the documentation for
+  your board.
+
+CONFIG_MTD_PHYSMAP_LEN
+  This is the total length of the mapping of the flash chips on
+  your particular board. If there is space, or aliases, in the
+  physical memory map between the chips, this could be larger
+  than the total amount of flash present. Refer to the memory
+  map which should hopefully be in the documentation for your
+  board.
+
+CONFIG_MTD_PHYSMAP_BUSWIDTH
+  This is the total width of the data bus of the flash devices
+  in octets. For example, if you have a data bus width of 32
+  bits, you would set the bus width octect value to 4. This is
+  used internally by the CFI drivers.
+
+CONFIG_MTD_SUN_UFLASH
+  This provides a 'mapping' driver which supports the way in 
+  which user-programmable flash chips are connected on various 
+  Sun Microsystems boardsets.  This driver will require CFI support 
+  in the kernel, so if you did not enable CFI previously, do that now.
+
+CONFIG_MTD_NORA
+  If you had to ask, you don't have one. Say 'N'.
+
+CONFIG_MTD_PNC2000
+  PNC-2000 is the name of Network Camera product from PHOTRON
+  Ltd. in Japan. It uses CFI-compliant flash.
+
+CONFIG_MTD_RPXLITE
+  The RPXLite PowerPC board has CFI-compliant chips mapped in
+  a strange sparse mapping. This 'mapping' driver supports that
+  arrangement, allowing the CFI probe and command set driver code
+  to communicate with the chips on the RPXLite board. More at
+  <http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm>.
+
+CONFIG_MTD_SC520CDP
+  The SC520 CDP board has two banks of CFI-compliant chips and one
+  Dual-in-line JEDEC chip. This 'mapping' driver supports that
+  arrangement, implementing three MTD devices.
+
+CONFIG_MTD_SBC_GXX
+  This provides a driver for the on-board flash of Arcom Control
+  Systems' SBC-GXn family of boards, formerly known as SBC-MediaGX.
+  By default the flash is split into 3 partitions which are accessed
+  as separate MTD devices.  This board utilizes Intel StrataFlash.
+  More info at
+  <http://www.arcomcontrols.com/products/icp/pc104/processors/>.
+
+CONFIG_MTD_DBOX2
+  This enables access routines for the flash chips on the Nokia/Sagem
+  D-Box 2 board. If you have one of these boards and would like to use
+  the flash chips on it, say 'Y'.
+
+CONFIG_MTD_IQ80310
+  This enables access routines for the flash chips on the Intel XScale
+  IQ80310 evaluation board. If you have one of these boards and would 
+  like to use the flash chips on it, say 'Y'.
+
+CONFIG_MTD_NETSC520
+  This enables access routines for the flash chips on the AMD NetSc520
+  demonstration board. If you have one of these boards and would like 
+  to use the flash chips on it, say 'Y'.
+
+CONFIG_MTD_ELAN_104NC
+  This provides a driver for the on-board flash of the Arcom Control
+  System's ELAN-104NC development board. By default the flash
+  is split into 3 partitions which are accessed as separate MTD
+  devices. This board utilizes Intel StrataFlash. More info at
+  <http://www.arcomcontrols.com/products/icp/pc104/processors/>.
+
+CONFIG_MTD_DC21285
+  This provides a driver for the flash accessed using Intel's
+  21285 bridge used with Intel's StrongARM processors. More info at
+  <http://developer.intel.com/design/bridge/quicklist/dsc-21285.htm>.
+
+CONFIG_MTD_CSTM_MIPS_IXX
+  This provides a mapping driver for the Integrated Tecnology Express,
+  Inc (ITE) QED-4N-S01B eval board and the Globespan IVR Reference
+  Board.  It provides the necessary addressing, length, buswidth, vpp
+  code and addition setup of the flash device for these boards.  In
+  addition, this mapping driver can be used for other boards via
+  setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/LEN/BUSWIDTH
+  parameters.  This mapping will provide one mtd device using one
+  partition.  The start address can be offset from the beginning of
+  flash and the len can be less than the total flash device size to
+  allow a window into the flash.  Both CFI and JEDEC probes are
+  called.
+
+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.
+
+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.
+
+CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH
+  This is the total bus width of the mapping of the flash chips
+  on your particular board.
+
+CONFIG_MTD_MIXMEM
+  This supports the paging arrangement for access to flash chips
+  on the MixCOM piggyback card, allowing the flash chip drivers
+  to get on with their job of driving the flash chips without
+  having to know about the paging. If you have one of these boards,
+  you probably want to enable this mapping driver. More info is at
+  <http://www.itc.hu/>.
+
+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>.
+
+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
+  Board Computer. More information on the board is available at
+  <http://www.tempustech.com/tt301.htm>.
+
+CONFIG_MTD_CFI_FLAGADM
+  Mapping for the Flaga digital module.  If you don´t have one, ignore
+  this setting.
+
+CONFIG_MTD_OCELOT
+  This enables access routines for the boot flash device and for the
+  NVRAM on the Momenco Ocelot board.  If you have one of these boards
+  and would like access to either of these, say 'Y'.
+
+CONFIG_MTD_CDB89712
+  This enables access to the flash or ROM chips on the CDB89712 board.
+  If you have such a board, say 'Y'.
+
+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.
+
+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.
+
+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>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/mtdblock.c linux/drivers/mtd/mtdblock.c
--- v2.5.2/linux/drivers/mtd/mtdblock.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/mtd/mtdblock.c	Mon Jan 14 21:49:42 2002
@@ -472,20 +472,14 @@
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
 
-	tsk->session = 1;
-	tsk->pgrp = 1;
 	/* we might get involved when memory gets low, so use PF_MEMALLOC */
 	tsk->flags |= PF_MEMALLOC;
 	strcpy(tsk->comm, "mtdblockd");
-	tsk->tty = NULL;
 	spin_lock_irq(&tsk->sigmask_lock);
 	sigfillset(&tsk->blocked);
 	recalc_sigpending(tsk);
 	spin_unlock_irq(&tsk->sigmask_lock);
-	exit_mm(tsk);
-	exit_files(tsk);
-	exit_sighand(tsk);
-	exit_fs(tsk);
+	daemonize();
 
 	while (!leaving) {
 		add_wait_queue(&thr_wq, &wait);
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/nand/Config.help linux/drivers/mtd/nand/Config.help
--- v2.5.2/linux/drivers/mtd/nand/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/mtd/nand/Config.help	Fri Jan 25 16:03:51 2002
@@ -0,0 +1,21 @@
+CONFIG_MTD_NAND
+  This enables support for accessing all type of NAND flash
+  devices.
+
+CONFIG_MTD_NAND_ECC
+  This enables software-based ECC for use with NAND flash chips. It
+  can detect and correct 1 bit errors per 256 byte blocks. This
+  should be used to increase the reliability of the data stored and
+  read on the device.
+
+CONFIG_MTD_NAND_VERIFY_WRITE
+  This adds an extra check when data is written to the flash. The
+  NAND flash device internally checks only bits transitioning
+  from 1 to 0. There is a rare possibility that even though the
+  device thinks the write was successful, a bit could have been
+  flipped accidentaly due to device wear, gamma rays, whatever.
+  Enable this if you are really paranoid.
+
+CONFIG_MTD_NAND_SPIA
+  If you had to ask, you don't have one. Say 'N'.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/net/8139cp.c linux/drivers/net/8139cp.c
--- v2.5.2/linux/drivers/net/8139cp.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/8139cp.c	Thu Jan 24 11:51:11 2002
@@ -77,17 +77,6 @@
 MODULE_PARM (multicast_filter_limit, "i");
 MODULE_PARM_DESC (multicast_filter_limit, "8139cp maximum number of filtered multicast addresses");
 
-/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
-#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
-        || defined(__sparc_) || defined(__ia64__) \
-        || defined(__sh__) || defined(__mips__)
-static int rx_copybreak = 1518;
-#else
-static int rx_copybreak = 100;
-#endif
-MODULE_PARM (rx_copybreak, "i");
-MODULE_PARM_DESC (rx_copybreak, "8139cp Breakpoint at which Rx packets are copied");
-
 #define PFX			DRV_NAME ": "
 
 #define CP_DEF_MSG_ENABLE	(NETIF_MSG_DRV		| \
@@ -334,8 +323,8 @@
 	netif_rx (skb);
 }
 
-static inline void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
-				   u32 status, u32 len)
+static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
+			    u32 status, u32 len)
 {
 	if (netif_msg_rx_err (cp))
 		printk (KERN_DEBUG
@@ -429,8 +418,8 @@
 	while (rx_work--) {
 		u32 status, len;
 		dma_addr_t mapping;
-		struct sk_buff *skb, *copy_skb;
-		unsigned copying_skb, buflen;
+		struct sk_buff *skb, *new_skb;
+		unsigned buflen;
 
 		skb = cp->rx_skb[rx_tail].skb;
 		if (!skb)
@@ -453,43 +442,30 @@
 			goto rx_next;
 		}
 
-		copying_skb = (len <= rx_copybreak);
-
 		if (netif_msg_rx_status(cp))
-			printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d copying? %d\n",
-			       cp->dev->name, rx_tail, status, len,
-			       copying_skb);
-
-		buflen = copying_skb ? len : cp->rx_buf_sz;
-		copy_skb = dev_alloc_skb (buflen + RX_OFFSET);
-		if (!copy_skb) {
+			printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n",
+			       cp->dev->name, rx_tail, status, len);
+
+		buflen = cp->rx_buf_sz + RX_OFFSET;
+		new_skb = dev_alloc_skb (buflen);
+		if (!new_skb) {
 			cp->net_stats.rx_dropped++;
 			goto rx_next;
 		}
 
-		skb_reserve(copy_skb, RX_OFFSET);
-		copy_skb->dev = cp->dev;
-
-		if (!copying_skb) {
-			pci_unmap_single(cp->pdev, mapping,
-					 buflen, PCI_DMA_FROMDEVICE);
-			skb->ip_summed = CHECKSUM_NONE;
-			skb_trim(skb, len);
-
-			mapping =
-			cp->rx_skb[rx_tail].mapping =
-				pci_map_single(cp->pdev, copy_skb->data,
-					       buflen, PCI_DMA_FROMDEVICE);
-			cp->rx_skb[rx_tail].skb = copy_skb;
-			skb_put(copy_skb, buflen);
-		} else {
-			skb_put(copy_skb, len);
-			pci_dma_sync_single(cp->pdev, mapping, len, PCI_DMA_FROMDEVICE);
-			memcpy(copy_skb->data, skb->data, len);
+		skb_reserve(new_skb, RX_OFFSET);
+		new_skb->dev = cp->dev;
 
-			/* We'll reuse the original ring buffer. */
-			skb = copy_skb;
-		}
+		pci_unmap_single(cp->pdev, mapping,
+				 buflen, PCI_DMA_FROMDEVICE);
+		skb->ip_summed = CHECKSUM_NONE;
+		skb_put(skb, len);
+
+		mapping =
+		cp->rx_skb[rx_tail].mapping =
+			pci_map_single(cp->pdev, new_skb->tail,
+				       buflen, PCI_DMA_FROMDEVICE);
+		cp->rx_skb[rx_tail].skb = new_skb;
 
 		cp_rx_skb(cp, skb);
 
@@ -884,10 +860,9 @@
 
 		skb->dev = cp->dev;
 		skb_reserve(skb, RX_OFFSET);
-		skb_put(skb, cp->rx_buf_sz);
 
 		cp->rx_skb[i].mapping = pci_map_single(cp->pdev,
-			skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			skb->tail, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 		cp->rx_skb[i].skb = skb;
 		cp->rx_skb[i].frag = 0;
 
@@ -1045,6 +1020,9 @@
 {
 	struct cp_private *cp = dev->priv;
 	int rc = 0;
+
+	if (!netif_running(dev))
+		return -EINVAL;
 
 	switch (cmd) {
 	case SIOCETHTOOL:
diff -u --recursive --new-file v2.5.2/linux/drivers/net/8139too.c linux/drivers/net/8139too.c
--- v2.5.2/linux/drivers/net/8139too.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/8139too.c	Thu Jan 24 11:51:11 2002
@@ -2301,6 +2301,9 @@
 	int rc = 0;
 	int phy = tp->phys[0] & 0x3f;
 
+	if (!netif_running(dev))
+		return -EINVAL;
+
 	if (cmd != SIOCETHTOOL) {
 		/* With SIOCETHTOOL, this would corrupt the pointer.  */
 		data->phy_id &= 0x1f;
diff -u --recursive --new-file v2.5.2/linux/drivers/net/Config.help linux/drivers/net/Config.help
--- v2.5.2/linux/drivers/net/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/Config.help	Fri Jan 25 16:04:23 2002
@@ -0,0 +1,1704 @@
+CONFIG_BAGETLANCE
+  Say Y to enable kernel support for AMD Lance Ethernet cards on the
+  MIPS-32-based Baget embedded system.  This chipset is better known
+  via the NE2100 cards.
+
+CONFIG_MIPS_JAZZ_SONIC
+  This is the driver for the onboard card of MIPS Magnum 4000,
+  Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
+
+CONFIG_MIPS_GT96100ETH
+  Say Y here to support the Ethernet subsystem on your GT96100 card.
+
+CONFIG_DUMMY
+  This is essentially a bit-bucket device (i.e. traffic you send to
+  this device is consigned into oblivion) with a configurable IP
+  address. It is most commonly used in order to make your currently
+  inactive SLIP address seem like a real address for local programs.
+  If you use SLIP or PPP, you might want to say Y here. Since this
+  thing often comes in handy, the default is Y. It won't enlarge your
+  kernel either. What a deal. Read about it in the Network
+  Administrator's Guide, available from
+  <http://www.linuxdoc.org/docs.html#guide>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called dummy.o.  If you want to use more than one dummy
+  device at a time, you need to compile this driver as a module.
+  Instead of 'dummy', the devices will then be called 'dummy0',
+  'dummy1' etc.
+
+CONFIG_BONDING
+  Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet
+  Channels together. This is called 'Etherchannel' by Cisco,
+  'Trunking' by Sun, and 'Bonding' in Linux.
+
+  If you have two Ethernet connections to some other computer, you can
+  make them behave like one double speed connection using this driver.
+  Naturally, this has to be supported at the other end as well, either
+  with a similar Bonding Linux driver, a Cisco 5500 switch or a
+  SunTrunking SunSoft driver.
+
+  This is similar to the EQL driver, but it merges Ethernet segments
+  instead of serial lines.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called bonding.o.
+
+CONFIG_SLIP
+  Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
+  connect to your Internet service provider or to connect to some
+  other local Unix box or if you want to configure your Linux box as a
+  Slip/CSlip server for other people to dial in. SLIP (Serial Line
+  Internet Protocol) is a protocol used to send Internet traffic over
+  serial connections such as telephone lines or null modem cables;
+  nowadays, the protocol PPP is more commonly used for this same
+  purpose.
+
+  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 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
+  <http://www.linuxdoc.org/docs.html#howto>, explains how to
+  configure SLIP. Note that you don't need this option if you just
+  want to run term (term is a program which gives you almost full
+  Internet connectivity if you have a regular dial up shell account on
+  some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). SLIP
+  support will enlarge your kernel by about 4 KB. If unsure, say N.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>. The module will be
+  called slip.o.
+
+CONFIG_SLIP_COMPRESSED
+  This protocol is faster than SLIP because it uses compression on the
+  TCP/IP headers (not on the data itself), but it has to be supported
+  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://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
+  CSLIP. This won't enlarge your kernel.
+
+CONFIG_SLIP_SMART
+  Adds additional capabilities to the SLIP driver to support the
+  RELCOM line fill and keepalive monitoring. Ideal on poor quality
+  analogue lines.
+
+CONFIG_SLIP_MODE_SLIP6
+  Just occasionally you may need to run IP over hostile serial
+  networks that don't pass all control characters or are only seven
+  bit. Saying Y here adds an extra mode you can use with SLIP:
+  "slip6". In this mode, SLIP will only send normal ASCII symbols over
+  the serial device. Naturally, this has to be supported at the other
+  end of the link as well. It's good enough, for example, to run IP
+  over the async ports of a Camtec JNT Pad. If unsure, say N.
+
+CONFIG_PPP
+  PPP (Point to Point Protocol) is a newer and better SLIP.  It serves
+  the same purpose: sending Internet traffic over telephone (and other
+  serial) lines.  Ask your access provider if they support it, because
+  otherwise you can't use it; most Internet access providers these
+  days support PPP rather than SLIP.
+
+  To use PPP, you need an additional program called pppd as described
+  in the PPP-HOWTO, available at
+  <http://www.linuxdoc.org/docs.html#howto>.  Make sure that you have
+  the version of pppd recommended in <file:Documentation/Changes>.
+  The PPP option enlarges your kernel by about 16 KB.
+
+  There are actually two versions of PPP: the traditional PPP for
+  asynchronous lines, such as regular analog phone lines, and
+  synchronous PPP which can be used over digital ISDN lines for
+  example.  If you want to use PPP over phone lines or other
+  asynchronous serial lines, you need to say Y (or M) here and also to
+  the next option, "PPP support for async serial ports".  For PPP over
+  synchronous lines, you should say Y (or M) here and to "Support
+  synchronous PPP", below.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you said Y to "Version information on all symbols" above, then
+  you cannot compile the PPP driver into the kernel; you can then only
+  compile it as a module.  The module will be called ppp_generic.o.
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_PPP_MULTILINK
+  PPP multilink is a protocol (defined in RFC 1990) which allows you
+  to combine several (logical or physical) lines into one logical PPP
+  connection, so that you can utilize your full bandwidth.
+
+  This has to be supported at the other end as well and you need a
+  version of the pppd daemon which understands the multilink protocol.
+
+  If unsure, say N.
+
+CONFIG_PPP_FILTER
+  Say Y here if you want to be able to filter the packets passing over
+  PPP interfaces.  This allows you to control which packets count as
+  activity (i.e. which packets will reset the idle timer or bring up
+  a demand-dialled link) and which packets are to be dropped entirely.
+  You need to say Y here if you wish to use the pass-filter and
+  active-filter options to pppd.
+
+  If unsure, say N.
+
+CONFIG_PPP_ASYNC
+  Say Y (or M) here if you want to be able to use PPP over standard
+  asynchronous serial ports, such as COM1 or COM2 on a PC.  If you use
+  a modem (not a synchronous or ISDN modem) to contact your ISP, you
+  need this option.
+
+  This code is also available as a module (code which can be inserted
+  into and removed from the running kernel).  If you want to compile
+  it as a module, say M here and read <file:Documentation/modules.txt>.
+
+  If unsure, say Y.
+
+CONFIG_PPP_SYNC_TTY
+  Say Y (or M) here if you want to be able to use PPP over synchronous
+  (HDLC) tty devices, such as the SyncLink adapter. These devices
+  are often used for high-speed leased lines like T1/E1.
+
+  This code is also available as a module (code which can be inserted
+  into and removed from the running kernel).  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+CONFIG_PPP_DEFLATE
+  Support for the Deflate compression method for PPP, which uses the
+  Deflate algorithm (the same algorithm that gzip uses) to compress
+  each PPP packet before it is sent over the wire.  The machine at the
+  other end of the PPP link (usually your ISP) has to support the
+  Deflate compression method as well for this to be useful.  Even if
+  they don't support it, it is safe to say Y here.
+
+  This code is also available as a module (code which can be inserted
+  into and removed from the running kernel).  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+CONFIG_PPP_BSDCOMP
+  Support for the BSD-Compress compression method for PPP, which uses
+  the LZW compression method to compress each PPP packet before it is
+  sent over the wire. The machine at the other end of the PPP link
+  (usually your ISP) has to support the BSD-Compress compression
+  method as well for this to be useful. Even if they don't support it,
+  it is safe to say Y here.
+
+  The PPP Deflate compression method ("PPP Deflate compression",
+  above) is preferable to BSD-Compress, because it compresses better
+  and is patent-free.
+
+  Note that the BSD compression code will always be compiled as a
+  module; it is called bsd_comp.o and will show up in the directory
+  modules once you have said "make modules". If unsure, say N.
+
+CONFIG_PPPOE
+  Support for PPP over Ethernet.
+
+  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/>.
+
+CONFIG_NET_RADIO
+  Support for wireless LANs and everything having to do with radio,
+  but not with amateur radio or FM broadcasting.
+
+  Saying Y here also enables the Wireless Extensions (creates
+  /proc/net/wireless and enables ifconfig access). The Wireless
+  Extension is a generic API allowing a driver to expose to the user
+  space configuration and statistics specific to common Wireless LANs.
+  The beauty of it is that a single set of tool can support all the
+  variations of Wireless LANs, regardless of their type (as long as
+  the driver supports Wireless Extension). Another advantage is that
+  these parameters may be changed on the fly without restarting the
+  driver (or Linux). If you wish to use Wireless Extensions with
+  wireless PCMCIA (PC-) cards, you need to say Y here; you can fetch
+  the tools from
+  <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+
+  Some user-level drivers for scarab devices which don't require
+  special kernel support are available from
+  <ftp://shadow.cabi.net/pub/Linux/>.
+
+CONFIG_STRIP
+  Say Y if you have a Metricom radio and intend to use Starmode Radio
+  IP. STRIP is a radio protocol developed for the MosquitoNet project
+  (on the WWW at <http://mosquitonet.stanford.edu/>) to send Internet
+  traffic using Metricom radios.  Metricom radios are small, battery
+  powered, 100kbit/sec packet radio transceivers, about the size and
+  weight of a cellular telephone. (You may also have heard them called
+  "Metricom modems" but we avoid the term "modem" because it misleads
+  many people into thinking that you can plug a Metricom modem into a
+  phone line and use it as a modem.)
+
+  You can use STRIP on any Linux machine with a serial port, although
+  it is obviously most useful for people with laptop computers. If you
+  think you might get a Metricom radio in the future, there is no harm
+  in saying Y to STRIP now, except that it makes the kernel a bit
+  bigger.
+
+  You can also compile this as a module ( = code which can be inserted
+  in and removed from the running kernel whenever you want), say M
+  here and read <file:Documentation/modules.txt>.  The module will be
+  called strip.o.
+
+CONFIG_ARLAN
+  Aironet makes Arlan, a class of wireless LAN adapters. These use the
+  www.Telxon.com chip, which is also used on several similar cards.
+  This driver is tested on the 655 and IC2200 series cards. Look at
+  <http://www.ylenurme.ee/~elmer/655/> for the latest information.
+
+  The driver is built as two modules, arlan and arlan-proc. The latter
+  is the /proc interface and is not needed most of time.
+
+  On some computers the card ends up in non-valid state after some
+  time. Use a ping-reset script to clear it.
+
+CONFIG_AIRONET4500
+  www.aironet.com (recently bought by Cisco) makes these 802.11 DS
+  adapters.  Driver by Elmer Joandi (elmer@ylenurme.ee).
+
+  Say Y here if you have such an adapter, and then say Y below to
+  the option that applies to your particular type of card (PCI, ISA,
+  or PCMCIA).
+
+  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 aironet4500_core.o. If you want to
+  compile it as a module, say M here and read
+  <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.
+
+  quick config parameters:
+	SSID=tsunami - "The Password"
+	adhoc=1  	there are no Access Points around
+	master=1 	Adhoc master (the one who creates network
+                        sync)
+	slave=1		Adhoc slave (btw, it is still forming own net
+			sometimes, and has problems with firmware...
+			change IbssJoinNetTimeout from /proc...)
+	channel=1..? 	meaningful in adhoc mode
+
+  If you have problems with screwing up card, both_bap_lock=1 is a
+  conservative value (performance hit 15%).
+
+  All other parameters can be set via the proc interface.
+
+CONFIG_AIRONET4500_NONCS
+  If you have an ISA, PCI or PCMCIA Aironet 4500/4800 wireless LAN
+  card, say Y here, and then also to the options below that apply
+  to you.
+
+  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 aironet4500_card.o.  If you want to
+  compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+CONFIG_AIRONET4500_PNP
+  If you have an ISA Aironet 4500/4800 card which you want to use in
+  PnP (Plug and Play) mode, say Y here. This is the recommended mode
+  for ISA cards. Remember however to enable the PnP jumper on the
+  board if you say Y here.
+
+CONFIG_AIRONET4500_PCI
+  If you have an PCI Aironet 4500/4800 card, say Y here.
+
+CONFIG_AIRONET4500_ISA
+  If you have an ISA Aironet 4500/4800 card which you want to run in
+  non-PnP mode, say Y here. This is not recommended and does not work
+  correctly at this point. Say N.
+
+CONFIG_AIRONET4500_I365
+  If you have a PCMCIA Aironet 4500/4800 card which you want to use
+  without the standard PCMCIA cardservices provided by the pcmcia-cs
+  package, say Y here. This is not recommended, so say N.
+
+CONFIG_AIRONET4500_PROC
+  If you say Y here (and to the "/proc file system" below), you will
+  be able to configure your Aironet card via the
+  /proc/sys/aironet4500 interface.
+
+  Additional info: look in <file:drivers/net/aironet4500_rid.c>.
+
+  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 aironet4500_proc.o. If you want to
+  compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+  NOTE: the proc interface uses a lot of memory, so it is recommended
+        to compile it as a module and remove the module after
+        configuration.
+
+CONFIG_PLIP
+  PLIP (Parallel Line Internet Protocol) is used to create a
+  reasonably fast mini network consisting of two (or, rarely, more)
+  local machines.  A PLIP link from a Linux box is a popular means to
+  install a Linux distribution on a machine which doesn't have a
+  CD-ROM drive (a minimal system has to be transferred with floppies
+  first). The kernels on both machines need to have this PLIP option
+  enabled for this to work.
+
+  The PLIP driver has two modes, mode 0 and mode 1.  The parallel
+  ports (the connectors at the computers with 25 holes) are connected
+  with "null printer" or "Turbo Laplink" cables which can transmit 4
+  bits at a time (mode 0) or with special PLIP cables, to be used on
+  bidirectional parallel ports only, which can transmit 8 bits at a
+  time (mode 1); you can find the wiring of these cables in
+  <file:Documentation/networking/PLIP.txt>.  The cables can be up to
+  15m long.  Mode 0 works also if one of the machines runs DOS/Windows
+  and has some PLIP software installed, e.g. the Crynwr PLIP packet
+  driver (<http://oak.oakland.edu/simtel.net/msdos/pktdrvr-pre.html>)
+  and winsock or NCSA's telnet.
+
+  If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well
+  as the NET-3-HOWTO, both available from
+  <http://www.linuxdoc.org/docs.html#howto>.  Note that the PLIP
+  protocol has been changed and this PLIP driver won't work together
+  with the PLIP support in Linux versions 1.0.x.  This option enlarges
+  your kernel by about 8 KB.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called plip.o.  If unsure, say Y or M, in case you buy a laptop
+  later.
+
+CONFIG_EQUALIZER
+  If you have two serial connections to some other computer (this
+  usually requires two modems and two telephone lines) and you use
+  SLIP (the protocol for sending Internet traffic over telephone
+  lines) or PPP (a better SLIP) on them, you can make them behave like
+  one double speed connection using this driver.  Naturally, this has
+  to be supported at the other end as well, either with a similar EQL
+  Linux driver or with a Livingston Portmaster 2e.
+
+  Say Y if you want this and read
+  <file:Documentation/networking/eql.txt>.  You may also want to read
+  section 6.2 of the NET-3-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called eql.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.  If
+  unsure, say N.
+
+CONFIG_TUN
+  TUN/TAP provides packet reception and transmission for user space
+  programs.  It can be viewed as a simple Point-to-Point or Ethernet
+  device, which instead of receiving packets from a physical media,
+  receives them from user space program and instead of sending packets
+  via physical media writes them to the user space program.
+
+  When a program opens /dev/net/tun, driver creates and registers
+  corresponding net device tunX or tapX.  After a program closed above
+  devices, driver will automatically delete tunXX or tapXX device and
+  all routes corresponding to it.
+
+  Please read <file:Documentation/networking/tuntap.txt> for more
+  information.
+
+  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 tun.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+  If you don't know what to use this for, you don't need it.
+
+CONFIG_ETHERTAP
+  If you say Y here (and have said Y to "Kernel/User network link
+  driver", above) and create a character special file /dev/tap0 with
+  major number 36 and minor number 16 using mknod ("man mknod"), you
+  will be able to have a user space program read and write raw
+  Ethernet frames from/to that special file.  tap0 can be configured
+  with ifconfig and route like any other Ethernet device but it is not
+  connected to any physical LAN; everything written by the user to
+  /dev/tap0 is treated by the kernel as if it had come in from a LAN
+  to the device tap0; everything the kernel wants to send out over the
+  device tap0 can instead be read by the user from /dev/tap0: the user
+  mode program replaces the LAN that would be attached to an ordinary
+  Ethernet device. Please read the file
+  <file:Documentation/networking/ethertap.txt> for more information.
+
+  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 ethertap.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+  If you don't know what to use this for, you don't need it.
+
+CONFIG_NET_FC
+  Fibre Channel is a high speed serial protocol mainly used to connect
+  large storage devices to the computer; it is compatible with and
+  intended to replace SCSI.
+
+  If you intend to use Fibre Channel, you need to have a Fibre channel
+  adaptor card in your computer; say Y here and to the driver for your
+  adaptor below. You also should have said Y to "SCSI support" and
+  "SCSI generic support".
+
+CONFIG_IPHASE5526
+  Say Y here if you have a Fibre Channel adaptor of this kind.
+
+  The 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 iph5526.o. For general information about
+  modules read <file:Documentation/modules.txt>.
+
+CONFIG_RCPCI
+  This is a driver for hardware which provides a Virtual Private
+  Network (VPN). Say Y if you have it.
+
+  This code is also available as a module called rcpci.o ( = 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>.
+
+CONFIG_NET_ETHERNET
+  Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
+  type of Local Area Network (LAN) in universities and companies.
+
+  Common varieties of Ethernet are: 10BASE-2 or Thinnet (10 Mbps over
+  coaxial cable, linking computers in a chain), 10BASE-T or twisted
+  pair (10 Mbps over twisted pair cable, linking computers to central
+  hubs), 10BASE-F (10 Mbps over optical fiber links, using hubs),
+  100BASE-TX (100 Mbps over two twisted pair cables, using hubs),
+  100BASE-T4 (100 Mbps over 4 standard voice-grade twisted pair
+  cables, using hubs), 100BASE-FX (100 Mbps over optical fiber links)
+  [the 100BASE varieties are also known as Fast Ethernet], and Gigabit
+  Ethernet (1 Gbps over optical fiber or short copper links).
+
+  If your Linux machine will be connected to an Ethernet and you have
+  an Ethernet network interface card (NIC) installed in your computer,
+  say Y here and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. You will then also have
+  to say Y to the driver for your particular NIC.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about Ethernet network cards. If unsure, say N.
+
+CONFIG_NET_VENDOR_SMC
+  If you have a network (Ethernet) card belonging to this class, say Y
+  and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about Western Digital cards. If you say Y, you will be
+  asked for your specific card in the following questions.
+
+CONFIG_WD80x3
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called wd.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_ULTRAMCA
+  If you have a network (Ethernet) card of this type and are running
+  an MCA based system (PS/2), say Y and read the Ethernet-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called smc-mca.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_ULTRA
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Important: There have been many reports that, with some motherboards
+  mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible,
+  such as some BusLogic models) causes corruption problems with many
+  operating systems. The Linux smc-ultra driver has a work-around for
+  this but keep it in mind if you have such a SCSI card and have
+  problems.
+
+  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 smc-ultra.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt> as
+  well as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_ULTRA32
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called smc-ultra32.o.  If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt> as
+  well as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_SMC9194
+  This is support for the SMC9xxx based Ethernet cards. Choose this
+  option if you have a DELL laptop with the docking station, or
+  another SMC9192/9194 based chipset.  Say Y if you want it compiled
+  into the kernel, and read the file
+  <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called smc9194.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_NE2K_PCI
+  This driver is for NE2000 compatible PCI cards. It will not work
+  with ISA NE2000 cards (they have their own driver, "NE2000/NE1000
+  support" below). If you have a PCI NE2000 network (Ethernet) card,
+  say Y and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver also works for the following NE2000 clone cards:
+    RealTek RTL-8029  Winbond 89C940  Compex RL2000  KTI ET32P2
+    NetVin NV5000SC   Via 86C926      SureCom NE34   Winbond
+    Holtek HT80232    Holtek HT80229
+
+  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 ne2k-pci.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt> as
+  well as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_NET_VENDOR_RACAL
+  If you have a network (Ethernet) card belonging to this class, such
+  as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about NI cards. If you say Y, you will be asked for
+  your specific card in the following questions.
+
+CONFIG_NI5010
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. Note that this is still
+  experimental code.
+
+  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 ni5010.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_NI52
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ni52.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_NI65
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ni65.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_8139CP
+  This is a driver for the Fast Ethernet PCI network cards based on
+  the RTL8139C+ chips. If you have one of those, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called 8139cp.o.
+
+CONFIG_8139TOO
+  This is a driver for the Fast Ethernet PCI network cards based on
+  the RTL8139 chips. If you have one of those, say Y and read
+  <file:Documentation/networking/8139too.txt> as well as the
+  Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called 8139too.o.
+
+CONFIG_8139TOO_PIO
+  This instructs the driver to use programmed I/O ports (PIO) instead
+  of PCI shared memory (MMIO).  This can possibly solve some problems
+  in case your mainboard has memory consistency issues.  If unsure,
+  say N.
+
+CONFIG_8139TOO_TUNE_TWISTER
+  This implements a function which might come in handy in case you are
+  using low quality on long cabling. It tries to match the transceiver
+  to the cable characteristics. This is experimental since hardly
+  documented by the manufacturer.  If unsure, say N.
+
+CONFIG_8139TOO_8129
+  This enables support for the older and uncommon RTL-8129 and
+  RTL-8130 chips, which support MII via an external transceiver,
+  instead of an internal one.  Disabling this option will save some
+  memory by making the code size smaller.  If unsure, say Y.
+
+CONFIG_SIS900
+  This is a driver for the Fast Ethernet PCI network cards based on
+  the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in
+  SiS 630 and SiS 540 chipsets.  If you have one of those, say Y and
+  read the Ethernet-HOWTO, available at
+  <http://www.linuxdoc.org/docs.html#howto>.  Please read
+  <file:Documentation/networking/sis900.txt> and comments at the
+  beginning of <file:drivers/net/sis900.c> for more information.
+
+  This driver also supports AMD 79C901 HomePNA so that you can use
+  your phone line as a network cable.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called sis900.o.
+
+CONFIG_YELLOWFIN
+  Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
+  adapter or the SYM53C885 Ethernet controller. The Gigabit adapter is
+  used by the Beowulf Linux cluster project.  See
+  <http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html> for more
+  information about this driver in particular and Beowulf in general.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called yellowfin.o.
+
+CONFIG_NET_SB1000
+  This is a driver for the General Instrument (also known as
+  NextLevel) SURFboard 1000 internal
+  cable modem. This is an ISA card which is used by a number of cable
+  TV companies to provide cable modem access. It's a one-way
+  downstream-only cable modem, meaning that your upstream net link is
+  provided by your regular phone modem.
+
+  At present this driver only compiles as a module, so say M here if
+  you have this card. The module will be called sb1000.o. Then read
+  <file:Documentation/networking/README.sb1000> for information on how
+  to use this module, as it needs special ppp scripts for establishing
+  a connection. Further documentation and the necessary scripts can be
+  found at:
+
+  <http://www.jacksonville.net/~fventuri/>
+  <http://home.adelphia.net/~siglercm/sb1000.html>
+  <http://linuxpower.cx/~cable/>
+
+  If you don't have this card, of course say N.
+
+CONFIG_ADAPTEC_STARFIRE
+  Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network
+  adapter. The DuraLAN chip is used on the 64 bit PCI boards from
+  Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip
+  driver.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called starfire.o.
+
+CONFIG_ACENIC
+  Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear
+  GA620, SGI Gigabit or Farallon PN9000-SX PCI Gigabit Ethernet
+  adapter. The driver allows for using the Jumbo Frame option (9000
+  bytes/frame) however it requires that your switches can handle this
+  as well. To enable Jumbo Frames, add `mtu 9000' to your ifconfig
+  line.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called acenic.o.
+
+CONFIG_ACENIC_OMIT_TIGON_I
+  Say Y here if you only have Tigon II based AceNICs and want to leave
+  out support for the older Tigon I based cards which are no longer
+  being sold (ie. the original Alteon AceNIC and 3Com 3C985 (non B
+  version)).  This will reduce the size of the driver object by
+  app. 100KB.  If you are not sure whether your card is a Tigon I or a
+  Tigon II, say N here.
+
+  The safe and default value for this is N.
+
+CONFIG_SK98LIN
+  Say Y here if you have a SysKonnect SK-98xx Gigabit Ethernet Server
+  Adapter. The following adapters are supported by this driver:
+  - SK-9841 (single link 1000Base-LX)
+  - SK-9842 (dual link   1000Base-LX)
+  - SK-9843 (single link 1000Base-SX)
+  - SK-9844 (dual link   1000Base-SX)
+  - SK-9821 (single link 1000Base-T)
+  - SK-9822 (dual link   1000Base-T)
+  - SK-9861 (single link Volition connector)
+  - SK-9862 (dual link   Volition connector)
+  The driver also supports the following adapters from Allied Telesyn:
+  - AT2970...
+
+  The dual link adapters support a link-failover feature.  Read
+  <file:Documentation/networking/sk98lin.txt> for information about
+  optional driver parameters.
+  Questions concerning this driver may be addressed to:
+    linux@syskonnect.de
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called sk98lin.o.
+
+CONFIG_SUNGEM
+  Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0.  See also
+  <http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>.
+
+CONFIG_MYRI_SBUS
+  This driver supports MyriCOM Sbus gigabit Ethernet cards.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called myri_sbus.o.
+
+CONFIG_DL2K
+  This driver supports D-Link 2000-based gigabit ethernet cards, which
+  includes
+       D-Link DGE-550T Gigabit Ethernet Adapter.
+       D-Link DL2000-based Gigabit Ethernet Adapter.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called dl2k.o.
+
+CONFIG_LANCE
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. Some LinkSys cards are
+  of this type.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called lance.o.
+
+CONFIG_SGI_IOC3_ETH
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+CONFIG_STNIC
+  Support for cards based on the National Semiconductor DP83902AV
+  ST-NIC Serial Network Interface Controller for Twisted Pair.  This
+  is a 10Mbit/sec Ethernet controller.  Product overview and specs at
+  <http://www.national.com/pf/DP/DP83902A.html>.
+
+  If unsure, say N.
+
+CONFIG_NET_VENDOR_3COM
+  If you have a network (Ethernet) card belonging to this class, say Y
+  and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about 3COM cards. If you say Y, you will be asked for
+  your specific card in the following questions.
+
+CONFIG_EL1
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  Also, consider buying a
+  new card, since the 3c501 is slow, broken, and obsolete: you will
+  have problems.  Some people suggest to ping ("man ping") a nearby
+  machine every minute ("man cron") when using this card.
+
+  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 3c501.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_EL2
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called 3c503.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_ELPLUS
+  Information about this network (Ethernet) card can be found in
+  <file:Documentation/networking/3c505.txt>.  If you have a card of
+  this type, say Y and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called 3c505.o.
+
+CONFIG_EL16
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called 3c507.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_ELMC
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called 3c523.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_ELMC_II
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called 3c527.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_EL3
+  If you have a network (Ethernet) card belonging to the 3Com
+  EtherLinkIII series, say Y and read the Ethernet-HOWTO, available
+  from <http://www.linuxdoc.org/docs.html#howto>.
+
+  If your card is not working you may need to use the DOS
+  setup disk to disable Plug & Play mode, and to select the default
+  media type.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called 3c509.o.
+
+CONFIG_3C515
+  If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet
+  network card, say Y and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called 3c515.o.
+
+CONFIG_VORTEX
+  This option enables driver support for a large number of 10mbps and
+  10/100mbps EISA, PCI and PCMCIA 3Com network cards:
+
+  "Vortex"    (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI
+  "Boomerang" (EtherLink XL 3c900 or 3c905)            PCI
+  "Cyclone"   (3c540/3c900/3c905/3c980/3c575/3c656)    PCI and Cardbus
+  "Tornado"   (3c905)                                  PCI
+  "Hurricane" (3c555/3cSOHO)                           PCI
+
+  If you have such a card, say Y and read the Ethernet-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>. More
+  specific information is in
+  <file:Documentation/networking/vortex.txt> and in the comments at
+  the beginning of <file:drivers/net/3c59x.c>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_NET_ISA
+  If your network (Ethernet) card hasn't been mentioned yet and its
+  bus system (that's the way the cards talks to the other components
+  of your computer) is ISA (as opposed to EISA, VLB or PCI), say Y.
+  Make sure you know the name of your card. Read the Ethernet-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  If unsure, say Y.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the remaining ISA network card questions. If you say Y, you will be
+  asked for your specific card in the following questions.
+
+CONFIG_E2100
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called e2100.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_CS89x0
+  Support for CS89x0 chipset based Ethernet cards. If you have a
+  network (Ethernet) card of this type, say Y and read the
+  Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto> as well as
+  <file:Documentation/networking/cs89x0.txt>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called cs89x.o.
+
+CONFIG_DEPCA
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto> as well as
+  <file:drivers/net/depca.c>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called
+  depca.o.
+
+CONFIG_EWRK3
+  This driver supports the DE203, DE204 and DE205 network (Ethernet)
+  cards. If this is for you, say Y and read
+  <file:Documentation/networking/ewrk3.txt> in the kernel source as
+  well as the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called ewrk3.o.
+
+CONFIG_SEEQ8005
+  This is a driver for the SEEQ 8005 network (Ethernet) card.  If this
+  is for you, read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called ewrk3.o.
+
+CONFIG_AT1700
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  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>.  The module will be
+  called at1700.o.
+
+CONFIG_FMV18X
+  If you have a Fujitsu FMV-181/182/183/184 network (Ethernet) card,
+  say Y and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you use an FMV-183 or FMV-184 and it is not working, you may need
+  to disable Plug & Play mode of the card.
+
+  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 fmv18x.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+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
+  that the EtherExpress PRO/100 Ethernet card has its own separate
+  driver.  Please read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called eepro.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_EEXPRESS
+  If you have an EtherExpress16 network (Ethernet) card, say Y and
+  read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  Note that the Intel
+  EtherExpress16 card used to be regarded as a very poor choice
+  because the driver was very unreliable. We now have a new driver
+  that should do better.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called eexpress.o.
+
+CONFIG_HAMACHI
+  If you have a Gigabit Ethernet card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called hamachi.o.
+
+CONFIG_HPLAN_PLUS
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called hp-plus.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_HPLAN
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called hp.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_HP100
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called hp100.o.
+
+CONFIG_NE2000
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  Many Ethernet cards
+  without a specific driver are compatible with NE2000.
+
+  If you have a PCI NE2000 card however, say N here and Y to "PCI
+  NE2000 support", above. If you have a NE2000 card and are running on
+  an MCA system (a bus system used on some IBM PS/2 computers and
+  laptops), say N here and Y to "NE/2 (ne2000 MCA version) support",
+  below.
+
+  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 ne.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_NATSEMI
+  This driver is for the National Semiconductor DP83810 series,
+  which is used in cards from PureData, NetGear, Linksys
+  and others, including the 83815 chip.
+  More specific information and updates are available from
+  <http://www.scyld.com/network/natsemi.html>.
+
+CONFIG_SK_G16
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+CONFIG_NE2_MCA
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ne2.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_SKMC
+  These are Micro Channel Ethernet adapters. You need to say Y to "MCA
+  support" in order to use this driver.  Supported cards are the SKnet
+  Junior MC2 and the SKnet MC2(+).  The driver automatically
+  distinguishes between the two cards. Note that using multiple boards
+  of different type hasn't been tested with this driver.  Say Y if you
+  have one of these Ethernet adapters.
+
+  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 is called sk_mca.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_IBMLANA
+  This is a Micro Channel Ethernet adapter.  You need to set
+  CONFIG_MCA to use this driver.  It is both available as an in-kernel
+  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>. 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
+  boards with this driver should be possible, but has not been tested
+  up to now due to lack of hardware.
+
+CONFIG_NET_PCI
+  This is another class of network cards which attach directly to the
+  bus. If you have one of those, say Y and read the Ethernet-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about this class of network cards. If you say Y, you
+  will be asked for your specific card in the following questions. If
+  you are unsure, say Y.
+
+CONFIG_PCNET32
+  If you have a PCnet32 or PCnetPCI based network (Ethernet) card,
+  answer Y here and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pcnet32.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_AC3200
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ac3200.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_LNE390
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called lne390.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_NE3210
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  Note that this driver
+  will NOT WORK for NE3200 cards as they are completely different.
+
+  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 ne3210.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_APRICOT
+  If you have a network (Ethernet) controller of this type, say Y and
+  read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called apricot.o.
+
+CONFIG_DE4X5
+  This is support for the DIGITAL series of PCI/EISA Ethernet cards.
+  These include the DE425, DE434, DE435, DE450 and DE500 models.  If
+  you have a network card of this type, say Y and read the
+  Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. More specific
+  information is contained in
+  <file:Documentation/networking/de4x5.txt>.
+
+  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 de4x5.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_TULIP
+  This driver is developed for the SMC EtherPower series Ethernet
+  cards and also works with cards based on the DECchip 
+  21040/21041/21140 (Tulip series) chips.  Some LinkSys PCI cards are
+  of this type.  (If your card is NOT SMC EtherPower 10/100 PCI
+  (smc9332dst), you can also try the driver for "Generic DECchip"
+  cards, above.  However, most people with a network card of this type
+  will say Y here.) Do read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  More specific
+  information is contained in 
+  <file:Documentation/networking/tulip.txt>.
+
+  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 tulip.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_DGRS
+  This is support for the Digi International RightSwitch series of
+  PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6
+  models.  If you have a network card of this type, say Y and read the
+  Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  More specific
+  information is contained in <file:Documentation/networking/dgrs.txt>.
+
+  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 dgrs.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_EEPRO100
+  If you have an Intel EtherExpress PRO/100 PCI network (Ethernet)
+  card, say Y and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called eepro100.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt> as
+  well as <file:Documentation/networking/net-modules.txt>.
+
+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/>.
+
+CONFIG_ETH16I
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called eth16i.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_TLAN
+  If you have a PCI Ethernet network card based on the ThunderLAN chip
+  which is supported by this driver, say Y and read the
+  Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Devices currently supported by this driver are Compaq Netelligent,
+  Compaq NetFlex and Olicom cards.  Please read the file
+  <file:Documentation/networking/tlan.txt> for more details.
+
+  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 tlan.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+  Please email feedback to  torben.mathiasen@compaq.com.
+
+CONFIG_VIA_RHINE
+  If you have a VIA "rhine" based network card (Rhine-I (3043) or
+  Rhine-2 (VT86c100A)), say Y here.
+
+  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 via-rhine.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt> as
+  well as <file:Documentation/networking/net-modules.txt>.
+
+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
+  (Ethernet) card, say Y.  Some information is contained in the file
+  <file:Documentation/networking/dmfe.txt>.
+
+  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 dmfe.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_ES3210
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called es3210.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_EPIC100
+  This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC,
+  which is based on the SMC83c17x (EPIC/100).
+  More specific information and updates are available from
+  <http://www.scyld.com/network/epic100.html>.
+
+CONFIG_DECLANCE
+  This driver is for the series of Ethernet controllers produced by
+  DEC (now Compaq) based on the AMD Lance chipset, including the
+  DEPCA series.  (This chipset is better known via the NE2100 cards.)
+
+CONFIG_SGISEEQ
+  Say Y here if you have an Seeq based Ethernet network card. This is
+  used in many Silicon Graphics machines.
+
+CONFIG_SUNDANCE
+  This driver is for the Sundance "Alta" chip.
+  More specific information and updates are available from
+  <http://www.scyld.com/network/sundance.html>.
+
+CONFIG_WINBOND_840
+  This driver is for the Winbond W89c840 chip.  It also works with
+  the TX9882 chip on the Compex RL100-ATX board.
+  More specific information and updates are available from
+  <http://www.scyld.com/network/drivers.html>.
+
+CONFIG_ZNET
+  The Zenith Z-Note notebook computer has a built-in network
+  (Ethernet) card, and this is the Linux driver for it. Note that the
+  IBM Thinkpad 300 is compatible with the Z-Note and is also supported
+  by this driver. Read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+CONFIG_LAN_SAA9730
+  The SAA9730 is a combined multimedia and peripheral controller used
+  in thin clients, Internet access terminals, and diskless
+  workstations.
+  See <http://www.semiconductors.philips.com/pip/SAA9730_flyer_1>.
+
+CONFIG_NET_POCKET
+  Cute little network (Ethernet) devices which attach to the parallel
+  port ("pocket adapters"), commonly used with laptops. If you have
+  one of those, say Y and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to plug a network (or some other) card into the PCMCIA
+  (or PC-card) slot of your laptop instead (PCMCIA is the standard for
+  credit card size extension cards used by all modern laptops), you
+  need the pcmcia-cs package (location contained in the file
+  <file:Documentation/Changes>) and you can say N here.
+
+  Laptop users should read the Linux Laptop home page at
+  <http://www.cs.utexas.edu/users/kharker/linux-laptop/>.
+
+  Note that the answer to this question doesn't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about this class of network devices. If you say Y, you
+  will be asked for your specific device in the following questions.
+
+CONFIG_ATP
+  This is a network (Ethernet) device which attaches to your parallel
+  port. Read <file:drivers/net/atp.c> as well as the Ethernet-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>, if you
+  want to use this.  If you intend to use this driver, you should have
+  said N to the "Parallel printer support", because the two drivers
+  don't like each other.
+
+  If you want to compile this driver as a module however ( = 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 atp.o.
+
+CONFIG_DE600
+  This is a network (Ethernet) device which attaches to your parallel
+  port. Read <file:Documentation/networking/DLINK.txt> as well as the
+  Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, if you want to use
+  this. It is possible to have several devices share a single parallel
+  port and it is safe to compile the corresponding drivers into the
+  kernel.
+
+  If you want to compile this driver as a module however ( = 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 de600.o.
+
+CONFIG_DE620
+  This is a network (Ethernet) device which attaches to your parallel
+  port. Read <file:Documentation/networking/DLINK.txt> as well as the
+  Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, if you want to use
+  this. It is possible to have several devices share a single parallel
+  port and it is safe to compile the corresponding drivers into the
+  kernel.
+
+  If you want to compile this driver as a module however ( = 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 de620.o.
+
+CONFIG_HAPPYMEAL
+  This driver supports the "hme" interface present on most Ultra
+  systems and as an option on older Sbus systems. This driver supports
+  both PCI and Sbus devices. This driver also supports the "qfe" quad
+  100baseT device available in both PCI and Sbus configurations.
+
+  This support is also available as a module called sunhme.o ( = 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>.
+
+CONFIG_SUNLANCE
+  This driver supports the "le" interface present on all 32-bit Sparc
+  systems, on some older Ultra systems and as an Sbus option.  These
+  cards are based on the AMD Lance chipset, which is better known
+  via the NE2100 cards.
+
+  This support is also available as a module called sunlance.o ( =
+  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>.
+
+CONFIG_SUNBMAC
+  This driver supports the "be" interface available as an Sbus option.
+  This is Sun's older 100baseT Ethernet device.
+
+  This support is also available as a module called sunbmac.o ( = 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>.
+
+CONFIG_SUNQE
+  This driver supports the "qe" 10baseT Ethernet device, available as
+  an Sbus option. Note that this is not the same as Quad FastEthernet
+  "qfe" which is supported by the Happy Meal driver instead.
+
+  This support is also available as a module called sunqe.o ( = 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>.
+
+CONFIG_SHAPER
+  The traffic shaper is a virtual network device that allows you to
+  limit the rate of outgoing data flow over some other network device.
+  The traffic that you want to slow down can then be routed through
+  these virtual devices. See
+  <file:Documentation/networking/shaper.txt> for more information.
+
+  An alternative to this traffic shaper is the experimental
+  Class-Based Queueing (CBQ) scheduling support which you get if you
+  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
+  shaper package.
+
+  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 shaper.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.  If
+  unsure, say N.
+
+CONFIG_FDDI
+  Fiber Distributed Data Interface is a high speed local area network
+  design; essentially a replacement for high speed Ethernet. FDDI can
+  run over copper or fiber. If you are connected to such a network and
+  want a driver for the FDDI card in your computer, say Y here (and
+  then also Y to the driver for your FDDI card, below). Most people
+  will say N.
+
+CONFIG_DEFXX
+  This is support for the DIGITAL series of EISA (DEFEA) and PCI
+  (DEFPA) controllers which can connect you to a local FDDI network.
+
+CONFIG_SKFP
+  Say Y here if you have a SysKonnect FDDI PCI adapter.
+  The following adapters are supported by this driver:
+  - SK-5521 (SK-NET FDDI-UP)
+  - SK-5522 (SK-NET FDDI-UP DAS)
+  - SK-5541 (SK-NET FDDI-FP)
+  - SK-5543 (SK-NET FDDI-LP)
+  - SK-5544 (SK-NET FDDI-LP DAS)
+  - SK-5821 (SK-NET FDDI-UP64)
+  - SK-5822 (SK-NET FDDI-UP64 DAS)
+  - SK-5841 (SK-NET FDDI-FP64)
+  - SK-5843 (SK-NET FDDI-LP64)
+  - SK-5844 (SK-NET FDDI-LP64 DAS)
+  - Netelligent 100 FDDI DAS Fibre SC
+  - Netelligent 100 FDDI SAS Fibre SC
+  - Netelligent 100 FDDI DAS UTP
+  - Netelligent 100 FDDI SAS UTP
+  - Netelligent 100 FDDI SAS Fibre MIC
+
+  Read <file:Documentation/networking/skfp.txt> for information about
+  the driver.
+
+  Questions concerning this driver can be addressed to:
+    linux@syskonnect.de
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called skfp.o.
+
+CONFIG_HIPPI
+  HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and
+  1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI
+  can run over copper (25m) or fiber (300m on multi-mode or 10km on
+  single-mode). HIPPI networks are commonly used for clusters and to
+  connect to super computers. If you are connected to a HIPPI network
+  and have a HIPPI network card in your computer that you want to use
+  under Linux, say Y here (you must also remember to enable the driver
+  for your HIPPI card below). Most people will say N here.
+
+CONFIG_ROADRUNNER
+  Say Y here if this is your PCI HIPPI network card.
+
+  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 rrunner.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.  If
+  unsure, say N.
+
+CONFIG_ROADRUNNER_LARGE_RINGS
+  If you say Y here, the RoadRunner driver will preallocate up to 2 MB
+  of additional memory to allow for fastest operation, both for
+  transmitting and receiving. This memory cannot be used by any other
+  kernel code or by user space programs. Say Y here only if you have
+  the memory.
+
+CONFIG_ARM_AM79C961A
+  If you wish to compile a kernel for the EBSA-110, then you should
+  always answer Y to this.
+
+CONFIG_ARIADNE
+  If you have a Village Tronic Ariadne Ethernet adapter, say Y.
+  Otherwise, say N.
+
+  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 is called ariadne.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_A2065
+  If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise,
+  say N.
+
+  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 is called a2065.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_HYDRA
+  If you have a Hydra Ethernet adapter, say Y. Otherwise, say N.
+
+  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 is called hydra.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MACE
+  Power Macintoshes and clones with Ethernet built-in on the
+  motherboard will usually use a MACE (Medium Access Control for
+  Ethernet) interface. Say Y to include support for the MACE chip.
+
+  This driver is also available as a module called mace.o ( = 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>.
+
+CONFIG_MACE_AAUI_PORT
+  Some Apple machines (notably the Apple Network Server) which use the
+  MACE ethernet chip have an Apple AUI port (small 15-pin connector),
+  instead of an 8-pin RJ45 connector for twisted-pair ethernet.  Say
+  Y here if you have such a machine.  If unsure, say N.
+  The driver will default to AAUI on ANS anyway, and if you use it as
+  a module, you can provide the port_aaui=0|1 to force the driver.
+
+CONFIG_BMAC
+  Say Y for support of BMAC Ethernet interfaces. These are used on G3
+  computers.
+
+  This driver is also available as a module called bmac.o ( = 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>.
+
+CONFIG_GMAC
+  Say Y for support of GMAC Ethernet interfaces. These are used on G4
+  and iBook computers.
+
+  This driver is also available as a module called gmac.o ( = 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>.
+
+CONFIG_OAKNET
+  Say Y if your machine has this type of Ethernet network card.
+
+  This driver is also available as a module called oaknet.o ( = 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>.
+
+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.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.5.2/linux/drivers/net/Config.in	Tue Dec 18 14:56:36 2001
+++ linux/drivers/net/Config.in	Mon Jan 21 16:04:47 2002
@@ -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
@@ -294,7 +292,6 @@
 bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO
 if [ "$CONFIG_NET_RADIO" = "y" ]; then
    dep_tristate '  STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET
-   tristate '  AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
    tristate '  Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
    tristate '  Aironet 4500/4800 series adapters' CONFIG_AIRONET4500
    dep_tristate '   Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500
diff -u --recursive --new-file v2.5.2/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.5.2/linux/drivers/net/Makefile	Tue Dec 18 14:56:36 2001
+++ linux/drivers/net/Makefile	Thu Jan 24 11:51:10 2002
@@ -17,7 +17,7 @@
 
 export-objs     :=	8390.o arlan.o aironet4500_core.o aironet4500_card.o \
 			ppp_async.o ppp_generic.o slhc.o pppox.o auto_irq.o \
-			net_init.o
+			net_init.o mii.o
 list-multi	:=	rcpci.o
 rcpci-objs	:=	rcpci45.o rclanmtl.o
 
@@ -166,7 +166,6 @@
 obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
 obj-$(CONFIG_8139CP) += 8139cp.o
 obj-$(CONFIG_8139TOO) += 8139too.o
-obj-$(CONFIG_WAVELAN) += wavelan.o
 obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o
 obj-$(CONFIG_ZNET) += znet.o
 obj-$(CONFIG_LAN_SAA9730) += saa9730.o
diff -u --recursive --new-file v2.5.2/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.5.2/linux/drivers/net/acenic.c	Mon Nov 19 15:19:42 2001
+++ linux/drivers/net/acenic.c	Tue Jan 15 11:48:13 2002
@@ -208,6 +208,8 @@
 	(((u64)(mask) & 0xffffffff00000000) == 0 ? 0 : -EIO)
 #define pci_dma_supported(dev, mask)		\
 	(((u64)(mask) & 0xffffffff00000000) == 0 ? 1 : 0)
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
 
 #elif (LINUX_VERSION_CODE < 0x02040d)
 
@@ -231,6 +233,8 @@
 }
 #define pci_unmap_page(cookie, dma_addr, size, dir)	\
 	pci_unmap_single(cookie, dma_addr, size, dir)
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
 #endif
 
 
@@ -839,9 +843,11 @@
 			struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
 
 			if (skb) {
+				struct ring_info *ringp;
 				dma_addr_t mapping;
 
-				mapping = ap->skb->rx_std_skbuff[i].mapping;
+				ringp = &ap->skb->rx_std_skbuff[i];
+				mapping = pci_unmap_addr(ringp, mapping);
 				pci_unmap_page(ap->pdev, mapping,
 					       ACE_STD_BUFSIZE - (2 + 16),
 					       PCI_DMA_FROMDEVICE);
@@ -856,9 +862,11 @@
 				struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb;
 
 				if (skb) {
+					struct ring_info *ringp;
 					dma_addr_t mapping;
 
-					mapping = ap->skb->rx_mini_skbuff[i].mapping;
+					ringp = &ap->skb->rx_mini_skbuff[i];
+					mapping = pci_unmap_addr(ringp,mapping);
 					pci_unmap_page(ap->pdev, mapping,
 						       ACE_MINI_BUFSIZE - (2 + 16),
 						       PCI_DMA_FROMDEVICE);
@@ -872,9 +880,11 @@
 		for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
 			struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb;
 			if (skb) {
+				struct ring_info *ringp;
 				dma_addr_t mapping;
 
-				mapping = ap->skb->rx_jumbo_skbuff[i].mapping;
+				ringp = &ap->skb->rx_jumbo_skbuff[i];
+				mapping = pci_unmap_addr(ringp, mapping);
 				pci_unmap_page(ap->pdev, mapping,
 					       ACE_JUMBO_BUFSIZE - (2 + 16),
 					       PCI_DMA_FROMDEVICE);
@@ -1832,7 +1842,8 @@
 				       ACE_STD_BUFSIZE - (2 + 16),
 				       PCI_DMA_FROMDEVICE);
 		ap->skb->rx_std_skbuff[idx].skb = skb;
-		ap->skb->rx_std_skbuff[idx].mapping = mapping;
+		pci_unmap_addr_set(&ap->skb->rx_std_skbuff[idx],
+				   mapping, mapping);
 
 		rd = &ap->rx_std_ring[idx];
 		set_aceaddr(&rd->addr, mapping);
@@ -1897,7 +1908,8 @@
 				       ACE_MINI_BUFSIZE - (2 + 16),
 				       PCI_DMA_FROMDEVICE);
 		ap->skb->rx_mini_skbuff[idx].skb = skb;
-		ap->skb->rx_mini_skbuff[idx].mapping = mapping;
+		pci_unmap_addr_set(&ap->skb->rx_mini_skbuff[idx],
+				   mapping, mapping);
 
 		rd = &ap->rx_mini_ring[idx];
 		set_aceaddr(&rd->addr, mapping);
@@ -1957,7 +1969,8 @@
 				       ACE_JUMBO_BUFSIZE - (2 + 16),
 				       PCI_DMA_FROMDEVICE);
 		ap->skb->rx_jumbo_skbuff[idx].skb = skb;
-		ap->skb->rx_jumbo_skbuff[idx].mapping = mapping;
+		pci_unmap_addr_set(&ap->skb->rx_jumbo_skbuff[idx],
+				   mapping, mapping);
 
 		rd = &ap->rx_jumbo_ring[idx];
 		set_aceaddr(&rd->addr, mapping);
@@ -2163,7 +2176,9 @@
 
 		skb = rip->skb;
 		rip->skb = NULL;
-		pci_unmap_page(ap->pdev, rip->mapping, mapsize,
+		pci_unmap_page(ap->pdev,
+			       pci_unmap_addr(rip, mapping),
+			       mapsize,
 			       PCI_DMA_FROMDEVICE);
 		skb_put(skb, retdesc->size);
 
@@ -2229,12 +2244,13 @@
 
 		info = ap->skb->tx_skbuff + idx;
 		skb = info->skb;
-		mapping = info->mapping;
+		mapping = pci_unmap_addr(info, mapping);
 
 		if (mapping) {
-			pci_unmap_page(ap->pdev, mapping, info->maplen,
+			pci_unmap_page(ap->pdev, mapping,
+				       pci_unmap_len(info, maplen),
 				       PCI_DMA_TODEVICE);
-			info->mapping = 0;
+			pci_unmap_addr_set(info, mapping, 0);
 		}
 
 		if (skb) {
@@ -2518,13 +2534,14 @@
 
 		info = ap->skb->tx_skbuff + i;
 		skb = info->skb;
-		mapping = info->mapping;
+		mapping = pci_unmap_addr(info, mapping);
 
 		if (mapping) {
 			memset(ap->tx_ring + i, 0, sizeof(struct tx_desc));
-			pci_unmap_page(ap->pdev, mapping, info->maplen,
+			pci_unmap_page(ap->pdev, mapping,
+				       pci_unmap_len(info, maplen),
 				       PCI_DMA_TODEVICE);
-			info->mapping = 0;
+			pci_unmap_addr_set(info, mapping, 0);
 		}
 		if (skb) {
 			dev_kfree_skb(skb);
@@ -2545,7 +2562,6 @@
 	return 0;
 }
 
-
 static inline dma_addr_t
 ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb,
 	       struct sk_buff *tail, u32 idx)
@@ -2559,8 +2575,8 @@
 
 	info = ap->skb->tx_skbuff + idx;
 	info->skb = tail;
-	info->mapping = mapping;
-	info->maplen = skb->len;
+	pci_unmap_addr_set(info, mapping, mapping);
+	pci_unmap_len_set(info, maplen, skb->len);
 	return mapping;
 }
 
@@ -2661,8 +2677,8 @@
 			} else {
 				info->skb = NULL;
 			}
-			info->mapping = mapping;
-			info->maplen = frag->size;
+			pci_unmap_addr_set(info, mapping, mapping);
+			pci_unmap_len_set(info, maplen, frag->size);
 			ace_load_tx_bd(desc, mapping, flagsize);
 		}
 	}
diff -u --recursive --new-file v2.5.2/linux/drivers/net/acenic.h linux/drivers/net/acenic.h
--- v2.5.2/linux/drivers/net/acenic.h	Mon Nov 19 15:19:42 2001
+++ linux/drivers/net/acenic.h	Tue Jan 15 14:34:38 2002
@@ -585,7 +585,7 @@
 
 struct ring_info {
 	struct sk_buff		*skb;
-	dma_addr_t		mapping;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
 
@@ -596,8 +596,8 @@
  */
 struct tx_ring_info {
 	struct sk_buff		*skb;
-	dma_addr_t		mapping;
-	int			maplen;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+	DECLARE_PCI_UNMAP_LEN(maplen)
 };
 
 
diff -u --recursive --new-file v2.5.2/linux/drivers/net/appletalk/Config.help linux/drivers/net/appletalk/Config.help
--- v2.5.2/linux/drivers/net/appletalk/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/appletalk/Config.help	Fri Jan 25 16:03:33 2002
@@ -0,0 +1,71 @@
+CONFIG_APPLETALK
+  AppleTalk is the way Apple computers speak to each other on a
+  network. If your Linux box is connected to such a network and you
+  want to join the conversation, say Y.
+
+CONFIG_IPDDP
+  This allows IP networking for users who only have AppleTalk
+  networking available. This feature is experimental. With this
+  driver, you can encapsulate IP inside AppleTalk (e.g. if your Linux
+  box is stuck on an AppleTalk only network) or decapsulate (e.g. if
+  you want your Linux box to act as an Internet gateway for a zoo of
+  AppleTalk connected Macs). Please see the file
+  <file:Documentation/networking/ipddp.txt> for more information.
+
+  If you say Y here, the AppleTalk-IP support will be compiled into
+  the kernel. In this case, you can either use encapsulation or
+  decapsulation, but not both. With the following two questions, you
+  decide which one you want.
+
+  If you say M here, the AppleTalk-IP support will be compiled as a
+  module ( = code which can be inserted in and removed from the
+  running kernel whenever you want, read
+  <file:Documentation/modules.txt>).  The module is called ipddp.o.
+  In this case, you will be able to use both encapsulation and
+  decapsulation simultaneously, by loading two copies of the module
+  and specifying different values for the module option ipddp_mode.
+
+CONFIG_IPDDP_ENCAP
+  If you say Y here, the AppleTalk-IP code will be able to encapsulate
+  IP packets inside AppleTalk frames; this is useful if your Linux box
+  is stuck on an AppleTalk network (which hopefully contains a
+  decapsulator somewhere). Please see
+  <file:Documentation/networking/ipddp.txt> for more information. If
+  you said Y to "AppleTalk-IP driver support" above and you say Y
+  here, then you cannot say Y to "AppleTalk-IP to IP Decapsulation
+  support", below.
+
+CONFIG_IPDDP_DECAP
+  If you say Y here, the AppleTalk-IP code will be able to decapsulate
+  AppleTalk-IP frames to IP packets; this is useful if you want your
+  Linux box to act as an Internet gateway for an AppleTalk network.
+  Please see <file:Documentation/networking/ipddp.txt> for more
+  information.  If you said Y to "AppleTalk-IP driver support" above
+  and you say Y here, then you cannot say Y to "IP to AppleTalk-IP
+  Encapsulation support", above.
+
+CONFIG_LTPC
+  This allows you to use the AppleTalk PC card to connect to LocalTalk
+  networks. The card is also known as the Farallon PhoneNet PC card.
+  If you are in doubt, this card is the one with the 65C02 chip on it.
+  You also need version 1.3.3 or later of the netatalk package.
+  This driver is experimental, which means that it may not work.
+  See the file <file:Documentation/networking/ltpc.txt>.
+
+CONFIG_COPS
+  This allows you to use COPS AppleTalk cards to connect to LocalTalk
+  networks. You also need version 1.3.3 or later of the netatalk
+  package. This driver is experimental, which means that it may not
+  work. This driver will only work if you choose "AppleTalk DDP"
+  networking support, above.
+  Please read the file <file:Documentation/networking/cops.txt>.
+
+CONFIG_COPS_DAYNA
+  Support COPS compatible cards with Dayna style firmware (Dayna
+  DL2000/ Daynatalk/PC (half length), COPS LT-95, Farallon PhoneNET PC
+  III, Farallon PhoneNET PC II).
+
+CONFIG_COPS_TANGENT
+  Support COPS compatible cards with Tangent style firmware (Tangent
+  ATB_II, Novell NL-1000, Daystar Digital LT-200.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/net/arcnet/Config.help linux/drivers/net/arcnet/Config.help
--- v2.5.2/linux/drivers/net/arcnet/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/arcnet/Config.help	Fri Jan 25 16:03:46 2002
@@ -0,0 +1,91 @@
+CONFIG_ARCNET
+  If you have a network card of this type, say Y and check out the
+  (arguably) beautiful poetry in
+  <file:Documentation/networking/arcnet.txt>.
+
+  You need both this driver, and the driver for the particular ARCnet
+  chipset of your card. If you don't know, then it's probably a
+  COM90xx type card, so say Y (or M) to "ARCnet COM90xx chipset
+  support" below.
+
+  You might also want to have a look at the Ethernet-HOWTO, available
+  from <http://www.linuxdoc.org/docs.html#howto>(even though ARCnet
+  is not really Ethernet).
+
+  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 arcnet.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_ARCNET_1051
+  This allows you to use RFC1051 with your ARCnet card via the virtual
+  arc0s device. You only need arc0s if you want to talk to ARCnet
+  software complying with the "old" standard, specifically, the DOS
+  arcnet.com packet driver, Amigas running AmiTCP, and some variants
+  of NetBSD. You do not need to say Y here to communicate with
+  industry-standard RFC1201 implementations, like the arcether.com
+  packet driver or most DOS/Windows ODI drivers. RFC1201 is included
+  automatically as the arc0 device. Please read the ARCnet
+  documentation in <file:Documentation/networking/arcnet.txt> for more
+  information about using arc0e and arc0s.
+
+CONFIG_ARCNET_1201
+  This allows you to use RFC1201 with your ARCnet card via the virtual
+  arc0 device.  You need to say Y here to communicate with
+  industry-standard RFC1201 implementations, like the arcether.com
+  packet driver or most DOS/Windows ODI drivers.  Please read the
+  ARCnet documentation in <file:Documentation/networking/arcnet.txt>
+  for more information about using arc0.
+
+CONFIG_ARCNET_RAW
+  ARCnet "raw mode" packet encapsulation, no soft headers.  Unlikely
+  to work unless talking to a copy of the same Linux arcnet driver,
+  but perhaps marginally faster in that case.
+
+CONFIG_ARCNET_COM90xx
+  This is the chipset driver for the standard COM90xx cards. If you
+  have always used the old ARCnet driver without knowing what type of
+  card you had, this is probably the one for you.
+
+  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 com90xx.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_ARCNET_COM90xxIO
+  This is the chipset driver for the COM90xx cards, using them in
+  IO-mapped mode instead of memory-mapped mode. This is slower than
+  the normal driver. Only use it if your card doesn't support shared
+  memory.
+
+  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 com90io.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_ARCNET_RIM_I
+  This is yet another chipset driver for the COM90xx cards, but this
+  time only using memory-mapped mode, and no IO ports at all. This
+  driver is completely untested, so if you have one of these cards,
+  please mail dwmw2@infradead.org, especially if it works!
+
+  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 arc-rimi.o.  If you want to compile
+  it as a module, say M here and read <file:Documentation/modules.txt>
+  as  well as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_ARCNET_COM20020
+  This is the driver for the new COM20020 chipset. It supports such
+  things as promiscuous mode, so packet sniffing is possible, and
+  extra diagnostic information.
+
+  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 com20020.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt> as
+  well as <file:Documentation/networking/net-modules.txt>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/net/au1000_eth.c linux/drivers/net/au1000_eth.c
--- v2.5.2/linux/drivers/net/au1000_eth.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/au1000_eth.c	Mon Jan 21 16:17:16 2002
@@ -1141,6 +1141,8 @@
 		//data[3] = mdio_read(ioaddr, data[0], data[1]); 
 		return 0;
 		case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
 		//mdio_write(ioaddr, data[0], data[1], data[2]);
 		return 0;
 		default:
diff -u --recursive --new-file v2.5.2/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.5.2/linux/drivers/net/cs89x0.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/net/cs89x0.c	Thu Jan 24 11:51:10 2002
@@ -537,7 +537,7 @@
                         dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8;
                 }
 		if (net_debug > 1)
-			printk(KERN_DEBUG "%s: new adapter_cnf: 0%x\n",
+			printk(KERN_DEBUG "%s: new adapter_cnf: 0x%x\n",
 				dev->name, lp->adapter_cnf);
         }
 
@@ -582,8 +582,8 @@
 		i = lp->isa_config & INT_NO_MASK;
 		if (lp->chip_type == CS8900) {
 			/* Translate the IRQ using the IRQ mapping table. */
-			if (i > sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
-				printk("\ncs89x0: bug: isa_config is %d\n", i);
+			if (i >= sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
+				printk("\ncs89x0: invalid ISA interrupt number %d\n", i);
 			else
 				i = cs8900_irq_map[i];
 			
diff -u --recursive --new-file v2.5.2/linux/drivers/net/de2104x.c linux/drivers/net/de2104x.c
--- v2.5.2/linux/drivers/net/de2104x.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/de2104x.c	Tue Jan 15 10:52:11 2002
@@ -45,6 +45,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/crc32.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
diff -u --recursive --new-file v2.5.2/linux/drivers/net/dl2k.c linux/drivers/net/dl2k.c
--- v2.5.2/linux/drivers/net/dl2k.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/dl2k.c	Mon Jan 21 16:17:16 2002
@@ -1040,6 +1040,8 @@
 		miidata->out_value = mii_read (dev, phy_addr, miidata->reg_num);
 		break;
 	case SIOCDEVPRIVATE + 2:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
 		mii_write (dev, phy_addr, miidata->reg_num, miidata->in_value);
 		break;
 	case SIOCDEVPRIVATE + 3:
diff -u --recursive --new-file v2.5.2/linux/drivers/net/fealnx.c linux/drivers/net/fealnx.c
--- v2.5.2/linux/drivers/net/fealnx.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/fealnx.c	Thu Jan 24 11:51:10 2002
@@ -1769,7 +1769,7 @@
 
 	case SIOCSMIIREG:		/* Write MII PHY register. */
 	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
-		if (!suser())
+		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
 		return 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/net/hamradio/Config.help linux/drivers/net/hamradio/Config.help
--- v2.5.2/linux/drivers/net/hamradio/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/hamradio/Config.help	Fri Jan 25 16:03:34 2002
@@ -0,0 +1,247 @@
+CONFIG_MKISS
+  KISS is a protocol used for the exchange of data between a computer
+  and a Terminal Node Controller (a small embedded system commonly
+  used for networking over AX.25 amateur radio connections; it
+  connects the computer's serial port with the radio's microphone
+  input and speaker output).
+
+  Although KISS is less advanced than the 6pack protocol, it has
+  the advantage that it is already supported by most modern TNCs
+  without the need for a firmware upgrade.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called mkiss.o.
+
+CONFIG_6PACK
+  6pack is a transmission protocol for the data exchange between your
+  PC and your TNC (the Terminal Node Controller acts as a kind of
+  modem connecting your computer's serial port to your radio's
+  microphone input and speaker output). This protocol can be used as
+  an alternative to KISS for networking over AX.25 amateur radio
+  connections, but it has some extended functionality.
+
+  Note that this driver is still experimental and might cause
+  problems. For details about the features and the usage of the
+  driver, read <file:Documentation/networking/6pack.txt>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called 6pack.o.
+
+CONFIG_BPQETHER
+  AX.25 is the protocol used for computer communication over amateur
+  radio. If you say Y here, you will be able to send and receive AX.25
+  traffic over Ethernet (also called "BPQ AX.25"), which could be
+  useful if some other computer on your local network has a direct
+  amateur radio connection.
+
+CONFIG_DMASCC
+  This is a driver for high-speed SCC boards, i.e. those supporting
+  DMA on one port. You usually use those boards to connect your
+  computer to an amateur radio modem (such as the WA4DSY 56kbps
+  modem), in order to send and receive AX.25 packet radio network
+  traffic.
+
+  Currently, this driver supports Ottawa PI/PI2, Paccomm/Gracilis
+  PackeTwin, and S5SCC/DMA boards. They are detected automatically.
+  If you have one of these cards, say Y here and read the AX25-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver can operate multiple boards simultaneously. If you
+  compile it as a module (by saying M instead of Y), it will be called
+  dmascc.o. If you don't pass any parameter to the driver, all
+  possible I/O addresses are probed. This could irritate other devices
+  that are currently not in use. You may specify the list of addresses
+  to be probed by "dmascc=addr1,addr2,..." (when compiled into the
+  kernel image) or "io=addr1,addr2,..." (when loaded as a module). The
+  network interfaces will be called dmascc0 and dmascc1 for the board
+  detected first, dmascc2 and dmascc3 for the second one, and so on.
+
+  Before you configure each interface with ifconfig, you MUST set
+  certain parameters, such as channel access timing, clock mode, and
+  DMA channel. This is accomplished with a small utility program,
+  dmascc_cfg, available at
+  <http://www.nt.tuwien.ac.at/~kkudielk/Linux/>. Please be sure to get
+  at least version 1.27 of dmascc_cfg, as older versions will not
+  work with the current driver.
+
+CONFIG_SCC
+  These cards are used to connect your Linux box to an amateur radio
+  in order to communicate with other computers. If you want to use
+  this, read <file:Documentation/networking/z8530drv.txt> and the
+  AX25-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. Also make sure to say Y
+  to "Amateur Radio AX.25 Level 2" support.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called scc.o.
+
+CONFIG_SCC_TRXECHO
+  Some transmitters feed the transmitted signal back to the receive
+  line.  Say Y here to foil this by explicitly disabling the receiver
+  during data transmission.  If in doubt, say Y.
+
+CONFIG_SCC_DELAY
+  Say Y here if you experience problems with the SCC driver not
+  working properly; please read
+  <file:Documentation/networking/z8530drv.txt> for details. If unsure,
+  say N.
+
+CONFIG_YAM
+  The YAM is a modem for packet radio which connects to the serial
+  port and includes some of the functions of a Terminal Node
+  Controller. If you have one of those, say Y here.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_BAYCOM_PAR
+  This is a driver for Baycom style simple amateur radio modems that
+  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
+  <file:Documentation/networking/baycom.txt>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called baycom_par.o.
+
+CONFIG_BAYCOM_EPP
+  This is a driver for Baycom style simple amateur radio modems that
+  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
+  <file:Documentation/networking/baycom.txt>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called baycom_par.o.
+
+CONFIG_BAYCOM_SER_FDX
+  This is one of two drivers for Baycom style simple amateur radio
+  modems that connect to a serial interface. The driver supports the
+  ser12 design in full-duplex mode. In addition, it allows the
+  baudrate to be set between 300 and 4800 baud (however not all modems
+  support all baudrates). This is the preferred driver. The next
+  driver, "BAYCOM ser12 half-duplex driver for AX.25" is the old
+  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
+  <file:Documentation/networking/baycom.txt>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called baycom_ser_fdx.o.
+
+CONFIG_BAYCOM_SER_HDX
+  This is one of two drivers for Baycom style simple amateur radio
+  modems that connect to a serial interface. The driver supports the
+  ser12 design in full-duplex mode. This is the old driver.  It is
+  still provided in case your serial interface chip does not work with
+  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
+  <file:Documentation/networking/baycom.txt>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called baycom_ser_hdx.o.
+
+CONFIG_SOUNDMODEM
+  This experimental driver allows a standard Sound Blaster or
+  WindowsSoundSystem compatible sound card to be used as a packet
+  radio modem (NOT as a telephone modem!), to send digital traffic
+  over amateur radio.
+
+  To configure the driver, use the sethdlc, smdiag and smmixer
+  utilities available in the standard ax25 utilities package. For
+  information on how to key the transmitter, see
+  <http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html> and
+  <file:Documentation/networking/soundmodem.txt>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called soundmodem.o.
+
+CONFIG_SOUNDMODEM_SBC
+  This option enables the soundmodem driver to use Sound Blaster and
+  compatible cards. If you have a dual mode card (i.e. a WSS cards
+  with a Sound Blaster emulation) you should say N here and Y to
+  "Sound card modem support for WSS and Crystal cards", below, because
+  this usually results in better performance. This option also
+  supports SB16/32/64 in full-duplex mode.
+
+CONFIG_SOUNDMODEM_WSS
+  This option enables the soundmodem driver to use WindowsSoundSystem
+  compatible cards. These cards feature a codec chip from either
+  Analog Devices (such as AD1848, AD1845, AD1812) or Crystal
+  Semiconductors (such as CS4248, CS423x). This option also supports
+  the WSS full-duplex operation which currently works with Crystal
+  CS423x chips. If you don't need full-duplex operation, do not enable
+  it to save performance.
+
+CONFIG_SOUNDMODEM_AFSK1200
+  This option enables the soundmodem driver 1200 baud AFSK modem,
+  compatible to popular modems using TCM3105 or AM7911. The
+  demodulator requires about 12% of the CPU power of a Pentium 75 CPU
+  per channel.
+
+CONFIG_SOUNDMODEM_AFSK2400_7
+  This option enables the soundmodem driver 2400 baud AFSK modem,
+  compatible to TCM3105 modems (over-)clocked with a 7.3728MHz
+  crystal. Note that the availability of this driver does _not_ imply
+  that I recommend building such links. It is only here since users
+  especially in eastern Europe have asked me to do so. In fact this
+  modulation scheme has many disadvantages, mainly its incompatibility
+  with many transceiver designs and the fact that the TCM3105 (if
+  used) is operated widely outside its specifications.
+
+CONFIG_SOUNDMODEM_AFSK2400_8
+  This option enables the soundmodem driver 2400 baud AFSK modem,
+  compatible to TCM3105 modems (over-)clocked with an 8MHz crystal.
+  Note that the availability of this driver does _not_ imply that I
+  recommend building such links. It is only here since users
+  especially in eastern Europe have asked me to do so. In fact this
+  modulation scheme has many disadvantages, mainly its incompatibility
+  with many transceiver designs and the fact that the TCM3105 (if
+  used) is operated widely outside its specifications.
+
+CONFIG_SOUNDMODEM_AFSK2666
+  This option enables the soundmodem driver 2666 baud AFSK modem.
+  This modem is experimental, and not compatible to anything
+  else I know of.
+
+CONFIG_SOUNDMODEM_PSK4800
+  This option enables the soundmodem driver 4800 baud 8PSK modem.
+  This modem is experimental, and not compatible to anything
+  else I know of.
+
+CONFIG_SOUNDMODEM_HAPN4800
+  This option enables the soundmodem driver 4800 baud HAPN-1
+  compatible modem. This modulation seems to be widely used 'down
+  under' and in the Netherlands. Here, nobody uses it, so I could not
+  test if it works. It is compatible to itself, however :-)
+
+CONFIG_SOUNDMODEM_FSK9600
+  This option enables the soundmodem driver 9600 baud FSK modem,
+  compatible to the G3RUH standard. The demodulator requires about 4%
+  of the CPU power of a Pentium 75 CPU per channel. You can say Y to
+  both 1200 baud AFSK and 9600 baud FSK if you want (but obviously you
+  can only use one protocol at a time, depending on what the other end
+  can understand).
+
diff -u --recursive --new-file v2.5.2/linux/drivers/net/i82586.h linux/drivers/net/i82586.h
--- v2.5.2/linux/drivers/net/i82586.h	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/i82586.h	Wed Dec 31 16:00:00 1969
@@ -1,413 +0,0 @@
-/*
- * Intel 82586 IEEE 802.3 Ethernet LAN Coprocessor.
- *
- * See:
- *	Intel Microcommunications 1991
- *	p1-1 to p1-37
- *	Intel order No. 231658
- *	ISBN 1-55512-119-5
- *
- *     Unfortunately, the above chapter mentions neither
- * the System Configuration Pointer (SCP) nor the
- * Intermediate System Configuration Pointer (ISCP),
- * so we probably need to look elsewhere for the
- * whole story -- some recommend the "Intel LAN
- * Components manual" but I have neither a copy
- * nor a full reference.  But "elsewhere" may be
- * in the same publication...
- *     The description of a later device, the
- * "82596CA High-Performance 32-Bit Local Area Network
- * Coprocessor", (ibid. p1-38 to p1-109) does mention
- * the SCP and ISCP and also has an i82586 compatibility
- * mode.  Even more useful is "AP-235 An 82586 Data Link
- * Driver" (ibid. p1-337 to p1-417).
- */
-
-#define	I82586_MEMZ	(64 * 1024)
-
-#define	I82586_SCP_ADDR	(I82586_MEMZ - sizeof(scp_t))
-
-#define	ADDR_LEN	6
-#define	I82586NULL	0xFFFF
-
-#define	toff(t,p,f) 	(unsigned short)((void *)(&((t *)((void *)0 + (p)))->f) - (void *)0)
-
-/*
- * System Configuration Pointer (SCP).
- */
-typedef struct scp_t	scp_t;
-struct scp_t
-{
-	unsigned short	scp_sysbus;	/* 82586 bus width:	*/
-#define		SCP_SY_16BBUS	(0x0 << 0)	/* 16 bits */
-#define		SCP_SY_8BBUS	(0x1 << 0)	/*  8 bits. */
-	unsigned short	scp_junk[2];	/* Unused */
-	unsigned short	scp_iscpl;	/* lower 16 bits of ISCP_ADDR */
-	unsigned short	scp_iscph;	/* upper 16 bits of ISCP_ADDR */
-};
-
-/*
- * Intermediate System Configuration Pointer (ISCP).
- */
-typedef struct iscp_t	iscp_t;
-struct iscp_t
-{
-	unsigned short	iscp_busy;	/* set by CPU before first CA,	*/
-					/* cleared by 82586 after read.	*/
-	unsigned short	iscp_offset;	/* offset of SCB		*/
-	unsigned short	iscp_basel;	/* base of SCB			*/
-	unsigned short	iscp_baseh;	/*  "				*/
-};
-
-/*
- * System Control Block (SCB).
- *	The 82586 writes its status to scb_status and then
- *	raises an interrupt to alert the CPU.
- *	The CPU writes a command to scb_command and
- *	then issues a Channel Attention (CA) to alert the 82586.
- */
-typedef struct scb_t	scb_t;
-struct scb_t
-{
-	unsigned short	scb_status;	/* Status of 82586		*/
-#define		SCB_ST_INT	(0xF << 12)	/* Some of:		*/
-#define		SCB_ST_CX	(0x1 << 15)	/* Cmd completed	*/
-#define		SCB_ST_FR	(0x1 << 14)	/* Frame received	*/
-#define		SCB_ST_CNA	(0x1 << 13)	/* Cmd unit not active	*/
-#define		SCB_ST_RNR	(0x1 << 12)	/* Rcv unit not ready	*/
-#define		SCB_ST_JUNK0	(0x1 << 11)	/* 0			*/
-#define		SCB_ST_CUS	(0x7 <<  8)	/* Cmd unit status	*/
-#define			SCB_ST_CUS_IDLE	(0 << 8)	/* Idle		*/
-#define			SCB_ST_CUS_SUSP	(1 << 8)	/* Suspended	*/
-#define			SCB_ST_CUS_ACTV	(2 << 8)	/* Active	*/
-#define		SCB_ST_JUNK1	(0x1 <<  7)	/* 0			*/
-#define		SCB_ST_RUS	(0x7 <<  4)	/* Rcv unit status	*/
-#define			SCB_ST_RUS_IDLE	(0 << 4)	/* Idle		*/
-#define			SCB_ST_RUS_SUSP	(1 << 4)	/* Suspended	*/
-#define			SCB_ST_RUS_NRES	(2 << 4)	/* No resources	*/
-#define			SCB_ST_RUS_RDY	(4 << 4)	/* Ready	*/
-	unsigned short	scb_command;	/* Next command			*/
-#define		SCB_CMD_ACK_CX	(0x1 << 15)	/* Ack cmd completion	*/
-#define		SCB_CMD_ACK_FR	(0x1 << 14)	/* Ack frame received	*/
-#define		SCB_CMD_ACK_CNA	(0x1 << 13)	/* Ack CU not active	*/
-#define		SCB_CMD_ACK_RNR	(0x1 << 12)	/* Ack RU not ready	*/
-#define		SCB_CMD_JUNKX	(0x1 << 11)	/* Unused		*/
-#define		SCB_CMD_CUC	(0x7 <<  8)	/* Command Unit command	*/
-#define			SCB_CMD_CUC_NOP	(0 << 8)	/* Nop		*/
-#define			SCB_CMD_CUC_GO	(1 << 8)	/* Start cbl_offset */
-#define			SCB_CMD_CUC_RES	(2 << 8)	/* Resume execution */
-#define			SCB_CMD_CUC_SUS	(3 << 8)	/* Suspend   "	*/
-#define			SCB_CMD_CUC_ABT	(4 << 8)	/* Abort     "	*/
-#define		SCB_CMD_RESET	(0x1 <<  7)	/* Reset chip (hardware) */
-#define		SCB_CMD_RUC	(0x7 <<  4)	/* Receive Unit command	*/
-#define			SCB_CMD_RUC_NOP	(0 << 4)	/* Nop		*/
-#define			SCB_CMD_RUC_GO	(1 << 4)	/* Start rfa_offset */
-#define			SCB_CMD_RUC_RES	(2 << 4)	/* Resume reception */
-#define			SCB_CMD_RUC_SUS	(3 << 4)	/* Suspend   "	*/
-#define			SCB_CMD_RUC_ABT	(4 << 4)	/* Abort     "	*/
-	unsigned short	scb_cbl_offset;	/* Offset of first command unit	*/
-					/* Action Command		*/
-	unsigned short	scb_rfa_offset;	/* Offset of first Receive	*/
-					/* Frame Descriptor in the	*/
-					/* Receive Frame Area		*/
-	unsigned short	scb_crcerrs;	/* Properly aligned frames	*/
-					/* received with a CRC error	*/
-	unsigned short	scb_alnerrs;	/* Misaligned frames received	*/
-					/* with a CRC error		*/
-	unsigned short	scb_rscerrs;	/* Frames lost due to no space	*/
-	unsigned short	scb_ovrnerrs;	/* Frames lost due to slow bus	*/
-};
-
-#define	scboff(p,f) 	toff(scb_t, p, f)
-
-/*
- * The eight Action Commands.
- */
-typedef enum acmd_e	acmd_e;
-enum acmd_e
-{
-	acmd_nop	= 0,	/* Do nothing				*/
-	acmd_ia_setup	= 1,	/* Load an (ethernet) address into the	*/
-				/* 82586				*/
-	acmd_configure	= 2,	/* Update the 82586 operating parameters */
-	acmd_mc_setup	= 3,	/* Load a list of (ethernet) multicast	*/
-				/* addresses into the 82586		*/
-	acmd_transmit	= 4,	/* Transmit a frame			*/
-	acmd_tdr	= 5,	/* Perform a Time Domain Reflectometer	*/
-				/* test on the serial link		*/
-	acmd_dump	= 6,	/* Copy 82586 registers to memory	*/
-	acmd_diagnose	= 7,	/* Run an internal self test		*/
-};
-
-/*
- * Generic Action Command header.
- */
-typedef struct ach_t	ach_t;
-struct ach_t
-{
-	unsigned short	ac_status;		/* Command status:	*/
-#define		AC_SFLD_C	(0x1 << 15)	/* Command completed	*/
-#define		AC_SFLD_B	(0x1 << 14)	/* Busy executing	*/
-#define		AC_SFLD_OK	(0x1 << 13)	/* Completed error free	*/
-#define		AC_SFLD_A	(0x1 << 12)	/* Command aborted	*/
-#define		AC_SFLD_FAIL	(0x1 << 11)	/* Selftest failed	*/
-#define		AC_SFLD_S10	(0x1 << 10)	/* No carrier sense	*/
-						/* during transmission	*/
-#define		AC_SFLD_S9	(0x1 <<  9)	/* Tx unsuccessful:	*/
-						/* (stopped) lost CTS	*/
-#define		AC_SFLD_S8	(0x1 <<  8)	/* Tx unsuccessful:	*/
-						/* (stopped) slow DMA	*/
-#define		AC_SFLD_S7	(0x1 <<  7)	/* Tx deferred:		*/
-						/* other link traffic	*/
-#define		AC_SFLD_S6	(0x1 <<  6)	/* Heart Beat: collision */
-						/* detect after last tx	*/
-#define		AC_SFLD_S5	(0x1 <<  5)	/* Tx stopped:		*/
-						/* excessive collisions	*/
-#define		AC_SFLD_MAXCOL	(0xF <<  0)	/* Collision count  	*/
-	unsigned short	ac_command;		/* Command specifier:	*/
-#define		AC_CFLD_EL	(0x1 << 15)	/* End of command list	*/
-#define		AC_CFLD_S	(0x1 << 14)	/* Suspend on completion */
-#define		AC_CFLD_I	(0x1 << 13)	/* Interrupt on completion */
-#define		AC_CFLD_CMD	(0x7 <<  0)	/* acmd_e		*/
-	unsigned short	ac_link;		/* Next Action Command	*/
-};
-
-#define	acoff(p,f) 	toff(ach_t, p, f)
-
-/*
- * The Nop Action Command.
- */
-typedef struct ac_nop_t	ac_nop_t;
-struct ac_nop_t
-{
-	ach_t	nop_h;
-};
-
-/*
- * The IA-Setup Action Command.
- */
-typedef struct ac_ias_t	ac_ias_t;
-struct ac_ias_t
-{
-	ach_t		ias_h;
-	unsigned char	ias_addr[ADDR_LEN]; /* The (ethernet) address	*/
-};
-
-/*
- * The Configure Action Command.
- */
-typedef struct ac_cfg_t	ac_cfg_t;
-struct ac_cfg_t
-{
-	ach_t		cfg_h;
-	unsigned char	cfg_byte_cnt;	/* Size foll data: 4-12	*/
-#define	AC_CFG_BYTE_CNT(v)	(((v) & 0xF) << 0)
-	unsigned char	cfg_fifolim;	/* FIFO threshold	*/
-#define	AC_CFG_FIFOLIM(v)	(((v) & 0xF) << 0)
-	unsigned char	cfg_byte8;
-#define	AC_CFG_SAV_BF(v) 	(((v) & 0x1) << 7)	/* Save rxd bad frames	*/
-#define	AC_CFG_SRDY(v) 		(((v) & 0x1) << 6)	/* SRDY/ARDY pin means	*/
-							/* external sync.	*/
-	unsigned char	cfg_byte9;
-#define	AC_CFG_ELPBCK(v)	(((v) & 0x1) << 7)	/* External loopback	*/
-#define	AC_CFG_ILPBCK(v)	(((v) & 0x1) << 6)	/* Internal loopback	*/
-#define	AC_CFG_PRELEN(v)	(((v) & 0x3) << 4)	/* Preamble length	*/
-#define		AC_CFG_PLEN_2		0		/*  2 bytes	*/
-#define		AC_CFG_PLEN_4		1		/*  4 bytes	*/
-#define		AC_CFG_PLEN_8		2		/*  8 bytes	*/
-#define		AC_CFG_PLEN_16		3		/* 16 bytes	*/
-#define	AC_CFG_ALOC(v)		(((v) & 0x1) << 3)	/* Addr/len data is	*/
-							/* explicit in buffers	*/
-#define	AC_CFG_ADDRLEN(v)	(((v) & 0x7) << 0)	/* Bytes per address	*/
-	unsigned char	cfg_byte10;
-#define	AC_CFG_BOFMET(v)	(((v) & 0x1) << 7)	/* Use alternate expo.	*/
-							/* backoff method	*/
-#define	AC_CFG_ACR(v)		(((v) & 0x7) << 4)	/* Accelerated cont. res. */
-#define	AC_CFG_LINPRIO(v)	(((v) & 0x7) << 0)	/* Linear priority	*/
-	unsigned char	cfg_ifs;	/* Interframe spacing		*/
-	unsigned char	cfg_slotl;	/* Slot time (low byte)		*/
-	unsigned char	cfg_byte13;
-#define	AC_CFG_RETRYNUM(v)	(((v) & 0xF) << 4)	/* Max. collision retry	*/
-#define	AC_CFG_SLTTMHI(v)	(((v) & 0x7) << 0)	/* Slot time (high bits) */
-	unsigned char	cfg_byte14;
-#define	AC_CFG_FLGPAD(v)	(((v) & 0x1) << 7)	/* Pad with HDLC flags	*/
-#define	AC_CFG_BTSTF(v)		(((v) & 0x1) << 6)	/* Do HDLC bitstuffing	*/
-#define	AC_CFG_CRC16(v)		(((v) & 0x1) << 5)	/* 16 bit CCITT CRC	*/
-#define	AC_CFG_NCRC(v)		(((v) & 0x1) << 4)	/* Insert no CRC	*/
-#define	AC_CFG_TNCRS(v)		(((v) & 0x1) << 3)	/* Tx even if no carrier */
-#define	AC_CFG_MANCH(v)		(((v) & 0x1) << 2)	/* Manchester coding	*/
-#define	AC_CFG_BCDIS(v)		(((v) & 0x1) << 1)	/* Disable broadcast	*/
-#define	AC_CFG_PRM(v)		(((v) & 0x1) << 0)	/* Promiscuous mode	*/
-	unsigned char	cfg_byte15;
-#define	AC_CFG_ICDS(v)		(((v) & 0x1) << 7)	/* Internal collision	*/
-							/* detect source	*/
-#define	AC_CFG_CDTF(v)		(((v) & 0x7) << 4)	/* Collision detect	*/
-							/* filter in bit times	*/
-#define	AC_CFG_ICSS(v)		(((v) & 0x1) << 3)	/* Internal carrier	*/
-							/* sense source		*/
-#define	AC_CFG_CSTF(v)		(((v) & 0x7) << 0)	/* Carrier sense	*/
-							/* filter in bit times	*/
-	unsigned short	cfg_min_frm_len;
-#define	AC_CFG_MNFRM(v)		(((v) & 0xFF) << 0)	/* Min. bytes/frame (<= 255) */
-};
-
-/*
- * The MC-Setup Action Command.
- */
-typedef struct ac_mcs_t	ac_mcs_t;
-struct ac_mcs_t
-{
-	ach_t		mcs_h;
-	unsigned short	mcs_cnt;	/* No. of bytes of MC addresses	*/
-#if 0
-	unsigned char	mcs_data[ADDR_LEN]; /* The first MC address ..	*/
-	...
-#endif
-};
-
-#define I82586_MAX_MULTICAST_ADDRESSES	128	/* Hardware hashed filter */
-
-/*
- * The Transmit Action Command.
- */
-typedef struct ac_tx_t	ac_tx_t;
-struct ac_tx_t
-{
-	ach_t		tx_h;
-	unsigned short	tx_tbd_offset;	/* Address of list of buffers.	*/
-#if	0
-Linux packets are passed down with the destination MAC address
-and length/type field already prepended to the data,
-so we do not need to insert it.  Consistent with this
-we must also set the AC_CFG_ALOC(..) flag during the
-ac_cfg_t action command.
-	unsigned char	tx_addr[ADDR_LEN]; /* The frame dest. address	*/
-	unsigned short	tx_length;	/* The frame length		*/
-#endif	/* 0 */
-};
-
-/*
- * The Time Domain Reflectometer Action Command.
- */
-typedef struct ac_tdr_t	ac_tdr_t;
-struct ac_tdr_t
-{
-	ach_t		tdr_h;
-	unsigned short	tdr_result;	/* Result.	*/
-#define		AC_TDR_LNK_OK	(0x1 << 15)	/* No link problem	*/
-#define		AC_TDR_XCVR_PRB	(0x1 << 14)	/* Txcvr cable problem	*/
-#define		AC_TDR_ET_OPN	(0x1 << 13)	/* Open on the link	*/
-#define		AC_TDR_ET_SRT	(0x1 << 12)	/* Short on the link	*/
-#define		AC_TDR_TIME	(0x7FF << 0)	/* Distance to problem	*/
-						/* site	in transmit	*/
-						/* clock cycles		*/
-};
-
-/*
- * The Dump Action Command.
- */
-typedef struct ac_dmp_t	ac_dmp_t;
-struct ac_dmp_t
-{
-	ach_t		dmp_h;
-	unsigned short	dmp_offset;	/* Result.	*/
-};
-
-/*
- * Size of the result of the dump command.
- */
-#define	DUMPBYTES	170
-
-/*
- * The Diagnose Action Command.
- */
-typedef struct ac_dgn_t	ac_dgn_t;
-struct ac_dgn_t
-{
-	ach_t		dgn_h;
-};
-
-/*
- * Transmit Buffer Descriptor (TBD).
- */
-typedef struct tbd_t	tbd_t;
-struct tbd_t
-{
-	unsigned short	tbd_status;		/* Written by the CPU	*/
-#define		TBD_STATUS_EOF	(0x1 << 15)	/* This TBD is the	*/
-						/* last for this frame	*/
-#define		TBD_STATUS_ACNT	(0x3FFF << 0)	/* Actual count of data	*/
-						/* bytes in this buffer	*/
-	unsigned short	tbd_next_bd_offset;	/* Next in list		*/
-	unsigned short	tbd_bufl;		/* Buffer address (low)	*/
-	unsigned short	tbd_bufh;		/*    "	     "	(high)	*/
-};
-
-/*
- * Receive Buffer Descriptor (RBD).
- */
-typedef struct rbd_t	rbd_t;
-struct rbd_t
-{
-	unsigned short	rbd_status;		/* Written by the 82586	*/
-#define		RBD_STATUS_EOF	(0x1 << 15)	/* This RBD is the	*/
-						/* last for this frame	*/
-#define		RBD_STATUS_F	(0x1 << 14)	/* ACNT field is valid	*/
-#define		RBD_STATUS_ACNT	(0x3FFF << 0)	/* Actual no. of data	*/
-						/* bytes in this buffer	*/
-	unsigned short	rbd_next_rbd_offset;	/* Next rbd in list	*/
-	unsigned short	rbd_bufl;		/* Data pointer (low)	*/
-	unsigned short	rbd_bufh;		/*  "	   "    (high)	*/
-	unsigned short	rbd_el_size;		/* EL+Data buf. size	*/
-#define		RBD_EL	(0x1 << 15)		/* This BD is the	*/
-						/* last in the list	*/
-#define		RBD_SIZE (0x3FFF << 0)		/* No. of bytes the	*/
-						/* buffer can hold	*/
-};
-
-#define	rbdoff(p,f) 	toff(rbd_t, p, f)
-
-/*
- * Frame Descriptor (FD).
- */
-typedef struct fd_t	fd_t;
-struct fd_t
-{
-	unsigned short	fd_status;		/* Written by the 82586	*/
-#define		FD_STATUS_C	(0x1 << 15)	/* Completed storing frame */
-#define		FD_STATUS_B	(0x1 << 14)	/* FD was consumed by RU */
-#define		FD_STATUS_OK	(0x1 << 13)	/* Frame rxd successfully */
-#define		FD_STATUS_S11	(0x1 << 11)	/* CRC error		*/
-#define		FD_STATUS_S10	(0x1 << 10)	/* Alignment error	*/
-#define		FD_STATUS_S9	(0x1 <<  9)	/* Ran out of resources	*/
-#define		FD_STATUS_S8	(0x1 <<  8)	/* Rx DMA overrun	*/
-#define		FD_STATUS_S7	(0x1 <<  7)	/* Frame too short	*/
-#define		FD_STATUS_S6	(0x1 <<  6)	/* No EOF flag		*/
-	unsigned short	fd_command;		/* Command		*/
-#define		FD_COMMAND_EL	(0x1 << 15)	/* Last FD in list	*/
-#define		FD_COMMAND_S	(0x1 << 14)	/* Suspend RU after rx	*/
-	unsigned short	fd_link_offset;		/* Next FD		*/
-	unsigned short	fd_rbd_offset;		/* First RBD (data)	*/
-						/* Prepared by CPU,	*/
-						/* updated by 82586	*/
-#if	0
-I think the rest is unused since we
-have set AC_CFG_ALOC(..).  However, just
-in case, we leave the space.
-#endif	/* 0 */
-	unsigned char	fd_dest[ADDR_LEN];	/* Destination address	*/
-						/* Written by 82586	*/
-	unsigned char	fd_src[ADDR_LEN];	/* Source address	*/
-						/* Written by 82586	*/
-	unsigned short	fd_length;		/* Frame length or type	*/
-						/* Written by 82586	*/
-};
-
-#define	fdoff(p,f) 	toff(fd_t, p, f)
-
-/*
- * This software may only be used and distributed
- * according to the terms of the GNU General Public License.
- *
- * For more details, see wavelan.c.
- */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/irda/Config.help linux/drivers/net/irda/Config.help
--- v2.5.2/linux/drivers/net/irda/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/irda/Config.help	Fri Jan 25 16:04:24 2002
@@ -0,0 +1,147 @@
+CONFIG_IRTTY_SIR
+  Say Y here if you want to build support for the IrTTY line
+  discipline.  If you want to compile it as a module (irtty.o), say M
+  here and read <file:Documentation/modules.txt>.  IrTTY makes it
+  possible to use Linux's own serial driver for all IrDA ports that
+  are 16550 compatible.  Most IrDA chips are 16550 compatible so you
+  should probably say Y to this option.  Using IrTTY will however
+  limit the speed of the connection to 115200 bps (IrDA SIR mode).
+
+  If unsure, say Y.
+
+CONFIG_IRPORT_SIR
+  Say Y here if you want to build support for the IrPORT IrDA device
+  driver. If you want to compile it as a module (irport.o), say M here
+  and read <file:Documentation/modules.txt>.  IrPORT can be used
+  instead of IrTTY and sometimes this can be better.  One example is
+  if your IrDA port does not have echo-canceling, which will work OK
+  with IrPORT since this driver is working in half-duplex mode only.
+  You don't need to use irattach with IrPORT, but you just insert it
+  the same way as FIR drivers (insmod irport io=0x3e8 irq=11).  Notice
+  that IrPORT is a SIR device driver which means that speed is limited
+  to 115200 bps.
+
+  If unsure, say Y.
+
+CONFIG_USB_IRDA
+  Say Y here if you want to build support for the USB IrDA FIR Dongle
+  device driver.  If you want to compile it as a module (irda-usb.o),
+  say M here and read <file:Documentation/modules.txt>.  IrDA-USB
+  support the various IrDA USB dongles available and most of their
+  pecularities.  Those dongles plug in the USB port of your computer,
+  are plug and play, and support SIR and FIR (4Mbps) speeds.  On the
+  other hand, those dongles tend to be less efficient than a FIR
+  chipset.
+
+  Please note that the driver is still experimental.  And of course,
+  you will need both USB and IrDA support in your kernel...
+
+CONFIG_WINBOND_FIR
+  Say Y here if you want to build IrDA support for the Winbond
+  W83977AF super-io chipset.  This driver should be used for the IrDA
+  chipset in the Corel NetWinder.  The driver supports SIR, MIR and
+  FIR (4Mbps) speeds.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  w83977af_ir.o.
+
+CONFIG_NSC_FIR
+  Say Y here if you want to build support for the NSC PC87108 and
+  PC87338 IrDA chipsets.  This driver supports SIR,
+  MIR and FIR (4Mbps) speeds.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  nsc-ircc.o.
+
+CONFIG_TOSHIBA_FIR
+  Say Y here if you want to build support for the Toshiba Type-O IR
+  chipset.  This chipset is used by the Toshiba Libretto 100CT, and
+  many more laptops.  If you want to compile it as a module, say M
+  here and read <file:Documentation/modules.txt>.  The module will be
+  called toshoboe.o.
+
+CONFIG_SMC_IRCC_FIR
+  Say Y here if you want to build support for the SMC Infrared
+  Communications Controller.  It is used in the Fujitsu Lifebook 635t
+  and Sony PCG-505TX.  If you want to compile it as a module, say M
+  here and read <file:Documentation/modules.txt>.  The module will be
+  called smc-ircc.o.
+
+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,
+  M1535, M1535D, M1535+, M1535D Sourth Bridge.  This driver supports
+  SIR, MIR and FIR (4Mbps) speeds.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  ali-ircc.o.
+
+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
+  and 5500 notebooks. The driver provides support for SIR, MIR and
+  FIR (4Mbps) speeds.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called vlsi_ir.o.
+
+CONFIG_DONGLE
+  Say Y here if you have an infrared device that connects to your
+  computer's serial port. These devices are called dongles. Then say Y
+  or M to the driver for your particular dongle below.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about serial dongles.
+
+CONFIG_ESI_DONGLE
+  Say Y here if you want to build support for the Extended Systems
+  JetEye PC dongle.  If you want to compile it as a module, say M here
+  and read <file:Documentation/modules.txt>.  The ESI dongle attaches
+  to the normal 9-pin serial port connector, and can currently only be
+  used by IrTTY.  To activate support for ESI dongles you will have to
+  start irattach like this: "irattach -d esi".
+
+CONFIG_ACTISYS_DONGLE
+  Say Y here if you want to build support for the ACTiSYS IR-220L and
+  IR220L+ dongles.  If you want to compile it as a module, say M here
+  and read <file:Documentation/modules.txt>.  The ACTiSYS dongles
+  attaches to the normal 9-pin serial port connector, and can
+  currently only be used by IrTTY.  To activate support for ACTiSYS
+  dongles you will have to start irattach like this:
+  "irattach -d actisys" or "irattach -d actisys+".
+
+CONFIG_TEKRAM_DONGLE
+  Say Y here if you want to build support for the Tekram IrMate 210B
+  dongle.  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The Tekram dongle attaches to the
+  normal 9-pin serial port connector, and can currently only be used
+  by IrTTY.  To activate support for Tekram dongles you will have to
+  start irattach like this: "irattach -d tekram".
+
+CONFIG_GIRBIL_DONGLE
+  Say Y here if you want to build support for the Greenwich GIrBIL
+  dongle.  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The Greenwich dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  used by IrTTY.  To activate support for Greenwich dongles you will
+  have to insert "irattach -d girbil" in the /etc/irda/drivers script.
+
+CONFIG_LITELINK_DONGLE
+  Say Y here if you want to build support for the Parallax Litelink
+  dongle.  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The Parallax dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  used by IrTTY.  To activate support for Parallax dongles you will
+  have to start irattach like this "irattach -d litelink".
+
+CONFIG_OLD_BELKIN_DONGLE
+  Say Y here if you want to build support for the Adaptec Airport 1000
+  and 2000 dongles.  If you want to compile it as a module, say M here
+  and read <file:Documentation/modules.txt>.  The module will be
+  called old_belkin.o.  Some information is contained in the comments
+  at the top of <file:drivers/net/irda/old_belkin.c>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/net/irda/ali-ircc.c linux/drivers/net/irda/ali-ircc.c
--- v2.5.2/linux/drivers/net/irda/ali-ircc.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/net/irda/ali-ircc.c	Wed Jan 23 15:28:39 2002
@@ -1496,7 +1496,7 @@
 		if (mtt) 
 		{
 			/* Check how much time we have used already */
-			get_fast_time(&self->now);
+			do_gettimeofday(&self->now);
 			
 			diff = self->now.tv_usec - self->stamp.tv_usec;
 			/* self->stamp is set from ali_ircc_dma_receive_complete() */
@@ -1913,7 +1913,7 @@
 			 * reduce the min turn time a bit since we will know
 			 * how much time we have used for protocol processing
 			 */
-			get_fast_time(&self->stamp);
+			do_gettimeofday(&self->stamp);
 
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  
diff -u --recursive --new-file v2.5.2/linux/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c
--- v2.5.2/linux/drivers/net/irda/irda-usb.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/irda/irda-usb.c	Wed Jan 23 15:28:39 2002
@@ -427,7 +427,7 @@
 		mtt = irda_get_mtt(skb);
 		if (mtt) {
 			int diff;
-			get_fast_time(&self->now);
+			do_gettimeofday(&self->now);
 			diff = self->now.tv_usec - self->stamp.tv_usec;
 #ifdef IU_USB_MIN_RTT
 			/* Factor in USB delays -> Get rid of udelay() that
@@ -798,7 +798,7 @@
 	 * reduce the min turn time a bit since we will know
 	 * how much time we have used for protocol processing
 	 */
-        get_fast_time(&self->stamp);
+        do_gettimeofday(&self->stamp);
 
 	/* Fix skb, and remove USB-IrDA header */
 	skb_put(skb, urb->actual_length);
diff -u --recursive --new-file v2.5.2/linux/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c
--- v2.5.2/linux/drivers/net/irda/nsc-ircc.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/irda/nsc-ircc.c	Wed Jan 23 15:28:39 2002
@@ -1163,7 +1163,7 @@
 		mtt = irda_get_mtt(skb);
 		if (mtt) {
 			/* Check how much time we have used already */
-			get_fast_time(&self->now);
+			do_gettimeofday(&self->now);
 			diff = self->now.tv_usec - self->stamp.tv_usec;
 			if (diff < 0) 
 				diff += 1000000;
@@ -1535,7 +1535,7 @@
 			 * reduce the min turn time a bit since we will know
 			 * how much time we have used for protocol processing
 			 */
-			get_fast_time(&self->stamp);
+			do_gettimeofday(&self->stamp);
 
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  {
diff -u --recursive --new-file v2.5.2/linux/drivers/net/mii.c linux/drivers/net/mii.c
--- v2.5.2/linux/drivers/net/mii.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/mii.c	Thu Jan 24 11:51:10 2002
@@ -0,0 +1,174 @@
+/*
+
+	mii.c: MII interface library
+
+	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2001 Jeff Garzik
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+
+int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
+{
+	struct net_device *dev = mii->dev;
+	u32 advert, bmcr, lpa, nego;
+
+	ecmd->supported =
+	    (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+	     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
+	     SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
+
+	/* only supports twisted-pair */
+	ecmd->port = PORT_MII;
+
+	/* only supports internal transceiver */
+	ecmd->transceiver = XCVR_INTERNAL;
+
+	/* this isn't fully supported at higher layers */
+	ecmd->phy_address = mii->phy_id;
+
+	ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+	advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
+	if (advert & ADVERTISE_10HALF)
+		ecmd->advertising |= ADVERTISED_10baseT_Half;
+	if (advert & ADVERTISE_10FULL)
+		ecmd->advertising |= ADVERTISED_10baseT_Full;
+	if (advert & ADVERTISE_100HALF)
+		ecmd->advertising |= ADVERTISED_100baseT_Half;
+	if (advert & ADVERTISE_100FULL)
+		ecmd->advertising |= ADVERTISED_100baseT_Full;
+
+	bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+	lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
+	if (bmcr & BMCR_ANENABLE) {
+		ecmd->advertising |= ADVERTISED_Autoneg;
+		ecmd->autoneg = AUTONEG_ENABLE;
+		
+		nego = mii_nway_result(advert & lpa);
+		if (nego == LPA_100FULL || nego == LPA_100HALF)
+			ecmd->speed = SPEED_100;
+		else
+			ecmd->speed = SPEED_10;
+		if (nego == LPA_100FULL || nego == LPA_10FULL) {
+			ecmd->duplex = DUPLEX_FULL;
+			mii->full_duplex = 1;
+		} else {
+			ecmd->duplex = DUPLEX_HALF;
+			mii->full_duplex = 0;
+		}
+	} else {
+		ecmd->autoneg = AUTONEG_DISABLE;
+
+		ecmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
+		ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+	}
+
+	/* ignore maxtxpkt, maxrxpkt for now */
+
+	return 0;
+}
+
+int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
+{
+	struct net_device *dev = mii->dev;
+
+	if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100)
+		return -EINVAL;
+	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
+		return -EINVAL;
+	if (ecmd->port != PORT_MII)
+		return -EINVAL;
+	if (ecmd->transceiver != XCVR_INTERNAL)
+		return -EINVAL;
+	if (ecmd->phy_address != mii->phy_id)
+		return -EINVAL;
+	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
+		return -EINVAL;
+				  
+	/* ignore supported, maxtxpkt, maxrxpkt */
+	
+	if (ecmd->autoneg == AUTONEG_ENABLE) {
+		u32 bmcr, advert, tmp;
+
+		if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
+					  ADVERTISED_10baseT_Full |
+					  ADVERTISED_100baseT_Half |
+					  ADVERTISED_100baseT_Full)) == 0)
+			return -EINVAL;
+
+		/* advertise only what has been requested */
+		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
+		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+		if (ADVERTISED_10baseT_Half)
+			tmp |= ADVERTISE_10HALF;
+		if (ADVERTISED_10baseT_Full)
+			tmp |= ADVERTISE_10FULL;
+		if (ADVERTISED_100baseT_Half)
+			tmp |= ADVERTISE_100HALF;
+		if (ADVERTISED_100baseT_Full)
+			tmp |= ADVERTISE_100FULL;
+		if (advert != tmp) {
+			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
+			mii->advertising = tmp;
+		}
+		
+		/* turn on autonegotiation, and force a renegotiate */
+		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
+
+		mii->duplex_lock = 0;
+	} else {
+		u32 bmcr, tmp;
+
+		/* turn off auto negotiation, set speed and duplexity */
+		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
+		if (ecmd->speed == SPEED_100)
+			bmcr |= BMCR_SPEED100;
+		if (ecmd->duplex == DUPLEX_FULL) {
+			bmcr |= BMCR_FULLDPLX;
+			mii->full_duplex = 1;
+		} else
+			mii->full_duplex = 0;
+		if (bmcr != tmp)
+			mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
+
+		mii->duplex_lock = 1;
+	}
+	return 0;
+}
+
+int mii_link_ok (struct mii_if_info *mii)
+{
+	if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
+		return 1;
+	return 0;
+}
+
+int mii_nway_restart (struct mii_if_info *mii)
+{
+	int bmcr;
+	int r = -EINVAL;
+
+	/* if autoneg is off, it's an error */
+	bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
+
+	if (bmcr & BMCR_ANENABLE) {
+		bmcr |= BMCR_ANRESTART;
+		mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
+		r = 0;
+	}
+
+	return r;
+}
+
+EXPORT_SYMBOL(mii_link_ok);
+EXPORT_SYMBOL(mii_nway_restart);
+EXPORT_SYMBOL(mii_ethtool_gset);
+EXPORT_SYMBOL(mii_ethtool_sset);
diff -u --recursive --new-file v2.5.2/linux/drivers/net/pcmcia/Config.help linux/drivers/net/pcmcia/Config.help
--- v2.5.2/linux/drivers/net/pcmcia/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/Config.help	Fri Jan 25 16:03:42 2002
@@ -0,0 +1,149 @@
+CONFIG_AIRONET4500_CS
+  Say Y here if you have a PCMCIA Aironet 4500/4800 card which you
+  want to use with the standard PCMCIA cardservices provided by the
+  pcmcia-cs package.
+
+  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 aironet4500_cs.o. If you want to
+  compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+CONFIG_NET_PCMCIA
+  Say Y if you would like to include support for any PCMCIA or CardBus
+  network adapters, then say Y to the driver for your particular card
+  below.  PCMCIA- or PC-cards are credit-card size devices often used
+  with laptops computers; CardBus is the newer and faster version of
+  PCMCIA.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  You also want to check out the PCMCIA-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  If unsure, say N.
+
+CONFIG_PCMCIA_3C589
+  Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA
+  (PC-card) Ethernet card to your computer.
+
+  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 3c589_cs.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>. If
+  unsure, say N.
+
+CONFIG_PCMCIA_3C574
+  Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA
+  (PC-card) Fast Ethernet card to your computer.
+
+  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 3c574_cs.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.  If
+  unsure, say N.
+
+CONFIG_PCMCIA_FMVJ18X
+  Say Y here if you intend to attach a Fujitsu FMV-J18x or compatible
+  PCMCIA (PC-card) Ethernet card to your computer.
+
+  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 fmvj18x_cs.o.  If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+  If unsure, say N.
+
+CONFIG_PCMCIA_PCNET
+  Say Y here if you intend to attach an NE2000 compatible PCMCIA
+  (PC-card) Ethernet or Fast Ethernet card to your computer.
+
+  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 pcnet_cs.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>. If
+  unsure, say N.
+
+CONFIG_PCMCIA_NMCLAN
+  Say Y here if you intend to attach a New Media Ethernet or LiveWire
+  PCMCIA (PC-card) Ethernet card to your computer.
+
+  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 nmclan_cs.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.  If
+  unsure, say N.
+
+CONFIG_PCMCIA_SMC91C92
+  Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA
+  (PC-card) Ethernet or Fast Ethernet card to your computer.
+
+  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 smc91c92_cs.o.  If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+  If unsure, say N.
+
+CONFIG_PCMCIA_XIRC2PS
+  Say Y here if you intend to attach a Xircom 16-bit PCMCIA (PC-card)
+  Ethernet or Fast Ethernet card to your computer.
+
+  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 xirc2ps_cs.o.  If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+  If unsure, say N.
+
+CONFIG_ARCNET_COM20020_CS
+  Say Y here if you intend to attach this type of ARCnet PCMCIA card
+  to your computer.
+
+  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 com20020_cs.o.  If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+  If unsure, say N.
+
+CONFIG_PCMCIA_IBMTR
+  Say Y here if you intend to attach this type of Token Ring PCMCIA
+  card to your computer. You then also need to say Y to "Token Ring
+  driver support".
+
+  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 ibmtr_cs.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+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
+  as with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and
+  ASIX.
+
+  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 xircom_tulip_cb.o.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>. If unsure, say N.
+
+CONFIG_NET_PCMCIA_RADIO
+  Say Y here if you would like to use a PCMCIA (PC-card) device to
+  connect to a wireless local area network. Then say Y to the driver
+  for your particular card below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location). You also want to check out the PCMCIA-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+CONFIG_PCMCIA_RAYCS
+  Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
+  (PC-card) wireless Ethernet networking card to your computer.
+  Please read the file <file:Documentation/networking/ray_cs.txt> for
+  details.
+
+  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 ray_cs.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.  If
+  unsure, say N.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in
--- v2.5.2/linux/drivers/net/pcmcia/Config.in	Mon Nov 12 09:35:43 2001
+++ linux/drivers/net/pcmcia/Config.in	Mon Jan 21 16:04:47 2002
@@ -28,8 +28,6 @@
    bool '  Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO
    if [ "$CONFIG_NET_PCMCIA_RADIO" = "y" ]; then
       dep_tristate '    Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA
-      dep_tristate '    Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA
-      dep_tristate '    AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA
       dep_tristate '    Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA
    fi
 fi
diff -u --recursive --new-file v2.5.2/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile
--- v2.5.2/linux/drivers/net/pcmcia/Makefile	Mon Nov 12 09:35:43 2001
+++ linux/drivers/net/pcmcia/Makefile	Mon Jan 21 16:04:47 2002
@@ -27,8 +27,6 @@
 
 # 16-bit wireless client drivers
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
-obj-$(CONFIG_PCMCIA_NETWAVE)	+= netwave_cs.o
-obj-$(CONFIG_PCMCIA_WAVELAN)	+= wavelan_cs.o
 obj-$(CONFIG_AIRONET4500_CS)	+= aironet4500_cs.o
 
 # Cardbus client drivers
diff -u --recursive --new-file v2.5.2/linux/drivers/net/pcmcia/i82593.h linux/drivers/net/pcmcia/i82593.h
--- v2.5.2/linux/drivers/net/pcmcia/i82593.h	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/i82593.h	Wed Dec 31 16:00:00 1969
@@ -1,224 +0,0 @@
-/*
- * Definitions for Intel 82593 CSMA/CD Core LAN Controller
- * The definitions are taken from the 1992 users manual with Intel
- * order number 297125-001.
- *
- * /usr/src/pc/RCS/i82593.h,v 1.1 1996/07/17 15:23:12 root Exp
- *
- * Copyright 1994, Anders Klemets <klemets@it.kth.se>
- *
- * This software may be freely distributed for noncommercial purposes
- * as long as this notice is retained.
- * 
- * HISTORY
- * i82593.h,v
- * Revision 1.1  1996/07/17 15:23:12  root
- * Initial revision
- *
- * Revision 1.3  1995/04/05  15:13:58  adj
- * Initial alpha release
- *
- * Revision 1.2  1994/06/16  23:57:31  klemets
- * Mirrored all the fields in the configuration block.
- *
- * Revision 1.1  1994/06/02  20:25:34  klemets
- * Initial revision
- *
- *
- */
-#ifndef	_I82593_H
-#define	_I82593_H
-
-/* Intel 82593 CSMA/CD Core LAN Controller */
-
-/* Port 0 Command Register definitions */
-
-/* Execution operations */
-#define OP0_NOP			0	/* CHNL = 0 */
-#define OP0_SWIT_TO_PORT_1	0	/* CHNL = 1 */
-#define OP0_IA_SETUP		1
-#define OP0_CONFIGURE		2
-#define OP0_MC_SETUP		3
-#define OP0_TRANSMIT		4
-#define OP0_TDR			5
-#define OP0_DUMP		6
-#define OP0_DIAGNOSE		7
-#define OP0_TRANSMIT_NO_CRC	9
-#define OP0_RETRANSMIT		12
-#define OP0_ABORT		13
-/* Reception operations */
-#define OP0_RCV_ENABLE		8
-#define OP0_RCV_DISABLE		10
-#define OP0_STOP_RCV		11
-/* Status pointer control operations */
-#define OP0_FIX_PTR		15	/* CHNL = 1 */
-#define OP0_RLS_PTR		15	/* CHNL = 0 */
-#define OP0_RESET		14
-
-#define CR0_CHNL		(1 << 4)	/* 0=Channel 0, 1=Channel 1 */
-#define CR0_STATUS_0		0x00
-#define CR0_STATUS_1		0x20
-#define CR0_STATUS_2		0x40
-#define CR0_STATUS_3		0x60
-#define CR0_INT_ACK		(1 << 7)	/* 0=No ack, 1=acknowledge */
-
-/* Port 0 Status Register definitions */
-
-#define SR0_NO_RESULT		0		/* dummy */
-#define SR0_EVENT_MASK		0x0f
-#define SR0_IA_SETUP_DONE	1
-#define SR0_CONFIGURE_DONE	2
-#define SR0_MC_SETUP_DONE	3
-#define SR0_TRANSMIT_DONE	4
-#define SR0_TDR_DONE		5
-#define SR0_DUMP_DONE		6
-#define SR0_DIAGNOSE_PASSED	7
-#define SR0_TRANSMIT_NO_CRC_DONE 9
-#define SR0_RETRANSMIT_DONE	12
-#define SR0_EXECUTION_ABORTED	13
-#define SR0_END_OF_FRAME	8
-#define SR0_RECEPTION_ABORTED	10
-#define SR0_DIAGNOSE_FAILED	15
-#define SR0_STOP_REG_HIT	11
-
-#define SR0_CHNL		(1 << 4)
-#define SR0_EXECUTION		(1 << 5)
-#define SR0_RECEPTION		(1 << 6)
-#define SR0_INTERRUPT		(1 << 7)
-#define SR0_BOTH_RX_TX		(SR0_EXECUTION | SR0_RECEPTION)
-
-#define SR3_EXEC_STATE_MASK	0x03
-#define SR3_EXEC_IDLE		0
-#define SR3_TX_ABORT_IN_PROGRESS 1
-#define SR3_EXEC_ACTIVE		2
-#define SR3_ABORT_IN_PROGRESS	3
-#define SR3_EXEC_CHNL		(1 << 2)
-#define SR3_STP_ON_NO_RSRC	(1 << 3)
-#define SR3_RCVING_NO_RSRC	(1 << 4)
-#define SR3_RCV_STATE_MASK	0x60
-#define SR3_RCV_IDLE		0x00
-#define SR3_RCV_READY		0x20
-#define SR3_RCV_ACTIVE		0x40
-#define SR3_RCV_STOP_IN_PROG	0x60
-#define SR3_RCV_CHNL		(1 << 7)
-
-/* Port 1 Command Register definitions */
-
-#define OP1_NOP			0
-#define OP1_SWIT_TO_PORT_0	1
-#define OP1_INT_DISABLE		2
-#define OP1_INT_ENABLE		3
-#define OP1_SET_TS		5
-#define OP1_RST_TS		7
-#define OP1_POWER_DOWN		8
-#define OP1_RESET_RING_MNGMT	11
-#define OP1_RESET		14
-#define OP1_SEL_RST		15
-
-#define CR1_STATUS_4		0x00
-#define CR1_STATUS_5		0x20
-#define CR1_STATUS_6		0x40
-#define CR1_STOP_REG_UPDATE	(1 << 7)
-
-/* Receive frame status bits */
-
-#define	RX_RCLD			(1 << 0)
-#define RX_IA_MATCH		(1 << 1)
-#define	RX_NO_AD_MATCH		(1 << 2)
-#define RX_NO_SFD		(1 << 3)
-#define RX_SRT_FRM		(1 << 7)
-#define RX_OVRRUN		(1 << 8)
-#define RX_ALG_ERR		(1 << 10)
-#define RX_CRC_ERR		(1 << 11)
-#define RX_LEN_ERR		(1 << 12)
-#define RX_RCV_OK		(1 << 13)
-#define RX_TYP_LEN		(1 << 15)
-
-/* Transmit status bits */
-
-#define TX_NCOL_MASK		0x0f
-#define TX_FRTL			(1 << 4)
-#define TX_MAX_COL		(1 << 5)
-#define TX_HRT_BEAT		(1 << 6)
-#define TX_DEFER		(1 << 7)
-#define TX_UND_RUN		(1 << 8)
-#define TX_LOST_CTS		(1 << 9)
-#define TX_LOST_CRS		(1 << 10)
-#define TX_LTCOL		(1 << 11)
-#define TX_OK			(1 << 13)
-#define TX_COLL			(1 << 15)
-
-struct i82593_conf_block {
-  u_char fifo_limit : 4,
-  	 forgnesi   : 1,
-  	 fifo_32    : 1,
-  	 d6mod      : 1,
-  	 throttle_enb : 1;
-  u_char throttle   : 6,
-	 cntrxint   : 1,
-	 contin	    : 1;
-  u_char addr_len   : 3,
-  	 acloc 	    : 1,
- 	 preamb_len : 2,
-  	 loopback   : 2;
-  u_char lin_prio   : 3,
-	 tbofstop   : 1,
-	 exp_prio   : 3,
-	 bof_met    : 1;
-  u_char	    : 4,
-	 ifrm_spc   : 4;
-  u_char	    : 5,
-	 slottim_low : 3;
-  u_char slottim_hi : 3,
-		    : 1,
-	 max_retr   : 4;
-  u_char prmisc     : 1,
-	 bc_dis     : 1,
-  		    : 1,
-	 crs_1	    : 1,
-	 nocrc_ins  : 1,
-	 crc_1632   : 1,
-  	 	    : 1,
-  	 crs_cdt    : 1;
-  u_char cs_filter  : 3,
-	 crs_src    : 1,
-	 cd_filter  : 3,
-		    : 1;
-  u_char	    : 2,
-  	 min_fr_len : 6;
-  u_char lng_typ    : 1,
-	 lng_fld    : 1,
-	 rxcrc_xf   : 1,
-	 artx	    : 1,
-	 sarec	    : 1,
-	 tx_jabber  : 1,	/* why is this called max_len in the manual? */
-	 hash_1	    : 1,
-  	 lbpkpol    : 1;
-  u_char	    : 6,
-  	 fdx	    : 1,
-  	  	    : 1;
-  u_char dummy_6    : 6,	/* supposed to be ones */
-  	 mult_ia    : 1,
-  	 dis_bof    : 1;
-  u_char dummy_1    : 1,	/* supposed to be one */
-	 tx_ifs_retrig : 2,
-	 mc_all     : 1,
-	 rcv_mon    : 2,
-	 frag_acpt  : 1,
-  	 tstrttrs   : 1;
-  u_char fretx	    : 1,
-	 runt_eop   : 1,
-	 hw_sw_pin  : 1,
-	 big_endn   : 1,
-	 syncrqs    : 1,
-	 sttlen     : 1,
-	 tx_eop     : 1,
-  	 rx_eop	    : 1;
-  u_char rbuf_size  : 5,
-	 rcvstop    : 1,
-  	 	    : 2;
-};
-
-#define I82593_MAX_MULTICAST_ADDRESSES	128	/* Hardware hashed filter */
-
-#endif /* _I82593_H */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c
--- v2.5.2/linux/drivers/net/pcmcia/netwave_cs.c	Fri Oct 12 14:21:18 2001
+++ linux/drivers/net/pcmcia/netwave_cs.c	Wed Dec 31 16:00:00 1969
@@ -1,1600 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      netwave_cs.c
- * Version:       0.4.1
- * Description:   Netwave AirSurfer Wireless LAN PC Card driver
- * Status:        Experimental.
- * Authors:       John Markus Bjørndalen <johnm@cs.uit.no>
- *                Dag Brattli <dagb@cs.uit.no>
- *                David Hinds <dahinds@users.sourceforge.net>
- * Created at:    A long time ago!
- * Modified at:   Mon Nov 10 11:54:37 1997
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1997 University of Tromsø, Norway
- *
- * Revision History:
- *
- *   08-Nov-97 15:14:47   John Markus Bjørndalen <johnm@cs.uit.no>
- *    - Fixed some bugs in netwave_rx and cleaned it up a bit. 
- *      (One of the bugs would have destroyed packets when receiving
- *      multiple packets per interrupt). 
- *    - Cleaned up parts of newave_hw_xmit. 
- *    - A few general cleanups. 
- *   24-Oct-97 13:17:36   Dag Brattli <dagb@cs.uit.no>
- *    - Fixed netwave_rx receive function (got updated docs)
- *   Others:
- *    - Changed name from xircnw to netwave, take a look at 
- *      http://www.netwave-wireless.com
- *    - Some reorganizing of the code
- *    - Removed possible race condition between interrupt handler and transmit
- *      function
- *    - Started to add wireless extensions, but still needs some coding
- *    - Added watchdog for better handling of transmission timeouts 
- *      (hopefully this works better)
- ********************************************************************/
-
-/* To have statistics (just packets sent) define this */
-#undef NETWAVE_STATS
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/errno.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#ifdef CONFIG_NET_PCMCIA_RADIO
-#include <linux/wireless.h>
-#endif
-
-#include <pcmcia/version.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/mem_op.h>
-
-#define NETWAVE_REGOFF         0x8000
-/* The Netwave IO registers, offsets to iobase */
-#define NETWAVE_REG_COR        0x0
-#define NETWAVE_REG_CCSR       0x2
-#define NETWAVE_REG_ASR        0x4
-#define NETWAVE_REG_IMR        0xa
-#define NETWAVE_REG_PMR        0xc
-#define NETWAVE_REG_IOLOW      0x6
-#define NETWAVE_REG_IOHI       0x7
-#define NETWAVE_REG_IOCONTROL  0x8
-#define NETWAVE_REG_DATA       0xf
-/* The Netwave Extended IO registers, offsets to RamBase */
-#define NETWAVE_EREG_ASCC      0x114
-#define NETWAVE_EREG_RSER      0x120
-#define NETWAVE_EREG_RSERW     0x124
-#define NETWAVE_EREG_TSER      0x130
-#define NETWAVE_EREG_TSERW     0x134
-#define NETWAVE_EREG_CB        0x100
-#define NETWAVE_EREG_SPCQ      0x154
-#define NETWAVE_EREG_SPU       0x155
-#define NETWAVE_EREG_LIF       0x14e
-#define NETWAVE_EREG_ISPLQ     0x156
-#define NETWAVE_EREG_HHC       0x158
-#define NETWAVE_EREG_NI        0x16e
-#define NETWAVE_EREG_MHS       0x16b
-#define NETWAVE_EREG_TDP       0x140
-#define NETWAVE_EREG_RDP       0x150
-#define NETWAVE_EREG_PA        0x160
-#define NETWAVE_EREG_EC        0x180
-#define NETWAVE_EREG_CRBP      0x17a
-#define NETWAVE_EREG_ARW       0x166
-
-/*
- * Commands used in the extended command buffer
- * NETWAVE_EREG_CB (0x100-0x10F) 
- */
-#define NETWAVE_CMD_NOP        0x00
-#define NETWAVE_CMD_SRC        0x01
-#define NETWAVE_CMD_STC        0x02
-#define NETWAVE_CMD_AMA        0x03
-#define NETWAVE_CMD_DMA        0x04
-#define NETWAVE_CMD_SAMA       0x05
-#define NETWAVE_CMD_ER         0x06
-#define NETWAVE_CMD_DR         0x07
-#define NETWAVE_CMD_TL         0x08
-#define NETWAVE_CMD_SRP        0x09
-#define NETWAVE_CMD_SSK        0x0a
-#define NETWAVE_CMD_SMD        0x0b
-#define NETWAVE_CMD_SAPD       0x0c
-#define NETWAVE_CMD_SSS        0x11
-/* End of Command marker */
-#define NETWAVE_CMD_EOC        0x00
-
-/* ASR register bits */
-#define NETWAVE_ASR_RXRDY   0x80
-#define NETWAVE_ASR_TXBA    0x01
-
-#define TX_TIMEOUT		((32*HZ)/100)
-
-static const unsigned int imrConfRFU1 = 0x10; /* RFU interrupt mask, keep high */
-static const unsigned int imrConfIENA = 0x02; /* Interrupt enable */
-
-static const unsigned int corConfIENA   = 0x01; /* Interrupt enable */
-static const unsigned int corConfLVLREQ = 0x40; /* Keep high */
-
-static const unsigned int rxConfRxEna  = 0x80; /* Receive Enable */
-static const unsigned int rxConfMAC    = 0x20; /* MAC host receive mode*/ 
-static const unsigned int rxConfPro    = 0x10; /* Promiscuous */
-static const unsigned int rxConfAMP    = 0x08; /* Accept Multicast Packets */
-static const unsigned int rxConfBcast  = 0x04; /* Accept Broadcast Packets */
-
-static const unsigned int txConfTxEna  = 0x80; /* Transmit Enable */
-static const unsigned int txConfMAC    = 0x20; /* Host sends MAC mode */
-static const unsigned int txConfEUD    = 0x10; /* Enable Uni-Data packets */
-static const unsigned int txConfKey    = 0x02; /* Scramble data packets */
-static const unsigned int txConfLoop   = 0x01; /* Loopback mode */
-
-/*
-   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
-   you do not define PCMCIA_DEBUG at all, all the debug code will be
-   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
-   be present but disabled -- but it can then be enabled for specific
-   modules at load time with a 'pc_debug=#' option to insmod.
-*/
-
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"netwave_cs.c 0.3.0 Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n";
-#else
-#define DEBUG(n, args...)
-#endif
-
-static dev_info_t dev_info = "netwave_cs";
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-/* Choose the domain, default is 0x100 */
-static u_int  domain = 0x100;
-
-/* Scramble key, range from 0x0 to 0xffff.  
- * 0x0 is no scrambling. 
- */
-static u_int  scramble_key = 0x0;
-
-/* Shared memory speed, in ns. The documentation states that 
- * the card should not be read faster than every 400ns. 
- * This timing should be provided by the HBA. If it becomes a 
- * problem, try setting mem_speed to 400. 
- */
-static int mem_speed;
-
-/* Bit map of interrupts to choose from */
-/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
-static u_int irq_mask = 0xdeb8;
-static int irq_list[4] = { -1 };
-
-MODULE_PARM(domain, "i");
-MODULE_PARM(scramble_key, "i");
-MODULE_PARM(mem_speed, "i");
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-
-/*====================================================================*/
-
-/* PCMCIA (Card Services) related functions */
-static void netwave_release(u_long arg);     /* Card removal */
-static int  netwave_event(event_t event, int priority, 
-					      event_callback_args_t *args);
-static void netwave_pcmcia_config(dev_link_t *arg); /* Runs after card 
-													   insertion */
-static dev_link_t *netwave_attach(void);     /* Create instance */
-static void netwave_detach(dev_link_t *);    /* Destroy instance */
-static void netwave_flush_stale_links(void);	     /* Destroy all staled instances */
-
-/* Hardware configuration */
-static void netwave_doreset(ioaddr_t iobase, u_char* ramBase);
-static void netwave_reset(struct net_device *dev);
-
-/* Misc device stuff */
-static int netwave_open(struct net_device *dev);  /* Open the device */
-static int netwave_close(struct net_device *dev); /* Close the device */
-static int netwave_config(struct net_device *dev, struct ifmap *map);
-
-/* Packet transmission and Packet reception */
-static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev);
-static int netwave_rx( struct net_device *dev);
-
-/* Interrupt routines */
-static void netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void netwave_watchdog(struct net_device *);
-
-/* Statistics */
-static void update_stats(struct net_device *dev);
-static struct net_device_stats *netwave_get_stats(struct net_device *dev);
-
-/* Wireless extensions */
-#ifdef WIRELESS_EXT
-static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev);
-#endif
-static int netwave_ioctl(struct net_device *, struct ifreq *, int);
-
-static void set_multicast_list(struct net_device *dev);
-
-/*
-   A linked list of "instances" of the skeleton device.  Each actual
-   PCMCIA card corresponds to one device instance, and is described
-   by one dev_link_t structure (defined in ds.h).
-
-   You may not want to use a linked list for this -- for example, the
-   memory card driver uses an array of dev_link_t pointers, where minor
-   device numbers are used to derive the corresponding array index.
-*/
-static dev_link_t *dev_list;
-
-/*
-   A dev_link_t structure has fields for most things that are needed
-   to keep track of a socket, but there will usually be some device
-   specific information that also needs to be kept track of.  The
-   'priv' pointer in a dev_link_t structure can be used to point to
-   a device-specific private data structure, like this.
-
-   A driver needs to provide a dev_node_t structure for each device
-   on a card.  In some cases, there is only one device per card (for
-   example, ethernet cards, modems).  In other cases, there may be
-   many actual or logical devices (SCSI adapters, memory cards with
-   multiple partitions).  The dev_node_t structures need to be kept
-   in a linked list starting at the 'dev' field of a dev_link_t
-   structure.  We allocate them in the card's private data structure,
-   because they generally can't be allocated dynamically.
-*/
-
-/* Wireless Extension Backward compatibility - Jean II
- * If the new wireless device private ioctl range is not defined,
- * default to standard device private ioctl range */
-#ifndef SIOCIWFIRSTPRIV
-#define SIOCIWFIRSTPRIV	SIOCDEVPRIVATE
-#endif /* SIOCIWFIRSTPRIV */
-
-#define SIOCGIPSNAP	SIOCIWFIRSTPRIV		/* Site Survey Snapshot */
-/*#define SIOCGIPQTHR	SIOCIWFIRSTPRIV + 1*/
-
-#define MAX_ESA 10
-
-typedef struct net_addr {
-    u_char addr48[6];
-} net_addr;
-
-struct site_survey {
-    u_short length;
-    u_char  struct_revision;
-    u_char  roaming_state;
-	
-    u_char  sp_existsFlag;
-    u_char  sp_link_quality;
-    u_char  sp_max_link_quality;
-    u_char  linkQualityGoodFairBoundary;
-    u_char  linkQualityFairPoorBoundary;
-    u_char  sp_utilization;
-    u_char  sp_goodness;
-    u_char  sp_hotheadcount;
-    u_char  roaming_condition;
-	
-    net_addr sp;
-    u_char   numAPs;
-    net_addr nearByAccessPoints[MAX_ESA];
-};	
-   
-typedef struct netwave_private {
-    dev_link_t link;
-    struct net_device      dev;
-    dev_node_t node;
-    u_char     *ramBase;
-    int        timeoutCounter;
-    int        lastExec;
-    struct timer_list      watchdog;	/* To avoid blocking state */
-    struct site_survey     nss;
-    struct net_device_stats stats;
-#ifdef WIRELESS_EXT
-    struct iw_statistics   iw_stats;    /* Wireless stats */
-#endif
-} netwave_private;
-
-#ifdef NETWAVE_STATS
-static struct net_device_stats *netwave_get_stats(struct net_device *dev);
-#endif
-
-/*
- * The Netwave card is little-endian, so won't work for big endian
- * systems.
- */
-static inline unsigned short get_uint16(u_char* staddr) 
-{
-    return readw(staddr); /* Return only 16 bits */
-}
-
-static inline short get_int16(u_char* staddr)
-{
-    return readw(staddr);
-}
-
-/**************************************************************************/
-
-static void cs_error(client_handle_t handle, int func, int ret)
-{
-    error_info_t err = { func, ret };
-    CardServices(ReportError, handle, &err);
-}
-
-/* 
- * Wait until the WOC (Write Operation Complete) bit in the 
- * ASR (Adapter Status Register) is asserted. 
- * This should have aborted if it takes too long time. 
- */
-static inline void wait_WOC(unsigned int iobase)
-{
-    /* Spin lock */
-    while ((inb(iobase + NETWAVE_REG_ASR) & 0x8) != 0x8) ; 
-}
-
-#ifdef WIRELESS_EXT
-static void netwave_snapshot(netwave_private *priv, u_char *ramBase, 
-			     ioaddr_t iobase) { 
-    u_short resultBuffer;
-
-    /* if time since last snapshot is > 1 sec. (100 jiffies?)  then take 
-     * new snapshot, else return cached data. This is the recommended rate.  
-     */
-    if ( jiffies - priv->lastExec > 100) { 
-	/* Take site survey  snapshot */ 
-	/*printk( KERN_DEBUG "Taking new snapshot. %ld\n", jiffies -
-	  priv->lastExec); */
-	wait_WOC(iobase); 
-	writeb(NETWAVE_CMD_SSS, ramBase + NETWAVE_EREG_CB + 0); 
-	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); 
-	wait_WOC(iobase); 
-
-	/* Get result and copy to cach */ 
-	resultBuffer = readw(ramBase + NETWAVE_EREG_CRBP); 
-	copy_from_pc( &priv->nss, ramBase+resultBuffer, 
-		      sizeof(struct site_survey)); 
-    } 
-}
-#endif
-
-#ifdef WIRELESS_EXT
-/*
- * Function netwave_get_wireless_stats (dev)
- *
- *    Wireless extensions statistics
- *
- */
-static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev)
-{	
-    unsigned long flags;
-    ioaddr_t iobase = dev->base_addr;
-    netwave_private *priv = (netwave_private *) dev->priv;
-    u_char *ramBase = priv->ramBase;
-    struct iw_statistics* wstats;
-	
-    wstats = &priv->iw_stats;
-
-    save_flags(flags);
-    cli();
-	
-    netwave_snapshot( priv, ramBase, iobase);
-
-    wstats->status = priv->nss.roaming_state;
-    wstats->qual.qual = readb( ramBase + NETWAVE_EREG_SPCQ); 
-    wstats->qual.level = readb( ramBase + NETWAVE_EREG_ISPLQ);
-    wstats->qual.noise = readb( ramBase + NETWAVE_EREG_SPU) & 0x3f;
-    wstats->discard.nwid = 0L;
-    wstats->discard.code = 0L;
-    wstats->discard.misc = 0L;
-
-    restore_flags(flags);
-    
-    return &priv->iw_stats;
-}
-#endif
-
-/*
- * Function netwave_attach (void)
- *
- *     Creates an "instance" of the driver, allocating local data 
- *     structures for one device.  The device is registered with Card 
- *     Services.
- *
- *     The dev_link structure is initialized, but we don't actually
- *     configure the card at this point -- we wait until we receive a
- *     card insertion event.
- */
-static dev_link_t *netwave_attach(void)
-{
-    client_reg_t client_reg;
-    dev_link_t *link;
-    struct net_device *dev;
-    netwave_private *priv;
-    int i, ret;
-    
-    DEBUG(0, "netwave_attach()\n");
-    
-    /* Perform some cleanup */
-    netwave_flush_stale_links();
-
-    /* Initialize the dev_link_t structure */
-    priv = kmalloc(sizeof(*priv), GFP_KERNEL);
-    if (!priv) return NULL;
-    memset(priv, 0, sizeof(*priv));
-    link = &priv->link; dev = &priv->dev;
-    link->priv = dev->priv = priv;
-    link->release.function = &netwave_release;
-    link->release.data = (u_long)link;
-	
-    /* The io structure describes IO port mapping */
-    link->io.NumPorts1 = 16;
-    link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-    /* link->io.NumPorts2 = 16; 
-       link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; */
-    link->io.IOAddrLines = 5;
-    
-    /* Interrupt setup */
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
-    if (irq_list[0] == -1)
-	link->irq.IRQInfo2 = irq_mask;
-    else
-	for (i = 0; i < 4; i++)
-	    link->irq.IRQInfo2 |= 1 << irq_list[i];
-    link->irq.Handler = &netwave_interrupt;
-    
-    /* General socket configuration */
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.ConfigIndex = 1;
-    link->conf.Present = PRESENT_OPTION;
-
-    /* Netwave specific entries in the device structure */
-    dev->hard_start_xmit = &netwave_start_xmit;
-    dev->set_config = &netwave_config;
-    dev->get_stats  = &netwave_get_stats;
-    dev->set_multicast_list = &set_multicast_list;
-    /* wireless extensions */
-#ifdef WIRELESS_EXT
-    dev->get_wireless_stats = &netwave_get_wireless_stats;
-#endif
-    dev->do_ioctl = &netwave_ioctl;
-
-    dev->tx_timeout = &netwave_watchdog;
-    dev->watchdog_timeo = TX_TIMEOUT;
-
-    ether_setup(dev);
-    dev->open = &netwave_open;
-    dev->stop = &netwave_close;
-    link->irq.Instance = dev;
-    
-    /* Register with Card Services */
-    link->next = dev_list;
-    dev_list = link;
-    client_reg.dev_info = &dev_info;
-    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &netwave_event;
-    client_reg.Version = 0x0210;
-    client_reg.event_callback_args.client_data = link;
-    ret = CardServices(RegisterClient, &link->handle, &client_reg);
-    if (ret != 0) {
-	cs_error(link->handle, RegisterClient, ret);
-	netwave_detach(link);
-	return NULL;
-    }
-
-    return link;
-} /* netwave_attach */
-
-/*
- * Function netwave_detach (link)
- *
- *    This deletes a driver "instance".  The device is de-registered
- *    with Card Services.  If it has been released, all local data
- *    structures are freed.  Otherwise, the structures will be freed
- *    when the device is released.
- */
-static void netwave_detach(dev_link_t *link)
-{
-    netwave_private *priv = link->priv;
-    dev_link_t **linkp;
-
-    DEBUG(0, "netwave_detach(0x%p)\n", link);
-  
-    /*
-	  If the device is currently configured and active, we won't
-	  actually delete it yet.  Instead, it is marked so that when
-	  the release() function is called, that will trigger a proper
-	  detach().
-	*/
-    del_timer(&link->release);
-    if (link->state & DEV_CONFIG) {
-	netwave_release((u_long) link);
-	if (link->state & DEV_STALE_CONFIG) {
-	    DEBUG(1, "netwave_cs: detach postponed, '%s' still "
-		  "locked\n", link->dev->dev_name);
-	    link->state |= DEV_STALE_LINK;
-	    return;
-	}
-    }
-	
-    /* Break the link with Card Services */
-    if (link->handle)
-	CardServices(DeregisterClient, link->handle);
-    
-    /* Locate device structure */
-    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-	if (*linkp == link) break;
-    if (*linkp == NULL)
-      {
-	DEBUG(1, "netwave_cs: detach fail, '%s' not in list\n",
-	      link->dev->dev_name);
-	return;
-      }
-
-    /* Unlink device structure, free pieces */
-    *linkp = link->next;
-    if (link->dev)
-	unregister_netdev(&priv->dev);
-    kfree(priv);
-    
-} /* netwave_detach */
-
-/*
- * Function netwave_flush_stale_links (void)
- *
- *    This deletes all driver "instances" that need to be deleted.
- *    Sometimes, netwave_detach can't be performed following a call from
- *    cardmgr (device still open) and the device is put in a STALE_LINK
- *    state.
- *    This function is in charge of making the cleanup...
- */
-static void netwave_flush_stale_links(void)
-{
-    dev_link_t *	link;		/* Current node in linked list */
-    dev_link_t *	next;		/* Next node in linked list */
-
-    DEBUG(1, "netwave_flush_stale_links(0x%p)\n", dev_list);
-
-    /* Go through the list */
-    for (link = dev_list; link; link = next) {
-        next = link->next;
-        /* Check if in need of being removed */
-        if(link->state & DEV_STALE_LINK)
-	    netwave_detach(link);
-    }
-} /* netwave_flush_stale_links */
-
-/*
- * Function netwave_ioctl (dev, rq, cmd)
- *
- *     Perform ioctl : config & info stuff
- *     This is the stuff that are treated the wireless extensions (iwconfig)
- *
- */
-static int netwave_ioctl(struct net_device *dev, /* ioctl device */
-			 struct ifreq *rq,	 /* Data passed */
-			 int	cmd)	     /* Ioctl number */
-{
-    unsigned long flags;
-    int			ret = 0;
-#ifdef WIRELESS_EXT
-    ioaddr_t iobase = dev->base_addr;
-    netwave_private *priv = (netwave_private *) dev->priv;
-    u_char *ramBase = priv->ramBase;
-    struct iwreq *wrq = (struct iwreq *) rq;
-#endif
-	
-    DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd);
-	
-    /* Disable interrupts & save flags */
-    save_flags(flags);
-    cli();
-
-    /* Look what is the request */
-    switch(cmd) {
-	/* --------------- WIRELESS EXTENSIONS --------------- */
-#ifdef WIRELESS_EXT
-    case SIOCGIWNAME:
-	/* Get name */
-	strcpy(wrq->u.name, "Netwave");
-	break;
-    case SIOCSIWNWID:
-	/* Set domain */
-#if WIRELESS_EXT > 8
-	if(!wrq->u.nwid.disabled) {
-	    domain = wrq->u.nwid.value;
-#else	/* WIRELESS_EXT > 8 */
-	if(wrq->u.nwid.on) {
-	    domain = wrq->u.nwid.nwid;
-#endif	/* WIRELESS_EXT > 8 */
-	    printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", 
-		    (domain >> 8) & 0x01, domain & 0xff);
-	    wait_WOC(iobase);
-	    writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0);
-	    writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1);
-	    writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2);
-	    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
-	} break;
-    case SIOCGIWNWID:
-	/* Read domain*/
-#if WIRELESS_EXT > 8
-	wrq->u.nwid.value = domain;
-	wrq->u.nwid.disabled = 0;
-	wrq->u.nwid.fixed = 1;
-#else	/* WIRELESS_EXT > 8 */
-	wrq->u.nwid.nwid = domain;
-	wrq->u.nwid.on = 1;
-#endif	/* WIRELESS_EXT > 8 */
-	break;
-#if WIRELESS_EXT > 8	/* Note : The API did change... */
-    case SIOCGIWENCODE:
-	/* Get scramble key */
-	if(wrq->u.encoding.pointer != (caddr_t) 0)
-	  {
-	    char	key[2];
-	    key[1] = scramble_key & 0xff;
-	    key[0] = (scramble_key>>8) & 0xff;
-	    wrq->u.encoding.flags = IW_ENCODE_ENABLED;
-	    wrq->u.encoding.length = 2;
-	    if(copy_to_user(wrq->u.encoding.pointer, key, 2))
-	      ret = -EFAULT;
-	  }
-	break;
-    case SIOCSIWENCODE:
-	/* Set  scramble key */
-	if(wrq->u.encoding.pointer != (caddr_t) 0)
-	  {
-	    char	key[2];
-	    if(copy_from_user(key, wrq->u.encoding.pointer, 2))
-	      {
-		ret = -EFAULT;
-		break;
-	      }
-	    scramble_key = (key[0] << 8) | key[1];
-	    wait_WOC(iobase);
-	    writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
-	    writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
-	    writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
-	    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
-	  }
-	break;
-    case SIOCGIWMODE:
-      /* Mode of operation */
-	if(domain & 0x100)
-	  wrq->u.mode = IW_MODE_INFRA;
-	else
-	  wrq->u.mode = IW_MODE_ADHOC;
-      break;
-#else /* WIRELESS_EXT > 8 */
-    case SIOCGIWENCODE:
-	/* Get scramble key */
-	wrq->u.encoding.code = scramble_key;
-	wrq->u.encoding.method = 1;
-	break;
-    case SIOCSIWENCODE:
-	/* Set  scramble key */
-	scramble_key = wrq->u.encoding.code;
-	wait_WOC(iobase);
-	writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
-	writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
-	writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
-	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
-	break;
-#endif /* WIRELESS_EXT > 8 */
-   case SIOCGIWRANGE:
-       /* Basic checking... */
-       if(wrq->u.data.pointer != (caddr_t) 0) {
-	   struct iw_range	range;
-		   
-	   /* Set the length (very important for backward compatibility) */
-	   wrq->u.data.length = sizeof(struct iw_range);
-
-	   /* Set all the info we don't care or don't know about to zero */
-	   memset(&range, 0, sizeof(range));
-
-#if WIRELESS_EXT > 10
-	   /* Set the Wireless Extension versions */
-	   range.we_version_compiled = WIRELESS_EXT;
-	   range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
-#endif /* WIRELESS_EXT > 10 */
-		   
-	   /* Set information in the range struct */
-	   range.throughput = 450 * 1000;	/* don't argue on this ! */
-	   range.min_nwid = 0x0000;
-	   range.max_nwid = 0x01FF;
-
-	   range.num_channels = range.num_frequency = 0;
-		   
-	   range.sensitivity = 0x3F;
-	   range.max_qual.qual = 255;
-	   range.max_qual.level = 255;
-	   range.max_qual.noise = 0;
-		   
-#if WIRELESS_EXT > 7
-	   range.num_bitrates = 1;
-	   range.bitrate[0] = 1000000;	/* 1 Mb/s */
-#endif /* WIRELESS_EXT > 7 */
-
-#if WIRELESS_EXT > 8
-	   range.encoding_size[0] = 2;		/* 16 bits scrambling */
-	   range.num_encoding_sizes = 1;
-	   range.max_encoding_tokens = 1;	/* Only one key possible */
-#endif /* WIRELESS_EXT > 8 */
-
-	   /* Copy structure to the user buffer */
-	   if(copy_to_user(wrq->u.data.pointer, &range,
-			sizeof(struct iw_range)))
-	     ret = -EFAULT;
-       }
-       break;
-    case SIOCGIWPRIV:
-	/* Basic checking... */
-	if(wrq->u.data.pointer != (caddr_t) 0) {
-	    struct iw_priv_args	priv[] =
-	    {	/* cmd,		set_args,	get_args,	name */
-		{ SIOCGIPSNAP, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 0, 
-		  sizeof(struct site_survey), 
-		  "getsitesurvey" },
-	    };
-			
-	    /* Set the number of ioctl available */
-	    wrq->u.data.length = 1;
-			
-	    /* Copy structure to the user buffer */
-	    if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
-			 sizeof(priv)))
-	      ret = -EFAULT;
-	} 
-	break;
-    case SIOCGIPSNAP:
-	if(wrq->u.data.pointer != (caddr_t) 0) {
-	    /* Take snapshot of environment */
-	    netwave_snapshot( priv, ramBase, iobase);
-	    wrq->u.data.length = priv->nss.length;
-	    /* Copy structure to the user buffer */
-	    if(copy_to_user(wrq->u.data.pointer, 
-			 (u_char *) &priv->nss,
-			 sizeof( struct site_survey)))
-	      {
-		printk(KERN_DEBUG "Bad buffer!\n");
-		break;
-	      }
-
-	    priv->lastExec = jiffies;
-	}
-	break;
-#endif
-    default:
-	ret = -EOPNOTSUPP;
-    }
-	
-    /* ReEnable interrupts & restore flags */
-    restore_flags(flags);
-    
-    return ret;
-}
-
-/*
- * Function netwave_pcmcia_config (link)
- *
- *     netwave_pcmcia_config() is scheduled to run after a CARD_INSERTION 
- *     event is received, to configure the PCMCIA socket, and to make the
- *     device available to the system. 
- *
- */
-
-#define CS_CHECK(fn, args...) \
-while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
-
-static void netwave_pcmcia_config(dev_link_t *link) {
-    client_handle_t handle = link->handle;
-    netwave_private *priv = link->priv;
-    struct net_device *dev = &priv->dev;
-    tuple_t tuple;
-    cisparse_t parse;
-    int i, j, last_ret, last_fn;
-    u_char buf[64];
-    win_req_t req;
-    memreq_t mem;
-    u_char *ramBase = NULL;
-
-    DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link);
-
-    /*
-      This reads the card's CONFIG tuple to find its configuration
-      registers.
-    */
-    tuple.Attributes = 0;
-    tuple.TupleData = (cisdata_t *) buf;
-    tuple.TupleDataMax = 64;
-    tuple.TupleOffset = 0;
-    tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, handle, &tuple);
-    CS_CHECK(GetTupleData, handle, &tuple);
-    CS_CHECK(ParseTuple, handle, &tuple, &parse);
-    link->conf.ConfigBase = parse.config.base;
-    link->conf.Present = parse.config.rmask[0];
-
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
-    /*
-     *  Try allocating IO ports.  This tries a few fixed addresses.
-     *  If you want, you can also read the card's config table to
-     *  pick addresses -- see the serial driver for an example.
-     */
-    for (i = j = 0x0; j < 0x400; j += 0x20) {
-	link->io.BasePort1 = j ^ 0x300;
-	i = CardServices(RequestIO, link->handle, &link->io);
-	if (i == CS_SUCCESS) break;
-    }
-    if (i != CS_SUCCESS) {
-	cs_error(link->handle, RequestIO, i);
-	goto failed;
-    }
-
-    /*
-     *  Now allocate an interrupt line.  Note that this does not
-     *  actually assign a handler to the interrupt.
-     */
-    CS_CHECK(RequestIRQ, handle, &link->irq);
-
-    /*
-     *  This actually configures the PCMCIA socket -- setting up
-     *  the I/O windows and the interrupt mapping.
-     */
-    CS_CHECK(RequestConfiguration, handle, &link->conf);
-
-    /*
-     *  Allocate a 32K memory window.  Note that the dev_link_t
-     *  structure provides space for one window handle -- if your
-     *  device needs several windows, you'll need to keep track of
-     *  the handles in your private data structure, link->priv.
-     */
-    DEBUG(1, "Setting mem speed of %d\n", mem_speed);
-
-    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
-    req.Base = 0; req.Size = 0x8000;
-    req.AccessSpeed = mem_speed;
-    link->win = (window_handle_t)link->handle;
-    CS_CHECK(RequestWindow, &link->win, &req);
-    mem.CardOffset = 0x20000; mem.Page = 0; 
-    CS_CHECK(MapMemPage, link->win, &mem);
-
-    /* Store base address of the common window frame */
-    ramBase = ioremap(req.Base, 0x8000);
-    ((netwave_private*)dev->priv)->ramBase = ramBase;
-
-    dev->irq = link->irq.AssignedIRQ;
-    dev->base_addr = link->io.BasePort1;
-    if (register_netdev(dev) != 0) {
-	printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n");
-	goto failed;
-    }
-
-    strcpy(priv->node.dev_name, dev->name);
-    link->dev = &priv->node;
-    link->state &= ~DEV_CONFIG_PENDING;
-
-    /* Reset card before reading physical address */
-    netwave_doreset(dev->base_addr, ramBase);
-
-    /* Read the ethernet address and fill in the Netwave registers. */
-    for (i = 0; i < 6; i++) 
-	dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i);
-
-    printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx id "
-	   "%c%c, hw_addr ", dev->name, dev->base_addr, dev->irq,
-	   (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI),
-	   (int) readb(ramBase+NETWAVE_EREG_NI+1));
-    for (i = 0; i < 6; i++)
-	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
-
-    /* get revision words */
-    printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", 
-	   get_uint16(ramBase + NETWAVE_EREG_ARW),
-	   get_uint16(ramBase + NETWAVE_EREG_ARW+2));
-    return;
-
-cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
-failed:
-    netwave_release((u_long)link);
-} /* netwave_pcmcia_config */
-
-/*
- * Function netwave_release (arg)
- *
- *    After a card is removed, netwave_release() will unregister the net
- *    device, and release the PCMCIA configuration.  If the device is
- *    still open, this will be postponed until it is closed.
- */
-static void netwave_release(u_long arg) {
-    dev_link_t *link = (dev_link_t *)arg;
-    netwave_private *priv = link->priv;
-
-    DEBUG(0, "netwave_release(0x%p)\n", link);
-
-    /*
-      If the device is currently in use, we won't release until it
-      is actually closed.
-      */
-    if (link->open) {
-	printk(KERN_DEBUG "netwave_cs: release postponed, '%s' still open\n",
-	       link->dev->dev_name);
-	link->state |= DEV_STALE_CONFIG;
-	return;
-    }
-
-    /* Don't bother checking to see if these succeed or not */
-    if (link->win) {
-	iounmap(priv->ramBase);
-	CardServices(ReleaseWindow, link->win);
-    }
-    CardServices(ReleaseConfiguration, link->handle);
-    CardServices(ReleaseIO, link->handle, &link->io);
-    CardServices(ReleaseIRQ, link->handle, &link->irq);
-
-    link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG);
-
-} /* netwave_release */
-
-/*
- * Function netwave_event (event, priority, args)
- *
- *    The card status event handler.  Mostly, this schedules other
- *    stuff to run after an event is received.  A CARD_REMOVAL event
- *    also sets some flags to discourage the net drivers from trying
- *    to talk to the card any more.
- *
- *    When a CARD_REMOVAL event is received, we immediately set a flag
- *    to block future accesses to this device.  All the functions that
- *    actually access the device should check this flag to make sure
- *    the card is still present.
- *
- */
-static int netwave_event(event_t event, int priority,
-			 event_callback_args_t *args) {
-    dev_link_t *link = args->client_data;
-    netwave_private *priv = link->priv;
-    struct net_device *dev = &priv->dev;
-	
-    DEBUG(1, "netwave_event(0x%06x)\n", event);
-  
-    switch (event) {
-    case CS_EVENT_REGISTRATION_COMPLETE:
-	DEBUG(0, "netwave_cs: registration complete\n");
-	break;
-
-    case CS_EVENT_CARD_REMOVAL:
-	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG) {
-	    netif_device_detach(dev);
-	    mod_timer(&link->release, jiffies + HZ/20);
-	}
-	break;
-    case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	netwave_pcmcia_config( link);
-	break;
-    case CS_EVENT_PM_SUSPEND:
-	link->state |= DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_RESET_PHYSICAL:
-	if (link->state & DEV_CONFIG) {
-	    if (link->open)
-		netif_device_detach(dev);
-	    CardServices(ReleaseConfiguration, link->handle);
-	}
-	break;
-    case CS_EVENT_PM_RESUME:
-	link->state &= ~DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_CARD_RESET:
-	if (link->state & DEV_CONFIG) {
-	    CardServices(RequestConfiguration, link->handle, &link->conf);
-	    if (link->open) {
-		netwave_reset(dev);
-		netif_device_attach(dev);
-	    }
-	}
-	break;
-    }
-    return 0;
-} /* netwave_event */
-
-/*
- * Function netwave_doreset (ioBase, ramBase)
- *
- *    Proper hardware reset of the card.
- */
-static void netwave_doreset(ioaddr_t ioBase, u_char* ramBase) {
-    /* Reset card */
-    wait_WOC(ioBase);
-    outb(0x80, ioBase + NETWAVE_REG_PMR);
-    writeb(0x08, ramBase + NETWAVE_EREG_ASCC); /* Bit 3 is WOC */
-    outb(0x0, ioBase + NETWAVE_REG_PMR); /* release reset */
-}
-
-/*
- * Function netwave_reset (dev)
- *
- *    Reset and restore all of the netwave registers 
- */
-static void netwave_reset(struct net_device *dev) {
-    /* u_char state; */
-    netwave_private *priv = (netwave_private*) dev->priv;
-    u_char *ramBase = priv->ramBase;
-    ioaddr_t iobase = dev->base_addr;
-
-    DEBUG(0, "netwave_reset: Done with hardware reset\n");
-
-    priv->timeoutCounter = 0;
-
-    /* Reset card */
-    netwave_doreset(iobase, ramBase);
-    printk(KERN_DEBUG "netwave_reset: Done with hardware reset\n");
-	
-    /* Write a NOP to check the card */
-    wait_WOC(iobase);
-    writeb(NETWAVE_CMD_NOP, ramBase + NETWAVE_EREG_CB + 0);
-    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
-	
-    /* Set receive conf */
-    wait_WOC(iobase);
-    writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0);
-    writeb(rxConfRxEna + rxConfBcast, ramBase + NETWAVE_EREG_CB + 1);
-    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
-    
-    /* Set transmit conf */
-    wait_WOC(iobase);
-    writeb(NETWAVE_CMD_STC, ramBase + NETWAVE_EREG_CB + 0);
-    writeb(txConfTxEna, ramBase + NETWAVE_EREG_CB + 1);
-    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
-    
-    /* Now set the MU Domain */
-    printk(KERN_DEBUG "Setting domain to 0x%x%02x\n", (domain >> 8) & 0x01, domain & 0xff);
-    wait_WOC(iobase);
-    writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0);
-    writeb(domain & 0xff, ramBase + NETWAVE_EREG_CB + 1);
-    writeb((domain>>8) & 0x01, ramBase + NETWAVE_EREG_CB + 2);
-    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
-	
-    /* Set scramble key */
-    printk(KERN_DEBUG "Setting scramble key to 0x%x\n", scramble_key);
-    wait_WOC(iobase);
-    writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
-    writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
-    writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
-    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
-
-    /* Enable interrupts, bit 4 high to keep unused
-     * source from interrupting us, bit 2 high to 
-     * set interrupt enable, 567 to enable TxDN, 
-     * RxErr and RxRdy
-     */
-    wait_WOC(iobase);
-    outb(imrConfIENA+imrConfRFU1, iobase + NETWAVE_REG_IMR);
-
-    /* Hent 4 bytes fra 0x170. Skal vaere 0a,29,88,36
-     * waitWOC
-     * skriv 80 til d000:3688
-     * sjekk om det ble 80
-     */
-    
-    /* Enable Receiver */
-    wait_WOC(iobase);
-    writeb(NETWAVE_CMD_ER, ramBase + NETWAVE_EREG_CB + 0);
-    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
-	
-    /* Set the IENA bit in COR */
-    wait_WOC(iobase);
-    outb(corConfIENA + corConfLVLREQ, iobase + NETWAVE_REG_COR);
-}
-
-/*
- * Function netwave_config (dev, map)
- *
- *    Configure device, this work is done by netwave_pcmcia_config when a
- *    card is inserted
- */
-static int netwave_config(struct net_device *dev, struct ifmap *map) {
-    return 0; 
-}
-
-/*
- * Function netwave_hw_xmit (data, len, dev)    
- */
-static int netwave_hw_xmit(unsigned char* data, int len,
-			   struct net_device* dev) {
-    unsigned long flags;
-    unsigned int TxFreeList,
-	         curBuff,
-	         MaxData, 
-                 DataOffset;
-    int tmpcount; 
-	
-    netwave_private *priv = (netwave_private *) dev->priv;
-    u_char* ramBase = priv->ramBase;
-    ioaddr_t iobase = dev->base_addr;
-
-    /* Disable interrupts & save flags */
-    save_flags(flags);
-    cli();
-
-    /* Check if there are transmit buffers available */
-    wait_WOC(iobase);
-    if ((inb(iobase+NETWAVE_REG_ASR) & NETWAVE_ASR_TXBA) == 0) {
-	/* No buffers available */
-	printk(KERN_DEBUG "netwave_hw_xmit: %s - no xmit buffers available.\n",
-	       dev->name);
-	restore_flags(flags);
-	return 1;
-    }
-
-    priv->stats.tx_bytes += len;
-
-    DEBUG(3, "Transmitting with SPCQ %x SPU %x LIF %x ISPLQ %x\n",
-	  readb(ramBase + NETWAVE_EREG_SPCQ),
-	  readb(ramBase + NETWAVE_EREG_SPU),
-	  readb(ramBase + NETWAVE_EREG_LIF),
-	  readb(ramBase + NETWAVE_EREG_ISPLQ));
-
-    /* Now try to insert it into the adapters free memory */
-    wait_WOC(iobase);
-    TxFreeList = get_uint16(ramBase + NETWAVE_EREG_TDP);
-    MaxData    = get_uint16(ramBase + NETWAVE_EREG_TDP+2);
-    DataOffset = get_uint16(ramBase + NETWAVE_EREG_TDP+4);
-	
-    DEBUG(3, "TxFreeList %x, MaxData %x, DataOffset %x\n",
-	  TxFreeList, MaxData, DataOffset);
-
-    /* Copy packet to the adapter fragment buffers */
-    curBuff = TxFreeList; 
-    tmpcount = 0; 
-    while (tmpcount < len) {
-	int tmplen = len - tmpcount; 
-	copy_to_pc(ramBase + curBuff + DataOffset, data + tmpcount, 
-		   (tmplen < MaxData) ? tmplen : MaxData);
-	tmpcount += MaxData;
-			
-	/* Advance to next buffer */
-	curBuff = get_uint16(ramBase + curBuff);
-    }
-    
-    /* Now issue transmit list */
-    wait_WOC(iobase);
-    writeb(NETWAVE_CMD_TL, ramBase + NETWAVE_EREG_CB + 0);
-    writeb(len & 0xff, ramBase + NETWAVE_EREG_CB + 1);
-    writeb((len>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
-    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
-
-    restore_flags( flags);
-    return 0;
-}
-
-static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
-	/* This flag indicate that the hardware can't perform a transmission.
-	 * Theoritically, NET3 check it before sending a packet to the driver,
-	 * but in fact it never do that and pool continuously.
-	 * As the watchdog will abort too long transmissions, we are quite safe...
-	 */
-
-    netif_stop_queue(dev);
-
-    {
-	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-	unsigned char* buf = skb->data;
-	
-	if (netwave_hw_xmit( buf, length, dev) == 1) {
-	    /* Some error, let's make them call us another time? */
-	    netif_start_queue(dev);
-	}
-	dev->trans_start = jiffies;
-    }
-    dev_kfree_skb(skb);
-    
-    return 0;
-} /* netwave_start_xmit */
-
-/*
- * Function netwave_interrupt (irq, dev_id, regs)
- *
- *    This function is the interrupt handler for the Netwave card. This
- *    routine will be called whenever: 
- *	  1. A packet is received.
- *	  2. A packet has successfully been transferred and the unit is
- *	     ready to transmit another packet.
- *	  3. A command has completed execution.
- */
-static void netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) {
-    ioaddr_t iobase;
-    u_char *ramBase;
-    struct net_device *dev = (struct net_device *)dev_id;
-    struct netwave_private *priv = dev->priv;
-    dev_link_t *link = &priv->link;
-    int i;
-    
-    if (!netif_device_present(dev))
-	return;
-    
-    iobase = dev->base_addr;
-    ramBase = priv->ramBase;
-	
-    /* Now find what caused the interrupt, check while interrupts ready */
-    for (i = 0; i < 10; i++) {
-	u_char status;
-		
-	wait_WOC(iobase);	
-	if (!(inb(iobase+NETWAVE_REG_CCSR) & 0x02))
-	    break; /* None of the interrupt sources asserted */
-	
-        status = inb(iobase + NETWAVE_REG_ASR);
-		
-	if (!DEV_OK(link)) {
-	    DEBUG(1, "netwave_interrupt: Interrupt with status 0x%x "
-		  "from removed or suspended card!\n", status);
-	    break;
-	}
-		
-	/* RxRdy */
-	if (status & 0x80) {
-	    netwave_rx(dev);
-	    /* wait_WOC(iobase); */
-	    /* RxRdy cannot be reset directly by the host */
-	}
-	/* RxErr */
-	if (status & 0x40) {
-	    u_char rser;
-			
-	    rser = readb(ramBase + NETWAVE_EREG_RSER);			
-	    
-	    if (rser & 0x04) {
-		++priv->stats.rx_dropped; 
-		++priv->stats.rx_crc_errors;
-	    }
-	    if (rser & 0x02)
-		++priv->stats.rx_frame_errors;
-			
-	    /* Clear the RxErr bit in RSER. RSER+4 is the
-	     * write part. Also clear the RxCRC (0x04) and 
-	     * RxBig (0x02) bits if present */
-	    wait_WOC(iobase);
-	    writeb(0x40 | (rser & 0x06), ramBase + NETWAVE_EREG_RSER + 4);
-
-	    /* Write bit 6 high to ASCC to clear RxErr in ASR,
-	     * WOC must be set first! 
-	     */
-	    wait_WOC(iobase);
-	    writeb(0x40, ramBase + NETWAVE_EREG_ASCC);
-
-	    /* Remember to count up priv->stats on error packets */
-	    ++priv->stats.rx_errors;
-	}
-	/* TxDN */
-	if (status & 0x20) {
-	    int txStatus;
-
-	    txStatus = readb(ramBase + NETWAVE_EREG_TSER);
-	    DEBUG(3, "Transmit done. TSER = %x id %x\n", 
-		  txStatus, readb(ramBase + NETWAVE_EREG_TSER + 1));
-	    
-	    if (txStatus & 0x20) {
-		/* Transmitting was okay, clear bits */
-		wait_WOC(iobase);
-		writeb(0x2f, ramBase + NETWAVE_EREG_TSER + 4);
-		++priv->stats.tx_packets;
-	    }
-			
-	    if (txStatus & 0xd0) {
-		if (txStatus & 0x80) {
-		    ++priv->stats.collisions; /* Because of /proc/net/dev*/
-		    /* ++priv->stats.tx_aborted_errors; */
-		    /* printk("Collision. %ld\n", jiffies - dev->trans_start); */
-		}
-		if (txStatus & 0x40) 
-		    ++priv->stats.tx_carrier_errors;
-		/* 0x80 TxGU Transmit giveup - nine times and no luck
-		 * 0x40 TxNOAP No access point. Discarded packet.
-		 * 0x10 TxErr Transmit error. Always set when 
-		 *      TxGU and TxNOAP is set. (Those are the only ones
-		 *      to set TxErr).
-		 */
-		DEBUG(3, "netwave_interrupt: TxDN with error status %x\n", 
-		      txStatus);
-		
-		/* Clear out TxGU, TxNOAP, TxErr and TxTrys */
-		wait_WOC(iobase);
-		writeb(0xdf & txStatus, ramBase+NETWAVE_EREG_TSER+4);
-		++priv->stats.tx_errors;
-	    }
-	    DEBUG(3, "New status is TSER %x ASR %x\n",
-		  readb(ramBase + NETWAVE_EREG_TSER),
-		  inb(iobase + NETWAVE_REG_ASR));
-
-	    netif_wake_queue(dev);
-	}
-	/* TxBA, this would trigger on all error packets received */
-	/* if (status & 0x01) {
-	   DEBUG(4, "Transmit buffers available, %x\n", status);
-	   }
-	   */
-    }
-} /* netwave_interrupt */
-
-/*
- * Function netwave_watchdog (a)
- *
- *    Watchdog : when we start a transmission, we set a timer in the
- *    kernel.  If the transmission complete, this timer is disabled. If
- *    it expire, we reset the card.
- *
- */
-static void netwave_watchdog(struct net_device *dev) {
-
-    DEBUG(1, "%s: netwave_watchdog: watchdog timer expired\n", dev->name);
-    netwave_reset(dev);
-    dev->trans_start = jiffies;
-    netif_wake_queue(dev);
-} /* netwave_watchdog */
-
-static struct net_device_stats *netwave_get_stats(struct net_device *dev) {
-    netwave_private *priv = (netwave_private*)dev->priv;
-
-    update_stats(dev);
-
-    DEBUG(2, "netwave: SPCQ %x SPU %x LIF %x ISPLQ %x MHS %x rxtx %x"
-	  " %x tx %x %x %x %x\n", 
-	  readb(priv->ramBase + NETWAVE_EREG_SPCQ),
-	  readb(priv->ramBase + NETWAVE_EREG_SPU),
-	  readb(priv->ramBase + NETWAVE_EREG_LIF),
-	  readb(priv->ramBase + NETWAVE_EREG_ISPLQ),
-	  readb(priv->ramBase + NETWAVE_EREG_MHS),
-	  readb(priv->ramBase + NETWAVE_EREG_EC + 0xe),
-	  readb(priv->ramBase + NETWAVE_EREG_EC + 0xf),
-	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x18),
-	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x19),
-	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x1a),
-	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x1b));
-
-    return &priv->stats;
-}
-
-static void update_stats(struct net_device *dev) {
-    unsigned long flags;
-
-    save_flags(flags);
-    cli();
-
-/*     netwave_private *priv = (netwave_private*) dev->priv;
-    priv->stats.rx_packets = readb(priv->ramBase + 0x18e); 
-    priv->stats.tx_packets = readb(priv->ramBase + 0x18f); */
-
-    restore_flags(flags);
-}
-
-static int netwave_rx(struct net_device *dev) {
-    netwave_private *priv = (netwave_private*)(dev->priv);
-    u_char *ramBase = priv->ramBase;
-    ioaddr_t iobase = dev->base_addr;
-    u_char rxStatus;
-    struct sk_buff *skb = NULL;
-    unsigned int curBuffer,
-		rcvList;
-    int rcvLen;
-    int tmpcount = 0;
-    int dataCount, dataOffset;
-    int i;
-    u_char *ptr;
-	
-    DEBUG(3, "xinw_rx: Receiving ... \n");
-
-    /* Receive max 10 packets for now. */
-    for (i = 0; i < 10; i++) {
-	/* Any packets? */
-	wait_WOC(iobase);
-	rxStatus = readb(ramBase + NETWAVE_EREG_RSER);		
-	if ( !( rxStatus & 0x80)) /* No more packets */
-	    break;
-		
-	/* Check if multicast/broadcast or other */
-	/* multicast = (rxStatus & 0x20);  */
-		
-	/* The receive list pointer and length of the packet */
-	wait_WOC(iobase);
-	rcvLen  = get_int16( ramBase + NETWAVE_EREG_RDP);
-	rcvList = get_uint16( ramBase + NETWAVE_EREG_RDP + 2);
-		
-	if (rcvLen < 0) {
-	    printk(KERN_DEBUG "netwave_rx: Receive packet with len %d\n", 
-		   rcvLen);
-	    return 0;
-	}
-		
-	skb = dev_alloc_skb(rcvLen+5);
-	if (skb == NULL) {
-	    DEBUG(1, "netwave_rx: Could not allocate an sk_buff of "
-		  "length %d\n", rcvLen);
-	    ++priv->stats.rx_dropped; 
-	    /* Tell the adapter to skip the packet */
-	    wait_WOC(iobase);
-	    writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0);
-	    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
-	    return 0;
-	}
-
-	skb_reserve( skb, 2);  /* Align IP on 16 byte */
-	skb_put( skb, rcvLen);
-	skb->dev = dev;
-
-	/* Copy packet fragments to the skb data area */
-	ptr = (u_char*) skb->data;
-	curBuffer = rcvList;
-	tmpcount = 0; 
-	while ( tmpcount < rcvLen) {
-	    /* Get length and offset of current buffer */
-	    dataCount  = get_uint16( ramBase+curBuffer+2);
-	    dataOffset = get_uint16( ramBase+curBuffer+4);
-		
-	    copy_from_pc( ptr + tmpcount,
-			  ramBase+curBuffer+dataOffset, dataCount);
-
-	    tmpcount += dataCount;
-		
-	    /* Point to next buffer */
-	    curBuffer = get_uint16(ramBase + curBuffer);
-	}
-	
-	skb->protocol = eth_type_trans(skb,dev);
-	/* Queue packet for network layer */
-	netif_rx(skb);
-
-	dev->last_rx = jiffies;
-	priv->stats.rx_packets++;
-	priv->stats.rx_bytes += rcvLen;
-
-	/* Got the packet, tell the adapter to skip it */
-	wait_WOC(iobase);
-	writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0);
-	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
-	DEBUG(3, "Packet reception ok\n");
-    }
-    return 0;
-}
-
-static int netwave_open(struct net_device *dev) {
-    netwave_private *priv = dev->priv;
-    dev_link_t *link = &priv->link;
-
-    DEBUG(1, "netwave_open: starting.\n");
-    
-    if (!DEV_OK(link))
-	return -ENODEV;
-
-    link->open++;
-    MOD_INC_USE_COUNT;
-
-    netif_start_queue(dev);
-    netwave_reset(dev);
-	
-    return 0;
-}
-
-static int netwave_close(struct net_device *dev) {
-    netwave_private *priv = (netwave_private *)dev->priv;
-    dev_link_t *link = &priv->link;
-
-    DEBUG(1, "netwave_close: finishing.\n");
-
-    link->open--;
-    netif_stop_queue(dev);
-    if (link->state & DEV_STALE_CONFIG)
-	mod_timer(&link->release, jiffies + HZ/20);
-	
-    MOD_DEC_USE_COUNT;
-    return 0;
-}
-
-static int __init init_netwave_cs(void) {
-    servinfo_t serv;
-
-    DEBUG(0, "%s\n", version);
-
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk("netwave_cs: Card Services release does not match!\n");
-	return -1;
-    }
- 
-    register_pccard_driver(&dev_info, &netwave_attach, &netwave_detach);
-	
-    return 0;
-}
-
-static void __exit exit_netwave_cs(void) {
-    DEBUG(1, "netwave_cs: unloading\n");
-
-    unregister_pccard_driver(&dev_info);
-
-    /* Do some cleanup of the device list */
-    netwave_flush_stale_links();
-    if(dev_list != NULL)	/* Critical situation */
-        printk("netwave_cs: devices remaining when removing module\n");
-}
-
-module_init(init_netwave_cs);
-module_exit(exit_netwave_cs);
-
-/* Set or clear the multicast filter for this adaptor.
-   num_addrs == -1	Promiscuous mode, receive all packets
-   num_addrs == 0	Normal mode, clear multicast list
-   num_addrs > 0	Multicast mode, receive normal and MC packets, and do
-   best-effort filtering.
- */
-static void set_multicast_list(struct net_device *dev)
-{
-    ioaddr_t iobase = dev->base_addr;
-    u_char* ramBase = ((netwave_private*) dev->priv)->ramBase;
-    u_char  rcvMode = 0;
-   
-#ifdef PCMCIA_DEBUG
-    if (pc_debug > 2) {
-	static int old;
-	if (old != dev->mc_count) {
-	    old = dev->mc_count;
-	    DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
-		  dev->name, dev->mc_count);
-	}
-    }
-#endif
-	
-    if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) {
-	/* Multicast Mode */
-	rcvMode = rxConfRxEna + rxConfAMP + rxConfBcast;
-    } else if (dev->flags & IFF_PROMISC) {
-	/* Promiscous mode */
-	rcvMode = rxConfRxEna + rxConfPro + rxConfAMP + rxConfBcast;
-    } else {
-	/* Normal mode */
-	rcvMode = rxConfRxEna + rxConfBcast;
-    }
-	
-    /* printk("netwave set_multicast_list: rcvMode to %x\n", rcvMode);*/
-    /* Now set receive mode */
-    wait_WOC(iobase);
-    writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0);
-    writeb(rcvMode, ramBase + NETWAVE_EREG_CB + 1);
-    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
-}
-MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.2/linux/drivers/net/pcmcia/wavelan.h linux/drivers/net/pcmcia/wavelan.h
--- v2.5.2/linux/drivers/net/pcmcia/wavelan.h	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/wavelan.h	Wed Dec 31 16:00:00 1969
@@ -1,383 +0,0 @@
-/*
- *	Wavelan Pcmcia driver
- *
- *		Jean II - HPLB '96
- *
- * Reorganization and extension of the driver.
- * Original copyright follow. See wavelan_cs.h for details.
- *
- * This file contain the declarations of the Wavelan hardware. Note that
- * the Pcmcia Wavelan include a i82593 controller (see definitions in
- * file i82593.h).
- *
- * The main difference between the pcmcia hardware and the ISA one is
- * the Ethernet Controller (i82593 instead of i82586). The i82593 allow
- * only one send buffer. The PSA (Parameter Storage Area : EEprom for
- * permanent storage of various info) is memory mapped, but not the
- * MMI (Modem Management Interface).
- */
-
-/*
- * Definitions for the AT&T GIS (formerly NCR) WaveLAN PCMCIA card: 
- *   An Ethernet-like radio transceiver controlled by an Intel 82593
- *   coprocessor.
- *
- *
- ****************************************************************************
- *   Copyright 1995
- *   Anthony D. Joseph
- *   Massachusetts Institute of Technology
- *
- *   Permission to use, copy, modify, and distribute this program
- *   for any purpose and without fee is hereby granted, provided
- *   that this copyright and permission notice appear on all copies
- *   and supporting documentation, the name of M.I.T. not be used
- *   in advertising or publicity pertaining to distribution of the
- *   program without specific prior permission, and notice be given
- *   in supporting documentation that copying and distribution is
- *   by permission of M.I.T.  M.I.T. makes no representations about
- *   the suitability of this software for any purpose.  It is pro-
- *   vided "as is" without express or implied warranty.         
- ****************************************************************************
- *
- *
- * Credits:
- *     Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht for
- *       providing extremely useful information about WaveLAN PCMCIA hardware
- *
- *     This driver is based upon several other drivers, in particular:
- *       David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter
- *       Bruce Janson's Linux driver for the AT-bus WaveLAN adapter
- *	 Anders Klemets' PCMCIA WaveLAN adapter driver
- *       Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter
- */
-
-#ifndef _WAVELAN_H
-#define	_WAVELAN_H
-
-/************************** MAGIC NUMBERS ***************************/
-
-/* The detection of the wavelan card is made by reading the MAC address
- * from the card and checking it. If you have a non AT&T product (OEM,
- * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this
- * part to accomodate your hardware...
- */
-const unsigned char	MAC_ADDRESSES[][3] =
-{
-  { 0x08, 0x00, 0x0E },		/* AT&T Wavelan (standard) & DEC RoamAbout */
-  { 0x08, 0x00, 0x6A },		/* AT&T Wavelan (alternate) */
-  { 0x00, 0x00, 0xE1 },		/* Hitachi Wavelan */
-  { 0x00, 0x60, 0x1D }		/* Lucent Wavelan (another one) */
-  /* Add your card here and send me the patch ! */
-};
-
-/*
- * Constants used to convert channels to frequencies
- */
-
-/* Frequency available in the 2.0 modem, in units of 250 kHz
- * (as read in the offset register of the dac area).
- * Used to map channel numbers used by `wfreqsel' to frequencies
- */
-const short	channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8,
-				    0xD0, 0xF0, 0xF8, 0x150 };
-
-/* Frequencies of the 1.0 modem (fixed frequencies).
- * Use to map the PSA `subband' to a frequency
- * Note : all frequencies apart from the first one need to be multiplied by 10
- */
-const int	fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
-
-/*************************** PC INTERFACE ****************************/
-
-/* WaveLAN host interface definitions */
-
-#define	LCCR(base)	(base)		/* LAN Controller Command Register */
-#define	LCSR(base)	(base)		/* LAN Controller Status Register */
-#define	HACR(base)	(base+0x1)	/* Host Adapter Command Register */
-#define	HASR(base)	(base+0x1)	/* Host Adapter Status Register */
-#define PIORL(base)	(base+0x2)	/* Program I/O Register Low */
-#define RPLL(base)	(base+0x2)	/* Receive Pointer Latched Low */
-#define PIORH(base)	(base+0x3)	/* Program I/O Register High */
-#define RPLH(base)	(base+0x3)	/* Receive Pointer Latched High */
-#define PIOP(base)	(base+0x4)	/* Program I/O Port */
-#define MMR(base)	(base+0x6)	/* MMI Address Register */
-#define MMD(base)	(base+0x7)	/* MMI Data Register */
-
-/* Host Adaptor Command Register bit definitions */
-
-#define HACR_LOF	  (1 << 3)	/* Lock Out Flag, toggle every 250ms */
-#define HACR_PWR_STAT	  (1 << 4)	/* Power State, 1=active, 0=sleep */
-#define HACR_TX_DMA_RESET (1 << 5)	/* Reset transmit DMA ptr on high */
-#define HACR_RX_DMA_RESET (1 << 6)	/* Reset receive DMA ptr on high */
-#define HACR_ROM_WEN	  (1 << 7)	/* EEPROM write enabled when true */
-
-#define HACR_RESET              (HACR_TX_DMA_RESET | HACR_RX_DMA_RESET)
-#define	HACR_DEFAULT		(HACR_PWR_STAT)
-
-/* Host Adapter Status Register bit definitions */
-
-#define HASR_MMI_BUSY	(1 << 2)	/* MMI is busy when true */
-#define HASR_LOF	(1 << 3)	/* Lock out flag status */
-#define HASR_NO_CLK	(1 << 4)	/* active when modem not connected */
-
-/* Miscellaneous bit definitions */
-
-#define PIORH_SEL_TX	(1 << 5)	/* PIOR points to 0=rx/1=tx buffer */
-#define MMR_MMI_WR	(1 << 0)	/* Next MMI cycle is 0=read, 1=write */
-#define PIORH_MASK	0x1f		/* only low 5 bits are significant */
-#define RPLH_MASK	0x1f		/* only low 5 bits are significant */
-#define MMI_ADDR_MASK	0x7e		/* Bits 1-6 of MMR are significant */
-
-/* Attribute Memory map */
-
-#define CIS_ADDR	0x0000		/* Card Information Status Register */
-#define PSA_ADDR	0x0e00		/* Parameter Storage Area address */
-#define EEPROM_ADDR	0x1000		/* EEPROM address (unused ?) */
-#define COR_ADDR	0x4000		/* Configuration Option Register */
-
-/* Configuration Option Register bit definitions */
-
-#define COR_CONFIG	(1 << 0)	/* Config Index, 0 when unconfigured */
-#define COR_SW_RESET	(1 << 7)	/* Software Reset on true */
-#define COR_LEVEL_IRQ	(1 << 6)	/* Level IRQ */
-
-/* Local Memory map */
-
-#define RX_BASE		0x0000		/* Receive memory, 8 kB */
-#define TX_BASE		0x2000		/* Transmit memory, 2 kB */
-#define UNUSED_BASE	0x2800		/* Unused, 22 kB */
-#define RX_SIZE		(TX_BASE-RX_BASE)	/* Size of receive area */
-#define RX_SIZE_SHIFT	6		/* Bits to shift in stop register */
-
-#define TRUE  1
-#define FALSE 0
-
-#define MOD_ENAL 1
-#define MOD_PROM 2
-
-/* Size of a MAC address */
-#define WAVELAN_ADDR_SIZE	6
-
-/* Maximum size of Wavelan packet */
-#define WAVELAN_MTU	1500
-
-#define	MAXDATAZ		(6 + 6 + 2 + WAVELAN_MTU)
-
-/********************** PARAMETER STORAGE AREA **********************/
-
-/*
- * Parameter Storage Area (PSA).
- */
-typedef struct psa_t	psa_t;
-struct psa_t
-{
-  /* For the PCMCIA Adapter, locations 0x00-0x0F are unused and fixed at 00 */
-  unsigned char	psa_io_base_addr_1;	/* [0x00] Base address 1 ??? */
-  unsigned char	psa_io_base_addr_2;	/* [0x01] Base address 2 */
-  unsigned char	psa_io_base_addr_3;	/* [0x02] Base address 3 */
-  unsigned char	psa_io_base_addr_4;	/* [0x03] Base address 4 */
-  unsigned char	psa_rem_boot_addr_1;	/* [0x04] Remote Boot Address 1 */
-  unsigned char	psa_rem_boot_addr_2;	/* [0x05] Remote Boot Address 2 */
-  unsigned char	psa_rem_boot_addr_3;	/* [0x06] Remote Boot Address 3 */
-  unsigned char	psa_holi_params;	/* [0x07] HOst Lan Interface (HOLI) Parameters */
-  unsigned char	psa_int_req_no;		/* [0x08] Interrupt Request Line */
-  unsigned char	psa_unused0[7];		/* [0x09-0x0F] unused */
-
-  unsigned char	psa_univ_mac_addr[WAVELAN_ADDR_SIZE];	/* [0x10-0x15] Universal (factory) MAC Address */
-  unsigned char	psa_local_mac_addr[WAVELAN_ADDR_SIZE];	/* [0x16-1B] Local MAC Address */
-  unsigned char	psa_univ_local_sel;	/* [0x1C] Universal Local Selection */
-#define		PSA_UNIVERSAL	0		/* Universal (factory) */
-#define		PSA_LOCAL	1		/* Local */
-  unsigned char	psa_comp_number;	/* [0x1D] Compatability Number: */
-#define		PSA_COMP_PC_AT_915	0 	/* PC-AT 915 MHz	*/
-#define		PSA_COMP_PC_MC_915	1 	/* PC-MC 915 MHz	*/
-#define		PSA_COMP_PC_AT_2400	2 	/* PC-AT 2.4 GHz	*/
-#define		PSA_COMP_PC_MC_2400	3 	/* PC-MC 2.4 GHz	*/
-#define		PSA_COMP_PCMCIA_915	4 	/* PCMCIA 915 MHz or 2.0 */
-  unsigned char	psa_thr_pre_set;	/* [0x1E] Modem Threshold Preset */
-  unsigned char	psa_feature_select;	/* [0x1F] Call code required (1=on) */
-#define		PSA_FEATURE_CALL_CODE	0x01 	/* Call code required (Japan) */
-  unsigned char	psa_subband;		/* [0x20] Subband	*/
-#define		PSA_SUBBAND_915		0	/* 915 MHz or 2.0 */
-#define		PSA_SUBBAND_2425	1	/* 2425 MHz	*/
-#define		PSA_SUBBAND_2460	2	/* 2460 MHz	*/
-#define		PSA_SUBBAND_2484	3	/* 2484 MHz	*/
-#define		PSA_SUBBAND_2430_5	4	/* 2430.5 MHz	*/
-  unsigned char	psa_quality_thr;	/* [0x21] Modem Quality Threshold */
-  unsigned char	psa_mod_delay;		/* [0x22] Modem Delay ??? (reserved) */
-  unsigned char	psa_nwid[2];		/* [0x23-0x24] Network ID */
-  unsigned char	psa_nwid_select;	/* [0x25] Network ID Select On Off */
-  unsigned char	psa_encryption_select;	/* [0x26] Encryption On Off */
-  unsigned char	psa_encryption_key[8];	/* [0x27-0x2E] Encryption Key */
-  unsigned char	psa_databus_width;	/* [0x2F] AT bus width select 8/16 */
-  unsigned char	psa_call_code[8];	/* [0x30-0x37] (Japan) Call Code */
-  unsigned char	psa_nwid_prefix[2];	/* [0x38-0x39] Roaming domain */
-  unsigned char	psa_reserved[2];	/* [0x3A-0x3B] Reserved - fixed 00 */
-  unsigned char	psa_conf_status;	/* [0x3C] Conf Status, bit 0=1:config*/
-  unsigned char	psa_crc[2];		/* [0x3D] CRC-16 over PSA */
-  unsigned char	psa_crc_status;		/* [0x3F] CRC Valid Flag */
-};
-
-/* Size for structure checking (if padding is correct) */
-#define	PSA_SIZE	64
-
-/* Calculate offset of a field in the above structure
- * Warning : only even addresses are used */
-#define	psaoff(p,f) 	((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL))
-
-/******************** MODEM MANAGEMENT INTERFACE ********************/
-
-/*
- * Modem Management Controller (MMC) write structure.
- */
-typedef struct mmw_t	mmw_t;
-struct mmw_t
-{
-  unsigned char	mmw_encr_key[8];	/* encryption key */
-  unsigned char	mmw_encr_enable;	/* enable/disable encryption */
-#define	MMW_ENCR_ENABLE_MODE	0x02	/* Mode of security option */
-#define	MMW_ENCR_ENABLE_EN	0x01	/* Enable security option */
-  unsigned char	mmw_unused0[1];		/* unused */
-  unsigned char	mmw_des_io_invert;	/* Encryption option */
-#define	MMW_DES_IO_INVERT_RES	0x0F	/* Reserved */
-#define	MMW_DES_IO_INVERT_CTRL	0xF0	/* Control ??? (set to 0) */
-  unsigned char	mmw_unused1[5];		/* unused */
-  unsigned char	mmw_loopt_sel;		/* looptest selection */
-#define	MMW_LOOPT_SEL_DIS_NWID	0x40	/* disable NWID filtering */
-#define	MMW_LOOPT_SEL_INT	0x20	/* activate Attention Request */
-#define	MMW_LOOPT_SEL_LS	0x10	/* looptest w/o collision avoidance */
-#define MMW_LOOPT_SEL_LT3A	0x08	/* looptest 3a */
-#define	MMW_LOOPT_SEL_LT3B	0x04	/* looptest 3b */
-#define	MMW_LOOPT_SEL_LT3C	0x02	/* looptest 3c */
-#define	MMW_LOOPT_SEL_LT3D	0x01	/* looptest 3d */
-  unsigned char	mmw_jabber_enable;	/* jabber timer enable */
-  /* Abort transmissions > 200 ms */
-  unsigned char	mmw_freeze;		/* freeze / unfreeeze signal level */
-  /* 0 : signal level & qual updated for every new message, 1 : frozen */
-  unsigned char	mmw_anten_sel;		/* antenna selection */
-#define MMW_ANTEN_SEL_SEL	0x01	/* direct antenna selection */
-#define	MMW_ANTEN_SEL_ALG_EN	0x02	/* antenna selection algo. enable */
-  unsigned char	mmw_ifs;		/* inter frame spacing */
-  /* min time between transmission in bit periods (.5 us) - bit 0 ignored */
-  unsigned char	mmw_mod_delay;	 	/* modem delay (synchro) */
-  unsigned char	mmw_jam_time;		/* jamming time (after collision) */
-  unsigned char	mmw_unused2[1];		/* unused */
-  unsigned char	mmw_thr_pre_set;	/* level threshold preset */
-  /* Discard all packet with signal < this value (4) */
-  unsigned char	mmw_decay_prm;		/* decay parameters */
-  unsigned char	mmw_decay_updat_prm;	/* decay update parameterz */
-  unsigned char	mmw_quality_thr;	/* quality (z-quotient) threshold */
-  /* Discard all packet with quality < this value (3) */
-  unsigned char	mmw_netw_id_l;		/* NWID low order byte */
-  unsigned char	mmw_netw_id_h;		/* NWID high order byte */
-  /* Network ID or Domain : create virtual net on the air */
-
-  /* 2.0 Hardware extension - frequency selection support */
-  unsigned char	mmw_mode_select;	/* for analog tests (set to 0) */
-  unsigned char	mmw_unused3[1];		/* unused */
-  unsigned char	mmw_fee_ctrl;		/* frequency eeprom control */
-#define	MMW_FEE_CTRL_PRE	0x10	/* Enable protected instructions */
-#define	MMW_FEE_CTRL_DWLD	0x08	/* Download eeprom to mmc */
-#define	MMW_FEE_CTRL_CMD	0x07	/* EEprom commands : */
-#define	MMW_FEE_CTRL_READ	0x06	/* Read */
-#define	MMW_FEE_CTRL_WREN	0x04	/* Write enable */
-#define	MMW_FEE_CTRL_WRITE	0x05	/* Write data to address */
-#define	MMW_FEE_CTRL_WRALL	0x04	/* Write data to all addresses */
-#define	MMW_FEE_CTRL_WDS	0x04	/* Write disable */
-#define	MMW_FEE_CTRL_PRREAD	0x16	/* Read addr from protect register */
-#define	MMW_FEE_CTRL_PREN	0x14	/* Protect register enable */
-#define	MMW_FEE_CTRL_PRCLEAR	0x17	/* Unprotect all registers */
-#define	MMW_FEE_CTRL_PRWRITE	0x15	/* Write addr in protect register */
-#define	MMW_FEE_CTRL_PRDS	0x14	/* Protect register disable */
-  /* Never issue this command (PRDS) : it's irreversible !!! */
-
-  unsigned char	mmw_fee_addr;		/* EEprom address */
-#define	MMW_FEE_ADDR_CHANNEL	0xF0	/* Select the channel */
-#define	MMW_FEE_ADDR_OFFSET	0x0F	/* Offset in channel data */
-#define	MMW_FEE_ADDR_EN		0xC0	/* FEE_CTRL enable operations */
-#define	MMW_FEE_ADDR_DS		0x00	/* FEE_CTRL disable operations */
-#define	MMW_FEE_ADDR_ALL	0x40	/* FEE_CTRL all operations */
-#define	MMW_FEE_ADDR_CLEAR	0xFF	/* FEE_CTRL clear operations */
-
-  unsigned char	mmw_fee_data_l;		/* Write data to EEprom */
-  unsigned char	mmw_fee_data_h;		/* high octet */
-  unsigned char	mmw_ext_ant;		/* Setting for external antenna */
-#define	MMW_EXT_ANT_EXTANT	0x01	/* Select external antenna */
-#define	MMW_EXT_ANT_POL		0x02	/* Polarity of the antenna */
-#define	MMW_EXT_ANT_INTERNAL	0x00	/* Internal antenna */
-#define	MMW_EXT_ANT_EXTERNAL	0x03	/* External antenna */
-#define	MMW_EXT_ANT_IQ_TEST	0x1C	/* IQ test pattern (set to 0) */
-};
-
-/* Size for structure checking (if padding is correct) */
-#define	MMW_SIZE	37
-
-/* Calculate offset of a field in the above structure */
-#define	mmwoff(p,f) 	(unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
-
-/*
- * Modem Management Controller (MMC) read structure.
- */
-typedef struct mmr_t	mmr_t;
-struct mmr_t
-{
-  unsigned char	mmr_unused0[8];		/* unused */
-  unsigned char	mmr_des_status;		/* encryption status */
-  unsigned char	mmr_des_avail;		/* encryption available (0x55 read) */
-#define	MMR_DES_AVAIL_DES	0x55		/* DES available */
-#define	MMR_DES_AVAIL_AES	0x33		/* AES (AT&T) available */
-  unsigned char	mmr_des_io_invert;	/* des I/O invert register */
-  unsigned char	mmr_unused1[5];		/* unused */
-  unsigned char	mmr_dce_status;		/* DCE status */
-#define	MMR_DCE_STATUS_RX_BUSY		0x01	/* receiver busy */
-#define	MMR_DCE_STATUS_LOOPT_IND	0x02	/* loop test indicated */
-#define	MMR_DCE_STATUS_TX_BUSY		0x04	/* transmitter on */
-#define	MMR_DCE_STATUS_JBR_EXPIRED	0x08	/* jabber timer expired */
-#define MMR_DCE_STATUS			0x0F	/* mask to get the bits */
-  unsigned char	mmr_dsp_id;		/* DSP id (AA = Daedalus rev A) */
-  unsigned char	mmr_unused2[2];		/* unused */
-  unsigned char	mmr_correct_nwid_l;	/* # of correct NWID's rxd (low) */
-  unsigned char	mmr_correct_nwid_h;	/* # of correct NWID's rxd (high) */
-  /* Warning : Read high order octet first !!! */
-  unsigned char	mmr_wrong_nwid_l;	/* # of wrong NWID's rxd (low) */
-  unsigned char	mmr_wrong_nwid_h;	/* # of wrong NWID's rxd (high) */
-  unsigned char	mmr_thr_pre_set;	/* level threshold preset */
-#define	MMR_THR_PRE_SET		0x3F		/* level threshold preset */
-#define	MMR_THR_PRE_SET_CUR	0x80		/* Current signal above it */
-  unsigned char	mmr_signal_lvl;		/* signal level */
-#define	MMR_SIGNAL_LVL		0x3F		/* signal level */
-#define	MMR_SIGNAL_LVL_VALID	0x80		/* Updated since last read */
-  unsigned char	mmr_silence_lvl;	/* silence level (noise) */
-#define	MMR_SILENCE_LVL		0x3F		/* silence level */
-#define	MMR_SILENCE_LVL_VALID	0x80		/* Updated since last read */
-  unsigned char	mmr_sgnl_qual;		/* signal quality */
-#define	MMR_SGNL_QUAL		0x0F		/* signal quality */
-#define	MMR_SGNL_QUAL_ANT	0x80		/* current antenna used */
-  unsigned char	mmr_netw_id_l;		/* NWID low order byte ??? */
-  unsigned char	mmr_unused3[3];		/* unused */
-
-  /* 2.0 Hardware extension - frequency selection support */
-  unsigned char	mmr_fee_status;		/* Status of frequency eeprom */
-#define	MMR_FEE_STATUS_ID	0xF0		/* Modem revision id */
-#define	MMR_FEE_STATUS_DWLD	0x08		/* Download in progress */
-#define	MMR_FEE_STATUS_BUSY	0x04		/* EEprom busy */
-  unsigned char	mmr_unused4[1];		/* unused */
-  unsigned char	mmr_fee_data_l;		/* Read data from eeprom (low) */
-  unsigned char	mmr_fee_data_h;		/* Read data from eeprom (high) */
-};
-
-/* Size for structure checking (if padding is correct) */
-#define	MMR_SIZE	36
-
-/* Calculate offset of a field in the above structure */
-#define	mmroff(p,f) 	(unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
-
-/* Make the two above structures one */
-typedef union mm_t
-{
-  struct mmw_t	w;	/* Write to the mmc */
-  struct mmr_t	r;	/* Read from the mmc */
-} mm_t;
-
-#endif /* _WAVELAN_H */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c
--- v2.5.2/linux/drivers/net/pcmcia/wavelan_cs.c	Fri Nov  9 15:22:54 2001
+++ linux/drivers/net/pcmcia/wavelan_cs.c	Wed Dec 31 16:00:00 1969
@@ -1,4841 +0,0 @@
-/*
- *	Wavelan Pcmcia driver
- *
- *		Jean II - HPLB '96
- *
- * Reorganisation and extension of the driver.
- * Original copyright follow. See wavelan_cs.h for details.
- *
- * This code is derived from Anthony D. Joseph's code and all the changes here
- * are also under the original copyright below.
- *
- * This code supports version 2.00 of WaveLAN/PCMCIA cards (2.4GHz), and
- * can work on Linux 2.0.36 with support of David Hinds' PCMCIA Card Services
- *
- * Joe Finney (joe@comp.lancs.ac.uk) at Lancaster University in UK added
- * critical code in the routine to initialize the Modem Management Controller.
- *
- * Thanks to Alan Cox and Bruce Janson for their advice.
- *
- *	-- Yunzhou Li (scip4166@nus.sg)
- *
-#ifdef WAVELAN_ROAMING	
- * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu)
- * based on patch by Joe Finney from Lancaster University.
-#endif :-)
- *
- * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An
- * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor.
- *
- *   A non-shared memory PCMCIA ethernet driver for linux
- *
- * ISA version modified to support PCMCIA by Anthony Joseph (adj@lcs.mit.edu)
- *
- *
- * Joseph O'Sullivan & John Langford (josullvn@cs.cmu.edu & jcl@cs.cmu.edu)
- *
- * Apr 2 '98  made changes to bring the i82593 control/int handling in line
- *             with offical specs...
- *
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
- * - reorganize kmallocs in wavelan_attach, checking all for failure
- *   and releasing the previous allocations if one fails
- *
- *
- ****************************************************************************
- *   Copyright 1995
- *   Anthony D. Joseph
- *   Massachusetts Institute of Technology
- *
- *   Permission to use, copy, modify, and distribute this program
- *   for any purpose and without fee is hereby granted, provided
- *   that this copyright and permission notice appear on all copies
- *   and supporting documentation, the name of M.I.T. not be used
- *   in advertising or publicity pertaining to distribution of the
- *   program without specific prior permission, and notice be given
- *   in supporting documentation that copying and distribution is
- *   by permission of M.I.T.  M.I.T. makes no representations about
- *   the suitability of this software for any purpose.  It is pro-
- *   vided "as is" without express or implied warranty.         
- ****************************************************************************
- *
- */
-
-#include "wavelan_cs.h"		/* Private header */
-
-/************************* MISC SUBROUTINES **************************/
-/*
- * Subroutines which won't fit in one of the following category
- * (wavelan modem or i82593)
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Wrapper for reporting error to cardservices
- */
-static void cs_error(client_handle_t handle, int func, int ret)
-{
-    error_info_t err = { func, ret };
-    CardServices(ReportError, handle, &err);
-}
-
-#ifdef STRUCT_CHECK
-/*------------------------------------------------------------------*/
-/*
- * Sanity routine to verify the sizes of the various WaveLAN interface
- * structures.
- */
-static char *
-wv_structuct_check(void)
-{
-#define	SC(t,s,n)	if (sizeof(t) != s) return(n);
-
-  SC(psa_t, PSA_SIZE, "psa_t");
-  SC(mmw_t, MMW_SIZE, "mmw_t");
-  SC(mmr_t, MMR_SIZE, "mmr_t");
-
-#undef	SC
-
-  return((char *) NULL);
-} /* wv_structuct_check */
-#endif	/* STRUCT_CHECK */
-
-/******************* MODEM MANAGEMENT SUBROUTINES *******************/
-/*
- * Usefull subroutines to manage the modem of the wavelan
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Read from card's Host Adaptor Status Register.
- */
-static inline u_char
-hasr_read(u_long	base)
-{
-  return(inb(HASR(base)));
-} /* hasr_read */
-
-/*------------------------------------------------------------------*/
-/*
- * Write to card's Host Adapter Command Register.
- */
-static inline void
-hacr_write(u_long	base,
-	   u_char	hacr)
-{
-  outb(hacr, HACR(base));
-} /* hacr_write */
-
-/*------------------------------------------------------------------*/
-/*
- * Write to card's Host Adapter Command Register. Include a delay for
- * those times when it is needed.
- */
-static inline void
-hacr_write_slow(u_long	base,
-		u_char	hacr)
-{
-  hacr_write(base, hacr);
-  /* delay might only be needed sometimes */
-  mdelay(1L);
-} /* hacr_write_slow */
-
-/*------------------------------------------------------------------*/
-/*
- * Read the Parameter Storage Area from the WaveLAN card's memory
- */
-static void
-psa_read(device *	dev,
-	 int		o,	/* offset in PSA */
-	 u_char *	b,	/* buffer to fill */
-	 int		n)	/* size to read */
-{
-  u_char *	ptr = ((u_char *)dev->mem_start) + PSA_ADDR + (o << 1);
-
-  while(n-- > 0)
-    {
-      *b++ = readb(ptr);
-      /* Due to a lack of address decode pins, the WaveLAN PCMCIA card
-       * only supports reading even memory addresses. That means the
-       * increment here MUST be two.
-       * Because of that, we can't use memcpy_fromio()...
-       */
-      ptr += 2;
-    }
-} /* psa_read */
-
-/*------------------------------------------------------------------*/
-/*
- * Write the Paramter Storage Area to the WaveLAN card's memory
- */
-static void
-psa_write(device *	dev,
-	  int		o,	/* Offset in psa */
-	  u_char *	b,	/* Buffer in memory */
-	  int		n)	/* Length of buffer */
-{
-  u_char *	ptr = ((u_char *) dev->mem_start) + PSA_ADDR + (o << 1);
-  int		count = 0;
-  ioaddr_t	base = dev->base_addr;
-  /* As there seem to have no flag PSA_BUSY as in the ISA model, we are
-   * oblige to verify this address to know when the PSA is ready... */
-  volatile u_char *	verify = ((u_char *) dev->mem_start) + PSA_ADDR +
-    (psaoff(0, psa_comp_number) << 1);
-
-  /* Authorize writting to PSA */
-  hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN);
-
-  while(n-- > 0)
-    {
-      /* write to PSA */
-      writeb(*b++, ptr);
-      ptr += 2;
-
-      /* I don't have the spec, so I don't know what the correct
-       * sequence to write is. This hack seem to work for me... */
-      count = 0;
-      while((readb(verify) != PSA_COMP_PCMCIA_915) && (count++ < 100))
-	mdelay(1);
-    }
-
-  /* Put the host interface back in standard state */
-  hacr_write(base, HACR_DEFAULT);
-} /* psa_write */
-
-#ifdef SET_PSA_CRC
-/*------------------------------------------------------------------*/
-/*
- * Calculate the PSA CRC
- * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code
- * NOTE: By specifying a length including the CRC position the
- * returned value should be zero. (i.e. a correct checksum in the PSA)
- *
- * The Windows drivers don't use the CRC, but the AP and the PtP tool
- * depend on it.
- */
-static u_short
-psa_crc(unsigned char *	psa,	/* The PSA */
-	int		size)	/* Number of short for CRC */
-{
-  int		byte_cnt;	/* Loop on the PSA */
-  u_short	crc_bytes = 0;	/* Data in the PSA */
-  int		bit_cnt;	/* Loop on the bits of the short */
-
-  for(byte_cnt = 0; byte_cnt < size; byte_cnt++ )
-    {
-      crc_bytes ^= psa[byte_cnt];	/* Its an xor */
-
-      for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ )
-	{
-	  if(crc_bytes & 0x0001)
-	    crc_bytes = (crc_bytes >> 1) ^ 0xA001;
-	  else
-	    crc_bytes >>= 1 ;
-        }
-    }
-
-  return crc_bytes;
-} /* psa_crc */
-#endif	/* SET_PSA_CRC */
-
-/*------------------------------------------------------------------*/
-/*
- * update the checksum field in the Wavelan's PSA
- */
-static void
-update_psa_checksum(device *	dev)
-{
-#ifdef SET_PSA_CRC
-  psa_t		psa;
-  u_short	crc;
-
-  /* read the parameter storage area */
-  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
-
-  /* update the checksum */
-  crc = psa_crc((unsigned char *) &psa,
-		sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1])
-		- sizeof(psa.psa_crc_status));
-
-  psa.psa_crc[0] = crc & 0xFF;
-  psa.psa_crc[1] = (crc & 0xFF00) >> 8;
-
-  /* Write it ! */
-  psa_write(dev, (char *)&psa.psa_crc - (char *)&psa,
-	    (unsigned char *)&psa.psa_crc, 2);
-
-#ifdef DEBUG_IOCTL_INFO
-  printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n",
-          dev->name, psa.psa_crc[0], psa.psa_crc[1]);
-
-  /* Check again (luxury !) */
-  crc = psa_crc((unsigned char *) &psa,
-		 sizeof(psa) - sizeof(psa.psa_crc_status));
-
-  if(crc != 0)
-    printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name);
-#endif /* DEBUG_IOCTL_INFO */
-#endif	/* SET_PSA_CRC */
-} /* update_psa_checksum */
-
-/*------------------------------------------------------------------*/
-/*
- * Write 1 byte to the MMC.
- */
-static inline void
-mmc_out(u_long		base,
-	u_short		o,
-	u_char		d)
-{
-  /* Wait for MMC to go idle */
-  while(inb(HASR(base)) & HASR_MMI_BUSY)
-    ;
-
-  outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base));
-  outb(d, MMD(base));
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Routine to write bytes to the Modem Management Controller.
- * We start by the end because it is the way it should be !
- */
-static inline void
-mmc_write(u_long	base,
-	  u_char	o,
-	  u_char *	b,
-	  int		n)
-{
-  o += n;
-  b += n;
-
-  while(n-- > 0 )
-    mmc_out(base, --o, *(--b));
-} /* mmc_write */
-
-/*------------------------------------------------------------------*/
-/*
- * Read 1 byte from the MMC.
- * Optimised version for 1 byte, avoid using memory...
- */
-static inline u_char
-mmc_in(u_long	base,
-       u_short	o)
-{
-  while(inb(HASR(base)) & HASR_MMI_BUSY)
-    ;
-  outb(o << 1, MMR(base));		/* Set the read address */
-
-  outb(0, MMD(base));			/* Required dummy write */
-
-  while(inb(HASR(base)) & HASR_MMI_BUSY)
-    ;
-  return (u_char) (inb(MMD(base)));	/* Now do the actual read */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Routine to read bytes from the Modem Management Controller.
- * The implementation is complicated by a lack of address lines,
- * which prevents decoding of the low-order bit.
- * (code has just been moved in the above function)
- * We start by the end because it is the way it should be !
- */
-static inline void
-mmc_read(u_long		base,
-	 u_char		o,
-	 u_char *	b,
-	 int		n)
-{
-  o += n;
-  b += n;
-
-  while(n-- > 0)
-    *(--b) = mmc_in(base, --o);
-} /* mmc_read */
-
-/*------------------------------------------------------------------*/
-/*
- * Get the type of encryption available...
- */
-static inline int
-mmc_encr(u_long		base)	/* i/o port of the card */
-{
-  int	temp;
-
-  temp = mmc_in(base, mmroff(0, mmr_des_avail));
-  if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES))
-    return 0;
-  else
-    return temp;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wait for the frequency EEprom to complete a command...
- * I hope this one will be optimally inlined...
- */
-static inline void
-fee_wait(u_long		base,	/* i/o port of the card */
-	 int		delay,	/* Base delay to wait for */
-	 int		number)	/* Number of time to wait */
-{
-  int		count = 0;	/* Wait only a limited time */
-
-  while((count++ < number) &&
-	(mmc_in(base, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY))
-    udelay(delay);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Read bytes from the Frequency EEprom (frequency select cards).
- */
-static void
-fee_read(u_long		base,	/* i/o port of the card */
-	 u_short	o,	/* destination offset */
-	 u_short *	b,	/* data buffer */
-	 int		n)	/* number of registers */
-{
-  b += n;		/* Position at the end of the area */
-
-  /* Write the address */
-  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1);
-
-  /* Loop on all buffer */
-  while(n-- > 0)
-    {
-      /* Write the read command */
-      mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ);
-
-      /* Wait until EEprom is ready (should be quick !) */
-      fee_wait(base, 10, 100);
-
-      /* Read the value */
-      *--b = ((mmc_in(base, mmroff(0, mmr_fee_data_h)) << 8) |
-	      mmc_in(base, mmroff(0, mmr_fee_data_l)));
-    }
-}
-
-#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
-
-/*------------------------------------------------------------------*/
-/*
- * Write bytes from the Frequency EEprom (frequency select cards).
- * This is a bit complicated, because the frequency eeprom has to
- * be unprotected and the write enabled.
- * Jean II
- */
-static void
-fee_write(u_long	base,	/* i/o port of the card */
-	  u_short	o,	/* destination offset */
-	  u_short *	b,	/* data buffer */
-	  int		n)	/* number of registers */
-{
-  b += n;		/* Position at the end of the area */
-
-#ifdef EEPROM_IS_PROTECTED	/* disabled */
-#ifdef DOESNT_SEEM_TO_WORK	/* disabled */
-  /* Ask to read the protected register */
-  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD);
-
-  fee_wait(base, 10, 100);
-
-  /* Read the protected register */
-  printk("Protected 2 : %02X-%02X\n",
-	 mmc_in(base, mmroff(0, mmr_fee_data_h)),
-	 mmc_in(base, mmroff(0, mmr_fee_data_l)));
-#endif	/* DOESNT_SEEM_TO_WORK */
-
-  /* Enable protected register */
-  mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
-  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
-
-  fee_wait(base, 10, 100);
-
-  /* Unprotect area */
-  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n);
-  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
-#ifdef DOESNT_SEEM_TO_WORK	/* disabled */
-  /* Or use : */
-  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
-#endif	/* DOESNT_SEEM_TO_WORK */
-
-  fee_wait(base, 10, 100);
-#endif	/* EEPROM_IS_PROTECTED */
-
-  /* Write enable */
-  mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
-  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
-
-  fee_wait(base, 10, 100);
-
-  /* Write the EEprom address */
-  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1);
-
-  /* Loop on all buffer */
-  while(n-- > 0)
-    {
-      /* Write the value */
-      mmc_out(base, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
-      mmc_out(base, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
-
-      /* Write the write command */
-      mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE);
-
-      /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */
-      mdelay(10);
-      fee_wait(base, 10, 100);
-    }
-
-  /* Write disable */
-  mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
-  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
-
-  fee_wait(base, 10, 100);
-
-#ifdef EEPROM_IS_PROTECTED	/* disabled */
-  /* Reprotect EEprom */
-  mmc_out(base, mmwoff(0, mmw_fee_addr), 0x00);
-  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
-
-  fee_wait(base, 10, 100);
-#endif	/* EEPROM_IS_PROTECTED */
-}
-#endif	/* WIRELESS_EXT */
-
-/******************* WaveLAN Roaming routines... ********************/
-
-#ifdef WAVELAN_ROAMING	/* Conditional compile, see wavelan_cs.h */
-
-unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00};
-  
-void wv_roam_init(struct net_device *dev)
-{
-  net_local  *lp= (net_local *)dev->priv;
-
-  /* Do not remove this unless you have a good reason */
-  printk(KERN_NOTICE "%s: Warning, you have enabled roaming on"
-	 " device %s !\n", dev->name, dev->name);
-  printk(KERN_NOTICE "Roaming is currently an experimental unsupported feature"
-	 " of the Wavelan driver.\n");
-  printk(KERN_NOTICE "It may work, but may also make the driver behave in"
-	 " erratic ways or crash.\n");
-
-  lp->wavepoint_table.head=NULL;           /* Initialise WavePoint table */
-  lp->wavepoint_table.num_wavepoints=0;
-  lp->wavepoint_table.locked=0;
-  lp->curr_point=NULL;                        /* No default WavePoint */
-  lp->cell_search=0;
-  
-  lp->cell_timer.data=(int)lp;                /* Start cell expiry timer */
-  lp->cell_timer.function=wl_cell_expiry;
-  lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
-  add_timer(&lp->cell_timer);
-  
-  wv_nwid_filter(NWID_PROMISC,lp) ;    /* Enter NWID promiscuous mode */
-  /* to build up a good WavePoint */
-                                           /* table... */
-  printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name);
-}
- 
-void wv_roam_cleanup(struct net_device *dev)
-{
-  wavepoint_history *ptr,*old_ptr;
-  net_local *lp= (net_local *)dev->priv;
-  
-  printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name);
-  
-  /* Fixme : maybe we should check that the timer exist before deleting it */
-  del_timer(&lp->cell_timer);          /* Remove cell expiry timer       */
-  ptr=lp->wavepoint_table.head;        /* Clear device's WavePoint table */
-  while(ptr!=NULL)
-    {
-      old_ptr=ptr;
-      ptr=ptr->next;	
-      wl_del_wavepoint(old_ptr,lp);	
-    }
-}
-
-/* Enable/Disable NWID promiscuous mode on a given device */
-void wv_nwid_filter(unsigned char mode, net_local *lp)
-{
-  mm_t                  m;
-  unsigned long         flags;
-  
-#ifdef WAVELAN_ROAMING_DEBUG
-  printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name);
-#endif
-  
-  /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
-  
-  m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
-  mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
-  
-  /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
-  if(mode==NWID_PROMISC)
-    lp->cell_search=1;
-  else
-	lp->cell_search=0;
-}
-
-/* Find a record in the WavePoint table matching a given NWID */
-wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp)
-{
-  wavepoint_history	*ptr=lp->wavepoint_table.head;
-  
-  while(ptr!=NULL){
-    if(ptr->nwid==nwid)
-      return ptr;	
-    ptr=ptr->next;
-  }
-  return NULL;
-}
-
-/* Create a new wavepoint table entry */
-wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp)
-{
-  wavepoint_history *new_wavepoint;
-
-#ifdef WAVELAN_ROAMING_DEBUG	
-  printk(KERN_DEBUG "WaveLAN: New Wavepoint, NWID:%.4X\n",nwid);
-#endif
-  
-  if(lp->wavepoint_table.num_wavepoints==MAX_WAVEPOINTS)
-    return NULL;
-  
-  new_wavepoint=(wavepoint_history *) kmalloc(sizeof(wavepoint_history),GFP_ATOMIC);
-  if(new_wavepoint==NULL)
-    return NULL;
-  
-  new_wavepoint->nwid=nwid;                       /* New WavePoints NWID */
-  new_wavepoint->average_fast=0;                    /* Running Averages..*/
-  new_wavepoint->average_slow=0;
-  new_wavepoint->qualptr=0;                       /* Start of ringbuffer */
-  new_wavepoint->last_seq=seq-1;                /* Last sequence no.seen */
-  memset(new_wavepoint->sigqual,0,WAVEPOINT_HISTORY);/* Empty ringbuffer */
-  
-  new_wavepoint->next=lp->wavepoint_table.head;/* Add to wavepoint table */
-  new_wavepoint->prev=NULL;
-  
-  if(lp->wavepoint_table.head!=NULL)
-    lp->wavepoint_table.head->prev=new_wavepoint;
-  
-  lp->wavepoint_table.head=new_wavepoint;
-  
-  lp->wavepoint_table.num_wavepoints++;     /* no. of visible wavepoints */
-  
-  return new_wavepoint;
-}
-
-/* Remove a wavepoint entry from WavePoint table */
-void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp)
-{
-  if(wavepoint==NULL)
-    return;
-  
-  if(lp->curr_point==wavepoint)
-    lp->curr_point=NULL;
-  
-  if(wavepoint->prev!=NULL)
-    wavepoint->prev->next=wavepoint->next;
-  
-  if(wavepoint->next!=NULL)
-    wavepoint->next->prev=wavepoint->prev;
-  
-  if(lp->wavepoint_table.head==wavepoint)
-    lp->wavepoint_table.head=wavepoint->next;
-  
-  lp->wavepoint_table.num_wavepoints--;
-  kfree(wavepoint);
-}
-
-/* Timer callback function - checks WavePoint table for stale entries */ 
-void wl_cell_expiry(unsigned long data)
-{
-  net_local *lp=(net_local *)data;
-  wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point;
-  
-#if WAVELAN_ROAMING_DEBUG > 1
-  printk(KERN_DEBUG "WaveLAN: Wavepoint timeout, dev %s\n",lp->dev->name);
-#endif
-  
-  if(lp->wavepoint_table.locked)
-    {
-#if WAVELAN_ROAMING_DEBUG > 1
-      printk(KERN_DEBUG "WaveLAN: Wavepoint table locked...\n");
-#endif
-      
-      lp->cell_timer.expires=jiffies+1; /* If table in use, come back later */
-      add_timer(&lp->cell_timer);
-      return;
-    }
-  
-  while(wavepoint!=NULL)
-    {
-      if(wavepoint->last_seen < jiffies-CELL_TIMEOUT)
-	{
-#ifdef WAVELAN_ROAMING_DEBUG
-	  printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid);
-#endif
-	  
-	  old_point=wavepoint;
-	  wavepoint=wavepoint->next;
-	  wl_del_wavepoint(old_point,lp);
-	}
-      else
-	wavepoint=wavepoint->next;
-    }
-  lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
-  add_timer(&lp->cell_timer);
-}
-
-/* Update SNR history of a wavepoint */
-void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq)	
-{
-  int i=0,num_missed=0,ptr=0;
-  int average_fast=0,average_slow=0;
-  
-  num_missed=(seq-wavepoint->last_seq)%WAVEPOINT_HISTORY;/* Have we missed
-							    any beacons? */
-  if(num_missed)
-    for(i=0;i<num_missed;i++)
-      {
-	wavepoint->sigqual[wavepoint->qualptr++]=0; /* If so, enter them as 0's */
-	wavepoint->qualptr %=WAVEPOINT_HISTORY;    /* in the ringbuffer. */
-      }
-  wavepoint->last_seen=jiffies;                 /* Add beacon to history */
-  wavepoint->last_seq=seq;	
-  wavepoint->sigqual[wavepoint->qualptr++]=sigqual;          
-  wavepoint->qualptr %=WAVEPOINT_HISTORY;
-  ptr=(wavepoint->qualptr-WAVEPOINT_FAST_HISTORY+WAVEPOINT_HISTORY)%WAVEPOINT_HISTORY;
-  
-  for(i=0;i<WAVEPOINT_FAST_HISTORY;i++)       /* Update running averages */
-    {
-      average_fast+=wavepoint->sigqual[ptr++];
-      ptr %=WAVEPOINT_HISTORY;
-    }
-  
-  average_slow=average_fast;
-  for(i=WAVEPOINT_FAST_HISTORY;i<WAVEPOINT_HISTORY;i++)
-    {
-      average_slow+=wavepoint->sigqual[ptr++];
-      ptr %=WAVEPOINT_HISTORY;
-    }
-  
-  wavepoint->average_fast=average_fast/WAVEPOINT_FAST_HISTORY;
-  wavepoint->average_slow=average_slow/WAVEPOINT_HISTORY;	
-}
-
-/* Perform a handover to a new WavePoint */
-void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
-{
-  ioaddr_t              base = lp->dev->base_addr;  
-  mm_t                  m;
-  unsigned long         flags;
-  
-  if(wavepoint==lp->curr_point)          /* Sanity check... */
-    {
-      wv_nwid_filter(!NWID_PROMISC,lp);
-      return;
-    }
-  
-#ifdef WAVELAN_ROAMING_DEBUG
-  printk(KERN_DEBUG "WaveLAN: Doing handover to %.4X, dev %s\n",wavepoint->nwid,lp->dev->name);
-#endif
- 	
-  /* Disable interrupts & save flags */
-  spin_lock_irqsave(&lp->lock, flags);
-  
-  m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
-  m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
-  
-  mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
-  
-  /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
-  wv_nwid_filter(!NWID_PROMISC,lp);
-  lp->curr_point=wavepoint;
-}
-
-/* Called when a WavePoint beacon is received */
-static inline void wl_roam_gather(device *  dev,
-				  u_char *  hdr,   /* Beacon header */
-				  u_char *  stats) /* SNR, Signal quality 
-						      of packet */
-{
-  wavepoint_beacon *beacon= (wavepoint_beacon *)hdr; /* Rcvd. Beacon */
-  unsigned short nwid=ntohs(beacon->nwid);  
-  unsigned short sigqual=stats[2] & MMR_SGNL_QUAL;   /* SNR of beacon */
-  wavepoint_history *wavepoint=NULL;                /* WavePoint table entry */
-  net_local *lp=(net_local *)dev->priv;              /* Device info */
-
-#if WAVELAN_ROAMING_DEBUG > 1
-  printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name);
-  printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual);
-#endif
-  
-  lp->wavepoint_table.locked=1;                            /* <Mutex> */
-  
-  wavepoint=wl_roam_check(nwid,lp);            /* Find WavePoint table entry */
-  if(wavepoint==NULL)                    /* If no entry, Create a new one... */
-    {
-      wavepoint=wl_new_wavepoint(nwid,beacon->seq,lp);
-      if(wavepoint==NULL)
-	goto out;
-    }
-  if(lp->curr_point==NULL)             /* If this is the only WavePoint, */
-    wv_roam_handover(wavepoint, lp);	         /* Jump on it! */
-  
-  wl_update_history(wavepoint, sigqual, beacon->seq); /* Update SNR history
-							 stats. */
-  
-  if(lp->curr_point->average_slow < SEARCH_THRESH_LOW) /* If our current */
-    if(!lp->cell_search)                  /* WavePoint is getting faint, */
-      wv_nwid_filter(NWID_PROMISC,lp);    /* start looking for a new one */
-  
-  if(wavepoint->average_slow > 
-     lp->curr_point->average_slow + WAVELAN_ROAMING_DELTA)
-    wv_roam_handover(wavepoint, lp);   /* Handover to a better WavePoint */
-  
-  if(lp->curr_point->average_slow > SEARCH_THRESH_HIGH) /* If our SNR is */
-    if(lp->cell_search)  /* getting better, drop out of cell search mode */
-      wv_nwid_filter(!NWID_PROMISC,lp);
-  
-out:
-  lp->wavepoint_table.locked=0;                        /* </MUTEX>   :-) */
-}
-
-/* Test this MAC frame a WavePoint beacon */
-static inline int WAVELAN_BEACON(unsigned char *data)
-{
-  wavepoint_beacon *beacon= (wavepoint_beacon *)data;
-  static wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00};
-  
-  if(memcmp(beacon,&beacon_template,9)==0)
-    return 1;
-  else
-    return 0;
-}
-#endif	/* WAVELAN_ROAMING */
-
-/************************ I82593 SUBROUTINES *************************/
-/*
- * Useful subroutines to manage the Ethernet controller
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Routine to synchronously send a command to the i82593 chip. 
- * Should be called with interrupts enabled.
- */
-static int
-wv_82593_cmd(device *	dev,
-	     char *	str,
-	     int	cmd,
-	     int	result)
-{
-  ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *)dev->priv;
-  int		status;
-  long		spin;
-  u_long	flags;
-
-  /* Spin until the chip finishes executing its current command (if any) */
-  do
-    {
-      spin_lock_irqsave (&lp->lock, flags);
-      outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
-      status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
-    }
-  while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
-
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
-
-  /* Issue the command to the controller */
-  outb(cmd, LCCR(base));
-
-  /* If we don't have to check the result of the command */
-  if(result == SR0_NO_RESULT)
-    {
-      wv_wait_completed = FALSE;
-      return(TRUE);
-    }
-
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 1000))
-    udelay(10);
-
-  /* If the interrupt handler hasn't be called */
-  if(wv_wait_completed)
-    {
-      outb(OP0_NOP, LCCR(base));
-      status = inb(LCSR(base));
-      if(status & SR0_INTERRUPT)
-	{
-	  /* There was an interrupt : call the interrupt handler */
-#ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_WARNING "wv_82593_cmd: interrupt handler not installed or interrupt disabled\n");
-#endif
-
-	  wavelan_interrupt(dev->irq, (void *) dev,
-			    (struct pt_regs *) NULL);
-	}
-      else
-	{
-	  wv_wait_completed = 0; /* XXX */
-#ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_INFO "wv_82593_cmd: %s timeout, status0 0x%02x\n",
-		 str, status);
-#endif
-	  /* We probably should reset the controller here */
-	  return(FALSE);
-	}
-    }
-
-  /* Check the return code provided by the interrupt handler against
-   * the expected return code provided by the caller */
-  if((lp->status & SR0_EVENT_MASK) != result)
-    {
-#ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "wv_82593_cmd: %s failed, status0 = 0x%x\n",
-	     str, lp->status);
-#endif
-      return(FALSE);
-    }
-
-  return(TRUE);
-} /* wv_82593_cmd */
-
-/*------------------------------------------------------------------*/
-/*
- * This routine does a 593 op-code number 7, and obtains the diagnose
- * status for the WaveLAN.
- */
-static inline int
-wv_diag(device *	dev)
-{
-  if(wv_82593_cmd(dev, "wv_diag(): diagnose",
-		  OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED))
-    return(TRUE);
-
-#ifdef DEBUG_CONFIG_ERROR
-  printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n");
-#endif
-  return(FALSE);
-} /* wv_diag */
-
-/*------------------------------------------------------------------*/
-/*
- * Routine to read len bytes from the i82593's ring buffer, starting at
- * chip address addr. The results read from the chip are stored in buf.
- * The return value is the address to use for next the call.
- */
-static int
-read_ringbuf(device *	dev,
-	     int	addr,
-	     char *	buf,
-	     int	len)
-{
-  ioaddr_t	base = dev->base_addr;
-  int		ring_ptr = addr;
-  int		chunk_len;
-  char *	buf_ptr = buf;
-
-#ifdef OLDIES
-  /* After having check skb_put (net/core/skbuff.c) in the kernel, it seem
-   * quite safe to remove this... */
-
-  /* If buf is NULL, just increment the ring buffer pointer */
-  if(buf == NULL)
-    return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE);
-#endif
-
-  /* Get all the buffer */
-  while(len > 0)
-    {
-      /* Position the Program I/O Register at the ring buffer pointer */
-      outb(ring_ptr & 0xff, PIORL(base));
-      outb(((ring_ptr >> 8) & PIORH_MASK), PIORH(base));
-
-      /* First, determine how much we can read without wrapping around the
-	 ring buffer */
-      if((addr + len) < (RX_BASE + RX_SIZE))
-	chunk_len = len;
-      else
-	chunk_len = RX_BASE + RX_SIZE - addr;
-      insb(PIOP(base), buf_ptr, chunk_len);
-      buf_ptr += chunk_len;
-      len -= chunk_len;
-      ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE;
-    }
-  return(ring_ptr);
-} /* read_ringbuf */
-
-/*------------------------------------------------------------------*/
-/*
- * Reconfigure the i82593, or at least ask for it...
- * Because wv_82593_config use the transmission buffer, we must do it
- * when we are sure that there is no transmission, so we do it now
- * or in wavelan_packet_xmit() (I can't find any better place,
- * wavelan_interrupt is not an option...), so you may experience
- * some delay sometime...
- */
-static inline void wv_82593_reconfig (device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	dev_link_t *link = ((net_local *) dev->priv)->link;
-
-	/* Check if we can do it now ! */
-	if (!(link->open)) {
-		lp->reconfig_82593 = TRUE;
-#ifdef DEBUG_IOCTL_INFO
-		printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n",
-			dev->name, link->open);
-#endif
-	} else {
-		netif_stop_queue (dev);
-
-		lp->reconfig_82593 = FALSE;
-		wv_82593_config (dev);
-		netif_wake_queue (dev);
-	}
-}
-
-#ifdef OLDIES
-/*------------------------------------------------------------------*/
-/*
- * Dumps the current i82593 receive buffer to the console.
- */
-static void wavelan_dump(device *dev)
-{
-  ioaddr_t base = dev->base_addr;
-  int i, c;
-
-  /* disable receiver so we can use channel 1 */
-  outb(OP0_RCV_DISABLE, LCCR(base));
-
-  /* reset receive DMA pointer */
-  hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET);
-  hacr_write(base, HACR_DEFAULT);
-
-  /* dump into receive buffer */
-  wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE);
-
-  /* set read pointer to start of receive buffer */
-  outb(0, PIORL(base));
-  outb(0, PIORH(base));
-
-  printk(KERN_DEBUG "wavelan_cs: dump:\n");
-  printk(KERN_DEBUG "     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
-  for(i = 0; i < 73; i++){
-    if((i % 16) == 0) {
-      printk("\n0x%02x:", i);
-      if (!i) {
-	printk("   ");
-	continue;
-      }
-    }
-    c = inb(PIOP(base));
-    printk("%02x ", c);
-  }
-  printk("\n");
-
-  /* enable the receiver again */
-  wv_ru_start(dev);
-}
-#endif
-
-/********************* DEBUG & INFO SUBROUTINES *********************/
-/*
- * This routines are used in the code to show debug informations.
- * Most of the time, it dump the content of hardware structures...
- */
-
-#ifdef DEBUG_PSA_SHOW
-/*------------------------------------------------------------------*/
-/*
- * Print the formatted contents of the Parameter Storage Area.
- */
-static void
-wv_psa_show(psa_t *	p)
-{
-  printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
-  printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
-	 p->psa_io_base_addr_1,
-	 p->psa_io_base_addr_2,
-	 p->psa_io_base_addr_3,
-	 p->psa_io_base_addr_4);
-  printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n",
-	 p->psa_rem_boot_addr_1,
-	 p->psa_rem_boot_addr_2,
-	 p->psa_rem_boot_addr_3);
-  printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
-  printk("psa_int_req_no: %d\n", p->psa_int_req_no);
-#ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-	 p->psa_unused0[0],
-	 p->psa_unused0[1],
-	 p->psa_unused0[2],
-	 p->psa_unused0[3],
-	 p->psa_unused0[4],
-	 p->psa_unused0[5],
-	 p->psa_unused0[6]);
-#endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	 p->psa_univ_mac_addr[0],
-	 p->psa_univ_mac_addr[1],
-	 p->psa_univ_mac_addr[2],
-	 p->psa_univ_mac_addr[3],
-	 p->psa_univ_mac_addr[4],
-	 p->psa_univ_mac_addr[5]);
-  printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	 p->psa_local_mac_addr[0],
-	 p->psa_local_mac_addr[1],
-	 p->psa_local_mac_addr[2],
-	 p->psa_local_mac_addr[3],
-	 p->psa_local_mac_addr[4],
-	 p->psa_local_mac_addr[5]);
-  printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel);
-  printk("psa_comp_number: %d, ", p->psa_comp_number);
-  printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
-  printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ",
-	 p->psa_feature_select);
-  printk("psa_subband/decay_update_prm: %d\n", p->psa_subband);
-  printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr);
-  printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay);
-  printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]);
-  printk("psa_nwid_select: %d\n", p->psa_nwid_select);
-  printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select);
-  printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
-	 p->psa_encryption_key[0],
-	 p->psa_encryption_key[1],
-	 p->psa_encryption_key[2],
-	 p->psa_encryption_key[3],
-	 p->psa_encryption_key[4],
-	 p->psa_encryption_key[5],
-	 p->psa_encryption_key[6],
-	 p->psa_encryption_key[7]);
-  printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width);
-  printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ",
-	 p->psa_call_code[0]);
-  printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-	 p->psa_call_code[0],
-	 p->psa_call_code[1],
-	 p->psa_call_code[2],
-	 p->psa_call_code[3],
-	 p->psa_call_code[4],
-	 p->psa_call_code[5],
-	 p->psa_call_code[6],
-	 p->psa_call_code[7]);
-#ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
-	 p->psa_reserved[0],
-	 p->psa_reserved[1],
-	 p->psa_reserved[2],
-	 p->psa_reserved[3]);
-#endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
-  printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
-  printk("psa_crc_status: 0x%02x\n", p->psa_crc_status);
-} /* wv_psa_show */
-#endif	/* DEBUG_PSA_SHOW */
-
-#ifdef DEBUG_MMC_SHOW
-/*------------------------------------------------------------------*/
-/*
- * Print the formatted status of the Modem Management Controller.
- * This function need to be completed...
- */
-static void
-wv_mmc_show(device *	dev)
-{
-  ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *)dev->priv;
-  mmr_t		m;
-
-  /* Basic check */
-  if(hasr_read(base) & HASR_NO_CLK)
-    {
-      printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n",
-	     dev->name);
-      return;
-    }
-
-  /* Read the mmc */
-  mmc_out(base, mmwoff(0, mmw_freeze), 1);
-  mmc_read(base, 0, (u_char *)&m, sizeof(m));
-  mmc_out(base, mmwoff(0, mmw_freeze), 0);
-
-#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
-  /* Don't forget to update statistics */
-  lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
-#endif	/* WIRELESS_EXT */
-
-  printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
-#ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-	 m.mmr_unused0[0],
-	 m.mmr_unused0[1],
-	 m.mmr_unused0[2],
-	 m.mmr_unused0[3],
-	 m.mmr_unused0[4],
-	 m.mmr_unused0[5],
-	 m.mmr_unused0[6],
-	 m.mmr_unused0[7]);
-#endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n",
-	 m.mmr_des_avail, m.mmr_des_status);
-#ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
-	 m.mmr_unused1[0],
-	 m.mmr_unused1[1],
-	 m.mmr_unused1[2],
-	 m.mmr_unused1[3],
-	 m.mmr_unused1[4]);
-#endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n",
-	 m.mmr_dce_status,
-	 (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"",
-	 (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ?
-	 "loop test indicated," : "",
-	 (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "",
-	 (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ?
-	 "jabber timer expired," : "");
-  printk(KERN_DEBUG "Dsp ID: %02X\n",
-	 m.mmr_dsp_id);
-#ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n",
-	 m.mmr_unused2[0],
-	 m.mmr_unused2[1]);
-#endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n",
-	 (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l,
-	 (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l);
-  printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n",
-	 m.mmr_thr_pre_set & MMR_THR_PRE_SET,
-	 (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below");
-  printk(KERN_DEBUG "signal_lvl: %d [%s], ",
-	 m.mmr_signal_lvl & MMR_SIGNAL_LVL,
-	 (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg");
-  printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL,
-	 (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update");
-  printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL,
-	 (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0");
-#ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l);
-#endif	/* DEBUG_SHOW_UNUSED */
-} /* wv_mmc_show */
-#endif	/* DEBUG_MMC_SHOW */
-
-#ifdef DEBUG_I82593_SHOW
-/*------------------------------------------------------------------*/
-/*
- * Print the formatted status of the i82593's receive unit.
- */
-static void
-wv_ru_show(device *	dev)
-{
-  net_local *lp = (net_local *) dev->priv;
-
-  printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n");
-  printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop);
-  /*
-   * Not implemented yet...
-   */
-  printk("\n");
-} /* wv_ru_show */
-#endif	/* DEBUG_I82593_SHOW */
-
-#ifdef DEBUG_DEVICE_SHOW
-/*------------------------------------------------------------------*/
-/*
- * Print the formatted status of the WaveLAN PCMCIA device driver.
- */
-static void
-wv_dev_show(device *	dev)
-{
-  printk(KERN_DEBUG "dev:");
-  printk(" trans_start=%ld,", dev->trans_start);
-  printk(" flags=0x%x,", dev->flags);
-  printk("\n");
-} /* wv_dev_show */
-
-/*------------------------------------------------------------------*/
-/*
- * Print the formatted status of the WaveLAN PCMCIA device driver's
- * private information.
- */
-static void
-wv_local_show(device *	dev)
-{
-  net_local *lp;
-
-  lp = (net_local *)dev->priv;
-
-  printk(KERN_DEBUG "local:");
-  /*
-   * Not implemented yet...
-   */
-  printk("\n");
-} /* wv_local_show */
-#endif	/* DEBUG_DEVICE_SHOW */
-
-#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO)
-/*------------------------------------------------------------------*/
-/*
- * Dump packet header (and content if necessary) on the screen
- */
-static inline void
-wv_packet_info(u_char *		p,		/* Packet to dump */
-	       int		length,		/* Length of the packet */
-	       char *		msg1,		/* Name of the device */
-	       char *		msg2)		/* Name of the function */
-{
-  int		i;
-  int		maxi;
-
-  printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
-	 msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
-  printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
-	 msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]);
-
-#ifdef DEBUG_PACKET_DUMP
-
-  printk(KERN_DEBUG "data=\"");
-
-  if((maxi = length) > DEBUG_PACKET_DUMP)
-    maxi = DEBUG_PACKET_DUMP;
-  for(i = 14; i < maxi; i++)
-    if(p[i] >= ' ' && p[i] <= '~')
-      printk(" %c", p[i]);
-    else
-      printk("%02X", p[i]);
-  if(maxi < length)
-    printk("..");
-  printk("\"\n");
-  printk(KERN_DEBUG "\n");
-#endif	/* DEBUG_PACKET_DUMP */
-}
-#endif	/* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */
-
-/*------------------------------------------------------------------*/
-/*
- * This is the information which is displayed by the driver at startup
- * There  is a lot of flag to configure it at your will...
- */
-static inline void
-wv_init_info(device *	dev)
-{
-  ioaddr_t	base = dev->base_addr;
-  psa_t		psa;
-  int		i;
-
-  /* Read the parameter storage area */
-  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
-
-#ifdef DEBUG_PSA_SHOW
-  wv_psa_show(&psa);
-#endif
-#ifdef DEBUG_MMC_SHOW
-  wv_mmc_show(dev);
-#endif
-#ifdef DEBUG_I82593_SHOW
-  wv_ru_show(dev);
-#endif
-
-#ifdef DEBUG_BASIC_SHOW
-  /* Now, let's go for the basic stuff */
-  printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr",
-	 dev->name, base, dev->irq);
-  for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
-    printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
-
-  /* Print current network id */
-  if(psa.psa_nwid_select)
-    printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]);
-  else
-    printk(", nwid off");
-
-  /* If 2.00 card */
-  if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
-       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
-    {
-      unsigned short	freq;
-
-      /* Ask the EEprom to read the frequency from the first area */
-      fee_read(base, 0x00 /* 1st area - frequency... */,
-	       &freq, 1);
-
-      /* Print frequency */
-      printk(", 2.00, %ld", (freq >> 6) + 2400L);
-
-      /* Hack !!! */
-      if(freq & 0x20)
-	printk(".5");
-    }
-  else
-    {
-      printk(", PCMCIA, ");
-      switch (psa.psa_subband)
-	{
-	case PSA_SUBBAND_915:
-	  printk("915");
-	  break;
-	case PSA_SUBBAND_2425:
-	  printk("2425");
-	  break;
-	case PSA_SUBBAND_2460:
-	  printk("2460");
-	  break;
-	case PSA_SUBBAND_2484:
-	  printk("2484");
-	  break;
-	case PSA_SUBBAND_2430_5:
-	  printk("2430.5");
-	  break;
-	default:
-	  printk("unknown");
-	}
-    }
-
-  printk(" MHz\n");
-#endif	/* DEBUG_BASIC_SHOW */
-
-#ifdef DEBUG_VERSION_SHOW
-  /* Print version information */
-  printk(KERN_NOTICE "%s", version);
-#endif
-} /* wv_init_info */
-
-/********************* IOCTL, STATS & RECONFIG *********************/
-/*
- * We found here routines that are called by Linux on differents
- * occasions after the configuration and not for transmitting data
- * These may be called when the user use ifconfig, /proc/net/dev
- * or wireless extensions
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Get the current ethernet statistics. This may be called with the
- * card open or closed.
- * Used when the user read /proc/net/dev
- */
-static en_stats	*
-wavelan_get_stats(device *	dev)
-{
-#ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
-#endif
-
-  return(&((net_local *) dev->priv)->stats);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Set or clear the multicast filter for this adaptor.
- * num_addrs == -1	Promiscuous mode, receive all packets
- * num_addrs == 0	Normal mode, clear multicast list
- * num_addrs > 0	Multicast mode, receive normal and MC packets,
- *			and do best-effort filtering.
- */
-
-static void
-wavelan_set_multicast_list(device *	dev)
-{
-  net_local *	lp = (net_local *) dev->priv;
-
-#ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name);
-#endif
-
-#ifdef DEBUG_IOCTL_INFO
-  printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n",
-	 dev->name, dev->flags, dev->mc_count);
-#endif
-
-  if(dev->flags & IFF_PROMISC)
-    {
-      /*
-       * Enable promiscuous mode: receive all packets.
-       */
-      if(!lp->promiscuous)
-	{
-	  lp->promiscuous = 1;
-	  lp->allmulticast = 0;
-	  lp->mc_count = 0;
-
-	  wv_82593_reconfig(dev);
-
-	  /* Tell the kernel that we are doing a really bad job... */
-	  dev->flags |= IFF_PROMISC;
-	}
-    }
-  else
-    /* If all multicast addresses
-     * or too much multicast addresses for the hardware filter */
-    if((dev->flags & IFF_ALLMULTI) ||
-       (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES))
-      {
-	/*
-	 * Disable promiscuous mode, but active the all multicast mode
-	 */
-	if(!lp->allmulticast)
-	  {
-	    lp->promiscuous = 0;
-	    lp->allmulticast = 1;
-	    lp->mc_count = 0;
-
-	    wv_82593_reconfig(dev);
-
-	    /* Tell the kernel that we are doing a really bad job... */
-	    dev->flags |= IFF_ALLMULTI;
-	  }
-      }
-    else
-      /* If there is some multicast addresses to send */
-      if(dev->mc_list != (struct dev_mc_list *) NULL)
-	{
-	  /*
-	   * Disable promiscuous mode, but receive all packets
-	   * in multicast list
-	   */
-#ifdef MULTICAST_AVOID
-	  if(lp->promiscuous || lp->allmulticast ||
-	     (dev->mc_count != lp->mc_count))
-#endif
-	    {
-	      lp->promiscuous = 0;
-	      lp->allmulticast = 0;
-	      lp->mc_count = dev->mc_count;
-
-	      wv_82593_reconfig(dev);
-	    }
-	}
-      else
-	{
-	  /*
-	   * Switch to normal mode: disable promiscuous mode and 
-	   * clear the multicast list.
-	   */
-	  if(lp->promiscuous || lp->mc_count == 0)
-	    {
-	      lp->promiscuous = 0;
-	      lp->allmulticast = 0;
-	      lp->mc_count = 0;
-
-	      wv_82593_reconfig(dev);
-	    }
-	}
-#ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name);
-#endif
-}
-
-/*------------------------------------------------------------------*/
-/*
- * This function doesn't exist...
- * (Note : it was a nice way to test the reconfigure stuff...)
- */
-#ifdef SET_MAC_ADDRESS
-static int
-wavelan_set_mac_address(device *	dev,
-			void *		addr)
-{
-  struct sockaddr *	mac = addr;
-
-  /* Copy the address */
-  memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
-
-  /* Reconfig the beast */
-  wv_82593_reconfig(dev);
-
-  return 0;
-}
-#endif	/* SET_MAC_ADDRESS */
-
-#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
-
-/*------------------------------------------------------------------*/
-/*
- * Frequency setting (for hardware able of it)
- * It's a bit complicated and you don't really want to look into it...
- * (called in wavelan_ioctl)
- */
-static inline int
-wv_set_frequency(u_long		base,	/* i/o port of the card */
-		 iw_freq *	frequency)
-{
-  const int	BAND_NUM = 10;	/* Number of bands */
-  long		freq = 0L;	/* offset to 2.4 GHz in .5 MHz */
-#ifdef DEBUG_IOCTL_INFO
-  int		i;
-#endif
-
-  /* Setting by frequency */
-  /* Theoritically, you may set any frequency between
-   * the two limits with a 0.5 MHz precision. In practice,
-   * I don't want you to have trouble with local
-   * regulations... */
-  if((frequency->e == 1) &&
-     (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
-    {
-      freq = ((frequency->m / 10000) - 24000L) / 5;
-    }
-
-  /* Setting by channel (same as wfreqsel) */
-  /* Warning : each channel is 22MHz wide, so some of the channels
-   * will interfere... */
-  if((frequency->e == 0) &&
-     (frequency->m >= 0) && (frequency->m < BAND_NUM))
-    {
-      /* Get frequency offset. */
-      freq = channel_bands[frequency->m] >> 1;
-    }
-
-  /* Verify if the frequency is allowed */
-  if(freq != 0L)
-    {
-      u_short	table[10];	/* Authorized frequency table */
-
-      /* Read the frequency table */
-      fee_read(base, 0x71 /* frequency table */,
-	       table, 10);
-
-#ifdef DEBUG_IOCTL_INFO
-      printk(KERN_DEBUG "Frequency table :");
-      for(i = 0; i < 10; i++)
-	{
-	  printk(" %04X",
-		 table[i]);
-	}
-      printk("\n");
-#endif
-
-      /* Look in the table if the frequency is allowed */
-      if(!(table[9 - ((freq - 24) / 16)] &
-	   (1 << ((freq - 24) % 16))))
-	return -EINVAL;		/* not allowed */
-    }
-  else
-    return -EINVAL;
-
-  /* If we get a usable frequency */
-  if(freq != 0L)
-    {
-      unsigned short	area[16];
-      unsigned short	dac[2];
-      unsigned short	area_verify[16];
-      unsigned short	dac_verify[2];
-      /* Corresponding gain (in the power adjust value table)
-       * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8
-       * & WCIN062D.DOC, page 6.2.9 */
-      unsigned short	power_limit[] = { 40, 80, 120, 160, 0 };
-      int		power_band = 0;		/* Selected band */
-      unsigned short	power_adjust;		/* Correct value */
-
-      /* Search for the gain */
-      power_band = 0;
-      while((freq > power_limit[power_band]) &&
-	    (power_limit[++power_band] != 0))
-	;
-
-      /* Read the first area */
-      fee_read(base, 0x00,
-	       area, 16);
-
-      /* Read the DAC */
-      fee_read(base, 0x60,
-	       dac, 2);
-
-      /* Read the new power adjust value */
-      fee_read(base, 0x6B - (power_band >> 1),
-	       &power_adjust, 1);
-      if(power_band & 0x1)
-	power_adjust >>= 8;
-      else
-	power_adjust &= 0xFF;
-
-#ifdef DEBUG_IOCTL_INFO
-      printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
-      for(i = 0; i < 16; i++)
-	{
-	  printk(" %04X",
-		 area[i]);
-	}
-      printk("\n");
-
-      printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
-	     dac[0], dac[1]);
-#endif
-
-      /* Frequency offset (for info only...) */
-      area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
-
-      /* Receiver Principle main divider coefficient */
-      area[3] = (freq >> 1) + 2400L - 352L;
-      area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
-
-      /* Transmitter Main divider coefficient */
-      area[13] = (freq >> 1) + 2400L;
-      area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
-
-      /* Others part of the area are flags, bit streams or unused... */
-
-      /* Set the value in the DAC */
-      dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
-      dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
-
-      /* Write the first area */
-      fee_write(base, 0x00,
-		area, 16);
-
-      /* Write the DAC */
-      fee_write(base, 0x60,
-		dac, 2);
-
-      /* We now should verify here that the EEprom writting was ok */
-
-      /* ReRead the first area */
-      fee_read(base, 0x00,
-	       area_verify, 16);
-
-      /* ReRead the DAC */
-      fee_read(base, 0x60,
-	       dac_verify, 2);
-
-      /* Compare */
-      if(memcmp(area, area_verify, 16 * 2) ||
-	 memcmp(dac, dac_verify, 2 * 2))
-	{
-#ifdef DEBUG_IOCTL_ERROR
-	  printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n");
-#endif
-	  return -EOPNOTSUPP;
-	}
-
-      /* We must download the frequency parameters to the
-       * synthetisers (from the EEprom - area 1)
-       * Note : as the EEprom is auto decremented, we set the end
-       * if the area... */
-      mmc_out(base, mmwoff(0, mmw_fee_addr), 0x0F);
-      mmc_out(base, mmwoff(0, mmw_fee_ctrl),
-	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
-
-      /* Wait until the download is finished */
-      fee_wait(base, 100, 100);
-
-      /* We must now download the power adjust value (gain) to
-       * the synthetisers (from the EEprom - area 7 - DAC) */
-      mmc_out(base, mmwoff(0, mmw_fee_addr), 0x61);
-      mmc_out(base, mmwoff(0, mmw_fee_ctrl),
-	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
-
-      /* Wait until the download is finished */
-      fee_wait(base, 100, 100);
-
-#ifdef DEBUG_IOCTL_INFO
-      /* Verification of what we have done... */
-
-      printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
-      for(i = 0; i < 16; i++)
-	{
-	  printk(" %04X",
-		 area_verify[i]);
-	}
-      printk("\n");
-
-      printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
-	     dac_verify[0], dac_verify[1]);
-#endif
-
-      return 0;
-    }
-  else
-    return -EINVAL;		/* Bah, never get there... */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Give the list of available frequencies
- */
-static inline int
-wv_frequency_list(u_long	base,	/* i/o port of the card */
-		  iw_freq *	list,	/* List of frequency to fill */
-		  int		max)	/* Maximum number of frequencies */
-{
-  u_short	table[10];	/* Authorized frequency table */
-  long		freq = 0L;	/* offset to 2.4 GHz in .5 MHz + 12 MHz */
-  int		i;		/* index in the table */
-#if WIRELESS_EXT > 7
-  const int	BAND_NUM = 10;	/* Number of bands */
-  int		c = 0;		/* Channel number */
-#endif /* WIRELESS_EXT */
-
-  /* Read the frequency table */
-  fee_read(base, 0x71 /* frequency table */,
-	   table, 10);
-
-  /* Look all frequencies */
-  i = 0;
-  for(freq = 0; freq < 150; freq++)
-    /* Look in the table if the frequency is allowed */
-    if(table[9 - (freq / 16)] & (1 << (freq % 16)))
-      {
-#if WIRELESS_EXT > 7
-	/* Compute approximate channel number */
-	while((((channel_bands[c] >> 1) - 24) < freq) &&
-	      (c < BAND_NUM))
-	  c++;
-	list[i].i = c;	/* Set the list index */
-#endif /* WIRELESS_EXT */
-
-	/* put in the list */
-	list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
-	list[i++].e = 1;
-
-	/* Check number */
-	if(i >= max)
-	  return(i);
-      }
-
-  return(i);
-}
-
-#ifdef WIRELESS_SPY
-/*------------------------------------------------------------------*/
-/*
- * Gather wireless spy statistics : for each packet, compare the source
- * address with out list, and if match, get the stats...
- * Sorry, but this function really need wireless extensions...
- */
-static inline void
-wl_spy_gather(device *	dev,
-	      u_char *	mac,		/* MAC address */
-	      u_char *	stats)		/* Statistics to gather */
-{
-  net_local *	lp = (net_local *) dev->priv;
-  int		i;
-
-  /* Look all addresses */
-  for(i = 0; i < lp->spy_number; i++)
-    /* If match */
-    if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE))
-      {
-	/* Update statistics */
-	lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL;
-	lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL;
-	lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL;
-	lp->spy_stat[i].updated = 0x7;
-      }
-}
-#endif	/* WIRELESS_SPY */
-
-#ifdef HISTOGRAM
-/*------------------------------------------------------------------*/
-/*
- * This function calculate an histogram on the signal level.
- * As the noise is quite constant, it's like doing it on the SNR.
- * We have defined a set of interval (lp->his_range), and each time
- * the level goes in that interval, we increment the count (lp->his_sum).
- * With this histogram you may detect if one wavelan is really weak,
- * or you may also calculate the mean and standard deviation of the level...
- */
-static inline void
-wl_his_gather(device *	dev,
-	      u_char *	stats)		/* Statistics to gather */
-{
-  net_local *	lp = (net_local *) dev->priv;
-  u_char	level = stats[0] & MMR_SIGNAL_LVL;
-  int		i;
-
-  /* Find the correct interval */
-  i = 0;
-  while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++]))
-    ;
-
-  /* Increment interval counter */
-  (lp->his_sum[i])++;
-}
-#endif	/* HISTOGRAM */
-
-/*------------------------------------------------------------------*/
-/*
- * Perform ioctl : config & info stuff
- * This is here that are treated the wireless extensions (iwconfig)
- */
-static int
-wavelan_ioctl(struct net_device *	dev,	/* Device on wich the ioctl apply */
-	      struct ifreq *	rq,	/* Data passed */
-	      int		cmd)	/* Ioctl number */
-{
-  ioaddr_t		base = dev->base_addr;
-  net_local *		lp = (net_local *)dev->priv;	/* lp is not unused */
-  struct iwreq *	wrq = (struct iwreq *) rq;
-  psa_t			psa;
-  mm_t			m;
-  unsigned long		flags;
-  int			ret = 0;
-
-#ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
-#endif
-
-  /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
-
-  /* Look what is the request */
-  switch(cmd)
-    {
-      /* --------------- WIRELESS EXTENSIONS --------------- */
-
-    case SIOCGIWNAME:
-      strcpy(wrq->u.name, "Wavelan");
-      break;
-
-    case SIOCSIWNWID:
-      /* Set NWID in wavelan */
-#if WIRELESS_EXT > 8
-      if(!wrq->u.nwid.disabled)
-	{
-	  /* Set NWID in psa */
-	  psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8;
-	  psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
-#else	/* WIRELESS_EXT > 8 */
-      if(wrq->u.nwid.on)
-	{
-	  /* Set NWID in psa */
-	  psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
-	  psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
-#endif	/* WIRELESS_EXT > 8 */
-	  psa.psa_nwid_select = 0x01;
-	  psa_write(dev, (char *)psa.psa_nwid - (char *)&psa,
-		    (unsigned char *)psa.psa_nwid, 3);
-
-	  /* Set NWID in mmc */
-	  m.w.mmw_netw_id_l = psa.psa_nwid[1];
-	  m.w.mmw_netw_id_h = psa.psa_nwid[0];
-	  mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m,
-		    (unsigned char *)&m.w.mmw_netw_id_l, 2);
-	  mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00);
-	}
-      else
-	{
-	  /* Disable nwid in the psa */
-	  psa.psa_nwid_select = 0x00;
-	  psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa,
-		    (unsigned char *)&psa.psa_nwid_select, 1);
-
-	  /* Disable nwid in the mmc (no filtering) */
-	  mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
-	}
-      /* update the Wavelan checksum */
-      update_psa_checksum(dev);
-      break;
-
-    case SIOCGIWNWID:
-      /* Read the NWID */
-      psa_read(dev, (char *)psa.psa_nwid - (char *)&psa,
-	       (unsigned char *)psa.psa_nwid, 3);
-#if WIRELESS_EXT > 8
-      wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
-      wrq->u.nwid.disabled = !(psa.psa_nwid_select);
-      wrq->u.nwid.fixed = 1;	/* Superfluous */
-#else	/* WIRELESS_EXT > 8 */
-      wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
-      wrq->u.nwid.on = psa.psa_nwid_select;
-#endif	/* WIRELESS_EXT > 8 */
-      break;
-
-    case SIOCSIWFREQ:
-      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
-      if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
-	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
-	ret = wv_set_frequency(base, &(wrq->u.freq));
-      else
-	ret = -EOPNOTSUPP;
-      break;
-
-    case SIOCGIWFREQ:
-      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-       * (does it work for everybody XXX - especially old cards...) */
-      if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
-	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
-	{
-	  unsigned short	freq;
-
-	  /* Ask the EEprom to read the frequency from the first area */
-	  fee_read(base, 0x00 /* 1st area - frequency... */,
-		   &freq, 1);
-	  wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
-	  wrq->u.freq.e = 1;
-	}
-      else
-	{
-	  psa_read(dev, (char *)&psa.psa_subband - (char *)&psa,
-		   (unsigned char *)&psa.psa_subband, 1);
-
-	  if(psa.psa_subband <= 4)
-	    {
-	      wrq->u.freq.m = fixed_bands[psa.psa_subband];
-	      wrq->u.freq.e = (psa.psa_subband != 0);
-	    }
-	  else
-	    ret = -EOPNOTSUPP;
-	}
-      break;
-
-    case SIOCSIWSENS:
-      /* Set the level threshold */
-#if WIRELESS_EXT > 7
-      /* We should complain loudly if wrq->u.sens.fixed = 0, because we
-       * can't set auto mode... */
-      psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
-#else	/* WIRELESS_EXT > 7 */
-      psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
-#endif	/* WIRELESS_EXT > 7 */
-      psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
-	       (unsigned char *)&psa.psa_thr_pre_set, 1);
-      /* update the Wavelan checksum */
-      update_psa_checksum(dev);
-      mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set);
-      break;
-
-    case SIOCGIWSENS:
-      /* Read the level threshold */
-      psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
-	       (unsigned char *)&psa.psa_thr_pre_set, 1);
-#if WIRELESS_EXT > 7
-      wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
-      wrq->u.sens.fixed = 1;
-#else	/* WIRELESS_EXT > 7 */
-      wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
-#endif	/* WIRELESS_EXT > 7 */
-      break;
-
-#if WIRELESS_EXT > 8
-    case SIOCSIWENCODE:
-      /* Set encryption key */
-      if(!mmc_encr(base))
-	{
-	  ret = -EOPNOTSUPP;
-	  break;
-	}
-
-      /* Basic checking... */
-      if(wrq->u.encoding.pointer != (caddr_t) 0)
-	{
-	  /* Check the size of the key */
-	  if(wrq->u.encoding.length != 8)
-	    {
-	      ret = -EINVAL;
-	      break;
-	    }
-
-	  /* Copy the key in the driver */
-	  if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer,
-			    wrq->u.encoding.length))
-	    {
-	      ret = -EFAULT;
-	      break;
-	    }
-
-	  psa.psa_encryption_select = 1;
-	  psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
-		    (unsigned char *) &psa.psa_encryption_select, 8+1);
-
-	  mmc_out(base, mmwoff(0, mmw_encr_enable),
-		  MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
-	  mmc_write(base, mmwoff(0, mmw_encr_key),
-		    (unsigned char *) &psa.psa_encryption_key, 8);
-	}
-
-      if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
-	{	/* disable encryption */
-	  psa.psa_encryption_select = 0;
-	  psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
-		    (unsigned char *) &psa.psa_encryption_select, 1);
-
-	  mmc_out(base, mmwoff(0, mmw_encr_enable), 0);
-	}
-      /* update the Wavelan checksum */
-      update_psa_checksum(dev);
-      break;
-
-    case SIOCGIWENCODE:
-      /* Read the encryption key */
-      if(!mmc_encr(base))
-	{
-	  ret = -EOPNOTSUPP;
-	  break;
-	}
-
-      /* only super-user can see encryption key */
-      if(!capable(CAP_NET_ADMIN))
-	{
-	  ret = -EPERM;
-	  break;
-	}
-
-      /* Basic checking... */
-      if(wrq->u.encoding.pointer != (caddr_t) 0)
-	{
-	  psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
-		   (unsigned char *) &psa.psa_encryption_select, 1+8);
-
-	  /* encryption is enabled ? */
-	  if(psa.psa_encryption_select)
-	    wrq->u.encoding.flags = IW_ENCODE_ENABLED;
-	  else
-	    wrq->u.encoding.flags = IW_ENCODE_DISABLED;
-	  wrq->u.encoding.flags |= mmc_encr(base);
-
-	  /* Copy the key to the user buffer */
-	  wrq->u.encoding.length = 8;
-	  if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8))
-	    ret = -EFAULT;
-	}
-      break;
-#endif	/* WIRELESS_EXT > 8 */
-
-#ifdef WAVELAN_ROAMING_EXT
-#if WIRELESS_EXT > 5
-    case SIOCSIWESSID:
-      /* Check if disable */
-      if(wrq->u.data.flags == 0)
-	lp->filter_domains = 0;
-      else
-	/* Basic checking... */
-	if(wrq->u.data.pointer != (caddr_t) 0)
-	  {
-	    char	essid[IW_ESSID_MAX_SIZE + 1];
-	    char *	endp;
-
-	    /* Check the size of the string */
-	    if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1)
-	      {
-		ret = -E2BIG;
-		break;
-	      }
-
-	    /* Copy the string in the driver */
-	    if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length))
-	      {
-		ret = -EFAULT;
-		break;
-	      }
-	    essid[IW_ESSID_MAX_SIZE] = '\0';
-
-#ifdef DEBUG_IOCTL_INFO
-	    printk(KERN_DEBUG "SetEssid : ``%s''\n", essid);
-#endif	/* DEBUG_IOCTL_INFO */
-
-	    /* Convert to a number (note : Wavelan specific) */
-	    lp->domain_id = simple_strtoul(essid, &endp, 16);
-	    /* Has it worked  ? */
-	    if(endp > essid)
-	      lp->filter_domains = 1;
-	    else
-	      {
-		lp->filter_domains = 0;
-		ret = -EINVAL;
-	      }
-	  }
-      break;
-
-    case SIOCGIWESSID:
-      /* Basic checking... */
-      if(wrq->u.data.pointer != (caddr_t) 0)
-	{
-	  char		essid[IW_ESSID_MAX_SIZE + 1];
-
-	  /* Is the domain ID active ? */
-	  wrq->u.data.flags = lp->filter_domains;
-
-	  /* Copy Domain ID into a string (Wavelan specific) */
-	  /* Sound crazy, be we can't have a snprintf in the kernel !!! */
-	  sprintf(essid, "%lX", lp->domain_id);
-	  essid[IW_ESSID_MAX_SIZE] = '\0';
-
-	  /* Set the length */
-	  wrq->u.data.length = strlen(essid) + 1;
-
-	  /* Copy structure to the user buffer */
-	  if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length))
-	    ret = -EFAULT;
-	}
-      break;
-
-    case SIOCSIWAP:
-#ifdef DEBUG_IOCTL_INFO
-      printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n",
-	     wrq->u.ap_addr.sa_data[0],
-	     wrq->u.ap_addr.sa_data[1],
-	     wrq->u.ap_addr.sa_data[2],
-	     wrq->u.ap_addr.sa_data[3],
-	     wrq->u.ap_addr.sa_data[4],
-	     wrq->u.ap_addr.sa_data[5]);
-#endif	/* DEBUG_IOCTL_INFO */
-
-      ret = -EOPNOTSUPP;	/* Not supported yet */
-      break;
-
-    case SIOCGIWAP:
-      /* Should get the real McCoy instead of own Ethernet address */
-      memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE);
-      wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
-
-      ret = -EOPNOTSUPP;	/* Not supported yet */
-      break;
-#endif	/* WIRELESS_EXT > 5 */
-#endif	/* WAVELAN_ROAMING_EXT */
-
-#if WIRELESS_EXT > 8
-#ifdef WAVELAN_ROAMING
-    case SIOCSIWMODE:
-      switch(wrq->u.mode)
-	{
-	case IW_MODE_ADHOC:
-	  if(do_roaming)
-	    {
-	      wv_roam_cleanup(dev);
-	      do_roaming = 0;
-	    }
-	  break;
-	case IW_MODE_INFRA:
-	  if(!do_roaming)
-	    {
-	      wv_roam_init(dev);
-	      do_roaming = 1;
-	    }
-	  break;
-	default:
-	  ret = -EINVAL;
-	}
-      break;
-
-    case SIOCGIWMODE:
-      if(do_roaming)
-	wrq->u.mode = IW_MODE_INFRA;
-      else
-	wrq->u.mode = IW_MODE_ADHOC;
-      break;
-#endif	/* WAVELAN_ROAMING */
-#endif /* WIRELESS_EXT > 8 */
-
-    case SIOCGIWRANGE:
-      /* Basic checking... */
-      if(wrq->u.data.pointer != (caddr_t) 0)
-	{
-	  struct iw_range	range;
-
-	  /* Set the length (very important for backward compatibility) */
-	  wrq->u.data.length = sizeof(struct iw_range);
-
-	  /* Set all the info we don't care or don't know about to zero */
-	  memset(&range, 0, sizeof(range));
-
-	  /* Set the Wireless Extension versions */
-	  range.we_version_compiled = WIRELESS_EXT;
-	  range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
-
-	  /* Set information in the range struct */
-	  range.throughput = 1.4 * 1000 * 1000;	/* don't argue on this ! */
-	  range.min_nwid = 0x0000;
-	  range.max_nwid = 0xFFFF;
-
-	  /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
-	  if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
-	       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
-	    {
-	      range.num_channels = 10;
-	      range.num_frequency = wv_frequency_list(base, range.freq,
-						      IW_MAX_FREQUENCIES);
-	    }
-	  else
-	    range.num_channels = range.num_frequency = 0;
-
-	  range.sensitivity = 0x3F;
-	  range.max_qual.qual = MMR_SGNL_QUAL;
-	  range.max_qual.level = MMR_SIGNAL_LVL;
-	  range.max_qual.noise = MMR_SILENCE_LVL;
-#if WIRELESS_EXT > 11
-	  range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
-	  /* Need to get better values for those two */
-	  range.avg_qual.level = 30;
-	  range.avg_qual.noise = 8;
-#endif /* WIRELESS_EXT > 11 */
-
-#if WIRELESS_EXT > 7
-	  range.num_bitrates = 1;
-	  range.bitrate[0] = 2000000;	/* 2 Mb/s */
-#endif /* WIRELESS_EXT > 7 */
-
-#if WIRELESS_EXT > 8
-	  /* Encryption supported ? */
-	  if(mmc_encr(base))
-	    {
-	      range.encoding_size[0] = 8;	/* DES = 64 bits key */
-	      range.num_encoding_sizes = 1;
-	      range.max_encoding_tokens = 1;	/* Only one key possible */
-	    }
-	  else
-	    {
-	      range.num_encoding_sizes = 0;
-	      range.max_encoding_tokens = 0;
-	    }
-#endif /* WIRELESS_EXT > 8 */
-
-	  /* Copy structure to the user buffer */
-	  if(copy_to_user(wrq->u.data.pointer, &range,
-			  sizeof(struct iw_range)))
-	    ret = -EFAULT;
-	}
-      break;
-
-    case SIOCGIWPRIV:
-      /* Basic checking... */
-      if(wrq->u.data.pointer != (caddr_t) 0)
-	{
-	  struct iw_priv_args	priv[] =
-	  {	/* cmd,		set_args,	get_args,	name */
-	    { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
-	    { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
-	    { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16,	0, "sethisto" },
-	    { SIOCGIPHISTO, 0,	    IW_PRIV_TYPE_INT | 16, "gethisto" },
-	    { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1 , 0, "setroam" },
-	    { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" },
-	  };
-
-	  /* Set the number of ioctl available */
-	  wrq->u.data.length = 6;
-
-	  /* Copy structure to the user buffer */
-	  if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
-		       sizeof(priv)))
-	    ret = -EFAULT;
-	}
-      break;
-
-#ifdef WIRELESS_SPY
-    case SIOCSIWSPY:
-      /* Set the spy list */
-
-      /* Check the number of addresses */
-      if(wrq->u.data.length > IW_MAX_SPY)
-	{
-	  ret = -E2BIG;
-	  break;
-	}
-      lp->spy_number = wrq->u.data.length;
-
-      /* If there is some addresses to copy */
-      if(lp->spy_number > 0)
-	{
-	  struct sockaddr	address[IW_MAX_SPY];
-	  int			i;
-
-	  /* Copy addresses to the driver */
-	  if(copy_from_user(address, wrq->u.data.pointer,
-			    sizeof(struct sockaddr) * lp->spy_number))
-	    {
-	      ret = -EFAULT;
-	      break;
-	    }
-
-	  /* Copy addresses to the lp structure */
-	  for(i = 0; i < lp->spy_number; i++)
-	    {
-	      memcpy(lp->spy_address[i], address[i].sa_data,
-		     WAVELAN_ADDR_SIZE);
-	    }
-
-	  /* Reset structure... */
-	  memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
-
-#ifdef DEBUG_IOCTL_INFO
-	  printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
-	  for(i = 0; i < wrq->u.data.length; i++)
-	    printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n",
-		   lp->spy_address[i][0],
-		   lp->spy_address[i][1],
-		   lp->spy_address[i][2],
-		   lp->spy_address[i][3],
-		   lp->spy_address[i][4],
-		   lp->spy_address[i][5]);
-#endif	/* DEBUG_IOCTL_INFO */
-	}
-
-      break;
-
-    case SIOCGIWSPY:
-      /* Get the spy list and spy stats */
-
-      /* Set the number of addresses */
-      wrq->u.data.length = lp->spy_number;
-
-      /* If the user want to have the addresses back... */
-      if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
-	{
-	  struct sockaddr	address[IW_MAX_SPY];
-	  int			i;
-
-	  /* Copy addresses from the lp structure */
-	  for(i = 0; i < lp->spy_number; i++)
-	    {
-	      memcpy(address[i].sa_data, lp->spy_address[i],
-		     WAVELAN_ADDR_SIZE);
-	      address[i].sa_family = ARPHRD_ETHER;
-	    }
-
-	  /* Copy addresses to the user buffer */
-	  if(copy_to_user(wrq->u.data.pointer, address,
-		       sizeof(struct sockaddr) * lp->spy_number))
-	    {
-	      ret = -EFAULT;
-	      break;
-	    }
-
-	  /* Copy stats to the user buffer (just after) */
-	  if(copy_to_user(wrq->u.data.pointer +
-		       (sizeof(struct sockaddr) * lp->spy_number),
-		       lp->spy_stat, sizeof(iw_qual) * lp->spy_number))
-	    {
-	      ret = -EFAULT;
-	      break;
-	    }
-
-	  /* Reset updated flags */
-	  for(i = 0; i < lp->spy_number; i++)
-	    lp->spy_stat[i].updated = 0x0;
-	}	/* if(pointer != NULL) */
-
-      break;
-#endif	/* WIRELESS_SPY */
-
-      /* ------------------ PRIVATE IOCTL ------------------ */
-
-    case SIOCSIPQTHR:
-      if(!capable(CAP_NET_ADMIN))
-	{
-	  ret = -EPERM;
-	  break;
-	}
-      psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
-      psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
-	       (unsigned char *)&psa.psa_quality_thr, 1);
-      /* update the Wavelan checksum */
-      update_psa_checksum(dev);
-      mmc_out(base, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr);
-      break;
-
-    case SIOCGIPQTHR:
-      psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
-	       (unsigned char *)&psa.psa_quality_thr, 1);
-      *(wrq->u.name) = psa.psa_quality_thr & 0x0F;
-      break;
-
-#ifdef WAVELAN_ROAMING
-    case SIOCSIPROAM:
-      /* Note : should check if user == root */
-      if(do_roaming && (*wrq->u.name)==0)
-	wv_roam_cleanup(dev);
-      else if(do_roaming==0 && (*wrq->u.name)!=0)
-	wv_roam_init(dev);
-
-      do_roaming = (*wrq->u.name);
-	  
-      break;
-
-    case SIOCGIPROAM:
-      *(wrq->u.name) = do_roaming;
-      break;
-#endif	/* WAVELAN_ROAMING */
-
-#ifdef HISTOGRAM
-    case SIOCSIPHISTO:
-      /* Verif if the user is root */
-      if(!capable(CAP_NET_ADMIN))
-	{
-	  ret = -EPERM;
-	}
-
-      /* Check the number of intervals */
-      if(wrq->u.data.length > 16)
-	{
-	  ret = -E2BIG;
-	  break;
-	}
-      lp->his_number = wrq->u.data.length;
-
-      /* If there is some addresses to copy */
-      if(lp->his_number > 0)
-	{
-	  /* Copy interval ranges to the driver */
-	  if(copy_from_user(lp->his_range, wrq->u.data.pointer,
-			 sizeof(char) * lp->his_number))
-	    {
-	      ret = -EFAULT;
-	      break;
-	    }
-
-	  /* Reset structure... */
-	  memset(lp->his_sum, 0x00, sizeof(long) * 16);
-	}
-      break;
-
-    case SIOCGIPHISTO:
-      /* Set the number of intervals */
-      wrq->u.data.length = lp->his_number;
-
-      /* Give back the distribution statistics */
-      if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
-	{
-	  /* Copy data to the user buffer */
-	  if(copy_to_user(wrq->u.data.pointer, lp->his_sum,
-		       sizeof(long) * lp->his_number))
-	    ret = -EFAULT;
-
-	}	/* if(pointer != NULL) */
-      break;
-#endif	/* HISTOGRAM */
-
-      /* ------------------- OTHER IOCTL ------------------- */
-
-    default:
-      ret = -EOPNOTSUPP;
-    }
-
-  /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-
-#ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
-#endif
-  return ret;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Get wireless statistics
- * Called by /proc/net/wireless...
- */
-static iw_stats *
-wavelan_get_wireless_stats(device *	dev)
-{
-  ioaddr_t		base = dev->base_addr;
-  net_local *		lp = (net_local *) dev->priv;
-  mmr_t			m;
-  iw_stats *		wstats;
-  unsigned long		flags;
-
-#ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
-#endif
-
-  if (lp == NULL) /* XXX will this ever occur? */
-    return NULL;
-
-  /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
-
-  wstats = &lp->wstats;
-
-  /* Get data from the mmc */
-  mmc_out(base, mmwoff(0, mmw_freeze), 1);
-
-  mmc_read(base, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
-  mmc_read(base, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2);
-  mmc_read(base, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4);
-
-  mmc_out(base, mmwoff(0, mmw_freeze), 0);
-
-  /* Copy data to wireless stuff */
-  wstats->status = m.mmr_dce_status & MMR_DCE_STATUS;
-  wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
-  wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
-  wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL;
-  wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) |
-			  ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) |
-			  ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5));
-  wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
-  wstats->discard.code = 0L;
-  wstats->discard.misc = 0L;
-
-  /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-
-#ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
-#endif
-  return &lp->wstats;
-}
-#endif	/* WIRELESS_EXT */
-
-/************************* PACKET RECEPTION *************************/
-/*
- * This part deal with receiving the packets.
- * The interrupt handler get an interrupt when a packet has been
- * successfully received and called this part...
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Calculate the starting address of the frame pointed to by the receive
- * frame pointer and verify that the frame seem correct
- * (called by wv_packet_rcv())
- */
-static inline int
-wv_start_of_frame(device *	dev,
-		  int		rfp,	/* end of frame */
-		  int		wrap)	/* start of buffer */
-{
-  ioaddr_t	base = dev->base_addr;
-  int		rp;
-  int		len;
-
-  rp = (rfp - 5 + RX_SIZE) % RX_SIZE;
-  outb(rp & 0xff, PIORL(base));
-  outb(((rp >> 8) & PIORH_MASK), PIORH(base));
-  len = inb(PIOP(base));
-  len |= inb(PIOP(base)) << 8;
-
-  /* Sanity checks on size */
-  /* Frame too big */
-  if(len > MAXDATAZ + 100)
-    {
-#ifdef DEBUG_RX_ERROR
-      printk(KERN_INFO "%s: wv_start_of_frame: Received frame too large, rfp %d len 0x%x\n",
-	     dev->name, rfp, len);
-#endif
-      return(-1);
-    }
-  
-  /* Frame too short */
-  if(len < 7)
-    {
-#ifdef DEBUG_RX_ERROR
-      printk(KERN_INFO "%s: wv_start_of_frame: Received null frame, rfp %d len 0x%x\n",
-	     dev->name, rfp, len);
-#endif
-      return(-1);
-    }
-  
-  /* Wrap around buffer */
-  if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE))	/* magic formula ! */
-    {
-#ifdef DEBUG_RX_ERROR
-      printk(KERN_INFO "%s: wv_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n",
-	     dev->name, wrap, rfp, len);
-#endif
-      return(-1);
-    }
-
-  return((rp - len + RX_SIZE) % RX_SIZE);
-} /* wv_start_of_frame */
-
-/*------------------------------------------------------------------*/
-/*
- * This routine does the actual copy of data (including the ethernet
- * header structure) from the WaveLAN card to an sk_buff chain that
- * will be passed up to the network interface layer. NOTE: We
- * currently don't handle trailer protocols (neither does the rest of
- * the network interface), so if that is needed, it will (at least in
- * part) be added here.  The contents of the receive ring buffer are
- * copied to a message chain that is then passed to the kernel.
- *
- * Note: if any errors occur, the packet is "dropped on the floor"
- * (called by wv_packet_rcv())
- */
-static inline void
-wv_packet_read(device *		dev,
-	       int		fd_p,
-	       int		sksize)
-{
-  net_local *		lp = (net_local *) dev->priv;
-  struct sk_buff *	skb;
-
-#ifdef DEBUG_RX_TRACE
-  printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n",
-	 dev->name, fd_p, sksize);
-#endif
-
-  /* Allocate some buffer for the new packet */
-  if((skb = dev_alloc_skb(sksize+2)) == (struct sk_buff *) NULL)
-    {
-#ifdef DEBUG_RX_ERROR
-      printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC)\n",
-	     dev->name, sksize);
-#endif
-      lp->stats.rx_dropped++;
-      /*
-       * Not only do we want to return here, but we also need to drop the
-       * packet on the floor to clear the interrupt.
-       */
-      return;
-    }
-
-  skb->dev = dev;
-
-  skb_reserve(skb, 2);
-  fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize);
-  skb->protocol = eth_type_trans(skb, dev);
-
-#ifdef DEBUG_RX_INFO
-  /* Another glitch : Due to the way the GET_PACKET macro is written,
-   * we are not sure to have the same thing in skb->data. On the other
-   * hand, skb->mac.raw is not defined everywhere...
-   * For versions between 1.2.13 and those where skb->mac.raw appear,
-   * I don't have a clue...
-   */
-  wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
-#endif	/* DEBUG_RX_INFO */
-     
-  /* Statistics gathering & stuff associated.
-   * It seem a bit messy with all the define, but it's really simple... */
-  if(
-#ifdef WIRELESS_SPY
-     (lp->spy_number > 0) ||
-#endif	/* WIRELESS_SPY */
-#ifdef HISTOGRAM
-     (lp->his_number > 0) ||
-#endif	/* HISTOGRAM */
-#ifdef WAVELAN_ROAMING
-     (do_roaming) ||
-#endif	/* WAVELAN_ROAMING */
-     0)
-    {
-      u_char	stats[3];	/* Signal level, Noise level, Signal quality */
-
-      /* read signal level, silence level and signal quality bytes */
-      fd_p = read_ringbuf(dev, (fd_p + 4) % RX_SIZE + RX_BASE,
-			  stats, 3);
-#ifdef DEBUG_RX_INFO
-      printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n",
-	     dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F);
-#endif
-
-#ifdef WAVELAN_ROAMING
-      if(do_roaming)
-	if(WAVELAN_BEACON(skb->data))
-	  wl_roam_gather(dev, skb->data, stats);
-#endif	/* WAVELAN_ROAMING */
-	  
-      /* Spying stuff */
-#ifdef WIRELESS_SPY
-      /* Same as above */
-      wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
-#endif	/* WIRELESS_SPY */
-#ifdef HISTOGRAM
-      wl_his_gather(dev, stats);
-#endif	/* HISTOGRAM */
-    }
-
-  /*
-   * Hand the packet to the Network Module
-   */
-  netif_rx(skb);
-
-  /* Keep stats up to date */
-  dev->last_rx = jiffies;
-  lp->stats.rx_packets++;
-  lp->stats.rx_bytes += sksize;
-
-#ifdef DEBUG_RX_TRACE
-  printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name);
-#endif
-  return;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * This routine is called by the interrupt handler to initiate a
- * packet transfer from the card to the network interface layer above
- * this driver.  This routine checks if a buffer has been successfully
- * received by the WaveLAN card.  If so, the routine wv_packet_read is
- * called to do the actual transfer of the card's data including the
- * ethernet header into a packet consisting of an sk_buff chain.
- * (called by wavelan_interrupt())
- */
-static inline void
-wv_packet_rcv(device *	dev)
-{
-  ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *) dev->priv;
-  int		newrfp;
-  int		rp;
-  int		len;
-  int		f_start;
-  int		status;
-  int		i593_rfp;
-  int		stat_ptr;
-  u_char	c[4];
-
-#ifdef DEBUG_RX_TRACE
-  printk(KERN_DEBUG "%s: ->wv_packet_rcv()\n", dev->name);
-#endif
-
-  /* Get the new receive frame pointer from the i82593 chip */
-  outb(CR0_STATUS_2 | OP0_NOP, LCCR(base));
-  i593_rfp = inb(LCSR(base));
-  i593_rfp |= inb(LCSR(base)) << 8;
-  i593_rfp %= RX_SIZE;
-
-  /* Get the new receive frame pointer from the WaveLAN card.
-   * It is 3 bytes more than the increment of the i82593 receive
-   * frame pointer, for each packet. This is because it includes the
-   * 3 roaming bytes added by the mmc.
-   */
-  newrfp = inb(RPLL(base));
-  newrfp |= inb(RPLH(base)) << 8;
-  newrfp %= RX_SIZE;
-
-#ifdef DEBUG_RX_INFO
-  printk(KERN_DEBUG "%s: wv_packet_rcv(): i593_rfp %d stop %d newrfp %d lp->rfp %d\n",
-	 dev->name, i593_rfp, lp->stop, newrfp, lp->rfp);
-#endif
-
-#ifdef DEBUG_RX_ERROR
-  /* If no new frame pointer... */
-  if(lp->overrunning || newrfp == lp->rfp)
-    printk(KERN_INFO "%s: wv_packet_rcv(): no new frame: i593_rfp %d stop %d newrfp %d lp->rfp %d\n",
-	   dev->name, i593_rfp, lp->stop, newrfp, lp->rfp);
-#endif
-
-  /* Read all frames (packets) received */
-  while(newrfp != lp->rfp)
-    {
-      /* A frame is composed of the packet, followed by a status word,
-       * the length of the frame (word) and the mmc info (SNR & qual).
-       * It's because the length is at the end that we can only scan
-       * frames backward. */
-
-      /* Find the first frame by skipping backwards over the frames */
-      rp = newrfp;	/* End of last frame */
-      while(((f_start = wv_start_of_frame(dev, rp, newrfp)) != lp->rfp) &&
-	    (f_start != -1))
-	  rp = f_start;
-
-      /* If we had a problem */
-      if(f_start == -1)
-	{
-#ifdef DEBUG_RX_ERROR
-	  printk(KERN_INFO "wavelan_cs: cannot find start of frame ");
-	  printk(" i593_rfp %d stop %d newrfp %d lp->rfp %d\n",
-		 i593_rfp, lp->stop, newrfp, lp->rfp);
-#endif
-	  lp->rfp = rp;		/* Get to the last usable frame */
-	  continue;
-	}
-
-      /* f_start point to the beggining of the first frame received
-       * and rp to the beggining of the next one */
-
-      /* Read status & length of the frame */
-      stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE;
-      stat_ptr = read_ringbuf(dev, stat_ptr, c, 4);
-      status = c[0] | (c[1] << 8);
-      len = c[2] | (c[3] << 8);
-
-      /* Check status */
-      if((status & RX_RCV_OK) != RX_RCV_OK)
-	{
-	  lp->stats.rx_errors++;
-	  if(status & RX_NO_SFD)
-	    lp->stats.rx_frame_errors++;
-	  if(status & RX_CRC_ERR)
-	    lp->stats.rx_crc_errors++;
-	  if(status & RX_OVRRUN)
-	    lp->stats.rx_over_errors++;
-
-#ifdef DEBUG_RX_FAIL
-	  printk(KERN_DEBUG "%s: wv_packet_rcv(): packet not received ok, status = 0x%x\n",
-		 dev->name, status);
-#endif
-	}
-      else
-	/* Read the packet and transmit to Linux */
-	wv_packet_read(dev, f_start, len - 2);
-
-      /* One frame has been processed, skip it */
-      lp->rfp = rp;
-    }
-
-  /*
-   * Update the frame stop register, but set it to less than
-   * the full 8K to allow space for 3 bytes of signal strength
-   * per packet.
-   */
-  lp->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
-  outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base));
-  outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
-  outb(OP1_SWIT_TO_PORT_0, LCCR(base));
-
-#ifdef DEBUG_RX_TRACE
-  printk(KERN_DEBUG "%s: <-wv_packet_rcv()\n", dev->name);
-#endif
-}
-
-/*********************** PACKET TRANSMISSION ***********************/
-/*
- * This part deal with sending packet through the wavelan
- * We copy the packet to the send buffer and then issue the send
- * command to the i82593. The result of this operation will be
- * checked in wavelan_interrupt()
- */
-
-/*------------------------------------------------------------------*/
-/*
- * This routine fills in the appropriate registers and memory
- * locations on the WaveLAN card and starts the card off on
- * the transmit.
- * (called in wavelan_packet_xmit())
- */
-static inline void
-wv_packet_write(device *	dev,
-		void *		buf,
-		short		length)
-{
-  net_local *		lp = (net_local *) dev->priv;
-  ioaddr_t		base = dev->base_addr;
-  unsigned long		flags;
-  int			clen = length;
-  register u_short	xmtdata_base = TX_BASE;
-
-#ifdef DEBUG_TX_TRACE
-  printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
-#endif
-
-  spin_lock_irqsave (&lp->lock, flags);
-
-  /* Check if we need some padding */
-  if(clen < ETH_ZLEN)
-    clen = ETH_ZLEN;
-
-  /* Write the length of data buffer followed by the buffer */
-  outb(xmtdata_base & 0xff, PIORL(base));
-  outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
-  outb(clen & 0xff, PIOP(base));	/* lsb */
-  outb(clen >> 8, PIOP(base));  	/* msb */
-
-  /* Send the data */
-  outsb(PIOP(base), buf, clen);
-
-  /* Indicate end of transmit chain */
-  outb(OP0_NOP, PIOP(base));
-  /* josullvn@cs.cmu.edu: need to send a second NOP for alignment... */
-  outb(OP0_NOP, PIOP(base));
-
-  /* Reset the transmit DMA pointer */
-  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
-  hacr_write(base, HACR_DEFAULT);
-  /* Send the transmit command */
-  wv_82593_cmd(dev, "wv_packet_write(): transmit",
-	       OP0_TRANSMIT, SR0_NO_RESULT);
-
-  /* Keep stats up to date */
-  lp->stats.tx_bytes += length;
-
-  /* If watchdog not already active, activate it... */
-  if (!timer_pending(&lp->watchdog))
-    {
-      /* set timer to expire in WATCHDOG_JIFFIES */
-      lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
-      add_timer(&lp->watchdog);
-    }
-
-  spin_unlock_irqrestore (&lp->lock, flags);
-
-#ifdef DEBUG_TX_INFO
-  wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
-#endif	/* DEBUG_TX_INFO */
-
-#ifdef DEBUG_TX_TRACE
-  printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
-#endif
-
-  netif_start_queue (dev);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the hardware is ready to accept
- * the packet. We also prevent reentrance. Then, we call the function
- * to send the packet...
- */
-static int wavelan_packet_xmit (struct sk_buff *skb,
-				device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-
-#ifdef DEBUG_TX_TRACE
-	printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
-		(unsigned) skb);
-#endif
-
-	/*
-	 * For ethernet, fill in the header.
-	 */
-
-	netif_stop_queue (dev);
-
-	/*
-	 * Block a timer-based transmit from overlapping a previous transmit.
-	 * In other words, prevent reentering this routine.
-	 */
-	if (1) {
-		/* If somebody has asked to reconfigure the controller, we can do it now */
-		if (lp->reconfig_82593) {
-			lp->reconfig_82593 = FALSE;
-			wv_82593_config (dev);
-		}
-#ifdef DEBUG_TX_ERROR
-		if (skb->next)
-			printk (KERN_INFO "skb has next\n");
-#endif
-
-		wv_packet_write (dev, skb->data, skb->len);
-	}
-	dev_kfree_skb (skb);
-
-#ifdef DEBUG_TX_TRACE
-	printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
-#endif
-	return (0);
-}
-
-/********************** HARDWARE CONFIGURATION **********************/
-/*
- * This part do the real job of starting and configuring the hardware.
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Routine to initialize the Modem Management Controller.
- * (called by wv_hw_config())
- */
-static inline int
-wv_mmc_init(device *	dev)
-{
-  ioaddr_t	base = dev->base_addr;
-  psa_t		psa;
-  mmw_t		m;
-  int		configured;
-  int		i;		/* Loop counter */
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
-#endif
-
-  /* Read the parameter storage area */
-  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
-
-  /*
-   * Check the first three octets of the MAC addr for the manufacturer's code.
-   * Note: If you get the error message below, you've got a
-   * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on
-   * how to configure your card...
-   */
-  for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
-    if((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) &&
-       (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) &&
-       (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2]))
-      break;
-
-  /* If we have not found it... */
-  if(i == (sizeof(MAC_ADDRESSES) / sizeof(char) / 3))
-    {
-#ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n",
-	     dev->name, psa.psa_univ_mac_addr[0],
-	     psa.psa_univ_mac_addr[1], psa.psa_univ_mac_addr[2]);
-#endif
-      return FALSE;
-    }
-
-  /* Get the MAC address */
-  memcpy(&dev->dev_addr[0], &psa.psa_univ_mac_addr[0], WAVELAN_ADDR_SIZE);
-
-#ifdef USE_PSA_CONFIG
-  configured = psa.psa_conf_status & 1;
-#else
-  configured = 0;
-#endif
-
-  /* Is the PSA is not configured */
-  if(!configured)
-    {
-      /* User will be able to configure NWID after (with iwconfig) */
-      psa.psa_nwid[0] = 0;
-      psa.psa_nwid[1] = 0;
-
-      /* As NWID is not set : no NWID checking */
-      psa.psa_nwid_select = 0;
-
-      /* Disable encryption */
-      psa.psa_encryption_select = 0;
-
-      /* Set to standard values
-       * 0x04 for AT,
-       * 0x01 for MCA,
-       * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
-       */
-      if (psa.psa_comp_number & 1)
-	psa.psa_thr_pre_set = 0x01;
-      else
-	psa.psa_thr_pre_set = 0x04;
-      psa.psa_quality_thr = 0x03;
-
-      /* It is configured */
-      psa.psa_conf_status |= 1;
-
-#ifdef USE_PSA_CONFIG
-      /* Write the psa */
-      psa_write(dev, (char *)psa.psa_nwid - (char *)&psa,
-		(unsigned char *)psa.psa_nwid, 4);
-      psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
-		(unsigned char *)&psa.psa_thr_pre_set, 1);
-      psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
-		(unsigned char *)&psa.psa_quality_thr, 1);
-      psa_write(dev, (char *)&psa.psa_conf_status - (char *)&psa,
-		(unsigned char *)&psa.psa_conf_status, 1);
-      /* update the Wavelan checksum */
-      update_psa_checksum(dev);
-#endif	/* USE_PSA_CONFIG */
-    }
-
-  /* Zero the mmc structure */
-  memset(&m, 0x00, sizeof(m));
-
-  /* Copy PSA info to the mmc */
-  m.mmw_netw_id_l = psa.psa_nwid[1];
-  m.mmw_netw_id_h = psa.psa_nwid[0];
-  
-  if(psa.psa_nwid_select & 1)
-    m.mmw_loopt_sel = 0x00;
-  else
-    m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID;
-
-  memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, 
-	 sizeof(m.mmw_encr_key));
-
-  if(psa.psa_encryption_select)
-    m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE;
-  else
-    m.mmw_encr_enable = 0;
-
-  m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
-  m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
-
-  /*
-   * Set default modem control parameters.
-   * See NCR document 407-0024326 Rev. A.
-   */
-  m.mmw_jabber_enable = 0x01;
-  m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
-  m.mmw_ifs = 0x20;
-  m.mmw_mod_delay = 0x04;
-  m.mmw_jam_time = 0x38;
-
-  m.mmw_des_io_invert = 0;
-  m.mmw_freeze = 0;
-  m.mmw_decay_prm = 0;
-  m.mmw_decay_updat_prm = 0;
-
-  /* Write all info to mmc */
-  mmc_write(base, 0, (u_char *)&m, sizeof(m));
-
-  /* The following code start the modem of the 2.00 frequency
-   * selectable cards at power on. It's not strictly needed for the
-   * following boots...
-   * The original patch was by Joe Finney for the PCMCIA driver, but
-   * I've cleaned it a bit and add documentation.
-   * Thanks to Loeke Brederveld from Lucent for the info.
-   */
-
-  /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-   * (does it work for everybody XXX - especially old cards...) */
-  /* Note : WFREQSEL verify that it is able to read from EEprom
-   * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
-   * is 0xA (Xilinx version) or 0xB (Ariadne version).
-   * My test is more crude but do work... */
-  if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
-       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
-    {
-      /* We must download the frequency parameters to the
-       * synthetisers (from the EEprom - area 1)
-       * Note : as the EEprom is auto decremented, we set the end
-       * if the area... */
-      m.mmw_fee_addr = 0x0F;
-      m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
-      mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m,
-		(unsigned char *)&m.mmw_fee_ctrl, 2);
-
-      /* Wait until the download is finished */
-      fee_wait(base, 100, 100);
-
-#ifdef DEBUG_CONFIG_INFO
-      /* The frequency was in the last word downloaded... */
-      mmc_read(base, (char *)&m.mmw_fee_data_l - (char *)&m,
-	       (unsigned char *)&m.mmw_fee_data_l, 2);
-
-      /* Print some info for the user */
-      printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n",
-	     dev->name,
-	     ((m.mmw_fee_data_h << 4) |
-	      (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L);
-#endif
-
-      /* We must now download the power adjust value (gain) to
-       * the synthetisers (from the EEprom - area 7 - DAC) */
-      m.mmw_fee_addr = 0x61;
-      m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
-      mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m,
-		(unsigned char *)&m.mmw_fee_ctrl, 2);
-
-      /* Wait until the download is finished */
-    }	/* if 2.00 card */
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name);
-#endif
-  return TRUE;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Routine to gracefully turn off reception, and wait for any commands
- * to complete.
- * (called in wv_ru_start() and wavelan_close() and wavelan_event())
- */
-static int
-wv_ru_stop(device *	dev)
-{
-  ioaddr_t	base = dev->base_addr;
-  net_local *lp = (net_local *) dev->priv;
-  unsigned long	flags;
-  int		status;
-  int		spin;
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
-#endif
-
-  /* First, send the LAN controller a stop receive command */
-  wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
-	       OP0_STOP_RCV, SR0_NO_RESULT);
-
-  /* Then, spin until the receive unit goes idle */
-  spin = 0;
-  do
-    {
-      udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
-      outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
-      status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
-    }
-  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300));
-
-  /* Now, spin until the chip finishes executing its current command */
-  do
-    {
-      udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
-      outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
-      status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
-    }
-  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300));
-
-  /* If there was a problem */
-  if(spin > 300)
-    {
-#ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n",
-	     dev->name);
-#endif
-      return FALSE;
-    }
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_ru_stop()\n", dev->name);
-#endif
-  return TRUE;
-} /* wv_ru_stop */
-
-/*------------------------------------------------------------------*/
-/*
- * This routine starts the receive unit running.  First, it checks if
- * the card is actually ready. Then the card is instructed to receive
- * packets again.
- * (called in wv_hw_reset() & wavelan_open())
- */
-static int
-wv_ru_start(device *	dev)
-{
-  ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *) dev->priv;
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
-#endif
-
-  /*
-   * We need to start from a quiescent state. To do so, we could check
-   * if the card is already running, but instead we just try to shut
-   * it down. First, we disable reception (in case it was already enabled).
-   */
-  if(!wv_ru_stop(dev))
-    return FALSE;
-
-  /* Now we know that no command is being executed. */
-
-  /* Set the receive frame pointer and stop pointer */
-  lp->rfp = 0;
-  outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base));
-
-  /* Reset ring management.  This sets the receive frame pointer to 1 */
-  outb(OP1_RESET_RING_MNGMT, LCCR(base));
-
-  /* but I set it to 3 bytes per packet less than 8K */
-  lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
-  outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
-  outb(OP1_INT_ENABLE, LCCR(base));
-  outb(OP1_SWIT_TO_PORT_0, LCCR(base));
-
-  /* Reset receive DMA pointer */
-  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
-  hacr_write_slow(base, HACR_DEFAULT);
-
-  /* Receive DMA on channel 1 */
-  wv_82593_cmd(dev, "wv_ru_start(): rcv-enable",
-	       CR0_CHNL | OP0_RCV_ENABLE, SR0_NO_RESULT);
-
-#ifdef DEBUG_I82593_SHOW
-  {
-    int	status;
-    unsigned long flags;
-    int	i = 0;
-
-    /* spin until the chip starts receiving */
-    do
-      {
-	spin_lock_irqsave (&lp->lock, flags);
-	outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
-	status = inb(LCSR(base));
-	spin_unlock_irqrestore (&lp->lock, flags);
-	if(i++ > 10000)
-	  break;
-      }
-    while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) &&
-	  ((status & SR3_RCV_STATE_MASK) != SR3_RCV_READY));
-    printk(KERN_DEBUG "rcv status is 0x%x [i:%d]\n",
-	   (status & SR3_RCV_STATE_MASK), i);
-  }
-#endif
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
-#endif
-  return TRUE;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * This routine does a standard config of the WaveLAN controller (i82593).
- * In the ISA driver, this is integrated in wavelan_hardware_reset()
- * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit())
- */
-static int
-wv_82593_config(device *	dev)
-{
-  ioaddr_t			base = dev->base_addr;
-  net_local *			lp = (net_local *) dev->priv;
-  struct i82593_conf_block	cfblk;
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name);
-#endif
-
-  /* Create & fill i82593 config block
-   *
-   * Now conform to Wavelan document WCIN085B
-   */
-  memset(&cfblk, 0x00, sizeof(struct i82593_conf_block));
-  cfblk.d6mod = FALSE;  	/* Run in i82593 advanced mode */
-  cfblk.fifo_limit = 5;         /* = 56 B rx and 40 B tx fifo thresholds */
-  cfblk.forgnesi = FALSE;       /* 0=82C501, 1=AMD7992B compatibility */
-  cfblk.fifo_32 = 1;
-  cfblk.throttle_enb = FALSE;
-  cfblk.contin = TRUE;          /* enable continuous mode */
-  cfblk.cntrxint = FALSE;       /* enable continuous mode receive interrupts */
-  cfblk.addr_len = WAVELAN_ADDR_SIZE;
-  cfblk.acloc = TRUE;           /* Disable source addr insertion by i82593 */
-  cfblk.preamb_len = 0;         /* 2 bytes preamble (SFD) */
-  cfblk.loopback = FALSE;
-  cfblk.lin_prio = 0;   	/* conform to 802.3 backoff algoritm */
-  cfblk.exp_prio = 5;	        /* conform to 802.3 backoff algoritm */
-  cfblk.bof_met = 1;	        /* conform to 802.3 backoff algoritm */
-  cfblk.ifrm_spc = 0x20;	/* 32 bit times interframe spacing */
-  cfblk.slottim_low = 0x20;	/* 32 bit times slot time */
-  cfblk.slottim_hi = 0x0;
-  cfblk.max_retr = 15;
-  cfblk.prmisc = ((lp->promiscuous) ? TRUE: FALSE);	/* Promiscuous mode */
-  cfblk.bc_dis = FALSE;         /* Enable broadcast reception */
-  cfblk.crs_1 = TRUE;		/* Transmit without carrier sense */
-  cfblk.nocrc_ins = FALSE;	/* i82593 generates CRC */	
-  cfblk.crc_1632 = FALSE;	/* 32-bit Autodin-II CRC */
-  cfblk.crs_cdt = FALSE;	/* CD not to be interpreted as CS */
-  cfblk.cs_filter = 0;  	/* CS is recognized immediately */
-  cfblk.crs_src = FALSE;	/* External carrier sense */
-  cfblk.cd_filter = 0;  	/* CD is recognized immediately */
-  cfblk.min_fr_len = ETH_ZLEN >> 2;     /* Minimum frame length 64 bytes */
-  cfblk.lng_typ = FALSE;	/* Length field > 1500 = type field */
-  cfblk.lng_fld = TRUE; 	/* Disable 802.3 length field check */
-  cfblk.rxcrc_xf = TRUE;	/* Don't transfer CRC to memory */
-  cfblk.artx = TRUE;		/* Disable automatic retransmission */
-  cfblk.sarec = TRUE;		/* Disable source addr trig of CD */
-  cfblk.tx_jabber = TRUE;	/* Disable jabber jam sequence */
-  cfblk.hash_1 = FALSE; 	/* Use bits 0-5 in mc address hash */
-  cfblk.lbpkpol = TRUE; 	/* Loopback pin active high */
-  cfblk.fdx = FALSE;		/* Disable full duplex operation */
-  cfblk.dummy_6 = 0x3f; 	/* all ones */
-  cfblk.mult_ia = FALSE;	/* No multiple individual addresses */
-  cfblk.dis_bof = FALSE;	/* Disable the backoff algorithm ?! */
-  cfblk.dummy_1 = TRUE; 	/* set to 1 */
-  cfblk.tx_ifs_retrig = 3;	/* Hmm... Disabled */
-#ifdef MULTICAST_ALL
-  cfblk.mc_all = (lp->allmulticast ? TRUE: FALSE);	/* Allow all multicasts */
-#else
-  cfblk.mc_all = FALSE;		/* No multicast all mode */
-#endif
-  cfblk.rcv_mon = 0;		/* Monitor mode disabled */
-  cfblk.frag_acpt = TRUE;	/* Do not accept fragments */
-  cfblk.tstrttrs = FALSE;	/* No start transmission threshold */
-  cfblk.fretx = TRUE;		/* FIFO automatic retransmission */
-  cfblk.syncrqs = FALSE; 	/* Synchronous DRQ deassertion... */
-  cfblk.sttlen = TRUE;  	/* 6 byte status registers */
-  cfblk.rx_eop = TRUE;  	/* Signal EOP on packet reception */
-  cfblk.tx_eop = TRUE;  	/* Signal EOP on packet transmission */
-  cfblk.rbuf_size = RX_SIZE>>11;	/* Set receive buffer size */
-  cfblk.rcvstop = TRUE; 	/* Enable Receive Stop Register */
-
-#ifdef DEBUG_I82593_SHOW
-  {
-    u_char *c = (u_char *) &cfblk;
-    int i;
-    printk(KERN_DEBUG "wavelan_cs: config block:");
-    for(i = 0; i < sizeof(struct i82593_conf_block); i++,c++)
-      {
-	if((i % 16) == 0) printk("\n" KERN_DEBUG);
-	printk("%02x ", *c);
-      }
-    printk("\n");
-  }
-#endif
-
-  /* Copy the config block to the i82593 */
-  outb(TX_BASE & 0xff, PIORL(base));
-  outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
-  outb(sizeof(struct i82593_conf_block) & 0xff, PIOP(base));    /* lsb */
-  outb(sizeof(struct i82593_conf_block) >> 8, PIOP(base));	/* msb */
-  outsb(PIOP(base), (char *) &cfblk, sizeof(struct i82593_conf_block));
-
-  /* reset transmit DMA pointer */
-  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
-  hacr_write(base, HACR_DEFAULT);
-  if(!wv_82593_cmd(dev, "wv_82593_config(): configure",
-		   OP0_CONFIGURE, SR0_CONFIGURE_DONE))
-    return(FALSE);
-
-  /* Initialize adapter's ethernet MAC address */
-  outb(TX_BASE & 0xff, PIORL(base));
-  outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
-  outb(WAVELAN_ADDR_SIZE, PIOP(base));	/* byte count lsb */
-  outb(0, PIOP(base));			/* byte count msb */
-  outsb(PIOP(base), &dev->dev_addr[0], WAVELAN_ADDR_SIZE);
-
-  /* reset transmit DMA pointer */
-  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
-  hacr_write(base, HACR_DEFAULT);
-  if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup",
-		   OP0_IA_SETUP, SR0_IA_SETUP_DONE))
-    return(FALSE);
-
-#ifdef WAVELAN_ROAMING
-    /* If roaming is enabled, join the "Beacon Request" multicast group... */
-    /* But only if it's not in there already! */
-  if(do_roaming)
-    dev_mc_add(dev,WAVELAN_BEACON_ADDRESS, WAVELAN_ADDR_SIZE, 1);
-#endif	/* WAVELAN_ROAMING */
-
-  /* If any multicast address to set */
-  if(lp->mc_count)
-    {
-      struct dev_mc_list *	dmi;
-      int			addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count;
-
-#ifdef DEBUG_CONFIG_INFO
-      printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n",
-	     dev->name, lp->mc_count);
-      for(dmi=dev->mc_list; dmi; dmi=dmi->next)
-	printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
-	       dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] );
-#endif
-
-      /* Initialize adapter's ethernet multicast addresses */
-      outb(TX_BASE & 0xff, PIORL(base));
-      outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
-      outb(addrs_len & 0xff, PIOP(base));	/* byte count lsb */
-      outb((addrs_len >> 8), PIOP(base));	/* byte count msb */
-      for(dmi=dev->mc_list; dmi; dmi=dmi->next)
-	outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen);
-
-      /* reset transmit DMA pointer */
-      hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
-      hacr_write(base, HACR_DEFAULT);
-      if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup",
-		       OP0_MC_SETUP, SR0_MC_SETUP_DONE))
-	return(FALSE);
-      lp->mc_count = dev->mc_count;	/* remember to avoid repeated reset */
-    }
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name);
-#endif
-  return(TRUE);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Read the Access Configuration Register, perform a software reset,
- * and then re-enable the card's software.
- *
- * If I understand correctly : reset the pcmcia interface of the
- * wavelan.
- * (called by wv_config())
- */
-static inline int
-wv_pcmcia_reset(device *	dev)
-{
-  int		i;
-  conf_reg_t	reg = { 0, CS_READ, CISREG_COR, 0 };
-  dev_link_t *	link = ((net_local *) dev->priv)->link;
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name);
-#endif
-
-  i = CardServices(AccessConfigurationRegister, link->handle, &reg);
-  if(i != CS_SUCCESS)
-    {
-      cs_error(link->handle, AccessConfigurationRegister, i);
-      return FALSE;
-    }
-      
-#ifdef DEBUG_CONFIG_INFO
-  printk(KERN_DEBUG "%s: wavelan_pcmcia_reset(): Config reg is 0x%x\n",
-	 dev->name, (u_int) reg.Value);
-#endif
-
-  reg.Action = CS_WRITE;
-  reg.Value = reg.Value | COR_SW_RESET;
-  i = CardServices(AccessConfigurationRegister, link->handle, &reg);
-  if(i != CS_SUCCESS)
-    {
-      cs_error(link->handle, AccessConfigurationRegister, i);
-      return FALSE;
-    }
-      
-  reg.Action = CS_WRITE;
-  reg.Value = COR_LEVEL_IRQ | COR_CONFIG;
-  i = CardServices(AccessConfigurationRegister, link->handle, &reg);
-  if(i != CS_SUCCESS)
-    {
-      cs_error(link->handle, AccessConfigurationRegister, i);
-      return FALSE;
-    }
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_pcmcia_reset()\n", dev->name);
-#endif
-  return TRUE;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * wavelan_hw_config() is called after a CARD_INSERTION event is
- * received, to configure the wavelan hardware.
- * Note that the reception will be enabled in wavelan->open(), so the
- * device is configured but idle...
- * Performs the following actions:
- * 	1. A pcmcia software reset (using wv_pcmcia_reset())
- *	2. A power reset (reset DMA)
- *	3. Reset the LAN controller
- *	4. Initialize the radio modem (using wv_mmc_init)
- *	5. Configure LAN controller (using wv_82593_config)
- *	6. Perform a diagnostic on the LAN controller
- * (called by wavelan_event() & wv_hw_reset())
- */
-static int
-wv_hw_config(device *	dev)
-{
-  net_local *		lp = (net_local *) dev->priv;
-  ioaddr_t		base = dev->base_addr;
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name);
-#endif
-
-#ifdef STRUCT_CHECK
-  if(wv_structuct_check() != (char *) NULL)
-    {
-      printk(KERN_WARNING "%s: wv_hw_config: structure/compiler botch: \"%s\"\n",
-	     dev->name, wv_structuct_check());
-      return FALSE;
-    }
-#endif	/* STRUCT_CHECK == 1 */
-
-  /* Reset the pcmcia interface */
-  if(wv_pcmcia_reset(dev) == FALSE)
-    return FALSE;
-
-  /* Power UP the module + reset the modem + reset host adapter
-   * (in fact, reset DMA channels) */
-  hacr_write_slow(base, HACR_RESET);
-  hacr_write(base, HACR_DEFAULT);
-
-  /* Check if the module has been powered up... */
-  if(hasr_read(base) & HASR_NO_CLK)
-    {
-#ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
-	     dev->name);
-#endif
-      return FALSE;
-    }
-
-  /* initialize the modem */
-  if(wv_mmc_init(dev) == FALSE)
-    return FALSE;
-
-  /* reset the LAN controller (i82593) */
-  outb(OP0_RESET, LCCR(base));
-  mdelay(1);	/* A bit crude ! */
-
-  /* Initialize the LAN controller */
-  if((wv_82593_config(dev) == FALSE) ||
-     (wv_diag(dev) == FALSE))
-    {
-#ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name);
-#endif
-      return FALSE;
-    }
-
-  /* 
-   * insert code for loopback test here
-   */
-
-  /* The device is now configured */
-  lp->configured = 1;
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
-#endif
-  return TRUE;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Totally reset the wavelan and restart it.
- * Performs the following actions:
- * 	1. Call wv_hw_config()
- *	2. Start the LAN controller's receive unit
- * (called by wavelan_event(), wavelan_watchdog() and wavelan_open())
- */
-static inline void
-wv_hw_reset(device *	dev)
-{
-  net_local *	lp = (net_local *) dev->priv;
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
-#endif
-
-  /* If watchdog was activated, kill it ! */
-  if (timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
-  lp->nresets++;
-  lp->configured = 0;
-  
-  /* Call wv_hw_config() for most of the reset & init stuff */
-  if(wv_hw_config(dev) == FALSE)
-    return;
-
-  /* start receive unit */
-  wv_ru_start(dev);
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name);
-#endif
-}
-
-/*------------------------------------------------------------------*/
-/*
- * wv_pcmcia_config() is called after a CARD_INSERTION event is
- * received, to configure the PCMCIA socket, and to make the ethernet
- * device available to the system.
- * (called by wavelan_event())
- */
-static inline int
-wv_pcmcia_config(dev_link_t *	link)
-{
-  client_handle_t	handle;
-  tuple_t		tuple;
-  cisparse_t		parse;
-  struct net_device *	dev;
-  int			i;
-  u_char		buf[64];
-  win_req_t		req;
-  memreq_t		mem;
-
-  handle = link->handle;
-  dev = (device *) link->priv;
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link);
-#endif
-
-  /*
-   * This reads the card's CONFIG tuple to find its configuration
-   * registers.
-   */
-  do
-    {
-      tuple.Attributes = 0;
-      tuple.DesiredTuple = CISTPL_CONFIG;
-      i = CardServices(GetFirstTuple, handle, &tuple);
-      if(i != CS_SUCCESS)
-	break;
-      tuple.TupleData = (cisdata_t *)buf;
-      tuple.TupleDataMax = 64;
-      tuple.TupleOffset = 0;
-      i = CardServices(GetTupleData, handle, &tuple);
-      if(i != CS_SUCCESS)
-	break;
-      i = CardServices(ParseTuple, handle, &tuple, &parse);
-      if(i != CS_SUCCESS)
-	break;
-      link->conf.ConfigBase = parse.config.base;
-      link->conf.Present = parse.config.rmask[0];
-    }
-  while(0);
-  if(i != CS_SUCCESS)
-    {
-      cs_error(link->handle, ParseTuple, i);
-      link->state &= ~DEV_CONFIG_PENDING;
-      return FALSE;
-    }
-    
-  /* Configure card */
-  link->state |= DEV_CONFIG;
-  do
-    {
-      i = CardServices(RequestIO, link->handle, &link->io);
-      if(i != CS_SUCCESS)
-	{
-	  cs_error(link->handle, RequestIO, i);
-	  break;
-	}
-
-      /*
-       * Now allocate an interrupt line.  Note that this does not
-       * actually assign a handler to the interrupt.
-       */
-      i = CardServices(RequestIRQ, link->handle, &link->irq);
-      if(i != CS_SUCCESS)
-	{
-	  cs_error(link->handle, RequestIRQ, i);
-	  break;
-	}
-
-      /*
-       * This actually configures the PCMCIA socket -- setting up
-       * the I/O windows and the interrupt mapping.
-       */
-      link->conf.ConfigIndex = 1;
-      i = CardServices(RequestConfiguration, link->handle, &link->conf);
-      if(i != CS_SUCCESS)
-	{
-	  cs_error(link->handle, RequestConfiguration, i);
-	  break;
-	}
-
-      /*
-       * Allocate a 4K memory window.  Note that the dev_link_t
-       * structure provides space for one window handle -- if your
-       * device needs several windows, you'll need to keep track of
-       * the handles in your private data structure, link->priv.
-       */
-      req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-      req.Base = 0; req.Size = 0x1000;
-      req.AccessSpeed = mem_speed;
-      link->win = (window_handle_t)link->handle;
-      i = CardServices(RequestWindow, &link->win, &req);
-      if(i != CS_SUCCESS)
-	{
-	  cs_error(link->handle, RequestWindow, i);
-	  break;
-	}
-
-      dev->rmem_start = dev->mem_start =
-	  (u_long)ioremap(req.Base, 0x1000);
-      dev->rmem_end = dev->mem_end = dev->mem_start + req.Size;
-
-      mem.CardOffset = 0; mem.Page = 0;
-      i = CardServices(MapMemPage, link->win, &mem);
-      if(i != CS_SUCCESS)
-	{
-	  cs_error(link->handle, MapMemPage, i);
-	  break;
-	}
-
-      /* Feed device with this info... */
-      dev->irq = link->irq.AssignedIRQ;
-      dev->base_addr = link->io.BasePort1;
-      netif_start_queue (dev);
-
-#ifdef DEBUG_CONFIG_INFO
-      printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
-	     (u_int) dev->mem_start, dev->irq, (u_int) dev->base_addr);
-#endif
-
-      i = register_netdev(dev);
-      if(i != 0)
-	{
-#ifdef DEBUG_CONFIG_ERRORS
-	  printk(KERN_INFO "wv_pcmcia_config(): register_netdev() failed\n");
-#endif
-	  break;
-	}
-    }
-  while(0);		/* Humm... Disguised goto !!! */
-
-  link->state &= ~DEV_CONFIG_PENDING;
-  /* If any step failed, release any partially configured state */
-  if(i != 0)
-    {
-      wv_pcmcia_release((u_long) link);
-      return FALSE;
-    }
-
-  /* XXX Could you explain me this, Dave ? */
-  link->dev = &((net_local *) dev->priv)->node;
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "<-wv_pcmcia_config()\n");
-#endif
-  return TRUE;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * After a card is removed, wv_pcmcia_release() will unregister the net
- * device, and release the PCMCIA configuration.  If the device is
- * still open, this will be postponed until it is closed.
- */
-static void
-wv_pcmcia_release(u_long	arg)	/* Address of the interface struct */
-{
-  dev_link_t *	link = (dev_link_t *) arg;
-  device *	dev = (device *) link->priv;
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link);
-#endif
-
-  /* If the device is currently in use, we won't release until it is
-   * actually closed. */
-  if(link->open)
-    {
-#ifdef DEBUG_CONFIG_INFO
-      printk(KERN_DEBUG "%s: wv_pcmcia_release: release postponed, device still open\n",
-	     dev->name);
-#endif
-      link->state |= DEV_STALE_CONFIG;
-      return;
-    }
-
-  /* Don't bother checking to see if these succeed or not */
-  iounmap((u_char *)dev->mem_start);
-  CardServices(ReleaseWindow, link->win);
-  CardServices(ReleaseConfiguration, link->handle);
-  CardServices(ReleaseIO, link->handle, &link->io);
-  CardServices(ReleaseIRQ, link->handle, &link->irq);
-
-  link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG);
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
-#endif
-} /* wv_pcmcia_release */
-
-/*------------------------------------------------------------------*/
-/*
- * Sometimes, netwave_detach can't be performed following a call from
- * cardmgr (device still open, pcmcia_release not done) and the device
- * is put in a STALE_LINK state and remains in memory.
- *
- * This function run through our current list of device and attempt
- * another time to remove them. We hope that since last time the
- * device has properly been closed.
- *
- * (called by wavelan_attach() & cleanup_module())
- */
-static void
-wv_flush_stale_links(void)
-{
-  dev_link_t *	link;		/* Current node in linked list */
-  dev_link_t *	next;		/* Next node in linked list */
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "-> wv_flush_stale_links(0x%p)\n", dev_list);
-#endif
-
-  /* Go through the list */
-  for (link = dev_list; link; link = next)
-    {
-      next = link->next;
-
-      /* Check if in need of being removed */
-      if((link->state & DEV_STALE_LINK) ||
-	 (! (link->state & DEV_PRESENT)))
-	wavelan_detach(link);
-
-    }
-
-#ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "<- wv_flush_stale_links()\n");
-#endif
-}
-
-/************************ INTERRUPT HANDLING ************************/
-
-/*
- * This function is the interrupt handler for the WaveLAN card. This
- * routine will be called whenever: 
- *	1. A packet is received.
- *	2. A packet has successfully been transferred and the unit is
- *	   ready to transmit another packet.
- *	3. A command has completed execution.
- */
-static void
-wavelan_interrupt(int		irq,
-		  void *	dev_id,
-		  struct pt_regs * regs)
-{
-  device *	dev;
-  net_local *	lp;
-  ioaddr_t	base;
-  int		status0;
-  u_int		tx_status;
-
-  if((dev = (device *)dev_id) == (device *) NULL)
-    {
-#ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n",
-	     irq);
-#endif
-      return;
-    }
-
-#ifdef DEBUG_INTERRUPT_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
-#endif
-
-  lp = (net_local *) dev->priv;
-  base = dev->base_addr;
-
-  spin_lock (&lp->lock);
-
-  /* Treat all pending interrupts */
-  while(1)
-    {
-      /* ---------------- INTERRUPT CHECKING ---------------- */
-      /*
-       * Look for the interrupt and verify the validity
-       */
-      outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
-      status0 = inb(LCSR(base));
-
-#ifdef DEBUG_INTERRUPT_INFO
-      printk(KERN_DEBUG "status0 0x%x [%s => 0x%x]", status0, 
-	     (status0&SR0_INTERRUPT)?"int":"no int",status0&~SR0_INTERRUPT);
-      if(status0&SR0_INTERRUPT)
-	{
-	  printk(" [%s => %d]\n", (status0 & SR0_CHNL) ? "chnl" :
-		 ((status0 & SR0_EXECUTION) ? "cmd" :
-		  ((status0 & SR0_RECEPTION) ? "recv" : "unknown")),
-		 (status0 & SR0_EVENT_MASK));
-	}
-      else
-	printk("\n");
-#endif
-
-      /* Return if no actual interrupt from i82593 (normal exit) */
-      if(!(status0 & SR0_INTERRUPT))
-	break;
-
-      /* If interrupt is both Rx and Tx or none...
-       * This code in fact is there to catch the spurious interrupt
-       * when you remove the wavelan pcmcia card from the socket */
-      if(((status0 & SR0_BOTH_RX_TX) == SR0_BOTH_RX_TX) ||
-	 ((status0 & SR0_BOTH_RX_TX) == 0x0))
-	{
-#ifdef DEBUG_INTERRUPT_INFO
-	  printk(KERN_INFO "%s: wv_interrupt(): bogus interrupt (or from dead card) : %X\n",
-		 dev->name, status0);
-#endif
-	  /* Acknowledge the interrupt */
-	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
-	  break;
-	}
-
-      lp->status = status0;	/* Save current status (for commands) */
-
-      /* ----------------- RECEIVING PACKET ----------------- */
-      /*
-       * When the wavelan signal the reception of a new packet,
-       * we call wv_packet_rcv() to copy if from the buffer and
-       * send it to NET3
-       */
-      if(status0 & SR0_RECEPTION)
-	{
-#ifdef DEBUG_INTERRUPT_INFO
-	  printk(KERN_DEBUG "%s: wv_interrupt(): receive\n", dev->name);
-#endif
-
-	  if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT)
-	    {
-#ifdef DEBUG_INTERRUPT_ERROR
-	      printk(KERN_INFO "%s: wv_interrupt(): receive buffer overflow\n",
-		     dev->name);
-#endif
-	      lp->stats.rx_over_errors++;
-	      lp->overrunning = 1;
-      	    }
-
-	  /* Get the packet */
-	  wv_packet_rcv(dev);
-	  lp->overrunning = 0;
-
-	  /* Acknowledge the interrupt */
-	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
-	  continue;
-    	}
-
-      /* ---------------- COMMAND COMPLETION ---------------- */
-      /*
-       * Interrupts issued when the i82593 has completed a command.
-       * Most likely : transmission done
-       */
-
-      /* If we are already waiting elsewhere for the command to complete */
-      if(wv_wait_completed)
-	{
-#ifdef DEBUG_INTERRUPT_INFO
-	  printk(KERN_DEBUG "%s: wv_interrupt(): command completed\n",
-		 dev->name);
-#endif
-
-	  /* Signal command completion */
-	  wv_wait_completed = 0;
-
-	  /* Acknowledge the interrupt */
-	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
-	  continue;
-    	}
-
-      /* If a transmission has been done */
-      if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
-	 (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
-	 (status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE)
-	{
-#ifdef DEBUG_TX_ERROR
-	  if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE)
-	    printk(KERN_INFO "%s: wv_interrupt(): packet transmitted without CRC.\n",
-		   dev->name);
-#endif
-
-	  /* If watchdog was activated, kill it ! */
-	  if(timer_pending(&lp->watchdog))
-	    del_timer(&lp->watchdog);
-
-	  /* Get transmission status */
-	  tx_status = inb(LCSR(base));
-	  tx_status |= (inb(LCSR(base)) << 8);
-#ifdef DEBUG_INTERRUPT_INFO
-	  printk(KERN_DEBUG "%s: wv_interrupt(): transmission done\n",
-		 dev->name);
-	  {
-	    u_int	rcv_bytes;
-	    u_char	status3;
-	    rcv_bytes = inb(LCSR(base));
-	    rcv_bytes |= (inb(LCSR(base)) << 8);
-	    status3 = inb(LCSR(base));
-	    printk(KERN_DEBUG "tx_status 0x%02x rcv_bytes 0x%02x status3 0x%x\n",
-		   tx_status, rcv_bytes, (u_int) status3);
-	  }
-#endif
-	  /* Check for possible errors */
-	  if((tx_status & TX_OK) != TX_OK)
-	    {
-	      lp->stats.tx_errors++;
-
-	      if(tx_status & TX_FRTL)
-		{
-#ifdef DEBUG_TX_ERROR
-		  printk(KERN_INFO "%s: wv_interrupt(): frame too long\n",
-			 dev->name);
-#endif
-		}
-	      if(tx_status & TX_UND_RUN)
-		{
-#ifdef DEBUG_TX_FAIL
-		  printk(KERN_DEBUG "%s: wv_interrupt(): DMA underrun\n",
-			 dev->name);
-#endif
-		  lp->stats.tx_aborted_errors++;
-		}
-	      if(tx_status & TX_LOST_CTS)
-		{
-#ifdef DEBUG_TX_FAIL
-		  printk(KERN_DEBUG "%s: wv_interrupt(): no CTS\n", dev->name);
-#endif
-		  lp->stats.tx_carrier_errors++;
-		}
-	      if(tx_status & TX_LOST_CRS)
-		{
-#ifdef DEBUG_TX_FAIL
-		  printk(KERN_DEBUG "%s: wv_interrupt(): no carrier\n",
-			 dev->name);
-#endif
-		  lp->stats.tx_carrier_errors++;
-		}
-	      if(tx_status & TX_HRT_BEAT)
-		{
-#ifdef DEBUG_TX_FAIL
-		  printk(KERN_DEBUG "%s: wv_interrupt(): heart beat\n", dev->name);
-#endif
-		  lp->stats.tx_heartbeat_errors++;
-		}
-	      if(tx_status & TX_DEFER)
-		{
-#ifdef DEBUG_TX_FAIL
-		  printk(KERN_DEBUG "%s: wv_interrupt(): channel jammed\n",
-			 dev->name);
-#endif
-		}
-	      /* Ignore late collisions since they're more likely to happen
-	       * here (the WaveLAN design prevents the LAN controller from
-	       * receiving while it is transmitting). We take action only when
-	       * the maximum retransmit attempts is exceeded.
-	       */
-	      if(tx_status & TX_COLL)
-		{
-		  if(tx_status & TX_MAX_COL)
-		    {
-#ifdef DEBUG_TX_FAIL
-		      printk(KERN_DEBUG "%s: wv_interrupt(): channel congestion\n",
-			     dev->name);
-#endif
-		      if(!(tx_status & TX_NCOL_MASK))
-			{
-			  lp->stats.collisions += 0x10;
-			}
-		    }
-		}
-	    }	/* if(!(tx_status & TX_OK)) */
-
-	  lp->stats.collisions += (tx_status & TX_NCOL_MASK);
-	  lp->stats.tx_packets++;
-
-	  netif_wake_queue (dev);
-	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
-    	} 
-      else	/* if interrupt = transmit done or retransmit done */
-	{
-#ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_INFO "wavelan_cs: unknown interrupt, status0 = %02x\n",
-		 status0);
-#endif
-	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
-    	}
-    }
-
-  spin_unlock_irq (&lp->lock);
-
-#ifdef DEBUG_INTERRUPT_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
-#endif
-} /* wv_interrupt */
-
-/*------------------------------------------------------------------*/
-/*
- * Watchdog : when we start a transmission, we set a timer in the
- * kernel.  If the transmission complete, this timer is disabled. If
- * it expire, it try to unlock the hardware.
- *
- * Note : this watchdog doesn't work on the same principle as the
- * watchdog in the ISA driver. I make it this way because the overhead
- * of add_timer() and del_timer() is nothing and that it avoid calling
- * the watchdog, saving some CPU... If you want to apply the same
- * watchdog to the ISA driver, you should be a bit carefull, because
- * of the many transmit buffers...
- * This watchdog is also move clever, it try to abort the current
- * command before reseting everything...
- */
-static void
-wavelan_watchdog(u_long		a)
-{
-  device *		dev;
-  net_local *		lp;
-  ioaddr_t		base;
-  int			spin;
-
-  dev = (device *) a;
-  base = dev->base_addr;
-  lp = (net_local *) dev->priv;
-
-#ifdef DEBUG_INTERRUPT_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
-#endif
-
-#ifdef DEBUG_INTERRUPT_ERROR
-  printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n",
-	 dev->name);
-#endif
-
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
-
-  /* Ask to abort the current command */
-  outb(OP0_ABORT, LCCR(base));
-
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 250))
-    udelay(10);
-
-  /* If the interrupt handler hasn't be called or invalid status */
-  if((wv_wait_completed) ||
-     ((lp->status & SR0_EVENT_MASK) != SR0_EXECUTION_ABORTED))
-    {
-      /* It seem that it wasn't enough */
-#ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "%s: wavelan_watchdog: abort failed, trying reset\n",
-	     dev->name);
-#endif
-      wv_hw_reset(dev);
-    }
-
-#ifdef DEBUG_PSA_SHOW
-  {
-    psa_t		psa;
-    psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
-    wv_psa_show(&psa);
-  }
-#endif
-#ifdef DEBUG_MMC_SHOW
-  wv_mmc_show(dev);
-#endif
-#ifdef DEBUG_I82593_SHOW
-  wv_ru_show(dev);
-#endif
-
-  /* We are no more waiting for something... */
-  netif_start_queue (dev);
-
-#ifdef DEBUG_INTERRUPT_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
-#endif
-}
-
-/********************* CONFIGURATION CALLBACKS *********************/
-/*
- * Here are the functions called by the pcmcia package (cardmgr) and
- * linux networking (NET3) for initialization, configuration and
- * deinstallations of the Wavelan Pcmcia Hardware.
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Configure and start up the WaveLAN PCMCIA adaptor.
- * Called by NET3 when it "open" the device.
- */
-static int
-wavelan_open(device *	dev)
-{
-  dev_link_t *	link = ((net_local *) dev->priv)->link;
-  net_local *	lp = (net_local *)dev->priv;
-  ioaddr_t	base = dev->base_addr;
-
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
-	 (unsigned int) dev);
-#endif
-
-  /* Check if the modem is powered up (wavelan_close() power it down */
-  if(hasr_read(base) & HASR_NO_CLK)
-    {
-      /* Power up (power up time is 250us) */
-      hacr_write(base, HACR_DEFAULT);
-
-      /* Check if the module has been powered up... */
-      if(hasr_read(base) & HASR_NO_CLK)
-	{
-#ifdef DEBUG_CONFIG_ERRORS
-	  printk(KERN_WARNING "%s: wavelan_open(): modem not connected\n",
-		 dev->name);
-#endif
-	  return FALSE;
-	}
-    }
-
-  /* Start reception and declare the driver ready */
-  if(!lp->configured)
-    return FALSE;
-  if(!wv_ru_start(dev))
-    wv_hw_reset(dev);		/* If problem : reset */
-  netif_start_queue (dev);
-
-  /* Mark the device as used */
-  link->open++;
-  MOD_INC_USE_COUNT;
-
-#ifdef WAVELAN_ROAMING
-  if(do_roaming)
-    wv_roam_init(dev);
-#endif	/* WAVELAN_ROAMING */
-
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
-#endif
-  return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Shutdown the WaveLAN PCMCIA adaptor.
- * Called by NET3 when it "close" the device.
- */
-static int
-wavelan_close(device *	dev)
-{
-  dev_link_t *	link = ((net_local *) dev->priv)->link;
-  net_local *	lp = (net_local *)dev->priv;
-  ioaddr_t	base = dev->base_addr;
-
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
-	 (unsigned int) dev);
-#endif
-
-  netif_stop_queue (dev);
-
-  /* If the device isn't open, then nothing to do */
-  if(!link->open)
-    {
-#ifdef DEBUG_CONFIG_INFO
-      printk(KERN_DEBUG "%s: wavelan_close(): device not open\n", dev->name);
-#endif
-      return 0;
-    }
-
-#ifdef WAVELAN_ROAMING
-  /* Cleanup of roaming stuff... */
-  if(do_roaming)
-    wv_roam_cleanup(dev);
-#endif	/* WAVELAN_ROAMING */
-
-  /* If watchdog was activated, kill it ! */
-  if(timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
-  link->open--;
-  MOD_DEC_USE_COUNT;
-
-  /* If the card is still present */
-  if (netif_device_present(dev))
-    {
-      netif_stop_queue (dev);
-
-      /* Stop receiving new messages and wait end of transmission */
-      wv_ru_stop(dev);
-
-      /* Power down the module */
-      hacr_write(base, HACR_DEFAULT & (~HACR_PWR_STAT));
-    }
-  else
-    /* The card is no more there (flag is activated in wv_pcmcia_release) */
-    if(link->state & DEV_STALE_CONFIG)
-      wv_pcmcia_release((u_long)link);
-
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name);
-#endif
-  return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * We never need to do anything when a wavelan device is "initialized"
- * by the net software, because we only register already-found cards.
- */
-static int
-wavelan_init(device *	dev)
-{
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "<>wavelan_init()\n");
-#endif
-
-  return(0);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * wavelan_attach() creates an "instance" of the driver, allocating
- * local data structures for one device (one interface).  The device
- * is registered with Card Services.
- *
- * The dev_link structure is initialized, but we don't actually
- * configure the card at this point -- we wait until we receive a
- * card insertion event.
- */
-static dev_link_t *
-wavelan_attach(void)
-{
-  client_reg_t	client_reg;	/* Register with cardmgr */
-  dev_link_t *	link;		/* Info for cardmgr */
-  device *	dev;		/* Interface generic data */
-  net_local *	lp;		/* Interface specific data */
-  int		i, ret;
-
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "-> wavelan_attach()\n");
-#endif
-
-  /* Perform some cleanup */
-  wv_flush_stale_links();
-
-  /* Initialize the dev_link_t structure */
-  link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-  if (!link)
-	  return NULL;
-  
-  /* Allocate the generic data structure */
-  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
-  if (!dev)
-	  goto fail_alloc_dev;
-  
-  /* Allocate the wavelan-specific data structure. */
-  lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
-  if (!lp)
-	  goto fail_alloc_dev_priv;
-  
-  memset(lp, 0, sizeof(net_local));
-  memset(link, 0, sizeof(struct dev_link_t));
-  memset(dev, 0, sizeof(struct net_device));
-
-  dev->priv = lp;
-
-  /* Unused for the Wavelan */
-  link->release.function = &wv_pcmcia_release;
-  link->release.data = (u_long) link;
-
-  /* The io structure describes IO port mapping */
-  link->io.NumPorts1 = 8;
-  link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-  link->io.IOAddrLines = 3;
-
-  /* Interrupt setup */
-  link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-  link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-  if (irq_list[0] == -1)
-    link->irq.IRQInfo2 = irq_mask;
-  else
-    for (i = 0; i < 4; i++)
-      link->irq.IRQInfo2 |= 1 << irq_list[i];
-  link->irq.Handler = wavelan_interrupt;
-
-  /* General socket configuration */
-  link->conf.Attributes = CONF_ENABLE_IRQ;
-  link->conf.Vcc = 50;
-  link->conf.IntType = INT_MEMORY_AND_IO;
-
-  /* Chain drivers */
-  link->next = dev_list;
-  dev_list = link;
-
-  link->priv = link->irq.Instance = dev;
-
-  /* Init specific data */
-  wv_wait_completed = 0;
-  lp->status = FALSE;
-  lp->configured = 0;
-  lp->reconfig_82593 = FALSE;
-  lp->nresets = 0;
-
-  /* Set the watchdog timer */
-  lp->watchdog.function = wavelan_watchdog;
-  lp->watchdog.data = (unsigned long) dev;
-
-  /* back links */
-  lp->link = link;
-  lp->dev = dev;
-
-  /* Standard setup for generic data */
-  ether_setup(dev);
-
-  /* wavelan NET3 callbacks */
-  dev->init = &wavelan_init;
-  dev->open = &wavelan_open;
-  dev->stop = &wavelan_close;
-  dev->hard_start_xmit = &wavelan_packet_xmit;
-  dev->get_stats = &wavelan_get_stats;
-  dev->set_multicast_list = &wavelan_set_multicast_list;
-#ifdef SET_MAC_ADDRESS
-  dev->set_mac_address = &wavelan_set_mac_address;
-#endif	/* SET_MAC_ADDRESS */
-
-#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
-  dev->do_ioctl = wavelan_ioctl;	/* wireless extensions */
-  dev->get_wireless_stats = wavelan_get_wireless_stats;
-#endif
-
-  /* Other specific data */
-  strcpy(dev->name, ((net_local *)dev->priv)->node.dev_name);
-  netif_start_queue (dev);
-  dev->mtu = WAVELAN_MTU;
-
-  /* Register with Card Services */
-  client_reg.dev_info = &dev_info;
-  client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-  client_reg.EventMask = 
-    CS_EVENT_REGISTRATION_COMPLETE |
-    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-  client_reg.event_handler = &wavelan_event;
-  client_reg.Version = 0x0210;
-  client_reg.event_callback_args.client_data = link;
-
-#ifdef DEBUG_CONFIG_INFO
-  printk(KERN_DEBUG "wavelan_attach(): almost done, calling CardServices\n");
-#endif
-
-  ret = CardServices(RegisterClient, &link->handle, &client_reg);
-  if(ret != 0)
-    {
-      cs_error(link->handle, RegisterClient, ret);
-      wavelan_detach(link);
-      return NULL;
-    }
-
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "<- wavelan_attach()\n");
-#endif
-
-  return link;
-
-fail_alloc_dev_priv:
-  kfree(dev);
-fail_alloc_dev:
-  kfree(link);
-  return NULL;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * This deletes a driver "instance".  The device is de-registered with
- * Card Services.  If it has been released, all local data structures
- * are freed.  Otherwise, the structures will be freed when the device
- * is released.
- */
-static void
-wavelan_detach(dev_link_t *	link)
-{
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link);
-#endif
-
-  /*
-   * If the device is currently configured and active, we won't
-   * actually delete it yet.  Instead, it is marked so that when the
-   * release() function is called, that will trigger a proper
-   * detach().
-   */
-  if(link->state & DEV_CONFIG)
-    {
-      /* Some others haven't done their job : give them another chance */
-      wv_pcmcia_release((u_long) link);
-      if(link->state & DEV_STALE_CONFIG)
-	{
-#ifdef DEBUG_CONFIG_INFO
-	  printk(KERN_DEBUG "wavelan_detach: detach postponed,"
-		 " '%s' still locked\n", link->dev->dev_name);
-#endif
-	  link->state |= DEV_STALE_LINK;
-	  return;
-	}
-    }
-
-  /* Break the link with Card Services */
-  if(link->handle)
-    CardServices(DeregisterClient, link->handle);
-    
-  /* Remove the interface data from the linked list */
-  if(dev_list == link)
-    dev_list = link->next;
-  else
-    {
-      dev_link_t *	prev = dev_list;
-
-      while((prev != (dev_link_t *) NULL) && (prev->next != link))
-	prev = prev->next;
-
-      if(prev == (dev_link_t *) NULL)
-	{
-#ifdef DEBUG_CONFIG_ERRORS
-	  printk(KERN_WARNING "wavelan_detach : Attempting to remove a nonexistent device.\n");
-#endif
-	  return;
-	}
-
-      prev->next = link->next;
-    }
-
-  /* Free pieces */
-  if(link->priv)
-    {
-      device *	dev = (device *) link->priv;
-
-      /* Remove ourselves from the kernel list of ethernet devices */
-      /* Warning : can't be called from interrupt, timer or wavelan_close() */
-      if(link->dev != NULL)
-	unregister_netdev(dev);
-      link->dev = NULL;
-
-      if(dev->priv)
-	{
-	  /* Sound strange, but safe... */
-	  ((net_local *) dev->priv)->link = (dev_link_t *) NULL;
-	  ((net_local *) dev->priv)->dev = (device *) NULL;
-	  kfree(dev->priv);
-	}
-      kfree(link->priv);
-    }
-  kfree(link);
-
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "<- wavelan_detach()\n");
-#endif
-}
-
-/*------------------------------------------------------------------*/
-/*
- * The card status event handler. Mostly, this schedules other stuff
- * to run after an event is received. A CARD_REMOVAL event also sets
- * some flags to discourage the net drivers from trying to talk to the
- * card any more.
- */
-static int
-wavelan_event(event_t		event,		/* The event received */
-	      int		priority,
-	      event_callback_args_t *	args)
-{
-  dev_link_t *	link = (dev_link_t *) args->client_data;
-  device *	dev = (device *) link->priv;
-
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "->wavelan_event(): %s\n",
-	 ((event == CS_EVENT_REGISTRATION_COMPLETE)?"registration complete" :
-	  ((event == CS_EVENT_CARD_REMOVAL) ? "card removal" :
-	   ((event == CS_EVENT_CARD_INSERTION) ? "card insertion" :
-	    ((event == CS_EVENT_PM_SUSPEND) ? "pm suspend" :
-	     ((event == CS_EVENT_RESET_PHYSICAL) ? "physical reset" :
-	      ((event == CS_EVENT_PM_RESUME) ? "pm resume" :
-	       ((event == CS_EVENT_CARD_RESET) ? "card reset" :
-		"unknown"))))))));
-#endif
-
-    switch(event)
-      {
-      case CS_EVENT_REGISTRATION_COMPLETE:
-#ifdef DEBUG_CONFIG_INFO
-	printk(KERN_DEBUG "wavelan_cs: registration complete\n");
-#endif
-	break;
-
-      case CS_EVENT_CARD_REMOVAL:
-	/* Oups ! The card is no more there */
-	link->state &= ~DEV_PRESENT;
-	if(link->state & DEV_CONFIG)
-	  {
-	    /* Accept no more transmissions */
-      	    netif_device_detach(dev);
-
-	    /* Release the card */
-	    wv_pcmcia_release((u_long) link);
-	  }
-	break;
-
-      case CS_EVENT_CARD_INSERTION:
-	/* Reset and configure the card */
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	if(wv_pcmcia_config(link) &&
-	   wv_hw_config(dev))
-	  wv_init_info(dev);
-	else
-	  dev->irq = 0;
-	break;
-
-      case CS_EVENT_PM_SUSPEND:
-	/* NB: wavelan_close will be called, but too late, so we are
-	 * obliged to close nicely the wavelan here. David, could you
-	 * close the device before suspending them ? And, by the way,
-	 * could you, on resume, add a "route add -net ..." after the
-	 * ifconfig up XXX Thanks... */
-
-	/* Stop receiving new messages and wait end of transmission */
-	wv_ru_stop(dev);
-
-	/* Power down the module */
-	hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT));
-
-	/* The card is now suspended */
-	link->state |= DEV_SUSPEND;
-	/* Fall through... */
-      case CS_EVENT_RESET_PHYSICAL:
-    	if(link->state & DEV_CONFIG)
-	  {
-      	    if(link->open)
-	      	netif_device_detach(dev);
-
-      	    CardServices(ReleaseConfiguration, link->handle);
-	  }
-	break;
-
-      case CS_EVENT_PM_RESUME:
-	link->state &= ~DEV_SUSPEND;
-	/* Fall through... */
-      case CS_EVENT_CARD_RESET:
-	if(link->state & DEV_CONFIG)
-	  {
-      	    CardServices(RequestConfiguration, link->handle, &link->conf);
-      	    if(link->open)	/* If RESET -> True, If RESUME -> False XXX */
-	      {
-		wv_hw_reset(dev);
-		netif_device_attach(dev);
-	      }
-	  }
-	break;
-    }
-
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "<-wavelan_event()\n");
-#endif
-  return 0;
-}
-
-/****************************** MODULE ******************************/
-/*
- * Module entry points : insertion & removal
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Module insertion : initialisation of the module.
- * Register the card with cardmgr...
- */
-static int __init
-init_wavelan_cs(void)
-{
-  servinfo_t	serv;
-
-#ifdef DEBUG_MODULE_TRACE
-  printk(KERN_DEBUG "-> init_wavelan_cs()\n");
-#ifdef DEBUG_VERSION_SHOW
-  printk(KERN_DEBUG "%s", version);
-#endif
-#endif
-
-  CardServices(GetCardServicesInfo, &serv);
-  if(serv.Revision != CS_RELEASE_CODE)
-    {
-#ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "init_wavelan_cs: Card Services release does not match!\n");
-#endif
-      return -1;
-    }
-
-  register_pccard_driver(&dev_info, &wavelan_attach, &wavelan_detach);
-
-#ifdef DEBUG_MODULE_TRACE
-  printk(KERN_DEBUG "<- init_wavelan_cs()\n");
-#endif
-  return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Module removal
- */
-static void __exit
-exit_wavelan_cs(void)
-{
-#ifdef DEBUG_MODULE_TRACE
-  printk(KERN_DEBUG "-> cleanup_module()\n");
-#endif
-#ifdef DEBUG_BASIC_SHOW
-  printk(KERN_NOTICE "wavelan_cs: unloading\n");
-#endif
-
-  /* Do some cleanup of the device list */
-  wv_flush_stale_links();
-
-  /* If there remain some devices... */
-#ifdef DEBUG_CONFIG_ERRORS
-  if(dev_list != NULL)
-    {
-      /* Honestly, if this happen we are in a deep s**t */
-      printk(KERN_INFO "wavelan_cs: devices remaining when removing module\n");
-      printk(KERN_INFO "Please flush your disks and reboot NOW !\n");
-    }
-#endif
-
-  unregister_pccard_driver(&dev_info);
-
-#ifdef DEBUG_MODULE_TRACE
-  printk(KERN_DEBUG "<- cleanup_module()\n");
-#endif
-}
-
-module_init(init_wavelan_cs);
-module_exit(exit_wavelan_cs);
-MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.2/linux/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h
--- v2.5.2/linux/drivers/net/pcmcia/wavelan_cs.h	Fri Oct 12 14:21:18 2001
+++ linux/drivers/net/pcmcia/wavelan_cs.h	Wed Dec 31 16:00:00 1969
@@ -1,778 +0,0 @@
-/*
- *	Wavelan Pcmcia driver
- *
- *		Jean II - HPLB '96
- *
- * Reorganisation and extension of the driver.
- *
- * This file contain all definition and declarations necessary for the
- * wavelan pcmcia driver. This file is a private header, so it should
- * be included only on wavelan_cs.c !!!
- */
-
-#ifndef WAVELAN_CS_H
-#define WAVELAN_CS_H
-
-/************************** DOCUMENTATION **************************/
-/*
- * This driver provide a Linux interface to the Wavelan Pcmcia hardware
- * The Wavelan is a product of Lucent (http://www.wavelan.com/).
- * This division was formerly part of NCR and then AT&T.
- * Wavelan are also distributed by DEC (RoamAbout DS)...
- *
- * To know how to use this driver, read the PCMCIA HOWTO.
- * If you want to exploit the many other fonctionalities, look comments
- * in the code...
- *
- * This driver is the result of the effort of many peoples (see below).
- */
-
-/* ------------------------ SPECIFIC NOTES ------------------------ */
-/*
- * Web page
- * --------
- *	I try to maintain a web page with the Wireless LAN Howto at :
- *	    http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
- *
- * Debugging and options
- * ---------------------
- *	You will find below a set of '#define" allowing a very fine control
- *	on the driver behaviour and the debug messages printed.
- *	The main options are :
- *	o WAVELAN_ROAMING, for the experimental roaming support.
- *	o SET_PSA_CRC, to have your card correctly recognised by
- *	  an access point and the Point-to-Point diagnostic tool.
- *	o USE_PSA_CONFIG, to read configuration from the PSA (EEprom)
- *	  (otherwise we always start afresh with some defaults)
- *
- * wavelan_cs.o is darn too big
- * -------------------------
- *	That's true ! There is a very simple way to reduce the driver
- *	object by 33% (yes !). Comment out the following line :
- *		#include <linux/wireless.h>
- *	Other compile options can also reduce the size of it...
- *
- * MAC address and hardware detection :
- * ----------------------------------
- *	The detection code of the wavelan chech that the first 3
- *	octets of the MAC address fit the company code. This type of
- *	detection work well for AT&T cards (because the AT&T code is
- *	hardcoded in wavelan.h), but of course will fail for other
- *	manufacturer.
- *
- *	If you are sure that your card is derived from the wavelan,
- *	here is the way to configure it :
- *	1) Get your MAC address
- *		a) With your card utilities (wfreqsel, instconf, ...)
- *		b) With the driver :
- *			o compile the kernel with DEBUG_CONFIG_INFO enabled
- *			o Boot and look the card messages
- *	2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h)
- *	3) Compile & verify
- *	4) Send me the MAC code - I will include it in the next version...
- *
- */
-
-/* --------------------- WIRELESS EXTENSIONS --------------------- */
-/*
- * This driver is the first one to support "wireless extensions".
- * This set of extensions provide you some way to control the wireless
- * caracteristics of the hardware in a standard way and support for
- * applications for taking advantage of it (like Mobile IP).
- *
- * You will need to enable the CONFIG_NET_RADIO define in the kernel
- * configuration to enable the wireless extensions (this is the one
- * giving access to the radio network device choice).
- *
- * It might also be a good idea as well to fetch the wireless tools to
- * configure the device and play a bit.
- */
-
-/* ---------------------------- FILES ---------------------------- */
-/*
- * wavelan_cs.c :	The actual code for the driver - C functions
- *
- * wavelan_cs.h :	Private header : local types / vars for the driver
- *
- * wavelan.h :		Description of the hardware interface & structs
- *
- * i82593.h :		Description if the Ethernet controller
- */
-
-/* --------------------------- HISTORY --------------------------- */
-/*
- * The history of the Wavelan drivers is as complicated as history of
- * the Wavelan itself (NCR -> AT&T -> Lucent).
- *
- * All started with Anders Klemets <klemets@paul.rutgers.edu>,
- * writting a Wavelan ISA driver for the MACH microkernel. Girish
- * Welling <welling@paul.rutgers.edu> had also worked on it.
- * Keith Moore modify this for the Pcmcia hardware.
- * 
- * Robert Morris <rtm@das.harvard.edu> port these two drivers to BSDI
- * and add specific Pcmcia support (there is currently no equivalent
- * of the PCMCIA package under BSD...).
- *
- * Jim Binkley <jrb@cs.pdx.edu> port both BSDI drivers to FreeBSD.
- *
- * Bruce Janson <bruce@cs.usyd.edu.au> port the BSDI ISA driver to Linux.
- *
- * Anthony D. Joseph <adj@lcs.mit.edu> started modify Bruce driver
- * (with help of the BSDI PCMCIA driver) for PCMCIA.
- * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
- * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
- * correctly 2.00 cards (2.4 GHz with frequency selection).
- * David Hinds <dhinds@pcmcia.sourceforge.org> integrated the whole in his
- * Pcmcia package (+ bug corrections).
- *
- * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
- * patchs to the Pcmcia driver. After, I added code in the ISA driver
- * for Wireless Extensions and full support of frequency selection
- * cards. Now, I'm doing the same to the Pcmcia driver + some
- * reorganisation.
- * Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me
- * much needed informations on the Wavelan hardware.
- */
-
-/* By the way : for the copyright & legal stuff :
- * Almost everybody wrote code under GNU or BSD license (or alike),
- * and want that their original copyright remain somewhere in the
- * code (for myself, I go with the GPL).
- * Nobody want to take responsibility for anything, except the fame...
- */
-
-/* --------------------------- CREDITS --------------------------- */
-/*
- * Credits:
- *    Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht and
- *	Loeke Brederveld of Lucent for providing extremely useful
- *	information about WaveLAN PCMCIA hardware
- *
- *    This driver is based upon several other drivers, in particular:
- *	David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter
- *	Bruce Janson's Linux driver for the AT-bus WaveLAN adapter
- *	Anders Klemets' PCMCIA WaveLAN adapter driver
- *	Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter
- *
- * Additional Credits:
- *
- *    This software was originally developed under Linux 1.2.3
- *	(Slackware 2.0 distribution).
- *    And then under Linux 2.0.x (Debian 1.1 - pcmcia 2.8.18-23) with
- *	HP OmniBook 4000 & 5500.
- *
- *    It is based on other device drivers and information either written
- *    or supplied by:
- *	James Ashton (jaa101@syseng.anu.edu.au),
- *	Ajay Bakre (bakre@paul.rutgers.edu),
- *	Donald Becker (becker@super.org),
- *	Jim Binkley <jrb@cs.pdx.edu>,
- *	Loeke Brederveld <lbrederv@wavelan.com>,
- *	Allan Creighton (allanc@cs.su.oz.au),
- *	Brent Elphick <belphick@uwaterloo.ca>,
- *	Joe Finney <joe@comp.lancs.ac.uk>,
- *	Matthew Geier (matthew@cs.su.oz.au),
- *	Remo di Giovanni (remo@cs.su.oz.au),
- *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
- *	David Hinds <dhinds@pcmcia.sourceforge.org>,
- *	Jan Hoogendoorn (c/o marteijn@lucent.com),
- *      Bruce Janson <bruce@cs.usyd.edu.au>,
- *	Anthony D. Joseph <adj@lcs.mit.edu>,
- *	Anders Klemets (klemets@paul.rutgers.edu),
- *	Yunzhou Li <yunzhou@strat.iol.unh.edu>,
- *	Marc Meertens (mmeertens@lucent.com),
- *	Keith Moore,
- *	Robert Morris (rtm@das.harvard.edu),
- *	Ian Parkin (ian@cs.su.oz.au),
- *	John Rosenberg (johnr@cs.su.oz.au),
- *	George Rossi (george@phm.gov.au),
- *	Arthur Scott (arthur@cs.su.oz.au),
- *	Stanislav Sinyagin <stas@isf.ru>
- *	Peter Storey,
- *	Jean Tourrilhes <jt@hpl.hp.com>,
- *	Girish Welling (welling@paul.rutgers.edu)
- *	Clark Woodworth <clark@hiway1.exit109.com>
- *	Yongguang Zhang <ygz@isl.hrl.hac.com>...
- */
-
-/* ------------------------- IMPROVEMENTS ------------------------- */
-/*
- * I proudly present :
- *
- * Changes made in 2.8.22 :
- * ----------------------
- *	- improved wv_set_multicast_list
- *	- catch spurious interrupt
- *	- correct release of the device
- *
- * Changes mades in release :
- * ------------------------
- *	- Reorganisation of the code, function name change
- *	- Creation of private header (wavelan_cs.h)
- *	- Reorganised debug messages
- *	- More comments, history, ...
- *	- Configure earlier (in "insert" instead of "open")
- *        and do things only once
- *	- mmc_init : configure the PSA if not done
- *	- mmc_init : 2.00 detection better code for 2.00 init
- *	- better info at startup
- *	- Correct a HUGE bug (volatile & uncalibrated busy loop)
- *	  in wv_82593_cmd => config speedup
- *	- Stop receiving & power down on close (and power up on open)
- *	  use "ifconfig down" & "ifconfig up ; route add -net ..."
- *	- Send packets : add watchdog instead of pooling
- *	- Receive : check frame wrap around & try to recover some frames
- *	- wavelan_set_multicast_list : avoid reset
- *	- add wireless extensions (ioctl & get_wireless_stats)
- *	  get/set nwid/frequency on fly, info for /proc/net/wireless
- *	- Suppress useless stuff from lp (net_local), but add link
- *	- More inlines
- *	- Lot of others minor details & cleanups
- *
- * Changes made in second release :
- * ------------------------------
- *	- Optimise wv_85893_reconfig stuff, fix potential problems
- *	- Change error values for ioctl
- *	- Non blocking wv_ru_stop() + call wv_reset() in case of problems
- *	- Remove development printk from wavelan_watchdog()
- *	- Remove of the watchdog to wavelan_close instead of wavelan_release
- *	  fix potential problems...
- *	- Start debugging suspend stuff (but it's still a bit weird)
- *	- Debug & optimize dump header/packet in Rx & Tx (debug)
- *	- Use "readb" and "writeb" to be kernel 2.1 compliant
- *	- Better handling of bogus interrupts
- *	- Wireless extension : SETSPY and GETSPY
- *	- Remove old stuff (stats - for those needing it, just ask me...)
- *	- Make wireless extensions optional
- *
- * Changes made in third release :
- * -----------------------------
- *	- cleanups & typos
- *	- modif wireless ext (spy -> only one pointer)
- *	- new private ioctl to set/get quality & level threshold
- *	- Init : correct default value of level threshold for pcmcia
- *	- kill watchdog in hw_reset
- *	- more 2.1 support (copy_to/from_user instead of memcpy_to/fromfs)
- *	- Add message level (debug stuff in /var/adm/debug & errors not
- *	  displayed at console and still in /var/adm/messages)
- *
- * Changes made in fourth release :
- * ------------------------------
- *	- multicast support (yes !) thanks to Yongguang Zhang.
- *
- * Changes made in fifth release (2.9.0) :
- * -------------------------------------
- *	- Revisited multicast code (it was mostly wrong).
- *	- protect code in wv_82593_reconfig with dev->tbusy (oups !)
- *
- * Changes made in sixth release (2.9.1a) :
- * --------------------------------------
- *	- Change the detection code for multi manufacturer code support
- *	- Correct bug (hang kernel) in init when we were "rejecting" a card 
- *
- * Changes made in seventh release (2.9.1b) :
- * ----------------------------------------
- *	- Update to wireless extensions changes
- *	- Silly bug in card initial configuration (psa_conf_status)
- *
- * Changes made in eigth release :
- * -----------------------------
- *	- Small bug in debug code (probably not the last one...)
- *	- 1.2.13 support (thanks to Clark Woodworth)
- *
- * Changes made for release in 2.9.2b :
- * ----------------------------------
- *	- Level threshold is now a standard wireless extension (version 4 !)
- *	- modules parameters types for kernel > 2.1.17
- *	- updated man page
- *	- Others cleanup from David Hinds
- *
- * Changes made for release in 2.9.5 :
- * ---------------------------------
- *	- byte count stats (courtesy of David Hinds)
- *	- Remove dev_tint stuff (courtesy of David Hinds)
- *	- Others cleanup from David Hinds
- *	- Encryption setting from Brent Elphick (thanks a lot !)
- *	- 'base' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin)
- *
- * Changes made for release in 2.9.6 :
- * ---------------------------------
- *	- fix bug : no longuer disable watchdog in case of bogus interrupt
- *	- increase timeout in config code for picky hardware
- *	- mask unused bits in status (Wireless Extensions)
- *
- * Changes integrated by Justin Seger <jseger@MIT.EDU> & David Hinds :
- * -----------------------------------------------------------------
- *	- Roaming "hack" from Joe Finney <joe@comp.lancs.ac.uk>
- *	- PSA CRC code from Bob Gray <rgray@bald.cs.dartmouth.edu>
- *	- Better initialisation of the i82593 controller
- *	  from Joseph K. O'Sullivan <josullvn+@cs.cmu.edu>
- *
- * Changes made for release in 3.0.10 :
- * ----------------------------------
- *	- Fix eject "hang" of the driver under 2.2.X :
- *		o create wv_flush_stale_links()
- *		o Rename wavelan_release to wv_pcmcia_release & move up
- *		o move unregister_netdev to wavelan_detach()
- *		o wavelan_release() no longer call wavelan_detach()
- *		o Suppress "release" timer
- *		o Other cleanups & fixes
- *	- New MAC address in the probe
- *	- Reorg PSA_CRC code (endian neutral & cleaner)
- *	- Correct initialisation of the i82593 from Lucent manual
- *	- Put back the watchdog, with larger timeout
- *	- TRANSMIT_NO_CRC is a "normal" error, so recover from it
- *	  from Derrick J Brashear <shadow@dementia.org>
- *	- Better handling of TX and RX normal failure conditions
- *	- #ifdef out all the roaming code
- *	- Add ESSID & "AP current address" ioctl stubs
- *	- General cleanup of the code
- *
- * Changes made for release in 3.0.13 :
- * ----------------------------------
- *	- Re-enable compilation of roaming code by default, but with
- *	  do_roaming = 0
- *	- Nuke `nwid=nwid^ntohs(beacon->domain_id)' in wl_roam_gather
- *	  at the demand of John Carol Langford <jcl@gs176.sp.cs.cmu.edu>
- *	- Introduced WAVELAN_ROAMING_EXT for incomplete ESSID stuff.
- *
- * Changes made for release in 3.0.15 :
- * ----------------------------------
- *	- Change e-mail and web page addresses
- *	- Watchdog timer is now correctly expressed in HZ, not in jiffies
- *	- Add channel number to the list of frequencies in range
- *	- Add the (short) list of bit-rates in range
- *	- Developp a new sensitivity... (sens.value & sens.fixed)
- *
- * Changes made for release in 3.1.2 :
- * ---------------------------------
- *	- Fix check for root permission (break instead of exit)
- *	- New nwid & encoding setting (Wireless Extension 9)
- *
- * Wishes & dreams:
- * ----------------
- *	- Cleanup and integrate the roaming code
- *	  (std debug, set DomainID, decay avg and co...)
- */
-
-/***************************** INCLUDES *****************************/
-
-/* Linux headers that we need */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-
-#ifdef CONFIG_NET_PCMCIA_RADIO
-#include <linux/wireless.h>		/* Wireless extensions */
-#endif	/* CONFIG_NET_PCMCIA_RADIO */
-
-/* Pcmcia headers that we need */
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/version.h>
-
-/* Wavelan declarations */
-#include "i82593.h"	/* Definitions for the Intel chip */
-
-#include "wavelan.h"	/* Others bits of the hardware */
-
-/************************** DRIVER OPTIONS **************************/
-/*
- * `#define' or `#undef' the following constant to change the behaviour
- * of the driver...
- */
-#define WAVELAN_ROAMING		/* Include experimental roaming code */
-#undef WAVELAN_ROAMING_EXT	/* Enable roaming wireless extensions */
-#undef SET_PSA_CRC		/* Set the CRC in PSA (slower) */
-#define USE_PSA_CONFIG		/* Use info from the PSA */
-#undef STRUCT_CHECK		/* Verify padding of structures */
-#undef EEPROM_IS_PROTECTED	/* Doesn't seem to be necessary */
-#define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical) */
-#undef SET_MAC_ADDRESS		/* Experimental */
-
-#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
-/* Warning : these stuff will slow down the driver... */
-#define WIRELESS_SPY		/* Enable spying addresses */
-#undef HISTOGRAM		/* Enable histogram of sig level... */
-#endif
-
-/****************************** DEBUG ******************************/
-
-#undef DEBUG_MODULE_TRACE	/* Module insertion/removal */
-#undef DEBUG_CALLBACK_TRACE	/* Calls made by Linux */
-#undef DEBUG_INTERRUPT_TRACE	/* Calls to handler */
-#undef DEBUG_INTERRUPT_INFO	/* type of interrupt & so on */
-#define DEBUG_INTERRUPT_ERROR	/* problems */
-#undef DEBUG_CONFIG_TRACE	/* Trace the config functions */
-#undef DEBUG_CONFIG_INFO	/* What's going on... */
-#define DEBUG_CONFIG_ERRORS	/* Errors on configuration */
-#undef DEBUG_TX_TRACE		/* Transmission calls */
-#undef DEBUG_TX_INFO		/* Header of the transmitted packet */
-#undef DEBUG_TX_FAIL		/* Normal failure conditions */
-#define DEBUG_TX_ERROR		/* Unexpected conditions */
-#undef DEBUG_RX_TRACE		/* Transmission calls */
-#undef DEBUG_RX_INFO		/* Header of the transmitted packet */
-#undef DEBUG_RX_FAIL		/* Normal failure conditions */
-#define DEBUG_RX_ERROR		/* Unexpected conditions */
-#undef DEBUG_PACKET_DUMP	/* Dump packet on the screen */
-#undef DEBUG_IOCTL_TRACE	/* Misc call by Linux */
-#undef DEBUG_IOCTL_INFO		/* Various debug info */
-#define DEBUG_IOCTL_ERROR	/* What's going wrong */
-#define DEBUG_BASIC_SHOW	/* Show basic startup info */
-#undef DEBUG_VERSION_SHOW	/* Print version info */
-#undef DEBUG_PSA_SHOW		/* Dump psa to screen */
-#undef DEBUG_MMC_SHOW		/* Dump mmc to screen */
-#undef DEBUG_SHOW_UNUSED	/* Show also unused fields */
-#undef DEBUG_I82593_SHOW	/* Show i82593 status */
-#undef DEBUG_DEVICE_SHOW	/* Show device parameters */
-
-/************************ CONSTANTS & MACROS ************************/
-
-#ifdef DEBUG_VERSION_SHOW
-static const char *version = "wavelan_cs.c : v21 (wireless extensions) 18/10/99\n";
-#endif
-
-/* Watchdog temporisation */
-#define	WATCHDOG_JIFFIES	(256*HZ/100)
-
-/* Fix a bug in some old wireless extension definitions */
-#ifndef IW_ESSID_MAX_SIZE
-#define IW_ESSID_MAX_SIZE	32
-#endif
-
-/* ------------------------ PRIVATE IOCTL ------------------------ */
-
-/* Wireless Extension Backward compatibility - Jean II
- * If the new wireless device private ioctl range is not defined,
- * default to standard device private ioctl range */
-#ifndef SIOCIWFIRSTPRIV
-#define SIOCIWFIRSTPRIV	SIOCDEVPRIVATE
-#endif /* SIOCIWFIRSTPRIV */
-
-#define SIOCSIPQTHR	SIOCIWFIRSTPRIV		/* Set quality threshold */
-#define SIOCGIPQTHR	SIOCIWFIRSTPRIV + 1	/* Get quality threshold */
-#define SIOCSIPROAM     SIOCIWFIRSTPRIV + 2	/* Set roaming state */
-#define SIOCGIPROAM     SIOCIWFIRSTPRIV + 3	/* Get roaming state */
-
-#define SIOCSIPHISTO	SIOCIWFIRSTPRIV + 6	/* Set histogram ranges */
-#define SIOCGIPHISTO	SIOCIWFIRSTPRIV + 7	/* Get histogram values */
-
-/*************************** WaveLAN Roaming  **************************/
-#ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
-
-#define WAVELAN_ROAMING_DEBUG	 0	/* 1 = Trace of handover decisions */
-					/* 2 = Info on each beacon rcvd... */
-#define MAX_WAVEPOINTS		7	/* Max visible at one time */
-#define WAVEPOINT_HISTORY	5	/* SNR sample history slow search */
-#define WAVEPOINT_FAST_HISTORY	2	/* SNR sample history fast search */
-#define SEARCH_THRESH_LOW	10	/* SNR to enter cell search */
-#define SEARCH_THRESH_HIGH	13	/* SNR to leave cell search */
-#define WAVELAN_ROAMING_DELTA	1	/* Hysteresis value (+/- SNR) */
-#define CELL_TIMEOUT		2*HZ	/* in jiffies */
-
-#define FAST_CELL_SEARCH	1	/* Boolean values... */
-#define NWID_PROMISC		1	/* for code clarity. */
-
-typedef struct wavepoint_beacon
-{
-  unsigned char		dsap,		/* Unused */
-			ssap,		/* Unused */
-			ctrl,		/* Unused */
-			O,U,I,		/* Unused */
-			spec_id1,	/* Unused */
-			spec_id2,	/* Unused */
-			pdu_type,	/* Unused */
-			seq;		/* WavePoint beacon sequence number */
-  unsigned short	domain_id,	/* WavePoint Domain ID */
-			nwid;		/* WavePoint NWID */
-} wavepoint_beacon;
-
-typedef struct wavepoint_history
-{
-  unsigned short	nwid;		/* WavePoint's NWID */
-  int			average_slow;	/* SNR running average */
-  int			average_fast;	/* SNR running average */
-  unsigned char	  sigqual[WAVEPOINT_HISTORY]; /* Ringbuffer of recent SNR's */
-  unsigned char		qualptr;	/* Index into ringbuffer */
-  unsigned char		last_seq;	/* Last seq. no seen for WavePoint */
-  struct wavepoint_history *next;	/* Next WavePoint in table */
-  struct wavepoint_history *prev;	/* Previous WavePoint in table */
-  unsigned long		last_seen;	/* Time of last beacon recvd, jiffies */
-} wavepoint_history;
-
-struct wavepoint_table
-{
-  wavepoint_history	*head;		/* Start of ringbuffer */
-  int			num_wavepoints;	/* No. of WavePoints visible */
-  unsigned char		locked;		/* Table lock */
-};
-
-#endif	/* WAVELAN_ROAMING */
-
-/****************************** TYPES ******************************/
-
-/* Shortcuts */
-typedef struct net_device	device;
-typedef struct net_device_stats	en_stats;
-typedef struct iw_statistics	iw_stats;
-typedef struct iw_quality	iw_qual;
-typedef struct iw_freq		iw_freq;
-typedef struct net_local	net_local;
-typedef struct timer_list	timer_list;
-
-/* Basic types */
-typedef u_char		mac_addr[WAVELAN_ADDR_SIZE];	/* Hardware address */
-
-/*
- * Static specific data for the interface.
- *
- * For each network interface, Linux keep data in two structure. "device"
- * keep the generic data (same format for everybody) and "net_local" keep
- * the additional specific data.
- * Note that some of this specific data is in fact generic (en_stats, for
- * example).
- */
-struct net_local
-{
-  spinlock_t	lock;
-  dev_node_t 	node;		/* ???? What is this stuff ???? */
-  device *	dev;		/* Reverse link... */
-  dev_link_t *	link;		/* pcmcia structure */
-  en_stats	stats;		/* Ethernet interface statistics */
-  int		nresets;	/* Number of hw resets */
-  u_char	configured;	/* If it is configured */
-  u_char	reconfig_82593;	/* Need to reconfigure the controller */
-  u_char	promiscuous;	/* Promiscuous mode */
-  u_char	allmulticast;	/* All Multicast mode */
-  int		mc_count;	/* Number of multicast addresses */
-  timer_list	watchdog;	/* To avoid blocking state */
-
-  u_char        status;		/* Current i82593 status */
-  int   	stop;		/* Current i82593 Stop Hit Register */
-  int   	rfp;		/* Last DMA machine receive pointer */
-  int		overrunning;	/* Receiver overrun flag */
-
-#ifdef WIRELESS_EXT
-  iw_stats	wstats;		/* Wireless specific stats */
-#endif
-
-#ifdef WIRELESS_SPY
-  int		spy_number;		/* Number of addresses to spy */
-  mac_addr	spy_address[IW_MAX_SPY];	/* The addresses to spy */
-  iw_qual	spy_stat[IW_MAX_SPY];		/* Statistics gathered */
-#endif	/* WIRELESS_SPY */
-#ifdef HISTOGRAM
-  int		his_number;		/* Number of intervals */
-  u_char	his_range[16];		/* Boundaries of interval ]n-1; n] */
-  u_long	his_sum[16];		/* Sum in interval */
-#endif	/* HISTOGRAM */
-#ifdef WAVELAN_ROAMING
-  u_long	domain_id;	/* Domain ID we lock on for roaming */
-  int		filter_domains;	/* Check Domain ID of beacon found */
- struct wavepoint_table	wavepoint_table;	/* Table of visible WavePoints*/
-  wavepoint_history *	curr_point;		/* Current wavepoint */
-  int			cell_search;		/* Searching for new cell? */
-  struct timer_list	cell_timer;		/* Garbage collection */
-#endif	/* WAVELAN_ROAMING */
-};
-
-/**************************** PROTOTYPES ****************************/
-
-#ifdef WAVELAN_ROAMING
-/* ---------------------- ROAMING SUBROUTINES -----------------------*/
-
-wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp);
-wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp);
-void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp);
-void wl_cell_expiry(unsigned long data);
-wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp);
-void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq);
-void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp);
-void wv_nwid_filter(unsigned char mode, net_local *lp);
-void wv_roam_init(struct net_device *dev);
-void wv_roam_cleanup(struct net_device *dev);
-#endif	/* WAVELAN_ROAMING */
-
-/* ----------------------- MISC SUBROUTINES ------------------------ */
-static void
-	cs_error(client_handle_t, /* Report error to cardmgr */
-		 int,
-		 int);
-/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
-static inline u_char		/* data */
-	hasr_read(u_long);	/* Read the host interface : base address */
-static inline void
-	hacr_write(u_long,	/* Write to host interface : base address */
-		   u_char),	/* data */
-	hacr_write_slow(u_long,
-		   u_char);
-static void
-	psa_read(device *,	/* Read the Parameter Storage Area */
-		 int,		/* offset in PSA */
-		 u_char *,	/* buffer to fill */
-		 int),		/* size to read */
-	psa_write(device *,	/* Write to the PSA */
-		  int,		/* Offset in psa */
-		  u_char *,	/* Buffer in memory */
-		  int);		/* Length of buffer */
-static inline void
-	mmc_out(u_long,		/* Write 1 byte to the Modem Manag Control */
-		u_short,
-		u_char),
-	mmc_write(u_long,	/* Write n bytes to the MMC */
-		  u_char,
-		  u_char *,
-		  int);
-static inline u_char		/* Read 1 byte from the MMC */
-	mmc_in(u_long,
-	       u_short);
-static inline void
-	mmc_read(u_long,	/* Read n bytes from the MMC */
-		 u_char,
-		 u_char *,
-		 int),
-	fee_wait(u_long,	/* Wait for frequency EEprom : base address */
-		 int,		/* Base delay to wait for */
-		 int);		/* Number of time to wait */
-static void
-	fee_read(u_long,	/* Read the frequency EEprom : base address */
-		 u_short,	/* destination offset */
-		 u_short *,	/* data buffer */
-		 int);		/* number of registers */
-/* ---------------------- I82593 SUBROUTINES ----------------------- */
-static int
-	wv_82593_cmd(device *,	/* synchronously send a command to i82593 */ 
-		     char *,
-		     int,
-		     int);
-static inline int
-	wv_diag(device *);	/* Diagnostique the i82593 */
-static int
-	read_ringbuf(device *,	/* Read a receive buffer */
-		     int,
-		     char *,
-		     int);
-static inline void
-	wv_82593_reconfig(device *);	/* Reconfigure the controller */
-/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */
-static inline void
-	wv_init_info(device *);	/* display startup info */
-/* ------------------- IOCTL, STATS & RECONFIG ------------------- */
-static en_stats	*
-	wavelan_get_stats(device *);	/* Give stats /proc/net/dev */
-/* ----------------------- PACKET RECEPTION ----------------------- */
-static inline int
-	wv_start_of_frame(device *,	/* Seek beggining of current frame */
-			  int,	/* end of frame */
-			  int);	/* start of buffer */
-static inline void
-	wv_packet_read(device *,	/* Read a packet from a frame */
-		       int,
-		       int),
-	wv_packet_rcv(device *);	/* Read all packets waiting */
-/* --------------------- PACKET TRANSMISSION --------------------- */
-static inline void
-	wv_packet_write(device *,	/* Write a packet to the Tx buffer */
-			void *,
-			short);
-static int
-	wavelan_packet_xmit(struct sk_buff *,	/* Send a packet */
-			    device *);
-/* -------------------- HARDWARE CONFIGURATION -------------------- */
-static inline int
-	wv_mmc_init(device *);	/* Initialize the modem */
-static int
-	wv_ru_stop(device *),	/* Stop the i82593 receiver unit */
-	wv_ru_start(device *);	/* Start the i82593 receiver unit */
-static int
-	wv_82593_config(device *);	/* Configure the i82593 */
-static inline int
-	wv_pcmcia_reset(device *);	/* Reset the pcmcia interface */
-static int
-	wv_hw_config(device *);	/* Reset & configure the whole hardware */
-static inline void
-	wv_hw_reset(device *);	/* Same, + start receiver unit */
-static inline int
-	wv_pcmcia_config(dev_link_t *);	/* Configure the pcmcia interface */
-static void
-	wv_pcmcia_release(u_long),	/* Remove a device */
-	wv_flush_stale_links(void);	/* "detach" all possible devices */
-/* ---------------------- INTERRUPT HANDLING ---------------------- */
-static void
-wavelan_interrupt(int,	/* Interrupt handler */
-		  void *,
-		  struct pt_regs *);
-static void
-	wavelan_watchdog(u_long);	/* Transmission watchdog */
-/* ------------------- CONFIGURATION CALLBACKS ------------------- */
-static int
-	wavelan_open(device *),		/* Open the device */
-	wavelan_close(device *),	/* Close the device */
-	wavelan_init(device *);		/* Do nothing */
-static dev_link_t *
-	wavelan_attach(void);		/* Create a new device */
-static void
-	wavelan_detach(dev_link_t *);	/* Destroy a removed device */
-static int
-	wavelan_event(event_t,		/* Manage pcmcia events */
-		      int,
-		      event_callback_args_t *);
-
-/**************************** VARIABLES ****************************/
-
-static dev_info_t dev_info = "wavelan_cs";
-static dev_link_t *dev_list;		/* Linked list of devices */
-
-/* WARNING : the following variable MUST be volatile
- * It is used by wv_82593_cmd to syncronise with wavelan_interrupt */ 
-static volatile int	wv_wait_completed;
-
-/*
- * Parameters that can be set with 'insmod'
- * The exact syntax is 'insmod wavelan_cs.o <var>=<value>'
- */
-
-/* Bit map of interrupts to choose from */
-/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4 and 3 */
-static int	irq_mask = 0xdeb8;
-static int 	irq_list[4] = { -1 };
-
-/* Shared memory speed, in ns */
-static int	mem_speed;
-
-/* New module interface */
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(mem_speed, "i");
-
-#ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
-/* Enable roaming mode ? No ! Please keep this to 0 */
-static int	do_roaming;
-MODULE_PARM(do_roaming, "i");
-#endif	/* WAVELAN_ROAMING */
-
-#endif	/* WAVELAN_CS_H */
-
diff -u --recursive --new-file v2.5.2/linux/drivers/net/ppp_deflate.c linux/drivers/net/ppp_deflate.c
--- v2.5.2/linux/drivers/net/ppp_deflate.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/net/ppp_deflate.c	Tue Jan 29 21:30:41 2002
@@ -39,7 +39,7 @@
 #include <linux/ppp_defs.h>
 #include <linux/ppp-comp.h>
 
-#include "zlib.c"
+#include <linux/zlib.h>
 
 /*
  * State for a Deflate (de)compressor.
@@ -56,10 +56,6 @@
 
 #define DEFLATE_OVHD	2		/* Deflate overhead/packet */
 
-static void	*zalloc __P((void *, unsigned int items, unsigned int size));
-static void	*zalloc_init __P((void *, unsigned int items,
-				  unsigned int size));
-static void	zfree __P((void *, void *ptr));
 static void	*z_comp_alloc __P((unsigned char *options, int opt_len));
 static void	*z_decomp_alloc __P((unsigned char *options, int opt_len));
 static void	z_comp_free __P((void *state));
@@ -80,72 +76,6 @@
 static void	z_decomp_reset __P((void *state));
 static void	z_comp_stats __P((void *state, struct compstat *stats));
 
-struct chunk_header {
-	int valloced;		/* allocated with valloc, not kmalloc */
-	int guard;		/* check for overwritten header */
-};
-
-#define GUARD_MAGIC	0x77a8011a
-#define MIN_VMALLOC	2048	/* use kmalloc for blocks < this */
-
-/*
- * Space allocation and freeing routines for use by zlib routines.
- */
-void
-zfree(arg, ptr)
-    void *arg;
-    void *ptr;
-{
-	struct chunk_header *hdr = ((struct chunk_header *)ptr) - 1;
-
-	if (hdr->guard != GUARD_MAGIC) {
-		printk(KERN_WARNING "zfree: header corrupted (%x %x) at %p\n",
-		       hdr->valloced, hdr->guard, hdr);
-		return;
-	}
-	if (hdr->valloced)
-		vfree(hdr);
-	else
-		kfree(hdr);
-}
-
-void *
-zalloc(arg, items, size)
-    void *arg;
-    unsigned int items, size;
-{
-	struct chunk_header *hdr;
-	unsigned nbytes;
-
-	nbytes = items * size + sizeof(*hdr);
-	hdr = kmalloc(nbytes, GFP_ATOMIC);
-	if (hdr == 0)
-		return 0;
-	hdr->valloced = 0;
-	hdr->guard = GUARD_MAGIC;
-	return (void *) (hdr + 1);
-}
-
-void *
-zalloc_init(arg, items, size)
-    void *arg;
-    unsigned int items, size;
-{
-	struct chunk_header *hdr;
-	unsigned nbytes;
-
-	nbytes = items * size + sizeof(*hdr);
-	if (nbytes >= MIN_VMALLOC)
-		hdr = vmalloc(nbytes);
-	else
-		hdr = kmalloc(nbytes, GFP_KERNEL);
-	if (hdr == 0)
-		return 0;
-	hdr->valloced = nbytes >= MIN_VMALLOC;
-	hdr->guard = GUARD_MAGIC;
-	return (void *) (hdr + 1);
-}
-
 static void
 z_comp_free(arg)
     void *arg;
@@ -153,7 +83,9 @@
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
 
 	if (state) {
-		deflateEnd(&state->strm);
+		zlib_deflateEnd(&state->strm);
+		if (state->strm.workspace)
+			kfree(state->strm.workspace);
 		kfree(state);
 		MOD_DEC_USE_COUNT;
 	}
@@ -180,22 +112,24 @@
 	if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
 		return NULL;
 
-	state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL);
+	state = (struct ppp_deflate_state *) kmalloc(sizeof(*state),
+						     GFP_KERNEL);
 	if (state == NULL)
 		return NULL;
 
 	MOD_INC_USE_COUNT;
 	memset (state, 0, sizeof (struct ppp_deflate_state));
-	state->strm.next_in = NULL;
-	state->strm.zalloc  = zalloc_init;
-	state->strm.zfree   = zfree;
-	state->w_size       = w_size;
+	state->strm.next_in   = NULL;
+	state->w_size         = w_size;
+	state->strm.workspace = kmalloc(zlib_deflate_workspacesize(),
+					GFP_KERNEL);
+	if (state->strm.workspace == NULL)
+		goto out_free;
 
-	if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
+	if (zlib_deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
 			 DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY)
 	    != Z_OK)
 		goto out_free;
-	state->strm.zalloc = zalloc;
 	return (void *) state;
 
 out_free:
@@ -224,7 +158,7 @@
 	state->unit  = unit;
 	state->debug = debug;
 
-	deflateReset(&state->strm);
+	zlib_deflateReset(&state->strm);
 
 	return 1;
 }
@@ -236,7 +170,7 @@
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
 
 	state->seqno = 0;
-	deflateReset(&state->strm);
+	zlib_deflateReset(&state->strm);
 }
 
 int
@@ -286,7 +220,7 @@
 	state->strm.avail_in = (isize - off);
 
 	for (;;) {
-		r = deflate(&state->strm, Z_PACKET_FLUSH);
+		r = zlib_deflate(&state->strm, Z_PACKET_FLUSH);
 		if (r != Z_OK) {
 			if (state->debug)
 				printk(KERN_ERR
@@ -337,7 +271,9 @@
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
 
 	if (state) {
-		inflateEnd(&state->strm);
+		zlib_inflateEnd(&state->strm);
+		if (state->strm.workspace)
+			kfree(state->strm.workspace);
 		kfree(state);
 		MOD_DEC_USE_COUNT;
 	}
@@ -370,14 +306,15 @@
 
 	MOD_INC_USE_COUNT;
 	memset (state, 0, sizeof (struct ppp_deflate_state));
-	state->w_size        = w_size;
-	state->strm.next_out = NULL;
-	state->strm.zalloc   = zalloc_init;
-	state->strm.zfree    = zfree;
+	state->w_size         = w_size;
+	state->strm.next_out  = NULL;
+	state->strm.workspace = kmalloc(zlib_inflate_workspacesize(),
+					GFP_KERNEL);
+	if (state->strm.workspace == NULL)
+		goto out_free;
 
-	if (inflateInit2(&state->strm, -w_size) != Z_OK)
+	if (zlib_inflateInit2(&state->strm, -w_size) != Z_OK)
 		goto out_free;
-	state->strm.zalloc = zalloc;
 	return (void *) state;
 
 out_free:
@@ -407,7 +344,7 @@
 	state->debug = debug;
 	state->mru   = mru;
 
-	inflateReset(&state->strm);
+	zlib_inflateReset(&state->strm);
 
 	return 1;
 }
@@ -419,7 +356,7 @@
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
 
 	state->seqno = 0;
-	inflateReset(&state->strm);
+	zlib_inflateReset(&state->strm);
 }
 
 /*
@@ -492,7 +429,7 @@
 	 * Call inflate, supplying more input or output as needed.
 	 */
 	for (;;) {
-		r = inflate(&state->strm, Z_PACKET_FLUSH);
+		r = zlib_inflate(&state->strm, Z_PACKET_FLUSH);
 		if (r != Z_OK) {
 			if (state->debug)
 				printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n",
@@ -575,7 +512,7 @@
 		++state->strm.avail_in;
 	}
 
-	r = inflateIncomp(&state->strm);
+	r = zlib_inflateIncomp(&state->strm);
 	if (r != Z_OK) {
 		/* gak! */
 		if (state->debug) {
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c
--- v2.5.2/linux/drivers/net/sunbmac.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sunbmac.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: sunbmac.c,v 1.28 2001/10/21 06:35:29 davem Exp $
+/* $Id: sunbmac.c,v 1.30 2002/01/15 06:48:55 davem Exp $
  * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -986,7 +986,7 @@
 	unsigned long bregs = bp->bregs;
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
-	int i, j, bit, byte;
+	int i;
 	u32 tmp, crc;
 
 	/* Disable the receiver.  The bit self-clears when
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sundance.c linux/drivers/net/sundance.c
--- v2.5.2/linux/drivers/net/sundance.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sundance.c	Thu Jan 24 11:51:10 2002
@@ -16,11 +16,16 @@
 
 	Support and updates available at
 	http://www.scyld.com/network/sundance.html
+
+
+	Version 1.01a (jgarzik):
+	- Replace some MII-related magic numbers with constants
+
 */
 
 #define DRV_NAME	"sundance"
-#define DRV_VERSION	"1.01"
-#define DRV_RELDATE	"4/09/00"
+#define DRV_VERSION	"1.01a"
+#define DRV_RELDATE	"11-Nov-2001"
 
 
 /* The user-configurable values.
@@ -443,7 +448,7 @@
 	int irq;
 	int i;
 	long ioaddr;
-	u16 mii_reg0;
+	u16 mii_ctl;
 	void *ring_space;
 	dma_addr_t ring_dma;
 
@@ -582,15 +587,15 @@
 		}
 	}
 	/* Reset PHY */
-	mdio_write (dev, np->phys[0], 0, 0x8000);
+	mdio_write (dev, np->phys[0], MII_BMCR, BMCR_RESET);
 	mdelay (300);
-	mdio_write (dev, np->phys[0], 0, 0x1200);
+	mdio_write (dev, np->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);
 	/* Force media type */
 	if (!np->an_enable) {
-		mii_reg0 = 0;
-		mii_reg0 |= (np->speed == 100) ? 0x2000 : 0;
-		mii_reg0 |= (np->full_duplex) ? 0x0100 : 0;
-		mdio_write (dev, np->phys[0], 0, mii_reg0);
+		mii_ctl = 0;
+		mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0;
+		mii_ctl |= (np->full_duplex) ? BMCR_FULLDPLX : 0;
+		mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl);
 		printk (KERN_INFO "Override speed=%d, %s duplex\n",
 			np->speed, np->full_duplex ? "Full" : "Half");
 
@@ -798,12 +803,12 @@
 {
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
-	int mii_reg5 = mdio_read(dev, np->phys[0], 5);
-	int negotiated = mii_reg5 & np->advertising;
+	int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
+	int negotiated = mii_lpa & np->advertising;
 	int duplex;
 	
 	/* Force media */
-	if (!np->an_enable || mii_reg5 == 0xffff) {
+	if (!np->an_enable || mii_lpa == 0xffff) {
 		if (np->full_duplex)
 			writew (readw (ioaddr + MACCtrl0) | EnbFullDuplex,
 				ioaddr + MACCtrl0);
@@ -1184,7 +1189,7 @@
 {
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = dev->priv;
-	u16 mii_reg0, mii_reg4, mii_reg5;
+	u16 mii_ctl, mii_advertise, mii_lpa;
 	int speed;
 
 	if (intr_status & IntrDrvRqst) {
@@ -1200,27 +1205,27 @@
 	}
 	if (intr_status & LinkChange) {
 		if (np->an_enable) {
-			mii_reg4 = mdio_read (dev, np->phys[0], 4);
-			mii_reg5= mdio_read (dev, np->phys[0], 5);
-			mii_reg4 &= mii_reg5;
+			mii_advertise = mdio_read (dev, np->phys[0], MII_ADVERTISE);
+			mii_lpa= mdio_read (dev, np->phys[0], MII_LPA);
+			mii_advertise &= mii_lpa;
 			printk (KERN_INFO "%s: Link changed: ", dev->name);
-			if (mii_reg4 & 0x0100)
+			if (mii_advertise & ADVERTISE_100FULL)
 				printk ("100Mbps, full duplex\n");
-			else if (mii_reg4 & 0x0080)
+			else if (mii_advertise & ADVERTISE_100HALF)
 				printk ("100Mbps, half duplex\n");
-			else if (mii_reg4 & 0x0040)
+			else if (mii_advertise & ADVERTISE_10FULL)
 				printk ("10Mbps, full duplex\n");
-			else if (mii_reg4 & 0x0020)
+			else if (mii_advertise & ADVERTISE_10HALF)
 				printk ("10Mbps, half duplex\n");
 			else
 				printk ("\n");
 
 		} else {
-			mii_reg0 = mdio_read (dev, np->phys[0], 0);
-			speed = (mii_reg0 & 0x2000) ? 100 : 10;
+			mii_ctl = mdio_read (dev, np->phys[0], MII_BMCR);
+			speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10;
 			printk (KERN_INFO "%s: Link changed: %dMbps ,",
 				dev->name, speed);
-			printk ("%s duplex.\n", (mii_reg0 & 0x0100) ?
+			printk ("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ?
 				"full" : "half");
 		}
 		check_duplex (dev);
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sungem.c linux/drivers/net/sungem.c
--- v2.5.2/linux/drivers/net/sungem.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sungem.c	Wed Jan 23 15:28:40 2002
@@ -1,4 +1,4 @@
-/* $Id: sungem.c,v 1.44 2001/12/08 04:06:27 davem Exp $
+/* $Id: sungem.c,v 1.49 2002/01/23 15:40:45 davem Exp $
  * sungem.c: Sun GEM ethernet driver.
  *
  * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
@@ -10,6 +10,10 @@
  *  - Get rid of all those nasty mdelay's and replace them
  * with schedule_timeout.
  *  - Implement WOL
+ *  - Currently, forced Gb mode is only supported on bcm54xx
+ *    PHY for which I use the SPD2 bit of the control register.
+ *    On m1011 PHY, I can't force as I don't have the specs, but
+ *    I can at least detect gigabit with autoneg.
  */
 
 #include <linux/module.h>
@@ -58,6 +62,10 @@
 
 #include "sungem.h"
 
+#define DEFAULT_MSG	(NETIF_MSG_DRV		| \
+			 NETIF_MSG_PROBE	| \
+			 NETIF_MSG_LINK)
+
 #define DRV_NAME	"sungem"
 #define DRV_VERSION	"0.96"
 #define DRV_RELDATE	"11/17/01"
@@ -71,16 +79,18 @@
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(gem_debug, "i");
-MODULE_PARM_DESC(gem_debug, "(ignored)");
+MODULE_PARM_DESC(gem_debug, "bitmapped message enable number");
 MODULE_PARM(link_mode, "i");
+MODULE_PARM_DESC(link_mode, "default link mode");
 
+int gem_debug = -1;
 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_SPD2, /* bcm54xx only */   /* 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 */
@@ -89,10 +99,9 @@
 #define GEM_MODULE_NAME	"gem"
 #define PFX GEM_MODULE_NAME ": "
 
-#ifdef GEM_DEBUG
-int gem_debug = GEM_DEBUG;
-#else
-int gem_debug = 1;
+/* Until this gets merged from 2.4.x... */
+#ifndef PCI_DEVICE_ID_APPLE_UNI_N_GMACP
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP 0x0024
 #endif
 
 static struct pci_device_id gem_pci_tbl[] __devinitdata = {
@@ -110,6 +119,8 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMAC,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMACP,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{0, }
 };
 
@@ -175,6 +186,8 @@
 
 static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits)
 {
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: mif interrupt\n", gp->dev->name);
 }
 
 static int gem_pcs_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status)
@@ -182,6 +195,10 @@
 	u32 pcs_istat = readl(gp->regs + PCS_ISTAT);
 	u32 pcs_miistat;
 
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: pcs interrupt, pcs_istat: 0x%x\n",
+			gp->dev->name, pcs_istat);
+
 	if (!(pcs_istat & PCS_ISTAT_LSC)) {
 		printk(KERN_ERR "%s: PCS irq but no link status change???\n",
 		       dev->name);
@@ -231,6 +248,10 @@
 {
 	u32 txmac_stat = readl(gp->regs + MAC_TXSTAT);
 
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: txmac interrupt, txmac_stat: 0x%x\n",
+			gp->dev->name, txmac_stat);
+
 	/* Defer timer expiration is quite normal,
 	 * don't even log the event.
 	 */
@@ -276,6 +297,10 @@
 {
 	u32 rxmac_stat = readl(gp->regs + MAC_RXSTAT);
 
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: rxmac interrupt, rxmac_stat: 0x%x\n",
+			gp->dev->name, rxmac_stat);
+
 	if (rxmac_stat & MAC_RXSTAT_OFLW) {
 		printk(KERN_ERR "%s: RX MAC fifo overflow.\n",
 		       dev->name);
@@ -302,6 +327,10 @@
 {
 	u32 mac_cstat = readl(gp->regs + MAC_CSTAT);
 
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: mac interrupt, mac_cstat: 0x%x\n",
+			gp->dev->name, mac_cstat);
+
 	/* This interrupt is just for pause frame and pause
 	 * tracking.  It is useful for diagnostics and debug
 	 * but probably by default we will mask these events.
@@ -402,11 +431,17 @@
 {
 	if (gem_status & GREG_STAT_RXNOBUF) {
 		/* Frame arrived, no free RX buffers available. */
+		if (netif_msg_rx_err(gp))
+			printk(KERN_DEBUG "%s: no buffer for rx frame\n",
+				gp->dev->name);
 		gp->net_stats.rx_dropped++;
 	}
 
 	if (gem_status & GREG_STAT_RXTAGERR) {
 		/* corrupt RX tag framing */
+		if (netif_msg_rx_err(gp))
+			printk(KERN_DEBUG "%s: corrupt rx tag framing\n",
+				gp->dev->name);
 		gp->net_stats.rx_errors++;
 
 		goto do_reset;
@@ -455,6 +490,10 @@
 {
 	int entry, limit;
 
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: tx interrupt, gem_status: 0x%x\n",
+			gp->dev->name, gem_status);
+
 	entry = gp->tx_old;
 	limit = ((gem_status & GREG_STAT_TXNR) >> GREG_STAT_TXNR_SHIFT);
 	while (entry != limit) {
@@ -464,6 +503,9 @@
 		u32 dma_len;
 		int frag;
 
+		if (netif_msg_tx_done(gp))
+			printk(KERN_DEBUG "%s: tx done, slot %d\n",
+				gp->dev->name, entry);
 		skb = gp->tx_skbs[entry];
 		if (skb_shinfo(skb)->nr_frags) {
 			int last = entry + skb_shinfo(skb)->nr_frags;
@@ -535,6 +577,10 @@
 {
 	int entry, drops;
 
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n",
+			gp->dev->name, readl(gp->regs + RXDMA_DONE), gp->rx_new);
+
 	entry = gp->rx_new;
 	drops = 0;
 	for (;;) {
@@ -786,6 +832,9 @@
 	if (TX_BUFFS_AVAIL(gp) <= 0)
 		netif_stop_queue(dev);
 
+	if (netif_msg_tx_queued(gp))
+		printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n",
+		       dev->name, entry, skb->len);
 	writel(gp->tx_new, gp->regs + TXDMA_KICK);
 	spin_unlock_irq(&gp->lock);
 
@@ -959,6 +1008,14 @@
 			*fd = 1;
 		if (val & (LPA_100FULL | LPA_100HALF))
 			*spd = 100;
+
+		if (gp->phy_mod == phymod_m1011) {
+			val = phy_read(gp, 0x0a);
+			if (val & 0xc00)
+				*spd = 1000;
+			if (val & 0x800)
+				*fd = 1;
+		}
 	}
 }
 
@@ -993,8 +1050,9 @@
 		speed = 1000;
 	}
 
-	printk(KERN_INFO "%s: Link is up at %d Mbps, %s-duplex.\n",
-	       gp->dev->name, speed, (full_duplex ? "full" : "half"));
+	if (netif_msg_link(gp))
+		printk(KERN_INFO "%s: Link is up at %d Mbps, %s-duplex.\n",
+			gp->dev->name, speed, (full_duplex ? "full" : "half"));
 
 	val = (MAC_TXCFG_EIPG0 | MAC_TXCFG_NGU);
 	if (full_duplex) {
@@ -1059,15 +1117,21 @@
 
 static int gem_mdio_link_not_up(struct gem *gp)
 {
+	u16 val;
+	
 	if (gp->lstate == link_force_ret) {
-		printk(KERN_INFO "%s: Autoneg failed again, keeping"
-			" forced mode\n", gp->dev->name);
+		if (netif_msg_link(gp))
+			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);
+		val = phy_read(gp, MII_BMCR);
 
+		if (netif_msg_link(gp))
+			printk(KERN_INFO "%s: switching to forced 100bt\n",
+				gp->dev->name);
 		/* Try forced modes. */
 		val &= ~(BMCR_ANRESTART | BMCR_ANENABLE);
 		val &= ~(BMCR_FULLDPLX);
@@ -1080,14 +1144,16 @@
 		 * If already at 10Mbps, warn user about the
 		 * situation every 10 ticks.
 		 */
-		u16 val = phy_read(gp, MII_BMCR);
+		val = phy_read(gp, MII_BMCR);
 		if (val & BMCR_SPEED100) {
 			val &= ~BMCR_SPEED100;
 			phy_write(gp, MII_BMCR, val);
 			gp->timer_ticks = 5;
-		} else {
+			if (netif_msg_link(gp))
+				printk(KERN_INFO "%s: switching to forced 10bt\n",
+					gp->dev->name);
+		} else
 			return 1;
-		}
 	}
 	return 0;
 }
@@ -1140,22 +1206,16 @@
 	if (gp->phy_type == phy_mii_mdio0 ||
 	    gp->phy_type == phy_mii_mdio1) {
 		u16 val = phy_read(gp, MII_BMSR);
+		u16 cntl = phy_read(gp, MII_BMCR);
 		int up;
 
 		/* 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 (cntl & BMCR_ANENABLE)
+			up = (val & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS);
+		else
+			up = (val & BMSR_LSTATUS) != 0;
 		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
@@ -1166,8 +1226,9 @@
 				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);
+				if (netif_msg_link(gp))
+					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) {
@@ -1183,7 +1244,9 @@
 			 */
 			if (gp->lstate == link_up) {
 				gp->lstate = link_down;
-				printk(KERN_INFO "%s: Link down\n", gp->dev->name);
+				if (netif_msg_link(gp))
+					printk(KERN_INFO "%s: Link down\n",
+						gp->dev->name);
 				gp->reset_task_pending = 1;
 				schedule_task(&gp->reset_task);
 				restart = 1;
@@ -1528,6 +1591,11 @@
 			gem_init_bcm5411_phy(gp);
 			gp->gigabit_capable = 1;
 			break;
+		case 0x1410c60:
+			printk("M1011 (Marvel ?)\n");
+			gp->phy_mod = phymod_m1011;
+			gp->gigabit_capable = 1;
+			break;
 
 		case 0x18074c0:
 			printk("Lucent\n");
@@ -1540,7 +1608,7 @@
 			break;
 
 		default:
-			printk("Unknown\n");
+			printk("Unknown (Using generic mode)\n");
 			gp->phy_mod = phymod_generic;
 			break;
 		};
@@ -1611,6 +1679,12 @@
 		writel(val, gp->regs + PCS_SCTRL);
 		gp->gigabit_capable = 1;
 	}
+
+	/* BMCR_SPD2 is a broadcom 54xx specific thing afaik */
+	if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 &&
+	    gp->phy_mod != phymod_bcm5411)
+	    	gp->link_cntl &= ~BMCR_SPD2;
+	    
 }
 
 static void gem_init_dma(struct gem *gp)
@@ -1650,6 +1724,48 @@
 		       gp->regs + RXDMA_BLANK);
 }
 
+static u32
+gem_setup_multicast(struct gem *gp)
+{
+	u32 rxcfg = 0;
+	int i;
+	
+	if ((gp->dev->flags & IFF_ALLMULTI) ||
+	    (gp->dev->mc_count > 256)) {
+	    	for (i=0; i<16; i++)
+			writel(0xffff, gp->regs + MAC_HASH0 + (i << 2));
+		rxcfg |= MAC_RXCFG_HFE;
+	} else if (gp->dev->flags & IFF_PROMISC) {
+		rxcfg |= MAC_RXCFG_PROM;
+	} else {
+		u16 hash_table[16];
+		u32 crc;
+		struct dev_mc_list *dmi = gp->dev->mc_list;
+		int i;
+
+		for (i = 0; i < 16; i++)
+			hash_table[i] = 0;
+
+		for (i = 0; i < gp->dev->mc_count; i++) {
+			char *addrs = dmi->dmi_addr;
+
+			dmi = dmi->next;
+
+			if (!(*addrs & 1))
+				continue;
+
+ 			crc = ether_crc_le(6, addrs);
+			crc >>= 24;
+			hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
+		}
+	    	for (i=0; i<16; i++)
+			writel(hash_table[i], gp->regs + MAC_HASH0 + (i << 2));
+		rxcfg |= MAC_RXCFG_HFE;
+	}
+
+	return rxcfg;
+}
+
 static void gem_init_mac(struct gem *gp)
 {
 	unsigned char *e = &gp->dev->dev_addr[0];
@@ -1690,65 +1806,7 @@
 	writel(0, gp->regs + MAC_AF21MSK);
 	writel(0, gp->regs + MAC_AF0MSK);
 
-	rxcfg = 0;
-	if ((gp->dev->flags & IFF_ALLMULTI) ||
-	    (gp->dev->mc_count > 256)) {
-		writel(0xffff, gp->regs + MAC_HASH0);
-		writel(0xffff, gp->regs + MAC_HASH1);
-		writel(0xffff, gp->regs + MAC_HASH2);
-		writel(0xffff, gp->regs + MAC_HASH3);
-		writel(0xffff, gp->regs + MAC_HASH4);
-		writel(0xffff, gp->regs + MAC_HASH5);
-		writel(0xffff, gp->regs + MAC_HASH6);
-		writel(0xffff, gp->regs + MAC_HASH7);
-		writel(0xffff, gp->regs + MAC_HASH8);
-		writel(0xffff, gp->regs + MAC_HASH9);
-		writel(0xffff, gp->regs + MAC_HASH10);
-		writel(0xffff, gp->regs + MAC_HASH11);
-		writel(0xffff, gp->regs + MAC_HASH12);
-		writel(0xffff, gp->regs + MAC_HASH13);
-		writel(0xffff, gp->regs + MAC_HASH14);
-		writel(0xffff, gp->regs + MAC_HASH15);
-	} else if (gp->dev->flags & IFF_PROMISC) {
-		rxcfg |= MAC_RXCFG_PROM;
-	} else {
-		u16 hash_table[16];
-		u32 crc;
-		struct dev_mc_list *dmi = gp->dev->mc_list;
-		int i;
-
-		for (i = 0; i < 16; i++)
-			hash_table[i] = 0;
-
-		for (i = 0; i < gp->dev->mc_count; i++) {
-			char *addrs = dmi->dmi_addr;
-
-			dmi = dmi->next;
-
-			if (!(*addrs & 1))
-				continue;
-
- 			crc = ether_crc_le(6, addrs);
-			crc >>= 24;
-			hash_table[crc >> 4] |= 1 << (crc & 0xf);
-		}
-		writel(hash_table[0], gp->regs + MAC_HASH0);
-		writel(hash_table[1], gp->regs + MAC_HASH1);
-		writel(hash_table[2], gp->regs + MAC_HASH2);
-		writel(hash_table[3], gp->regs + MAC_HASH3);
-		writel(hash_table[4], gp->regs + MAC_HASH4);
-		writel(hash_table[5], gp->regs + MAC_HASH5);
-		writel(hash_table[6], gp->regs + MAC_HASH6);
-		writel(hash_table[7], gp->regs + MAC_HASH7);
-		writel(hash_table[8], gp->regs + MAC_HASH8);
-		writel(hash_table[9], gp->regs + MAC_HASH9);
-		writel(hash_table[10], gp->regs + MAC_HASH10);
-		writel(hash_table[11], gp->regs + MAC_HASH11);
-		writel(hash_table[12], gp->regs + MAC_HASH12);
-		writel(hash_table[13], gp->regs + MAC_HASH13);
-		writel(hash_table[14], gp->regs + MAC_HASH14);
-		writel(hash_table[15], gp->regs + MAC_HASH15);
-	}
+	rxcfg = gem_setup_multicast(gp);
 
 	writel(0, gp->regs + MAC_NCOLL);
 	writel(0, gp->regs + MAC_FASUCC);
@@ -1816,9 +1874,8 @@
 	u32 mif_cfg;
 
 	/* 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.
+	 * was been powered down by the firmware. The PHY is looked
+	 * up later on.
 	 */
 	if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
 		gp->phy_type = phy_mii_mdio0;
@@ -1943,7 +2000,8 @@
 
 	pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1);
 
-	udelay(100);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout((21 * HZ) / 1000);
 
 	pci_read_config_word(gp->pdev, PCI_COMMAND, &cmd);
 	cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
@@ -2013,7 +2071,8 @@
 				  val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
 #endif				
 			phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
-		}
+		} else if (gp->phy_mod == phymod_m1011)
+			phy_write(gp, MII_BMCR, BMCR_PDOWN);
 
 		/* According to Apple, we must set the MDIO pins to this begnign
 		 * state or we may 1) eat more current, 2) damage some PHYs
@@ -2041,16 +2100,14 @@
 		schedule();
 	
 	/* Actually stop the chip */
-	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+	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)
+		/* Power down the chip */
 		gem_apple_powerdown(gp);
 #endif /* CONFIG_ALL_PPC */
+	} else
+		gem_stop(gp);
 }
 
 static void gem_pm_task(void *data)
@@ -2112,6 +2169,7 @@
 	 */
 	if (request_irq(gp->pdev->irq, gem_interrupt,
 			SA_SHIRQ, dev->name, (void *)dev)) {
+		printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name);
 #ifdef CONFIG_ALL_PPC
 		if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
 			gem_apple_powerdown(gp);
@@ -2274,81 +2332,28 @@
 static void gem_set_multicast(struct net_device *dev)
 {
 	struct gem *gp = dev->priv;
-
+	u32 rxcfg, rxcfg_new;
+	int limit = 10000;
+	
 	if (!gp->hw_running)
 		return;
 		
 	netif_stop_queue(dev);
 
-	if ((gp->dev->flags & IFF_ALLMULTI) ||
-	    (gp->dev->mc_count > 256)) {
-		writel(0xffff, gp->regs + MAC_HASH0);
-		writel(0xffff, gp->regs + MAC_HASH1);
-		writel(0xffff, gp->regs + MAC_HASH2);
-		writel(0xffff, gp->regs + MAC_HASH3);
-		writel(0xffff, gp->regs + MAC_HASH4);
-		writel(0xffff, gp->regs + MAC_HASH5);
-		writel(0xffff, gp->regs + MAC_HASH6);
-		writel(0xffff, gp->regs + MAC_HASH7);
-		writel(0xffff, gp->regs + MAC_HASH8);
-		writel(0xffff, gp->regs + MAC_HASH9);
-		writel(0xffff, gp->regs + MAC_HASH10);
-		writel(0xffff, gp->regs + MAC_HASH11);
-		writel(0xffff, gp->regs + MAC_HASH12);
-		writel(0xffff, gp->regs + MAC_HASH13);
-		writel(0xffff, gp->regs + MAC_HASH14);
-		writel(0xffff, gp->regs + MAC_HASH15);
-	} else if (gp->dev->flags & IFF_PROMISC) {
-		u32 rxcfg = readl(gp->regs + MAC_RXCFG);
-		int limit = 10000;
-
-		writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
-		while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) {
-			if (!limit--)
-				break;
-			udelay(10);
-		}
-
-		rxcfg |= MAC_RXCFG_PROM;
-		writel(rxcfg, gp->regs + MAC_RXCFG);
-	} else {
-		u16 hash_table[16];
-		u32 crc;
-		struct dev_mc_list *dmi = gp->dev->mc_list;
-		int i;
-
-		for (i = 0; i < 16; i++)
-			hash_table[i] = 0;
-
-		for (i = 0; i < dev->mc_count; i++) {
-			char *addrs = dmi->dmi_addr;
-
-			dmi = dmi->next;
+	rxcfg = readl(gp->regs + MAC_RXCFG);
+	rxcfg_new = gem_setup_multicast(gp);
+	
+	writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
+	while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) {
+		if (!limit--)
+			break;
+		udelay(10);
+	}
 
-			if (!(*addrs & 1))
-				continue;
+	rxcfg &= ~(MAC_RXCFG_PROM | MAC_RXCFG_HFE);
+	rxcfg |= rxcfg_new;
 
-			crc = ether_crc_le(6, addrs);
-			crc >>= 24;
-			hash_table[crc >> 4] |= 1 << (crc & 0xf);
-		}
-		writel(hash_table[0], gp->regs + MAC_HASH0);
-		writel(hash_table[1], gp->regs + MAC_HASH1);
-		writel(hash_table[2], gp->regs + MAC_HASH2);
-		writel(hash_table[3], gp->regs + MAC_HASH3);
-		writel(hash_table[4], gp->regs + MAC_HASH4);
-		writel(hash_table[5], gp->regs + MAC_HASH5);
-		writel(hash_table[6], gp->regs + MAC_HASH6);
-		writel(hash_table[7], gp->regs + MAC_HASH7);
-		writel(hash_table[8], gp->regs + MAC_HASH8);
-		writel(hash_table[9], gp->regs + MAC_HASH9);
-		writel(hash_table[10], gp->regs + MAC_HASH10);
-		writel(hash_table[11], gp->regs + MAC_HASH11);
-		writel(hash_table[12], gp->regs + MAC_HASH12);
-		writel(hash_table[13], gp->regs + MAC_HASH13);
-		writel(hash_table[14], gp->regs + MAC_HASH14);
-		writel(hash_table[15], gp->regs + MAC_HASH15);
-	}
+	writel(rxcfg, gp->regs + MAC_RXCFG);
 
 	/* Hrm... we may walk on the reset task here... */
 	netif_wake_queue(dev);
@@ -2470,7 +2475,7 @@
 	case ETHTOOL_GMSGLVL: {
 		struct ethtool_value edata = { cmd: ETHTOOL_GMSGLVL };
 
-		edata.data = gem_debug;
+		edata.data = gp->msg_enable;
 		if (copy_to_user(ep_user, &edata, sizeof(edata)))
 			return -EFAULT;
 		return 0;
@@ -2482,7 +2487,7 @@
 
 		if (copy_from_user(&edata, ep_user, sizeof(edata)))
 			return -EFAULT;
-		gem_debug = edata.data;
+		gp->msg_enable = edata.data;
 		return 0;
 	}
 
@@ -2678,6 +2683,8 @@
 	dev->base_addr = (long) pdev;
 	gp->dev = dev;
 
+	gp->msg_enable = (gem_debug < 0 ? DEFAULT_MSG : gem_debug);
+
 	spin_lock_init(&gp->lock);
 	init_MUTEX(&gp->pm_sem);
 
@@ -2712,25 +2719,15 @@
 	 * not have properly shut down the PHY.
 	 */
 #ifdef CONFIG_ALL_PPC
-	if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
+	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);
-		if (gem_check_invariants(gp))
-			goto err_out_iounmap;
-		gp->hw_running = 1;
-	}
+	gem_stop(gp);
+	if (gem_check_invariants(gp))
+		goto err_out_iounmap;
+	gp->hw_running = 1;
+	gem_init_phy(gp);
+	gem_begin_auto_negotiation(gp, NULL);
 
 	/* It is guarenteed that the returned buffer will be at least
 	 * PAGE_SIZE aligned.
@@ -2838,7 +2835,7 @@
 	name:		GEM_MODULE_NAME,
 	id_table:	gem_pci_tbl,
 	probe:		gem_init_one,
-	remove:		__devexit_p(gem_remove_one),
+	remove:		gem_remove_one,
 #ifdef CONFIG_PM
 	suspend:	gem_suspend,
 	resume:		gem_resume,
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sungem.h linux/drivers/net/sungem.h
--- v2.5.2/linux/drivers/net/sungem.h	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sungem.h	Wed Jan 23 15:28:40 2002
@@ -1,4 +1,4 @@
-/* $Id: sungem.h,v 1.10 2001/11/29 03:57:33 davem Exp $
+/* $Id: sungem.h,v 1.12 2002/01/23 15:40:45 davem Exp $
  * sungem.h: Definitions for Sun GEM ethernet driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -941,6 +941,7 @@
 	phymod_bcm5400,
 	phymod_bcm5401,
 	phymod_bcm5411,
+	phymod_m1011,
 };
 
 enum link_state {
@@ -972,6 +973,8 @@
 	struct sk_buff *rx_skbs[RX_RING_SIZE];
 	struct sk_buff *tx_skbs[RX_RING_SIZE];
 
+	u32			msg_enable;
+
 	struct net_device_stats net_stats;
 
 	enum gem_phy_type	phy_type;
@@ -995,8 +998,8 @@
 	volatile int		reset_task_pending;
 	
 	/* Diagnostic counters and state. */
-	u64 pause_entered;
-	u16 pause_last_time_recvd;
+	u64			pause_entered;
+	u16			pause_last_time_recvd;
 
 	dma_addr_t gblock_dvma;
 	struct pci_dev *pdev;
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.5.2/linux/drivers/net/sunhme.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sunhme.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.123 2001/10/02 02:22:30 davem Exp $
+/* $Id: sunhme.c,v 1.124 2002/01/15 06:25:51 davem Exp $
  * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.5.2/linux/drivers/net/sunlance.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sunlance.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.109 2001/10/21 06:35:29 davem Exp $
+/* $Id: sunlance.c,v 1.112 2002/01/15 06:48:55 davem Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *	Written 1995, 1996 by Miguel de Icaza
@@ -924,14 +924,14 @@
 
 	last_dev = dev;
 
+	STOP_LANCE(lp);
+
 	if (request_irq(dev->irq, &lance_interrupt, SA_SHIRQ,
 			lancestr, (void *) dev)) {
 		printk(KERN_ERR "Lance: Can't get irq %s\n", __irq_itoa(dev->irq));
 		return -EAGAIN;
 	}
 
-	STOP_LANCE(lp);
-
 	/* On the 4m, setup the ledma to provide the upper bits for buffers */
 	if (lp->dregs) {
 		u32 regval = lp->init_block_dvma & 0xff000000;
@@ -1181,7 +1181,7 @@
 	volatile u16 *mcast_table = (u16 *) &ib->filter;
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
-	int i, j, bit, byte;
+	int i;
 	u32 crc;
 	
 	/* set all multicast bits */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.5.2/linux/drivers/net/sunqe.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sunqe.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: sunqe.c,v 1.53 2001/12/21 00:54:31 davem Exp $
+/* $Id: sunqe.c,v 1.55 2002/01/15 06:48:55 davem Exp $
  * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
  *          Once again I am out to prove that every ethernet
  *          controller out there can be most efficiently programmed
@@ -629,7 +629,7 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	u8 new_mconfig = qep->mconfig;
 	char *addrs;
-	int i, j, bit, byte;
+	int i;
 	u32 crc;
 
 	/* Lock out others. */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/tokenring/Config.help linux/drivers/net/tokenring/Config.help
--- v2.5.2/linux/drivers/net/tokenring/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tokenring/Config.help	Fri Jan 25 16:03:48 2002
@@ -0,0 +1,131 @@
+CONFIG_TR
+  Token Ring is IBM's way of communication on a local network; the
+  rest of the world uses Ethernet. To participate on a Token Ring
+  network, you need a special Token ring network card. If you are
+  connected to such a Token Ring network and want to use your Token
+  Ring card under Linux, say Y here and to the driver for your
+  particular card below and read the Token-Ring mini-HOWTO, available
+  from <http://www.linuxdoc.org/docs.html#howto>. Most people can
+  say N here.
+
+CONFIG_IBMTR
+  This is support for all IBM Token Ring cards that don't use DMA. If
+  you have such a beast, say Y and read the Token-Ring mini-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  Warning: this driver will almost definitely fail if more than one
+  active Token Ring card is present.
+
+  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 ibmtr.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_IBMOL
+  This is support for all non-Lanstreamer IBM PCI Token Ring Cards.
+  Specifically this is all IBM PCI, PCI Wake On Lan, PCI II, PCI II
+  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>.
+
+  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 olympic.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+  Also read <file:Documentation/networking/olympic.txt> or check the
+  Linux Token Ring Project site for the latest information at
+  <http://www.linuxtr.net/>.
+
+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 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).
+  The modules will be called lanstreamer.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_TMS380TR
+  This driver provides generic support for token ring adapters
+  based on the Texas Instruments TMS380 series chipsets.  This
+  includes the SysKonnect TR4/16(+) ISA (SK-4190), SysKonnect
+  TR4/16(+) PCI (SK-4590), SysKonnect TR4/16 PCI (SK-4591),
+  Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and several
+  Madge adapters.  If you say Y here, you will be asked to select
+  which cards to support below.  If you're using modules, each
+  class of card will be supported by a separate module.
+
+  If you have such an adapter and would like to use it, say Y and
+  read the Token-Ring mini-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Also read the file <file:Documentation/networking/tms380tr.txt> or
+  check <http://www.auk.cx/tms380tr/>.
+
+  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 tms380tr.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_TMSPCI
+  This tms380 module supports generic TMS380-based PCI cards.
+
+  These cards are known to work:
+     - Compaq 4/16 TR PCI
+     - SysKonnect TR4/16 PCI (SK-4590/SK-4591)
+     - Thomas-Conrad TC4048 PCI 4/16
+     - 3Com Token Link Velocity
+
+  This driver is available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tmspci.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_TMSISA
+  This tms380 module supports generic TMS380-based ISA cards.
+
+  These cards are known to work:
+     - SysKonnect TR4/16 ISA (SK-4190)
+
+  This driver is available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tmsisa.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_ABYSS
+  This tms380 module supports the Madge Smart 16/4 PCI Mk2
+  cards (51-02).
+
+  This driver is available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called abyss.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MADGEMC
+  This tms380 module supports the Madge Smart 16/4 MC16 and MC32
+  MicroChannel adapters.
+
+  This driver is available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called madgemc.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SMCTR
+  This is support for the ISA and MCA SMC Token Ring cards,
+  specifically SMC TokenCard Elite (8115T) and SMC TokenCard Elite/A
+  (8115T/A) adapters.
+
+  If you have such an adapter and would like to use it, say Y or M and
+  read the Token-Ring mini-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto> and the file
+  <file:Documentation/networking/smctr.txt>.
+
+  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 smctr.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wan/Config.help linux/drivers/net/wan/Config.help
--- v2.5.2/linux/drivers/net/wan/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/Config.help	Fri Jan 25 16:03:44 2002
@@ -0,0 +1,427 @@
+CONFIG_LAPBETHER
+  This is a driver for a pseudo device (typically called /dev/lapb0)
+  which allows you to open an LAPB point-to-point connection to some
+  other computer on your Ethernet network.  In order to do this, you
+  need to say Y or M to the driver for your Ethernet card as well as
+  to "LAPB Data Link Driver".
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called lapbether.o.  If unsure, say N.
+
+CONFIG_X25_ASY
+  This is a driver for sending and receiving X.25 frames over regular
+  asynchronous serial lines such as telephone lines equipped with
+  ordinary modems.  Experts should note that this driver doesn't
+  currently comply with the asynchronous HDLS framing protocols in
+  CCITT recommendation X.25.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called x25_asy.o.  If unsure, say N.
+
+CONFIG_SEALEVEL_4021
+  This is a driver for the Sealevel Systems ACB 56 serial I/O adapter.
+
+  This driver can only be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to do that, say M here. The module will be called
+  sealevel.o.
+
+CONFIG_SYNCLINK_SYNCPPP
+  Enables HDLC/SYNCPPP support for the SyncLink WAN driver.
+  Normally the SyncLink WAN driver works with the main PPP
+  driver (ppp.c) and pppd program. HDLC/SYNCPPP support allows use
+  of the Cisco HDLC/PPP driver (syncppp.c).
+  The SyncLink WAN driver (in character devices) must also be enabled.
+
+CONFIG_FARSYNC
+  This driver supports the FarSync T-Series X.21 (and V.35/V.24) cards
+  from FarSite Communications Ltd.
+  Synchronous communication is supported on all ports at speeds up to
+  8Mb/s (128K on V.24) using synchronous PPP or Cisco HDLC.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  say M here and read <file:Documentation/modules.txt>.
+  The module will be called farsync.o and if you want the module to be
+  automatically loaded when the interface is referenced then you
+  should add "alias syncX farsync" to /etc/modules.conf for each
+  interface, where X is 0, 1, 2, ...
+
+CONFIG_DLCI
+  This is support for the frame relay protocol; frame relay is a fast
+  low-cost way to connect to a remote Internet access provider or to
+  form a private wide area network. The one physical line from your
+  box to the local "switch" (i.e. the entry point to the frame relay
+  network, usually at the phone company) can carry several logical
+  point-to-point connections to other computers connected to the frame
+  relay network. For a general explanation of the protocol, check out
+  <http://www.frforum.com/> on the WWW. To use frame relay, you need
+  supporting hardware (called FRAD) and certain programs from the
+  net-tools package as explained in
+  <file:Documentation/networking/framerelay.txt>.
+
+  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 dlci.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_DLCI_COUNT
+  This is the maximal number of logical point-to-point frame relay
+  connections (the identifiers of which are called DCLIs) that
+  the driver can handle. The default is probably fine.
+
+CONFIG_DLCI_MAX
+  You can specify here how many logical point-to-point frame relay
+  connections (the identifiers of which are called DCLIs) should be
+  handled by each of your hardware frame relay access devices. Go with
+  the default.
+
+CONFIG_SDLA
+  Say Y here if you need a driver for the Sangoma S502A, S502E, and
+  S508 Frame Relay Access Devices. These are multi-protocol cards, but
+  only frame relay is supported by the driver at this time. Please
+  read <file:Documentation/framerelay.txt>.
+
+  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 sdla.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_WAN
+  Wide Area Networks (WANs), such as X.25, frame relay and leased
+  lines, are used to interconnect Local Area Networks (LANs) over vast
+  distances with data transfer rates significantly higher than those
+  achievable with commonly used asynchronous modem connections.
+  Usually, a quite expensive external device called a `WAN router' is
+  needed to connect to a WAN.
+
+  As an alternative, a relatively inexpensive WAN interface card can
+  allow your Linux box to directly connect to a WAN. If you have one
+  of those cards and wish to use it under Linux, say Y here and also
+  to the WAN driver for your card, below.
+
+  If unsure, say N.
+
+CONFIG_HOSTESS_SV11
+  This is a network card for low speed synchronous serial links, at
+  up to 256Kbps. It supports both PPP and Cisco HDLC.
+
+  At this point, the driver can only be compiled as a module.
+
+CONFIG_COSA
+  This is a driver for COSA and SRP synchronous serial boards. These
+  boards allow to connect synchronous serial devices (for example
+  base-band modems, or any other device with the X.21, V.24, V.35 or
+  V.36 interface) to your Linux box. The cards can work as the
+  character device, synchronous PPP network device, or the Cisco HDLC
+  network device.
+
+  To actually use the COSA or SRP board, you will need user-space
+  utilities for downloading the firmware to the cards and to set them
+  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/wan/cosa.c> for details about the cards and the driver
+  itself.
+
+  The driver will be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cosa.o. For general information about
+  modules read <file:Documentation/modules.txt>.
+
+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/>
+  for further informations about the driver and his configuration.
+
+  The driver will be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called dscc4.o. For general information about
+  modules read <file:Documentation/modules.txt>.
+
+CONFIG_LANMEDIA
+  This is a driver for the following Lan Media family of serial
+  boards.
+
+  LMC 1000 board allows you to connect synchronous serial devices (for
+  example base-band modems, or any other device with the X.21, V.24,
+  V.35 or V.36 interface) to your Linux box.
+
+  LMC 1200 with on board DSU board allows you to connect your Linux
+  box dirrectly to a T1 or E1 circuit.
+
+  LMC 5200 board provides a HSSI interface capable of running up to
+  52 mbits per second.
+
+  LMC 5245 board connects directly to a T3 circuit saving the
+  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/>.
+
+  This code is also available as a module called lmc.o ( = 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>.
+
+CONFIG_SBNI
+  This is a driver for ISA SBNI12-xx cards which are low cost
+  alternatives to leased line modems. Say Y if you want to insert
+  the driver into the kernel or say M to compile it as a module (the
+  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
+  can send email to sbni@granch.ru.
+
+  Say N if unsure.
+
+CONFIG_SBNI_MULTILINE
+  Schedule traffic for some parallel lines, via SBNI12 adapters.
+  If you have two computers connected with two parallel lines it's
+  possible to increase transfer rate nearly twice. You should have
+  a program named 'sbniconfig' to configure adapters.
+
+  Say N if unsure.
+
+CONFIG_WAN_ROUTER_DRIVERS
+  If you have a WAN interface card and you want your Linux box to act
+  as a WAN router, thereby connecting you Local Area Network to the
+  outside world over the WAN connection, say Y here and then to the
+  driver for your card below. In addition, you need to say Y to "Wan
+  Router".
+
+  You will need the wan-tools package which is available from
+  <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
+  kernel: saying N will just cause the configurator to skip all
+  the questions about WAN router drivers. If unsure, say N.
+
+CONFIG_VENDOR_SANGOMA
+  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
+  S508-ISA.  These cards support
+
+    - X.25, Frame Relay, PPP, Cisco HDLC protocols.
+
+    - API support for protocols like HDLC (LAPB),
+      HDLC Streaming, X.25, Frame Relay and BiSync.
+
+    - Ethernet Bridging over Frame Relay protocol.
+
+    - MULTILINK PPP
+
+    - Async PPP (Modem Dialup)
+
+  If you have one or more of these cards, say M to this option; you
+  may then also want to read the file
+  <file:Documentation/networking/wanpipe.txt>.  The next questions
+  will ask you about the protocols you want the driver to support.
+
+  The driver will be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called wanpipe.o.  For general information about
+  modules read <file:Documentation/modules.txt>.
+
+CONFIG_WANPIPE_X25
+  Say Y to this option if you are planning to connect a WANPIPE card
+  to an X.25 network.  Note, this feature also includes the X.25 API
+  support used to develope custom applications over the X.25 protocol.
+  If you say N, the X.25 support will not be included in the driver.
+  The X.25 option is supported on S514-PCI and S508-ISA cards.
+
+CONFIG_WANPIPE_FR
+  Say Y to this option if you are planning to connect a WANPIPE card
+  to a frame relay network, or use frame relay API to develope
+  custom applications over the Frame  Relay protocol.
+  This feature also contains the Ethernet Bridging over Frame Relay,
+  where a WANPIPE frame relay link can be directly connected to the
+  Linux kernel bridge.  If you say N, the frame relay support will
+  not be included in the driver. The Frame Relay option is
+  supported on S514-PCI and S508-ISA cards.
+
+CONFIG_WANPIPE_PPP
+  Say Y to this option if you are planning to connect a WANPIPE card
+  to a leased line using Point-to-Point protocol (PPP). If you say N,
+  the PPP support will not be included in the driver. The PPP option
+  is supported on S514-PCI/S508-ISA cards.
+
+CONFIG_WANPIPE_MULTPPP
+  Say Y to this option if you are planning to connect a WANPIPE card
+  to a leased line using Point-to-Point protocol (PPP).  Note, the
+  MultiPort PPP uses the Linux Kernel SyncPPP protocol over the
+  Sangoma HDLC Streaming adapter.  In this case each Sangoma adapter
+  port can support an independent PPP connection.  For example, a
+  single Quad-Port PCI adapter can support up to four independent
+  PPP links. If you say N,the PPP support will not be included in the
+  driver.  The PPP option is supported on S514-PCI/S508-ISA cards.
+
+CONFIG_WANPIPE_CHDLC
+  Say Y to this option if you are planning to connect a WANPIPE card
+  to a leased line using the Cisco HDLC protocol. This now supports
+  Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards.
+  This support also allows user to build applications using the
+  HDLC streaming API.
+
+  CHDLC Streaming driver also supports MULTILINK PPP
+  support that can bind multiple WANPIPE T1 cards into
+  a single logical channel.
+
+  If you say  N, the Cisco HDLC support and
+  HDLC streaming API and MULTILINK PPP will not be
+  included in the driver.
+
+CONFIG_COMX
+  Say Y if you want to use any board from the MultiGate (COMX) family.
+  These boards are synchronous serial adapters for the PC,
+  manufactured by ITConsult-Pro Co, Hungary.
+
+  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>.
+
+  You must say Y to "/proc file system support" (CONFIG_PROC_FS) to
+  use this driver.
+
+  If you want to compile this as a module, say M and read
+  <file:Documentation/modules.txt>.  The module will be called comx.o.
+
+CONFIG_COMX_HW_COMX
+  Hardware driver for the 'CMX', 'COMX' and 'HiCOMX' boards from the
+  MultiGate family. Say Y if you have one of these.
+
+  You will need additional firmware to use these cards, which are
+  downloadable from <ftp://ftp.itc.hu/>.
+
+  If you want to compile this as a module, say M and read
+  <file:Documentation/modules.txt>.  The module will be called
+  comx-hw-comx.o.
+
+CONFIG_COMX_HW_LOCOMX
+  Hardware driver for the 'LoCOMX' board from the MultiGate family.
+  Say Y if you have a board like this.
+
+  If you want to compile this as a module, say M and read
+  <file:Documentation/modules.txt>.  The module will be called
+  comx-hw-locomx.o.
+
+CONFIG_COMX_HW_MIXCOM
+  Hardware driver for the 'MixCOM' board from the MultiGate family.
+  Say Y if you have a board like this.
+
+  If you want to use the watchdog device on this card, you should
+  select it in the Watchdog Cards section of the Character Devices
+  configuration. The ISDN interface of this card is Teles 16.3
+  compatible, you should enable it in the ISDN configuration menu. The
+  driver for the flash ROM of this card is available separately on
+  <ftp://ftp.itc.hu/>.
+
+  If you want to compile this as a module, say M and read
+  <file:Documentation/modules.txt>. The module will be called
+  comx-hw-mixcom.o.
+
+CONFIG_COMX_PROTO_PPP
+  Cisco-HDLC and synchronous PPP protocol driver for all MultiGate
+  boards. Say Y if you want to use either protocol on your MultiGate
+  boards.
+
+  If you want to compile this as a module, say M and read
+  <file:Documentation/modules.txt>.  The module will be called
+  comx-proto-ppp.o.
+
+CONFIG_COMX_PROTO_LAPB
+  LAPB protocol driver for all MultiGate boards. Say Y if you
+  want to use this protocol on your MultiGate boards.
+
+  If you want to compile this as a module, say M and read
+  <file:Documentation/modules.txt>.  The module will be called
+  comx-proto-lapb.o.
+
+CONFIG_COMX_PROTO_FR
+  Frame Relay protocol driver for all MultiGate boards. Say Y if you
+  want to use this protocol on your MultiGate boards.
+
+  If you want to compile this as a module, say M and read
+  <file:Documentation/modules.txt>.  The module will be called
+  comx-proto-fr.o.
+
+CONFIG_CYCLADES_SYNC
+  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
+  the protocols you want the driver to support (for now only X.25 is
+  supported).
+
+  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
+  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/>).
+
+  Feel free to contact me or the cycsyn-devel mailing list at
+  acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for
+  additional details, I hope to have documentation available as soon
+  as possible. (Cyclades Brazil is writing the Documentation).
+
+  The driver will be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cyclomx.o. For general information about
+  modules read <file:Documentation/modules.txt>.
+
+CONFIG_CYCLOMX_X25
+  Say Y to this option if you are planning to connect a Cyclom 2X card
+  to an X.25 network.
+
+  If you say N, the X.25 support will not be included in the driver
+  (saves about 11 KB of kernel memory).
+
+CONFIG_HDLC
+  Say Y to this option if your Linux box contains a WAN card supported
+  by this driver and you are planning to connect the box to a WAN
+  ( = Wide Area Network). You will need supporting software from
+  <http://hq.pm.waw.pl/hdlc/>.
+  Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame
+  Relay, synchronous Point-to-Point Protocol (PPP) and X.25.
+
+  If unsure, say N here.
+
+CONFIG_HDLC_PPP
+  Say Y to this option if you want generic HDLC driver to support
+  PPP over WAN (Wide Area Network) connections.
+
+  If unsure, say N here.
+
+CONFIG_HDLC_X25
+  Say Y to this option if you want generic HDLC driver to support
+  X.25 protocol over WAN (Wide Area Network) connections.
+
+  If unsure, say N here.
+
+CONFIG_N2
+  This driver is for RISCom/N2 single or dual channel ISA cards
+  made by SDL Communications Inc.  If you have such a card,
+  say Y here and see <http://hq.pm.waw.pl/pub/hdlc/>.
+
+  Note that N2csu and N2dds cards are not supported by this driver.
+
+  If unsure, say N here.
+
+CONFIG_C101
+  This driver is for C101 SuperSync ISA cards made by Moxa
+  Technologies Co., Ltd. If you have such a card,
+  say Y here and see <http://hq.pm.waw.pl/pub/hdlc/>
+
+  If unsure, say N here.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wan/dscc4.c linux/drivers/net/wan/dscc4.c
--- v2.5.2/linux/drivers/net/wan/dscc4.c	Fri Nov  9 13:41:42 2001
+++ linux/drivers/net/wan/dscc4.c	Mon Jan 28 15:15:15 2002
@@ -72,12 +72,19 @@
  * the documentation/chipset releases. An on-line errata would be welcome.
  *
  * TODO:
- * - some trivial error lurk,
- * - the stats are fscked,
+ * - syncppp oopses. X25 untested.
  * - use polling at high irq/s,
  * - performance analysis,
  * - endianness.
  *
+ * 2001/12/10	Daniela Squassoni  <daniela@cyclades.com>
+ * - Contribution to support the new generic HDLC layer.
+ *
+ * 2002/01	Ueimor
+ * - old style interface removal
+ * - dscc4_release_ring fix (related to DMA mapping)
+ * - hard_start_xmit fix (hint: TxSizeMax)
+ * - misc crapectomy.
  */
 
 #include <linux/version.h>
@@ -107,17 +114,34 @@
 #include <linux/hdlc.h>
 
 /* Version */
-static const char version[] = "$Id: dscc4.c,v 1.130 2001/02/25 15:27:34 romieu Exp $\n";
+static const char version[] = "$Id: dscc4.c,v 1.157 2002/01/28 01:54:19 romieu Exp $\n";
 static int debug;
+static int quartz;
+
+#define	DRV_NAME	"dscc4"
 
+#undef DSCC4_POLLING
+#define DEBUG
 
 /* Module parameters */
+
 MODULE_AUTHOR("Maintainer: Francois Romieu <romieu@cogenit.fr>");
-MODULE_DESCRIPTION("Siemens PEB20534 PCI Controller");
+MODULE_DESCRIPTION("Siemens PEB20534 PCI Controler");
 MODULE_LICENSE("GPL");
 MODULE_PARM(debug,"i");
+MODULE_PARM_DESC(debug,"Enable/disable extra messages");
+MODULE_PARM(quartz,"i");
+MODULE_PARM_DESC(quartz,"If present, on-board quartz frequency (Hz)");
+
+EXPORT_NO_SYMBOLS;
 
 /* Structures */
+
+struct thingie {
+	int define;
+	u32 bits;
+};
+
 struct TxFD {
 	u32 state;
 	u32 next;
@@ -135,18 +159,19 @@
 };
 
 #define DEBUG
-#define DEBUG_PARANOID
+#define DEBUG_PARANOIA
 #define TX_RING_SIZE    32
 #define RX_RING_SIZE    32
 #define IRQ_RING_SIZE   64 /* Keep it A multiple of 32 */
 #define TX_TIMEOUT      (HZ/10)
+#define DSCC4_HZ_MAX	33000000
 #define BRR_DIVIDER_MAX 64*0x00008000
 #define dev_per_card	4
 
 #define SOURCE_ID(flags) ((flags >> 28 ) & 0x03)
 #define TO_SIZE(state) ((state >> 16) & 0x1fff)
 #define TO_STATE(len) cpu_to_le32((len & TxSizeMax) << 16)
-#define RX_MAX(len) ((((len) >> 5) + 1) << 5)
+#define RX_MAX(len) ((((len) >> 5) + 1)<< 5)
 #define SCC_REG_START(id) SCC_START+(id)*SCC_OFFSET
 
 #undef DEBUG
@@ -157,7 +182,7 @@
         spinlock_t lock;
         struct pci_dev *pdev;
 
-        struct net_device *root;
+        struct dscc4_dev_priv *root;
         dma_addr_t iqcfg_dma;
 	u32 xtal_hz;
 };
@@ -186,19 +211,21 @@
         dma_addr_t iqtx_dma;
         dma_addr_t iqrx_dma;
 
-        struct net_device_stats stats;
 	struct timer_list timer;
 
         struct dscc4_pci_priv *pci_priv;
         spinlock_t lock;
 
         int dev_id;
-	u32 flags;
+	volatile u32 flags;
 	u32 timer_help;
 	u32 hi_expected;
 
-	struct hdlc_device_struct hdlc;
-	int usecount;
+	hdlc_device hdlc;
+	sync_serial_settings settings;
+	unsigned short encoding;
+	unsigned short parity;
+	u32 pad __attribute__ ((aligned (4)));
 };
 
 /* GLOBAL registers definitions */
@@ -232,6 +259,9 @@
 #define ISR     0x58
 
 /* Bit masks */
+#define EncodingMask	0x00700000
+#define CrcMask		0x00000003
+
 #define IntRxScc0       0x10000000
 #define IntTxScc0       0x01000000
 
@@ -242,10 +272,9 @@
 #define Rdt		0x00200000
 #define Idr		0x00100000
 #define Idt		0x00080000
-#define TxSccRes       0x01000000
-#define RxSccRes       0x00010000
-#define TxSizeMax	0x1ffc
-#define RxSizeMax	0x1ffc
+#define TxSccRes	0x01000000
+#define RxSccRes	0x00010000
+#define TxSizeMax	0x1fff
 
 #define Ccr0ClockMask	0x0000003f
 #define Ccr1LoopMask	0x00000200
@@ -258,6 +287,7 @@
 #define FrameVfr	0x80
 #define FrameRdo	0x40
 #define FrameCrc	0x20
+#define FrameRab	0x10
 #define FrameAborted	0x00000200
 #define FrameEnd	0x80000000
 #define DataComplete	0x40000000
@@ -293,63 +323,103 @@
 #define RdoSet		0x00000004
 
 /* Functions prototypes */
-static __inline__ void dscc4_rx_irq(struct dscc4_pci_priv *, struct net_device *);
-static __inline__ void dscc4_tx_irq(struct dscc4_pci_priv *, struct net_device *);
+static inline void dscc4_rx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *);
+static inline void dscc4_tx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *);
 static int dscc4_found1(struct pci_dev *, unsigned long ioaddr);
 static int dscc4_init_one(struct pci_dev *, const struct pci_device_id *ent);
 static int dscc4_open(struct net_device *);
 static int dscc4_start_xmit(struct sk_buff *, struct net_device *);
 static int dscc4_close(struct net_device *);
 static int dscc4_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int dscc4_change_mtu(struct net_device *dev, int mtu);
 static int dscc4_init_ring(struct net_device *);
 static void dscc4_release_ring(struct dscc4_dev_priv *);
 static void dscc4_timer(unsigned long);
 static void dscc4_tx_timeout(struct net_device *);
 static void dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs);
-static struct net_device_stats *dscc4_get_stats(struct net_device *);
-static int dscc4_attach_hdlc_device(struct net_device *);
-static void dscc4_unattach_hdlc_device(struct net_device *);
-static int dscc4_hdlc_open(struct hdlc_device_struct *);
-static void dscc4_hdlc_close(struct hdlc_device_struct *);
-static int dscc4_hdlc_ioctl(struct hdlc_device_struct *, struct ifreq *, int);
-static int dscc4_hdlc_xmit(hdlc_device *, struct sk_buff *);
-#ifdef EXPERIMENTAL_POLLING
+static int dscc4_hdlc_attach(hdlc_device *, unsigned short, unsigned short);
+static int dscc4_set_iface(struct net_device *);
+static inline int dscc4_set_quartz(struct dscc4_dev_priv *, int);
+#ifdef DSCC4_POLLING
 static int dscc4_tx_poll(struct dscc4_dev_priv *, struct net_device *);
 #endif
 
-void inline reset_TxFD(struct TxFD *tx_fd) {
-	/* FIXME: test with the last arg (size specification) = 0 */
-	tx_fd->state = FrameEnd | Hold | 0x00100000;
-	tx_fd->complete = 0x00000000;
+static inline void dscc4_patch_register(u32 ioaddr, u32 mask, u32 value)
+{
+	u32 state;
+
+	state = readl(ioaddr);
+	state &= ~mask;
+	state |= value;
+	writel(state, ioaddr); 
 }
 
-void inline dscc4_release_ring_skbuff(struct sk_buff **p, int n)
+int state_check(u32 state, struct dscc4_dev_priv *dpriv, 
+	struct net_device *dev, const char *msg)
 {
-	for(; n > 0; n--) {
-		if (*p)
-			dev_kfree_skb(*p);
-		p++;
+#ifdef DEBUG_PARANOIA
+	if (SOURCE_ID(state) != dpriv->dev_id) {
+		printk(KERN_DEBUG "%s (%s): Source Id=%d, state=%08x\n",
+		       dev->name, msg, SOURCE_ID(state), state );
+		return -1;
 	}
+	if (state & 0x0df80c00) {
+		printk(KERN_DEBUG "%s (%s): state=%08x (UFO alert)\n",
+		       dev->name, msg, state);
+		return -1;
+	}
+	return 0;
+#else
+	return 1;
+#endif
+}
+
+void inline reset_TxFD(struct TxFD *tx_fd) {
+	/* FIXME: test with the last arg (size specification) = 0 */
+	tx_fd->state = FrameEnd | Hold | 0x00100000;
+	tx_fd->complete = 0x00000000;
 }
 
 static void dscc4_release_ring(struct dscc4_dev_priv *dpriv)
 {
 	struct pci_dev *pdev = dpriv->pci_priv->pdev;
+	struct TxFD *tx_fd = dpriv->tx_fd;
+	struct RxFD *rx_fd = dpriv->rx_fd;
+	struct sk_buff **skbuff;
+	int i;
 
-	pci_free_consistent(pdev, TX_RING_SIZE*sizeof(struct TxFD),
-			    dpriv->tx_fd, dpriv->tx_fd_dma);
-	pci_free_consistent(pdev, RX_RING_SIZE*sizeof(struct RxFD),
-			    dpriv->rx_fd, dpriv->rx_fd_dma);
-	dscc4_release_ring_skbuff(dpriv->tx_skbuff, TX_RING_SIZE);
-	dscc4_release_ring_skbuff(dpriv->rx_skbuff, RX_RING_SIZE);
+	pci_free_consistent(pdev, TX_RING_SIZE*sizeof(struct TxFD), tx_fd, 
+			    dpriv->tx_fd_dma);
+	pci_free_consistent(pdev, RX_RING_SIZE*sizeof(struct RxFD), rx_fd, 
+			    dpriv->rx_fd_dma);
+
+	skbuff = dpriv->tx_skbuff;
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (*skbuff) {
+			pci_unmap_single(pdev, tx_fd->data, (*skbuff)->len, 
+				PCI_DMA_TODEVICE);
+			dev_kfree_skb(*skbuff);
+		}
+		skbuff++;
+		tx_fd++;
+	}
+
+	skbuff = dpriv->rx_skbuff;
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		if (*skbuff) {
+			pci_unmap_single(pdev, rx_fd->data, (*skbuff)->len, 
+				PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(*skbuff);
+		}
+		skbuff++;
+		rx_fd++;
+	}
 }
 
 void inline try_get_rx_skb(struct dscc4_dev_priv *priv, int cur, struct net_device *dev)
 {
 	struct sk_buff *skb;
 
-	skb = dev_alloc_skb(RX_MAX(HDLC_MAX_MRU+2));
+	skb = dev_alloc_skb(RX_MAX(HDLC_MAX_MRU));
 	priv->rx_skbuff[cur] = skb;
 	if (!skb) {
 		priv->rx_fd[cur--].data = (u32) NULL;
@@ -376,6 +446,7 @@
 			printk(KERN_ERR "%s: %s timeout\n", dev->name, msg);
 			return -1;
 		}
+		rmb();
 	}
 	printk(KERN_DEBUG "%s: %s ack (%d try)\n", dev->name, msg, i);
 	return 0;
@@ -406,22 +477,26 @@
 	return -1;
 }
 
-static __inline__ int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
+static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
 {
-	int cur;
+	int cur, ret = 0;
 	s16 i;
 
 	cur = dpriv->iqtx_current%IRQ_RING_SIZE;
 	for (i = 0; i >= 0; i++) {
 		if (!(dpriv->flags & (NeedIDR | NeedIDT)) ||
 		    (dpriv->iqtx[cur] & Xpr))
-			return 0;
+			break;
+		smp_rmb();
 	}
-	printk(KERN_ERR "%s: %s timeout\n", "dscc4", "XPR");
-	return -1;
+	if (i < 0) {
+		printk(KERN_ERR "%s: %s timeout\n", "dscc4", "XPR");
+		ret = -1;
+	}
+	return ret;
 }
 
-static __inline__ void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur,
+static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur,
 	struct RxFD *rx_fd, struct net_device *dev)
 {
 	struct pci_dev *pdev = dpriv->pci_priv->pdev;
@@ -433,24 +508,23 @@
 	pci_dma_sync_single(pdev, rx_fd->data, pkt_len + 1, PCI_DMA_FROMDEVICE);
 	if((skb->data[pkt_len] & FrameOk) == FrameOk) {
 		pci_unmap_single(pdev, rx_fd->data, skb->len, PCI_DMA_FROMDEVICE);
-		dpriv->stats.rx_packets++;
-		dpriv->stats.rx_bytes += pkt_len;
+		dev_to_hdlc(dev)->stats.rx_packets++;
+		dev_to_hdlc(dev)->stats.rx_bytes += pkt_len;
 		skb->tail += pkt_len;
 		skb->len = pkt_len;
        		if (netif_running(hdlc_to_dev(&dpriv->hdlc)))
-			hdlc_netif_rx(&dpriv->hdlc, skb);
-		else
-			netif_rx(skb);
+			skb->protocol = htons(ETH_P_HDLC);
+		netif_rx(skb);
 		try_get_rx_skb(dpriv, cur, dev);
 	} else {
 		if(skb->data[pkt_len] & FrameRdo)
-			dpriv->stats.rx_fifo_errors++;
+			dev_to_hdlc(dev)->stats.rx_fifo_errors++;
 		else if(!(skb->data[pkt_len] | ~FrameCrc))
-			dpriv->stats.rx_crc_errors++;
-		else if(!(skb->data[pkt_len] | ~FrameVfr))
-			dpriv->stats.rx_length_errors++;
+			dev_to_hdlc(dev)->stats.rx_crc_errors++;
+		else if(!(skb->data[pkt_len] | ~(FrameVfr | FrameRab)))
+			dev_to_hdlc(dev)->stats.rx_length_errors++;
 		else
-			dpriv->stats.rx_errors++;
+			dev_to_hdlc(dev)->stats.rx_errors++;
 	}
 	rx_fd->state1 |= Hold;
 	rx_fd->state2 = 0x00000000;
@@ -468,9 +542,9 @@
 {
 	struct dscc4_pci_priv *priv;
 	struct dscc4_dev_priv *dpriv;
-	int i;
 	static int cards_found = 0;
 	unsigned long ioaddr;
+	int i;
 
 	printk(KERN_DEBUG "%s", version);
 
@@ -478,26 +552,29 @@
 		goto err_out;
 	if (!request_mem_region(pci_resource_start(pdev, 0),
 	                	pci_resource_len(pdev, 0), "registers")) {
-	        printk (KERN_ERR "dscc4: can't reserve MMIO region (regs)\n");
+	        printk(KERN_ERR "%s: can't reserve MMIO region (regs)\n",
+			DRV_NAME);
 	        goto err_out;
 	}
 	if (!request_mem_region(pci_resource_start(pdev, 1),
 	                        pci_resource_len(pdev, 1), "LBI interface")) {
-	        printk (KERN_ERR "dscc4: can't reserve MMIO region (lbi)\n");
+	        printk(KERN_ERR "%s: can't reserve MMIO region (lbi)\n",
+			DRV_NAME);
 	        goto err_out_free_mmio_region0;
 	}
 	ioaddr = (unsigned long)ioremap(pci_resource_start(pdev, 0),
 					pci_resource_len(pdev, 0));
 	if (!ioaddr) {
-		printk(KERN_ERR "dscc4: cannot remap MMIO region %lx @ %lx\n",
-	                pci_resource_len(pdev, 0), pci_resource_start(pdev, 0));
+		printk(KERN_ERR "%s: cannot remap MMIO region %lx @ %lx\n", 
+			DRV_NAME, pci_resource_len(pdev, 0),
+			pci_resource_start(pdev, 0));
 		goto err_out_free_mmio_region;
 	}
-	printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#lx (regs), %#lx (lbi), IRQ %d.\n",
+	printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#lx (regs), %#lx (lbi), IRQ %d\n",
 	        pci_resource_start(pdev, 0),
 	        pci_resource_start(pdev, 1), pdev->irq);
 
-	/* High PCI latency useless. Cf app. note. */
+	/* No need for High PCI latency. Cf app. note. */
 	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x10);
 	pci_set_master(pdev);
 
@@ -506,11 +583,10 @@
 
 	priv = (struct dscc4_pci_priv *)pci_get_drvdata(pdev);
 
-	if (request_irq(pdev->irq, &dscc4_irq, SA_SHIRQ, "dscc4", priv->root)) {
-		printk(KERN_WARNING "dscc4: IRQ %d is busy\n", pdev->irq);
+	if (request_irq(pdev->irq, &dscc4_irq, SA_SHIRQ, DRV_NAME, priv->root)){
+		printk(KERN_WARNING "%s: IRQ %d busy\n", DRV_NAME, pdev->irq);
 		goto err_out_iounmap;
 	}
-	priv->pdev = pdev;
 
 	/* power up/little endian/dma core controlled via hold bit */
 	writel(0x00000000, ioaddr + GMODE);
@@ -537,7 +613,7 @@
 	 * IQRX/TXi needs to be set soon. Learned it the hard way...
 	 */
 	for(i = 0; i < dev_per_card; i++) {
-		dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv;
+		dpriv = priv->root + i;
 		dpriv->iqtx = (u32 *) pci_alloc_consistent(pdev,
 			IRQ_RING_SIZE*sizeof(u32), &dpriv->iqtx_dma);
 		if (!dpriv->iqtx)
@@ -545,7 +621,7 @@
 		writel(dpriv->iqtx_dma, ioaddr + IQTX0 + i*4);
 	}
 	for(i = 0; i < dev_per_card; i++) {
-		dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv;
+		dpriv = priv->root + i;
 		dpriv->iqrx = (u32 *) pci_alloc_consistent(pdev,
 			IRQ_RING_SIZE*sizeof(u32), &dpriv->iqrx_dma);
 		if (!dpriv->iqrx)
@@ -553,10 +629,7 @@
 		writel(dpriv->iqrx_dma, ioaddr + IQRX0 + i*4);
 	}
 
-	/* 
-	 * Cf application hint. Beware of hard-lock condition on 
-	 * threshold .
-	 */
+	/* Cf application hint. Beware of hard-lock condition on threshold. */
 	writel(0x42104000, ioaddr + FIFOCR1);
 	//writel(0x9ce69800, ioaddr + FIFOCR2);
 	writel(0xdef6d800, ioaddr + FIFOCR2);
@@ -572,14 +645,14 @@
 
 err_out_free_iqrx:
 	while (--i >= 0) {
-		dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv;
+		dpriv = priv->root + i;
 		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), 
 				    dpriv->iqrx, dpriv->iqrx_dma);
 	}
 	i = dev_per_card;
 err_out_free_iqtx:
 	while (--i >= 0) {
-		dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv;
+		dpriv = priv->root + i;
 		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), 
 				    dpriv->iqtx, dpriv->iqtx_dma);
 	}
@@ -599,88 +672,102 @@
 	return -ENODEV;
 };
 
+/* 
+ * Let's hope the default values are decent enough to protect my
+ * feet from the user's gun - Ueimor
+ */
+static void dscc4_init_registers(u32 base_addr, int dev_id)
+{
+	u32 ioaddr = base_addr + SCC_REG_START(dev_id);
+
+	writel(0x80001000, ioaddr + CCR0);
+
+	writel(LengthCheck | (HDLC_MAX_MRU >> 5), ioaddr + RLCR);
+
+	/* no address recognition/crc-CCITT/cts enabled */
+	writel(0x021c8000, ioaddr + CCR1);
+
+	/* crc not forwarded */
+	writel(0x00050008 & ~RxActivate, ioaddr + CCR2);
+	// crc forwarded
+	//writel(0x00250008 & ~RxActivate, ioaddr + CCR2);
+
+	/* Don't mask RDO. Ever. */
+#ifdef DSCC4_POLLING
+	writel(0xfffeef7f, ioaddr + IMR); /* Interrupt mask */
+#else
+	//writel(0xfffaef7f, ioaddr + IMR); /* Interrupt mask */
+	writel(0xfffaef7e, ioaddr + IMR); /* Interrupt mask */
+#endif
+}
+
 static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr)
 {
 	struct dscc4_pci_priv *ppriv;
-	struct dscc4_dev_priv *dpriv;
-	struct net_device *dev;
+	struct dscc4_dev_priv *root;
 	int i = 0;
 
-	dpriv = (struct dscc4_dev_priv *)
-		kmalloc(dev_per_card*sizeof(struct dscc4_dev_priv), GFP_KERNEL);
-	if (!dpriv) {
-		printk(KERN_ERR "dscc4: can't allocate data\n");
+	root = (struct dscc4_dev_priv *)
+		kmalloc(dev_per_card*sizeof(*root), GFP_KERNEL);
+	if (!root) {
+		printk(KERN_ERR "%s: can't allocate data\n", DRV_NAME);
 		goto err_out;
 	}
-	memset(dpriv, 0, dev_per_card*sizeof(struct dscc4_dev_priv));
-
-	dev = (struct net_device *)
-	      kmalloc(dev_per_card*sizeof(struct net_device), GFP_KERNEL);
-	if (!dev) {
-		printk(KERN_ERR "dscc4: can't allocate net_device\n");
-		goto err_dealloc_priv;
-	}
-	memset(dev, 0, dev_per_card*sizeof(struct net_device));
+	memset(root, 0, dev_per_card*sizeof(*root));
 
-	ppriv = (struct dscc4_pci_priv *)
-		kmalloc(sizeof(struct dscc4_pci_priv), GFP_KERNEL);
+	ppriv = (struct dscc4_pci_priv *) kmalloc(sizeof(*ppriv), GFP_KERNEL);
 	if (!ppriv) {
-		printk(KERN_ERR "dscc4: can't allocate pci private data.\n");
-		goto err_dealloc_dev;
+		printk(KERN_ERR "%s: can't allocate private data\n", DRV_NAME);
+		goto err_free_dev;
 	}
 	memset(ppriv, 0, sizeof(struct dscc4_pci_priv));
 
 	for (i = 0; i < dev_per_card; i++) {
-		struct dscc4_dev_priv *p;
-		struct net_device *d;
+		struct dscc4_dev_priv *dpriv = root + i;
+		hdlc_device *hdlc = &dpriv->hdlc;
+		struct net_device *d = hdlc_to_dev(hdlc);
 
-	        d = dev + i;
 	        d->base_addr = ioaddr;
 		d->init = NULL;
 	        d->irq = pdev->irq;
-		/* The card adds the crc */
-		d->type = ARPHRD_RAWHDLC;
 	        d->open = dscc4_open;
 	        d->stop = dscc4_close;
-	        d->hard_start_xmit = dscc4_start_xmit;
 		d->set_multicast_list = NULL;
 	        d->do_ioctl = dscc4_ioctl;
-		d->get_stats = dscc4_get_stats;
-		d->change_mtu = dscc4_change_mtu;
-	        d->mtu = HDLC_MAX_MTU;
-	        d->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
 		d->tx_timeout = dscc4_tx_timeout;
 		d->watchdog_timeo = TX_TIMEOUT;
 
-		p = dpriv + i;
-		p->dev_id = i;
-		p->pci_priv = ppriv;
-		spin_lock_init(&p->lock);
-		d->priv = p;
-
-		if (dev_alloc_name(d, "scc%d")<0) {
-			printk(KERN_ERR "dev_alloc_name failed for scc.\n");
-			goto err_dealloc_dev;
-		}
-	        if (register_netdev(d)) {
-			printk(KERN_ERR "%s: register_netdev != 0.\n", d->name);
-			goto err_dealloc_dev;
+		dpriv->dev_id = i;
+		dpriv->pci_priv = ppriv;
+		spin_lock_init(&dpriv->lock);
+		d->priv = dpriv;
+
+		hdlc->xmit = dscc4_start_xmit;
+		hdlc->attach = dscc4_hdlc_attach;
+
+	        if (register_hdlc_device(hdlc)) {
+			printk(KERN_ERR "%s: unable to register\n", DRV_NAME);
+			goto err_unregister;
 	        }
-		dscc4_attach_hdlc_device(d);
+		hdlc->proto = IF_PROTO_HDLC;
 		SET_MODULE_OWNER(d);
-	}
-	ppriv->root = dev;
-	ppriv->pdev = pdev;
+		dscc4_init_registers(ioaddr, i);
+		dpriv->parity = PARITY_CRC16_PR0_CCITT;
+		dpriv->encoding = ENCODING_NRZ;
+	}
+	if (dscc4_set_quartz(root, quartz) < 0)
+		goto err_unregister;
+	ppriv->root = root;
 	spin_lock_init(&ppriv->lock);
 	pci_set_drvdata(pdev, ppriv);
 	return 0;
 
-err_dealloc_dev:
+err_unregister:
 	while (--i >= 0)
-		unregister_netdev(dev + i);
-	kfree(dev);
-err_dealloc_priv:
-	kfree(dpriv);
+		unregister_hdlc_device(&root[i].hdlc);
+	kfree(ppriv);
+err_free_dev:
+	kfree(root);
 err_out:
 	return -1;
 };
@@ -701,7 +788,7 @@
 			printk(KERN_DEBUG "%s: pending events\n", dev->name);
 			dev->trans_start = jiffies;
 			spin_lock_irqsave(&ppriv->lock, flags);
-			dscc4_tx_irq(ppriv, dev);
+			dscc4_tx_irq(ppriv, dpriv);
 			spin_unlock_irqrestore(&ppriv->lock, flags);
 		} else {
 			struct TxFD *tx_fd;
@@ -711,7 +798,7 @@
 			printk(KERN_DEBUG "%s: missing events\n", dev->name);
 			i = dpriv->tx_dirty%TX_RING_SIZE; 
 			j = dpriv->tx_current - dpriv->tx_dirty;
-			dpriv->stats.tx_dropped += j;
+			dev_to_hdlc(dev)->stats.tx_dropped += j;
 			while(j--) {
 				skb = dpriv->tx_skbuff[i];
 				tx_fd = dpriv->tx_fd + i;
@@ -740,13 +827,34 @@
 static void dscc4_tx_timeout(struct net_device *dev)
 {
 	/* FIXME: something is missing there */
-};
+}
+
+static int dscc4_loopback_check(struct dscc4_dev_priv *dpriv)
+{
+	sync_serial_settings *settings = &dpriv->settings;
+
+	if (settings->loopback && (settings->clock_type != CLOCK_INT)) {
+		struct net_device *dev = hdlc_to_dev(&dpriv->hdlc);
+
+		printk(KERN_INFO "%s: loopback requires clock\n", dev->name);
+		return -1;
+	}
+	return 0;
+}
 
 static int dscc4_open(struct net_device *dev)
 {
-	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+	struct dscc4_dev_priv *dpriv = dev->priv;
+	hdlc_device *hdlc = &dpriv->hdlc;
 	struct dscc4_pci_priv *ppriv;
-	u32 ioaddr = 0;
+	u32 ioaddr;
+	int ret = -EAGAIN;
+
+	if ((dscc4_loopback_check(dpriv) < 0) || !dev->hard_start_xmit)
+		goto err;
+
+	if ((ret = hdlc_open(hdlc)))
+		goto err;
 
 	MOD_INC_USE_COUNT;
 
@@ -757,24 +865,6 @@
 
 	ioaddr = dev->base_addr + SCC_REG_START(dpriv->dev_id);
 
-	/* FIXME: VIS */
-	writel(readl(ioaddr + CCR0) | 0x80001000, ioaddr + CCR0);
-
-	writel(LengthCheck | (HDLC_MAX_MRU >> 5), ioaddr + RLCR);
-
-	/* no address recognition/crc-CCITT/cts enabled */
-	writel(readl(ioaddr + CCR1) | 0x021c8000, ioaddr + CCR1);
-
-	/* Ccr2.Rac = 0 */
-	writel(0x00050008 & ~RxActivate, ioaddr + CCR2);
-
-#ifdef EXPERIMENTAL_POLLING
-	writel(0xfffeef7f, ioaddr + IMR); /* Interrupt mask */
-#else
-	/* Don't mask RDO. Ever. */
-	//writel(0xfffaef7f, ioaddr + IMR); /* Interrupt mask */
-	writel(0xfffaef7e, ioaddr + IMR); /* Interrupt mask */
-#endif
 	/* IDT+IDR during XPR */
 	dpriv->flags = NeedIDR | NeedIDT;
 
@@ -789,9 +879,10 @@
 		printk(KERN_ERR "%s busy. Try later\n", dev->name);
 		goto err_free_ring;
 	}
+
+	/* Posted write is flushed in the busy-waiting loop */
 	writel(TxSccRes | RxSccRes, ioaddr + CMDR);
 
-	/* ... the following isn't */
 	if (dscc4_wait_ack_cec(ioaddr, dev, "Cec"))
 		goto err_free_ring;
 
@@ -819,16 +910,18 @@
 err_free_ring:
 	dscc4_release_ring(dpriv);
 err_out:
+	hdlc_close(hdlc);
 	MOD_DEC_USE_COUNT;
-	return -EAGAIN;
+err:
+	return ret;
 }
 
-#ifdef EXPERIMENTAL_POLLING
+#ifdef DSCC4_POLLING
 static int dscc4_tx_poll(struct dscc4_dev_priv *dpriv, struct net_device *dev)
 {
 	/* FIXME: it's gonna be easy (TM), for sure */
 }
-#endif /* EXPERIMENTAL_POLLING */
+#endif /* DSCC4_POLLING */
 
 static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
@@ -842,13 +935,14 @@
 	next = dpriv->tx_current%TX_RING_SIZE;
 	dpriv->tx_skbuff[next] = skb;
 	tx_fd = dpriv->tx_fd + next;
-	tx_fd->state = FrameEnd | Hold | TO_STATE(skb->len & TxSizeMax);
+	printk(KERN_DEBUG "%s: %d sent\n", dev->name, skb->len);
+	tx_fd->state = FrameEnd | Hold | TO_STATE(skb->len);
 	tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len,
 				     PCI_DMA_TODEVICE);
 	tx_fd->complete = 0x00000000;
 	mb(); // FIXME: suppress ?
 
-#ifdef EXPERIMENTAL_POLLING
+#ifdef DSCC4_POLLING
 	spin_lock(&dpriv->lock);
 	while(dscc4_tx_poll(dpriv, dev));
 	spin_unlock(&dpriv->lock);
@@ -881,6 +975,7 @@
 	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
 	u32 ioaddr = dev->base_addr;
 	int dev_id;
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 
 	del_timer_sync(&dpriv->timer);
 	netif_stop_queue(dev);
@@ -890,26 +985,45 @@
 	writel(0x00050000, ioaddr + SCC_REG_START(dev_id) + CCR2);
 	writel(MTFi|Rdr|Rdt, ioaddr + CH0CFG + dev_id*0x0c); /* Reset Rx/Tx */
 	writel(0x00000001, ioaddr + GCMDR);
+	readl(ioaddr + GCMDR);
 
+	/* 
+	 * FIXME: wait for the command ack before returning the memory
+	 * structures to the kernel.
+	 */
+	hdlc_close(hdlc);
 	dscc4_release_ring(dpriv);
 
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
+static inline int dscc4_check_clock_ability(int port)
+{
+	int ret = 0;
+
+#ifdef CONFIG_DSCC4_CLOCK_ON_TWO_PORTS_ONLY
+	if (port >= 2)
+		ret = -1;
+#endif
+	return ret;
+}
+
 static int dscc4_set_clock(struct net_device *dev, u32 *bps, u32 *state)
 {
 	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
 	u32 brr;
 
 	*state &= ~Ccr0ClockMask;
-	if (*bps) { /* DCE */
+	if (*bps) { /* Clock generated - required for DCE */
 		u32 n = 0, m = 0, divider;
 		int xtal;
 
 		xtal = dpriv->pci_priv->xtal_hz;
 		if (!xtal)
 			return -1;
+		if (dscc4_check_clock_ability(dpriv->dev_id) < 0)
+			return -1;
 		divider = xtal / *bps;
 		if (divider > BRR_DIVIDER_MAX) {
 			divider >>= 4;
@@ -933,8 +1047,9 @@
 		if (!(*state & 0x00000001)) /* Clock mode 6b */
 			divider <<= 4;
 		*bps = xtal / divider;
-	} else { /* DTE */
+	} else {
 		/* 
+		 * External clock - DTE 
 		 * "state" already reflects Clock mode 0a. 
 		 * Nothing more to be done 
 		 */
@@ -945,214 +1060,201 @@
 	return 0;
 }
 
-#ifdef LATER_PLEASE
-/*
- * -*- [RFC] Configuring Synchronous Interfaces in Linux -*-
- */
+static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct if_settings *if_s = &ifr->ifr_settings;
+	const size_t size = sizeof(dpriv->settings);
+	int ret = 0;
 
-// FIXME: MEDIA already defined in linux/hdlc.h
-#define HDLC_MEDIA_V35		0
-#define HDLC_MEDIA_RS232	1
-#define HDLC_MEDIA_X21		2
-#define HDLC_MEDIA_E1		3
-#define HDLC_MEDIA_HSSI		4
-
-#define HDLC_CODING_NRZ		0
-#define HDLC_CODING_NRZI	1
-#define HDLC_CODING_FM0		2
-#define HDLC_CODING_FM1		3
-#define HDLC_CODING_MANCHESTER	4
-
-#define HDLC_CRC_NONE		0
-#define HDLC_CRC_16		1
-#define HDLC_CRC_32		2
-#define HDLC_CRC_CCITT		3
-
-/* RFC: add the crc reset value ? */
-struct hdlc_physical {
-	u8 media;
-	u8 coding;
-	u32 rate;
-	u8 crc;
-	u8 crc_siz;		/* 2 or 4 bytes */
-	u8 shared_flags;	/* Discouraged on the DSCC4 */
-};
+        if (dev->flags & IFF_UP)
+                return -EBUSY;
 
-// FIXME: PROTO already defined in linux/hdlc.h
-#define HDLC_PROTO_RAW		0
-#define HDLC_PROTO_FR		1
-#define HDLC_PROTO_X25		2
-#define HDLC_PROTO_PPP		3
-#define HDLC_PROTO_CHDLC	4
+	if (cmd != SIOCDEVICE)
+		return -EOPNOTSUPP;
 
-struct hdlc_protocol {
-	u8 proto; 
-	
-	union {
-	} u;
-};
+	switch(ifr->ifr_settings.type) {
+	case IF_GET_IFACE:
+		if_s->type = IF_IFACE_SYNC_SERIAL;
+		if (if_s->data_length == 0)
+			return 0;
+		if (if_s->data_length < size)
+			return -ENOMEM;
+		if (copy_to_user(if_s->data, &dpriv->settings, size))
+			return -EFAULT;
+		if_s->data_length = size;
+		break;
 
-struct screq {
-	u16 media_group;
+	case IF_IFACE_SYNC_SERIAL:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
 
-	union {
-		struct hdlc_physical hdlc_phy;
-		struct hdlc_protocol hdlc_proto;
-	} u;
-};
+		if (if_s->data_length != size)
+			return -ENOMEM;
 
-// FIXME: go sub-module 
-static struct {
-	u16 coding;
-	u16 bits;
-} map[] = {
-	{HDLC_CODING_NRZ,		0x00},
-	{HDLC_CODING_NRZI,		0x20},
-	{HDLC_CODING_FM0,		0x40},
-	{HDLC_CODING_FM1,		0x50},
-	{HDLC_CODING_MANCHESTER,	0x60},
-	{65535,	0x00}
-};
-#endif /* LATER_PLEASE */
+		if (copy_from_user(&dpriv->settings, if_s->data, size))
+			return -EFAULT;
+		ret = dscc4_set_iface(dev);
+		break;
 
-static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+	default:
+		ret = hdlc_ioctl(dev, ifr, cmd);
+		break;
+	}
+
+	return ret;
+}
+
+static inline int dscc4_set_quartz(struct dscc4_dev_priv *dpriv, int hz)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
-	u32 state, ioaddr;
+	int ret = 0;
 
-        if (dev->flags & IFF_UP)
-                return -EBUSY;
+	if ((hz < 0) || (hz > DSCC4_HZ_MAX))
+		ret = -EOPNOTSUPP;
+	else
+		dpriv->pci_priv->xtal_hz = hz;
 
-	switch (cmd) {
-		/* Set built-in quartz frequency */
-		case SIOCDEVPRIVATE: {
-			u32 hz;
-
-			hz = ifr->ifr_ifru.ifru_ivalue;
-			if (hz >= 33000000) /* 33 MHz */
-				return -EOPNOTSUPP;
-			dpriv->pci_priv->xtal_hz = hz;
-			return 0;
-		}
-		/* Set/unset loopback */
-		case SIOCDEVPRIVATE+1: {
-			u32 flags;
-	
-			ioaddr = dev->base_addr + CCR1 +
-				 SCC_REG_START(dpriv->dev_id);
-			state = readl(ioaddr);
-			flags = ifr->ifr_ifru.ifru_ivalue;
-			if (flags & 0x00000001) {
-				printk(KERN_DEBUG "%s: loopback\n", dev->name);
-				state |= 0x00000100;
-			} else {
-				printk(KERN_DEBUG "%s: normal\n", dev->name);
-				state &= ~0x00000100;
-			}
-			writel(state, ioaddr);
-			return 0;
-		}
+	return ret;
+}
 
-#ifdef LATER_PLEASE
-		case SIOCDEVPRIVATE+2: {
-		{
-			struct screq scr;
-
-			err = copy_from_user(&scr, ifr->ifr_ifru.ifru_data, sizeof(struct screq));
-			if (err)
-				return err;
-			do {
-				if (scr.u.hdlc_phy.coding == map[i].coding)
-					break;
-			} while (map[++i].coding != 65535);
-			if (!map[i].coding)
-				return -EOPNOTSUPP;
-			
-			ioaddr = dev->base_addr + CCR0 +
-				 SCC_REG_START(dpriv->dev_id);
-			state = readl(ioaddr) & ~EncodingMask;
-			state |= (u32)map[i].bits << 16;
-			writel(state, ioaddr);	
-			printk("state: %08x\n", state); /* DEBUG */
-			return 0;
-		}
-		case SIOCDEVPRIVATE+3: {
-			struct screq *scr = (struct screq *)ifr->ifr_ifru.ifru_data;
+static int dscc4_match(struct thingie *p, int value)
+{
+	int i;
 
-			ioaddr = dev->base_addr + CCR0 +
-				 SCC_REG_START(dpriv->dev_id);
-			state = (readl(ioaddr) & EncodingMask) >> 16;
-			do {
-				if (state == map[i].bits)
-					break;
-			} while (map[++i].coding);
-			return put_user(map[i].coding, (u16 *)scr->u.hdlc_phy.coding);
-		}
-#endif /* LATER_PLEASE */
+	for (i = 0; p[i].define != -1; i++) {
+		if (value == p[i].define)
+			break;
+	}
+	if (p[i].define == -1)
+		return -1;
+	else
+		return i;
+}
 
-		case HDLCSCLOCKRATE:
-		{
-			u32 state, bps;
- 
-			bps = ifr->ifr_ifru.ifru_ivalue;
-			ioaddr = dev->base_addr + CCR0 +
-				 SCC_REG_START(dpriv->dev_id);
-			state = readl(ioaddr);
-			if(dscc4_set_clock(dev, &bps, &state) < 0)
-				return -EOPNOTSUPP;
-			if (bps) { /* DCE */
-				printk(KERN_DEBUG "%s: generated RxClk (DCE)\n",
-				       dev->name);
-				ifr->ifr_ifru.ifru_ivalue = bps;
-			} else { /* DTE */
-				state = 0x80001000;
-				printk(KERN_DEBUG "%s: external RxClk (DTE)\n",
-				       dev->name);
-			}
-			writel(state, ioaddr);	
-			return 0;
-		}
-		case HDLCGCLOCKRATE: {
-			u32 brr;
-			int bps;
-
-			brr = readl(dev->base_addr + BRR + 
-				    SCC_REG_START(dpriv->dev_id));
-			bps = dpriv->pci_priv->xtal_hz >> (brr >> 8);
-			bps /= (brr & 0x3f) + 1;
-			ifr->ifr_ifru.ifru_ivalue = bps;
-			return 0;
+static int dscc4_clock_setting(struct net_device *dev)
+{
+	struct dscc4_dev_priv *dpriv = dev->priv;
+	sync_serial_settings *settings = &dpriv->settings;
+	u32 bps, state;
+	u32 ioaddr;
+
+	bps = settings->clock_rate;
+	ioaddr = dev->base_addr + CCR0 + SCC_REG_START(dpriv->dev_id);
+	state = readl(ioaddr);
+	if(dscc4_set_clock(dev, &bps, &state) < 0)
+		return -EOPNOTSUPP;
+	if (bps) { /* DCE */
+		printk(KERN_DEBUG "%s: generated RxClk (DCE)\n", dev->name);
+		if (settings->clock_rate != bps) {
+			settings->clock_rate = bps;
+			printk(KERN_DEBUG "%s: clock adjusted from %08d to %08d \n",
+				dev->name, dpriv->settings.clock_rate, bps);
 		}
+	} else { /* DTE */
+		state = 0x80001000;
+		printk(KERN_DEBUG "%s: external RxClk (DTE)\n", dev->name);
+	}
+	writel(state, ioaddr); 
+	return 0;
+}
+
+static int dscc4_encoding_setting(struct net_device *dev)
+{
+	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct thingie encoding[] = {
+		{ ENCODING_NRZ,		0x00000000 },
+		{ ENCODING_NRZI,	0x00200000 },
+		{ ENCODING_FM_MARK,	0x00400000 },
+		{ ENCODING_FM_SPACE,	0x00500000 },
+		{ ENCODING_MANCHESTER,	0x00600000 },
+		{ -1,			0}
+	};
+	int i, ret = 0;
+
+	i = dscc4_match(encoding, dpriv->encoding);
+	if (i >= 0) {
+		u32 ioaddr;
+
+		ioaddr = dev->base_addr + CCR0 + SCC_REG_START(dpriv->dev_id);
+		dscc4_patch_register(ioaddr, EncodingMask, encoding[i].bits);
+	} else
+		ret = -EOPNOTSUPP;
+	return ret;
+}
 
-		default:
-			return -EOPNOTSUPP;
+static int dscc4_loopback_setting(struct net_device *dev)
+{
+	struct dscc4_dev_priv *dpriv = dev->priv;
+	sync_serial_settings *settings = &dpriv->settings;
+	u32 ioaddr, state;
+
+	ioaddr = dev->base_addr + CCR1 + SCC_REG_START(dpriv->dev_id);
+	state = readl(ioaddr);
+	if (settings->loopback) {
+		printk(KERN_DEBUG "%s: loopback\n", dev->name);
+		state |= 0x00000100;
+	} else {
+		printk(KERN_DEBUG "%s: normal\n", dev->name);
+		state &= ~0x00000100;
 	}
+	writel(state, ioaddr);
+	return 0;
 }
 
-static int dscc4_change_mtu(struct net_device *dev, int mtu)
+static int dscc4_crc_setting(struct net_device *dev)
 {
-	/* FIXME: chainsaw coded... */
-	if ((mtu <= 3) || (mtu > 65531))
-		return -EINVAL;
-        if(dev->flags & IFF_UP)
-                return -EBUSY;
-	dev->mtu = mtu;
-        return(0);
+	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct thingie crc[] = {
+		{ PARITY_CRC16_PR0_CCITT,	0x00000010 },
+		{ PARITY_CRC16_PR1_CCITT,	0x00000000 },
+		{ PARITY_CRC32_PR0_CCITT,	0x00000011 },
+		{ PARITY_CRC32_PR1_CCITT,	0x00000001 }
+	};
+	int i, ret = 0;
+
+	i = dscc4_match(crc, dpriv->parity);
+	if (i >= 0) {
+		u32 ioaddr;
+
+		ioaddr = dev->base_addr + CCR1 + SCC_REG_START(dpriv->dev_id);
+		dscc4_patch_register(ioaddr, CrcMask, crc[i].bits);
+	} else
+		ret = -EOPNOTSUPP;
+	return ret;
+}
+
+static int dscc4_set_iface(struct net_device *dev)
+{
+	struct {
+		int (*action)(struct net_device *);
+	} *p, do_setting[] = {
+		{ dscc4_encoding_setting },
+		{ dscc4_clock_setting },
+		{ dscc4_loopback_setting },
+		{ dscc4_crc_setting },
+		{ NULL }
+	};
+	int ret = 0;
+
+	for (p = do_setting; p->action; p++) {
+		if ((ret = p->action(dev)) < 0)
+			break;
+	}
+	return ret;
 }
 
-static void dscc4_irq(int irq, void *dev_instance, struct pt_regs *ptregs)
+static void dscc4_irq(int irq, void *token, struct pt_regs *ptregs)
 {
-	struct net_device *dev = dev_instance;
+	struct dscc4_dev_priv *root = token;
 	struct dscc4_pci_priv *priv;
+	struct net_device *dev;
 	u32 ioaddr, state;
 	unsigned long flags;
 	int i;
 
-	priv = ((struct dscc4_dev_priv *)dev->priv)->pci_priv;
-	/* 
-	 * FIXME: shorten the protected area (set some bit telling we're
-	 * in an interrupt or increment some work-to-do counter etc...)
-	 */
+	priv = root->pci_priv;
+	dev = hdlc_to_dev(&root->hdlc);
+
 	spin_lock_irqsave(&priv->lock, flags);
 
 	ioaddr = dev->base_addr;
@@ -1179,14 +1281,14 @@
 	if (state & RxEvt) {
 		i = dev_per_card - 1;
 		do {
-			dscc4_rx_irq(priv, dev + i);
+			dscc4_rx_irq(priv, root + i);
 		} while (--i >= 0);
 		state &= ~RxEvt;
 	}
 	if (state & TxEvt) {
 		i = dev_per_card - 1;
 		do {
-			dscc4_tx_irq(priv, dev + i);
+			dscc4_tx_irq(priv, root + i);
 		} while (--i >= 0);
 		state &= ~TxEvt;
 	}
@@ -1194,10 +1296,9 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static __inline__ void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, 
-				    struct net_device *dev)
+static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, struct dscc4_dev_priv *dpriv)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct net_device *dev = hdlc_to_dev(&dpriv->hdlc);
 	u32 state;
 	int cur, loop = 0;
 
@@ -1218,18 +1319,9 @@
 	dpriv->iqtx[cur] = 0;
 	dpriv->iqtx_current++;
 
-#ifdef DEBUG_PARANOID
-	if (SOURCE_ID(state) != dpriv->dev_id) {
-		printk(KERN_DEBUG "%s (Tx): Source Id=%d, state=%08x\n",
-		       dev->name, SOURCE_ID(state), state );
-		return;
-	}
-	if (state & 0x0df80c00) {
-		printk(KERN_DEBUG "%s (Tx): state=%08x (UFO alert)\n",
-		       dev->name, state);
+	if (state_check(state, dpriv, dev, "Tx"))
 		return;
-	}
-#endif
+
 	// state &= 0x0fffffff; /* Tracking the analyzed bits */
 	if (state & SccEvt) {
 		if (state & Alls) {
@@ -1259,12 +1351,12 @@
 				       "%s: DataComplete=0 cur=%d isr=%08x state=%08x\n",
 				       dev->name, cur, isr, state);
 				writel(isr, ioaddr);
-				dpriv->stats.tx_dropped++;
+				dev_to_hdlc(dev)->stats.tx_dropped++;
 			} else {
 				tx_fd->complete &= ~DataComplete;
 				if (tx_fd->state & FrameEnd) {
-					dpriv->stats.tx_packets++;
-					dpriv->stats.tx_bytes += skb->len;
+					dev_to_hdlc(dev)->stats.tx_packets++;
+					dev_to_hdlc(dev)->stats.tx_bytes += skb->len;
 				}
 			}
 
@@ -1285,7 +1377,7 @@
 		 * Transmit Data Underrun
 		 */
 		if (state & Xdu) {
-			printk(KERN_ERR "dscc4: XDU. Contact maintainer\n");
+			printk(KERN_ERR "%s: XDU. Ask maintainer\n", DRV_NAME);
 			dpriv->flags = NeedIDT; 
 			/* Tx reset */
 			writel(MTFi | Rdt, 
@@ -1340,7 +1432,7 @@
 		}
 	} else { /* ! SccEvt */
 		if (state & Hi) {
-#ifdef EXPERIMENTAL_POLLING
+#ifdef DSCC4_POLLING
 			while(!dscc4_tx_poll(dpriv, dev));
 #endif
 			state &= ~Hi;
@@ -1349,17 +1441,18 @@
 		 * FIXME: it may be avoided. Re-re-re-read the manual.
 		 */
 		if (state & Err) {
-			printk(KERN_ERR "%s: Tx ERR\n", dev->name);
-			dpriv->stats.tx_errors++;
+			printk(KERN_ERR "%s (Tx): ERR\n", dev->name);
+			dev_to_hdlc(dev)->stats.tx_errors++;
 			state &= ~Err;
 		}
 	}
 	goto try;
 }
 
-static __inline__ void dscc4_rx_irq(struct dscc4_pci_priv *priv, struct net_device *dev)
+static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv,
+				    struct dscc4_dev_priv *dpriv)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct net_device *dev = hdlc_to_dev(&dpriv->hdlc);
 	u32 state;
 	int cur;
 
@@ -1371,18 +1464,9 @@
 	dpriv->iqrx[cur] = 0;
 	dpriv->iqrx_current++;
 
-#ifdef DEBUG_PARANOID
-	if (SOURCE_ID(state) != dpriv->dev_id) {
-		printk(KERN_DEBUG "%s (Rx): Source Id=%d, state=%08x\n",
-		       dev->name, SOURCE_ID(state), state);
-		goto try;
-	}
-	if (state & 0x0df80c00) {
-		printk(KERN_DEBUG "%s (Rx): state=%08x (UFO alert)\n",
-		       dev->name, state);
-		goto try;
-	}
-#endif
+	if (state_check(state, dpriv, dev, "Tx"))
+		return;
+
 	if (!(state & SccEvt)){
 		struct RxFD *rx_fd;
 
@@ -1450,8 +1534,8 @@
 #ifdef DEBUG_PARANOIA
 		for (i = 0; evts[i].irq_name; i++) {
 			if (state & evts[i].mask) {
-				printk(KERN_DEBUG "dscc4(%s): %s\n",
-					dev->name, evts[i].irq_name);
+				printk(KERN_DEBUG "%s: %s\n", dev->name, 
+					evts[i].irq_name);
 				if (!(state &= ~evts[i].mask))
 					goto try;
 			}
@@ -1492,7 +1576,7 @@
 				if (!(rx_fd->state2 & DataComplete))
 					break;
 				if (rx_fd->state2 & FrameAborted) {
-					dpriv->stats.rx_over_errors++;
+					dev_to_hdlc(dev)->stats.rx_over_errors++;
 					rx_fd->state1 |= Hold;
 					rx_fd->state2 = 0x00000000;
 					rx_fd->end = 0xbabeface;
@@ -1503,7 +1587,7 @@
 			if (debug) {
 				if (dpriv->flags & RdoSet)
 					printk(KERN_DEBUG 
-					       "dscc4: no RDO in Rx data\n");
+					       "%s: no RDO in Rx data\n", DRV_NAME);
 			}
 #ifdef DSCC4_RDO_EXPERIMENTAL_RECOVERY
 			/*
@@ -1540,6 +1624,7 @@
 				goto try;
 		}
 		if (state & Flex) {
+			printk(KERN_DEBUG "%s: Flex. Ttttt...\n", DRV_NAME);
 			if (!(state &= ~Flex))
 				goto try;
 		}
@@ -1588,7 +1673,7 @@
 	 * - Fe=1 (required by No=0 or we got an Err irq and must reset).
 	 * Alas, it fails (and locks solid). Thus the introduction of a dummy
 	 * skb to avoid No=0 (choose one: Ugly [ ] Tasteless [ ] VMS [ ]).
-	 * TODO: fiddle the tx threshold when time permits.
+	 * 2002/01: errata sheet acknowledges the problem [X].
 	 */
 	struct sk_buff *skb;
 
@@ -1609,7 +1694,7 @@
 	        rx_fd->state1 = HiDesc; /* Hi, no Hold */
 	        rx_fd->state2 = 0x00000000;
 	        rx_fd->end = 0xbabeface;
-	        rx_fd->state1 |= ((u32)(HDLC_MAX_MRU & RxSizeMax)) << 16;
+	        rx_fd->state1 |= (RX_MAX(HDLC_MAX_MRU) << 16);
 		try_get_rx_skb(dpriv, i, dev);
 		i++;
 		rx_fd->next = (u32)(dpriv->rx_fd_dma + i*sizeof(struct RxFD));
@@ -1627,44 +1712,36 @@
 	return -1;
 }
 
-static struct net_device_stats *dscc4_get_stats(struct net_device *dev)
-{
-	struct dscc4_dev_priv *priv = (struct dscc4_dev_priv *)dev->priv;
-
-	return &priv->stats;
-}
-
 static void __exit dscc4_remove_one(struct pci_dev *pdev)
 {
 	struct dscc4_pci_priv *ppriv;
-	struct net_device *root;
+	struct dscc4_dev_priv *root;
+	u32 ioaddr;
 	int i;
 
 	ppriv = pci_get_drvdata(pdev);
 	root = ppriv->root;
 
+	ioaddr = hdlc_to_dev(&root->hdlc)->base_addr;
 	free_irq(pdev->irq, root);
 	pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), ppriv->iqcfg, 
 			    ppriv->iqcfg_dma);
-	for (i=0; i < dev_per_card; i++) {
-		struct dscc4_dev_priv *dpriv;
-		struct net_device *dev;
+	for (i = 0; i < dev_per_card; i++) {
+		struct dscc4_dev_priv *dpriv = root + i;
+		hdlc_device *hdlc = &dpriv->hdlc;
 
-		dev = ppriv->root + i;
-		dscc4_unattach_hdlc_device(dev);
+		unregister_hdlc_device(hdlc);
 
-		dpriv = (struct dscc4_dev_priv *)dev->priv;
 		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), 
 				    dpriv->iqrx, dpriv->iqrx_dma);
 		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), 
 				    dpriv->iqtx, dpriv->iqtx_dma);
-		unregister_netdev(dev);
 	}
-	kfree(root->priv);
 
-	iounmap((void *)root->base_addr);
+	iounmap((void *)ioaddr);
 	kfree(root);
 
+	pci_set_drvdata(pdev, NULL);
 	kfree(ppriv);
 
 	release_mem_region(pci_resource_start(pdev, 1),
@@ -1673,72 +1750,28 @@
 			   pci_resource_len(pdev, 0));
 }
 
-static int dscc4_hdlc_ioctl(struct hdlc_device_struct *hdlc, struct ifreq *ifr, int cmd)
-{
-	struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr;
-	int result;
-
-	/* FIXME: locking ? */
-	result = dscc4_ioctl(dev, ifr, cmd);
-	return result;
-}
-
-static int dscc4_hdlc_open(struct hdlc_device_struct *hdlc)
-{
-	struct net_device *dev = (struct net_device *)(hdlc->netdev.base_addr);
-
-        if (netif_running(dev)) {
-		printk(KERN_DEBUG "%s: already running\n", dev->name); // DEBUG
-		return 0;
-	}
-	return dscc4_open(dev);
-}
-
-static int dscc4_hdlc_xmit(hdlc_device *hdlc, struct sk_buff *skb)
-{
-	struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr;
-
-	return dscc4_start_xmit(skb, dev);
-}
-
-static void dscc4_hdlc_close(struct hdlc_device_struct *hdlc)
-{
-	struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr;
-	struct dscc4_dev_priv *dpriv;
-
-	dpriv = dev->priv;
-	--dpriv->usecount;
-}
-
-/* Operated under dev lock */
-static int dscc4_attach_hdlc_device(struct net_device *dev) 
+static int dscc4_hdlc_attach(hdlc_device *hdlc, unsigned short encoding, 
+	unsigned short parity)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
-	struct hdlc_device_struct *hdlc;
-	int result;
+	struct dscc4_dev_priv *dpriv = hdlc_to_dev(hdlc)->priv;
 
-	hdlc = &dpriv->hdlc;
-	/* XXX: Don't look at the next line */
-	hdlc->netdev.base_addr = (unsigned long)dev;
-	hdlc->set_mode = NULL;
-	hdlc->open = dscc4_hdlc_open;
-	hdlc->close = dscc4_hdlc_close;
-	hdlc->ioctl = dscc4_hdlc_ioctl;
-	hdlc->xmit = dscc4_hdlc_xmit;
-
-	result = register_hdlc_device(hdlc);
-	if (!result)
-		dpriv->usecount++;
-	return result;
-}
+	if (encoding != ENCODING_NRZ &&
+	    encoding != ENCODING_NRZI &&
+	    encoding != ENCODING_FM_MARK &&
+	    encoding != ENCODING_FM_SPACE &&
+	    encoding != ENCODING_MANCHESTER)
+		return -EINVAL;
 
-/* Operated under dev lock */
-static void dscc4_unattach_hdlc_device(struct net_device *dev) 
-{
-	struct dscc4_dev_priv *dpriv = dev->priv;
+	if (parity != PARITY_NONE &&
+	    parity != PARITY_CRC16_PR0_CCITT &&
+	    parity != PARITY_CRC16_PR1_CCITT &&
+	    parity != PARITY_CRC32_PR0_CCITT &&
+	    parity != PARITY_CRC32_PR1_CCITT)
+		return -EINVAL;
 
-	unregister_hdlc_device(&dpriv->hdlc);
-	dpriv->usecount--;
+        dpriv->encoding = encoding;
+        dpriv->parity = parity;
+	return 0;
 }
 
 static struct pci_device_id dscc4_pci_tbl[] __devinitdata = {
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.5.2/linux/drivers/net/wavelan.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/wavelan.c	Wed Dec 31 16:00:00 1969
@@ -1,4342 +0,0 @@
-/*
- *	WaveLAN ISA driver
- *
- *		Jean II - HPLB '96
- *
- * Reorganisation and extension of the driver.
- * Original copyright follows (also see the end of this file).
- * See wavelan.p.h for details.
- *
- *
- *
- * AT&T GIS (nee NCR) WaveLAN card:
- *	An Ethernet-like radio transceiver
- *	controlled by an Intel 82586 coprocessor.
- */
-
-#include "wavelan.p.h"		/* Private header */
-
-/************************* MISC SUBROUTINES **************************/
-/*
- * Subroutines which won't fit in one of the following category
- * (WaveLAN modem or i82586)
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Wrapper for disabling interrupts and locking the driver.
- * (note : inline, so optimised away)
- */
-static inline void wv_splhi(net_local *		lp,
-			    unsigned long *	pflags)
-{
-	spin_lock_irqsave(&lp->spinlock, *pflags);
-	/* Note : above does the cli(); itself */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wrapper for re-enabling interrupts and un-locking the driver.
- */
-static inline void wv_splx(net_local *		lp,
-			   unsigned long *	pflags)
-{
-	spin_unlock_irqrestore(&lp->spinlock, *pflags);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Translate irq number to PSA irq parameter
- */
-static u8 wv_irq_to_psa(int irq)
-{
-	if (irq < 0 || irq >= NELS(irqvals))
-		return 0;
-
-	return irqvals[irq];
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Translate PSA irq parameter to irq number 
- */
-static int __init wv_psa_to_irq(u8 irqval)
-{
-	int irq;
-
-	for (irq = 0; irq < NELS(irqvals); irq++)
-		if (irqvals[irq] == irqval)
-			return irq;
-
-	return -1;
-}
-
-#ifdef STRUCT_CHECK
-/*------------------------------------------------------------------*/
-/*
- * Sanity routine to verify the sizes of the various WaveLAN interface
- * structures.
- */
-static char *wv_struct_check(void)
-{
-#define	SC(t,s,n)	if (sizeof(t) != s) return(n);
-
-	SC(psa_t, PSA_SIZE, "psa_t");
-	SC(mmw_t, MMW_SIZE, "mmw_t");
-	SC(mmr_t, MMR_SIZE, "mmr_t");
-	SC(ha_t, HA_SIZE, "ha_t");
-
-#undef	SC
-
-	return ((char *) NULL);
-}				/* wv_struct_check */
-#endif				/* STRUCT_CHECK */
-
-/********************* HOST ADAPTER SUBROUTINES *********************/
-/*
- * Useful subroutines to manage the WaveLAN ISA interface
- *
- * One major difference with the PCMCIA hardware (except the port mapping)
- * is that we have to keep the state of the Host Control Register
- * because of the interrupt enable & bus size flags.
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Read from card's Host Adaptor Status Register.
- */
-static inline u16 hasr_read(unsigned long ioaddr)
-{
-	return (inw(HASR(ioaddr)));
-}				/* hasr_read */
-
-/*------------------------------------------------------------------*/
-/*
- * Write to card's Host Adapter Command Register.
- */
-static inline void hacr_write(unsigned long ioaddr, u16 hacr)
-{
-	outw(hacr, HACR(ioaddr));
-}				/* hacr_write */
-
-/*------------------------------------------------------------------*/
-/*
- * Write to card's Host Adapter Command Register. Include a delay for
- * those times when it is needed.
- */
-static inline void hacr_write_slow(unsigned long ioaddr, u16 hacr)
-{
-	hacr_write(ioaddr, hacr);
-	/* delay might only be needed sometimes */
-	mdelay(1);
-}				/* hacr_write_slow */
-
-/*------------------------------------------------------------------*/
-/*
- * Set the channel attention bit.
- */
-static inline void set_chan_attn(unsigned long ioaddr, u16 hacr)
-{
-	hacr_write(ioaddr, hacr | HACR_CA);
-}				/* set_chan_attn */
-
-/*------------------------------------------------------------------*/
-/*
- * Reset, and then set host adaptor into default mode.
- */
-static inline void wv_hacr_reset(unsigned long ioaddr)
-{
-	hacr_write_slow(ioaddr, HACR_RESET);
-	hacr_write(ioaddr, HACR_DEFAULT);
-}				/* wv_hacr_reset */
-
-/*------------------------------------------------------------------*/
-/*
- * Set the I/O transfer over the ISA bus to 8-bit mode
- */
-static inline void wv_16_off(unsigned long ioaddr, u16 hacr)
-{
-	hacr &= ~HACR_16BITS;
-	hacr_write(ioaddr, hacr);
-}				/* wv_16_off */
-
-/*------------------------------------------------------------------*/
-/*
- * Set the I/O transfer over the ISA bus to 8-bit mode
- */
-static inline void wv_16_on(unsigned long ioaddr, u16 hacr)
-{
-	hacr |= HACR_16BITS;
-	hacr_write(ioaddr, hacr);
-}				/* wv_16_on */
-
-/*------------------------------------------------------------------*/
-/*
- * Disable interrupts on the WaveLAN hardware.
- * (called by wv_82586_stop())
- */
-static inline void wv_ints_off(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	
-	lp->hacr &= ~HACR_INTRON;
-	hacr_write(ioaddr, lp->hacr);
-}				/* wv_ints_off */
-
-/*------------------------------------------------------------------*/
-/*
- * Enable interrupts on the WaveLAN hardware.
- * (called by wv_hw_reset())
- */
-static inline void wv_ints_on(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-
-	lp->hacr |= HACR_INTRON;
-	hacr_write(ioaddr, lp->hacr);
-}				/* wv_ints_on */
-
-/******************* MODEM MANAGEMENT SUBROUTINES *******************/
-/*
- * Useful subroutines to manage the modem of the WaveLAN
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Read the Parameter Storage Area from the WaveLAN card's memory
- */
-/*
- * Read bytes from the PSA.
- */
-static void psa_read(unsigned long ioaddr, u16 hacr, int o,	/* offset in PSA */
-		     u8 * b,	/* buffer to fill */
-		     int n)
-{				/* size to read */
-	wv_16_off(ioaddr, hacr);
-
-	while (n-- > 0) {
-		outw(o, PIOR2(ioaddr));
-		o++;
-		*b++ = inb(PIOP2(ioaddr));
-	}
-
-	wv_16_on(ioaddr, hacr);
-}				/* psa_read */
-
-/*------------------------------------------------------------------*/
-/*
- * Write the Parameter Storage Area to the WaveLAN card's memory.
- */
-static void psa_write(unsigned long ioaddr, u16 hacr, int o,	/* Offset in PSA */
-		      u8 * b,	/* Buffer in memory */
-		      int n)
-{				/* Length of buffer */
-	int count = 0;
-
-	wv_16_off(ioaddr, hacr);
-
-	while (n-- > 0) {
-		outw(o, PIOR2(ioaddr));
-		o++;
-
-		outb(*b, PIOP2(ioaddr));
-		b++;
-
-		/* Wait for the memory to finish its write cycle */
-		count = 0;
-		while ((count++ < 100) &&
-		       (hasr_read(ioaddr) & HASR_PSA_BUSY)) mdelay(1);
-	}
-
-	wv_16_on(ioaddr, hacr);
-}				/* psa_write */
-
-#ifdef SET_PSA_CRC
-/*------------------------------------------------------------------*/
-/*
- * Calculate the PSA CRC
- * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code
- * NOTE: By specifying a length including the CRC position the
- * returned value should be zero. (i.e. a correct checksum in the PSA)
- *
- * The Windows drivers don't use the CRC, but the AP and the PtP tool
- * depend on it.
- */
-static inline u16 psa_crc(u8 * psa,	/* The PSA */
-			      int size)
-{				/* Number of short for CRC */
-	int byte_cnt;		/* Loop on the PSA */
-	u16 crc_bytes = 0;	/* Data in the PSA */
-	int bit_cnt;		/* Loop on the bits of the short */
-
-	for (byte_cnt = 0; byte_cnt < size; byte_cnt++) {
-		crc_bytes ^= psa[byte_cnt];	/* Its an xor */
-
-		for (bit_cnt = 1; bit_cnt < 9; bit_cnt++) {
-			if (crc_bytes & 0x0001)
-				crc_bytes = (crc_bytes >> 1) ^ 0xA001;
-			else
-				crc_bytes >>= 1;
-		}
-	}
-
-	return crc_bytes;
-}				/* psa_crc */
-#endif				/* SET_PSA_CRC */
-
-/*------------------------------------------------------------------*/
-/*
- * update the checksum field in the Wavelan's PSA
- */
-static void update_psa_checksum(device * dev, unsigned long ioaddr, u16 hacr)
-{
-#ifdef SET_PSA_CRC
-	psa_t psa;
-	u16 crc;
-
-	/* read the parameter storage area */
-	psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa));
-
-	/* update the checksum */
-	crc = psa_crc((unsigned char *) &psa,
-		      sizeof(psa) - sizeof(psa.psa_crc[0]) -
-		      sizeof(psa.psa_crc[1])
-		      - sizeof(psa.psa_crc_status));
-
-	psa.psa_crc[0] = crc & 0xFF;
-	psa.psa_crc[1] = (crc & 0xFF00) >> 8;
-
-	/* Write it ! */
-	psa_write(ioaddr, hacr, (char *) &psa.psa_crc - (char *) &psa,
-		  (unsigned char *) &psa.psa_crc, 2);
-
-#ifdef DEBUG_IOCTL_INFO
-	printk(KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n",
-	       dev->name, psa.psa_crc[0], psa.psa_crc[1]);
-
-	/* Check again (luxury !) */
-	crc = psa_crc((unsigned char *) &psa,
-		      sizeof(psa) - sizeof(psa.psa_crc_status));
-
-	if (crc != 0)
-		printk(KERN_WARNING
-		       "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n",
-		       dev->name);
-#endif				/* DEBUG_IOCTL_INFO */
-#endif				/* SET_PSA_CRC */
-}				/* update_psa_checksum */
-
-/*------------------------------------------------------------------*/
-/*
- * Write 1 byte to the MMC.
- */
-static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d)
-{
-	/* Wait for MMC to go idle */
-	while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
-
-	outw((u16) (((u16) d << 8) | (o << 1) | 1), MMCR(ioaddr));
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Routine to write bytes to the Modem Management Controller.
- * We start at the end because it is the way it should be!
- */
-static inline void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n)
-{
-	o += n;
-	b += n;
-
-	while (n-- > 0)
-		mmc_out(ioaddr, --o, *(--b));
-}				/* mmc_write */
-
-/*------------------------------------------------------------------*/
-/*
- * Read a byte from the MMC.
- * Optimised version for 1 byte, avoid using memory.
- */
-static inline u8 mmc_in(unsigned long ioaddr, u16 o)
-{
-	while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
-	outw(o << 1, MMCR(ioaddr));
-
-	while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
-	return (u8) (inw(MMCR(ioaddr)) >> 8);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Routine to read bytes from the Modem Management Controller.
- * The implementation is complicated by a lack of address lines,
- * which prevents decoding of the low-order bit.
- * (code has just been moved in the above function)
- * We start at the end because it is the way it should be!
- */
-static inline void mmc_read(unsigned long ioaddr, u8 o, u8 * b, int n)
-{
-	o += n;
-	b += n;
-
-	while (n-- > 0)
-		*(--b) = mmc_in(ioaddr, --o);
-}				/* mmc_read */
-
-/*------------------------------------------------------------------*/
-/*
- * Get the type of encryption available.
- */
-static inline int mmc_encr(unsigned long ioaddr)
-{				/* I/O port of the card */
-	int temp;
-
-	temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail));
-	if ((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES))
-		return 0;
-	else
-		return temp;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wait for the frequency EEPROM to complete a command.
- * I hope this one will be optimally inlined.
- */
-static inline void fee_wait(unsigned long ioaddr,	/* I/O port of the card */
-			    int delay,	/* Base delay to wait for */
-			    int number)
-{				/* Number of time to wait */
-	int count = 0;		/* Wait only a limited time */
-
-	while ((count++ < number) &&
-	       (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
-		MMR_FEE_STATUS_BUSY)) udelay(delay);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Read bytes from the Frequency EEPROM (frequency select cards).
- */
-static void fee_read(unsigned long ioaddr,	/* I/O port of the card */
-		     u16 o,	/* destination offset */
-		     u16 * b,	/* data buffer */
-		     int n)
-{				/* number of registers */
-	b += n;			/* Position at the end of the area */
-
-	/* Write the address */
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
-
-	/* Loop on all buffer */
-	while (n-- > 0) {
-		/* Write the read command */
-		mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
-			MMW_FEE_CTRL_READ);
-
-		/* Wait until EEPROM is ready (should be quick). */
-		fee_wait(ioaddr, 10, 100);
-
-		/* Read the value. */
-		*--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) |
-			mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
-	}
-}
-
-#ifdef WIRELESS_EXT		/* if the wireless extension exists in the kernel */
-
-/*------------------------------------------------------------------*/
-/*
- * Write bytes from the Frequency EEPROM (frequency select cards).
- * This is a bit complicated, because the frequency EEPROM has to
- * be unprotected and the write enabled.
- * Jean II
- */
-static void fee_write(unsigned long ioaddr,	/* I/O port of the card */
-		      u16 o,	/* destination offset */
-		      u16 * b,	/* data buffer */
-		      int n)
-{				/* number of registers */
-	b += n;			/* Position at the end of the area. */
-
-#ifdef EEPROM_IS_PROTECTED	/* disabled */
-#ifdef DOESNT_SEEM_TO_WORK	/* disabled */
-	/* Ask to read the protected register */
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD);
-
-	fee_wait(ioaddr, 10, 100);
-
-	/* Read the protected register. */
-	printk("Protected 2:  %02X-%02X\n",
-	       mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
-	       mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
-#endif				/* DOESNT_SEEM_TO_WORK */
-
-	/* Enable protected register. */
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
-
-	fee_wait(ioaddr, 10, 100);
-
-	/* Unprotect area. */
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
-#ifdef DOESNT_SEEM_TO_WORK	/* disabled */
-	/* or use: */
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
-#endif				/* DOESNT_SEEM_TO_WORK */
-
-	fee_wait(ioaddr, 10, 100);
-#endif				/* EEPROM_IS_PROTECTED */
-
-	/* Write enable. */
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
-
-	fee_wait(ioaddr, 10, 100);
-
-	/* Write the EEPROM address. */
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
-
-	/* Loop on all buffer */
-	while (n-- > 0) {
-		/* Write the value. */
-		mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
-		mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
-
-		/* Write the write command. */
-		mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
-			MMW_FEE_CTRL_WRITE);
-
-		/* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */
-		mdelay(10);
-		fee_wait(ioaddr, 10, 100);
-	}
-
-	/* Write disable. */
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
-
-	fee_wait(ioaddr, 10, 100);
-
-#ifdef EEPROM_IS_PROTECTED	/* disabled */
-	/* Reprotect EEPROM. */
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00);
-	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
-
-	fee_wait(ioaddr, 10, 100);
-#endif				/* EEPROM_IS_PROTECTED */
-}
-#endif				/* WIRELESS_EXT */
-
-/************************ I82586 SUBROUTINES *************************/
-/*
- * Useful subroutines to manage the Ethernet controller
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Read bytes from the on-board RAM.
- * Why does inlining this function make it fail?
- */
-static /*inline */ void obram_read(unsigned long ioaddr,
-				   u16 o, u8 * b, int n)
-{
-	outw(o, PIOR1(ioaddr));
-	insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Write bytes to the on-board RAM.
- */
-static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n)
-{
-	outw(o, PIOR1(ioaddr));
-	outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Acknowledge the reading of the status issued by the i82586.
- */
-static void wv_ack(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	u16 scb_cs;
-	int i;
-
-	obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
-		   (unsigned char *) &scb_cs, sizeof(scb_cs));
-	scb_cs &= SCB_ST_INT;
-
-	if (scb_cs == 0)
-		return;
-
-	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
-		    (unsigned char *) &scb_cs, sizeof(scb_cs));
-
-	set_chan_attn(ioaddr, lp->hacr);
-
-	for (i = 1000; i > 0; i--) {
-		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
-			   (unsigned char *) &scb_cs, sizeof(scb_cs));
-		if (scb_cs == 0)
-			break;
-
-		udelay(10);
-	}
-	udelay(100);
-
-#ifdef DEBUG_CONFIG_ERROR
-	if (i <= 0)
-		printk(KERN_INFO
-		       "%s: wv_ack(): board not accepting command.\n",
-		       dev->name);
-#endif
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Set channel attention bit and busy wait until command has
- * completed, then acknowledge completion of the command.
- */
-static inline int wv_synchronous_cmd(device * dev, const char *str)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	u16 scb_cmd;
-	ach_t cb;
-	int i;
-
-	scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO;
-	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
-		    (unsigned char *) &scb_cmd, sizeof(scb_cmd));
-
-	set_chan_attn(ioaddr, lp->hacr);
-
-	for (i = 1000; i > 0; i--) {
-		obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb,
-			   sizeof(cb));
-		if (cb.ac_status & AC_SFLD_C)
-			break;
-
-		udelay(10);
-	}
-	udelay(100);
-
-	if (i <= 0 || !(cb.ac_status & AC_SFLD_OK)) {
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_INFO "%s: %s failed; status = 0x%x\n",
-		       dev->name, str, cb.ac_status);
-#endif
-#ifdef DEBUG_I82586_SHOW
-		wv_scb_show(ioaddr);
-#endif
-		return -1;
-	}
-
-	/* Ack the status */
-	wv_ack(dev);
-
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Configuration commands completion interrupt.
- * Check if done, and if OK.
- */
-static inline int
-wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp)
-{
-	unsigned short mcs_addr;
-	unsigned short status;
-	int ret;
-
-#ifdef DEBUG_INTERRUPT_TRACE
-	printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name);
-#endif
-
-	mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t)
-	    + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t);
-
-	/* Read the status of the last command (set mc list). */
-	obram_read(ioaddr, acoff(mcs_addr, ac_status),
-		   (unsigned char *) &status, sizeof(status));
-
-	/* If not completed -> exit */
-	if ((status & AC_SFLD_C) == 0)
-		ret = 0;	/* Not ready to be scrapped */
-	else {
-#ifdef DEBUG_CONFIG_ERROR
-		unsigned short cfg_addr;
-		unsigned short ias_addr;
-
-		/* Check mc_config command */
-		if ((status & AC_SFLD_OK) != AC_SFLD_OK)
-			printk(KERN_INFO
-			       "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n",
-			       dev->name, status);
-
-		/* check ia-config command */
-		ias_addr = mcs_addr - sizeof(ac_ias_t);
-		obram_read(ioaddr, acoff(ias_addr, ac_status),
-			   (unsigned char *) &status, sizeof(status));
-		if ((status & AC_SFLD_OK) != AC_SFLD_OK)
-			printk(KERN_INFO
-			       "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n",
-			       dev->name, status);
-
-		/* Check config command. */
-		cfg_addr = ias_addr - sizeof(ac_cfg_t);
-		obram_read(ioaddr, acoff(cfg_addr, ac_status),
-			   (unsigned char *) &status, sizeof(status));
-		if ((status & AC_SFLD_OK) != AC_SFLD_OK)
-			printk(KERN_INFO
-			       "%s: wv_config_complete(): configure failed; status = 0x%x\n",
-			       dev->name, status);
-#endif	/* DEBUG_CONFIG_ERROR */
-
-		ret = 1;	/* Ready to be scrapped */
-	}
-
-#ifdef DEBUG_INTERRUPT_TRACE
-	printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name,
-	       ret);
-#endif
-	return ret;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Command completion interrupt.
- * Reclaim as many freed tx buffers as we can.
- * (called in wavelan_interrupt()).
- * Note : the spinlock is already grabbed for us.
- */
-static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp)
-{
-	int nreaped = 0;
-
-#ifdef DEBUG_INTERRUPT_TRACE
-	printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name);
-#endif
-
-	/* Loop on all the transmit buffers */
-	while (lp->tx_first_in_use != I82586NULL) {
-		unsigned short tx_status;
-
-		/* Read the first transmit buffer */
-		obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status),
-			   (unsigned char *) &tx_status,
-			   sizeof(tx_status));
-
-		/* If not completed -> exit */
-		if ((tx_status & AC_SFLD_C) == 0)
-			break;
-
-		/* Hack for reconfiguration */
-		if (tx_status == 0xFFFF)
-			if (!wv_config_complete(dev, ioaddr, lp))
-				break;	/* Not completed */
-
-		/* We now remove this buffer */
-		nreaped++;
-		--lp->tx_n_in_use;
-
-/*
-if (lp->tx_n_in_use > 0)
-	printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);
-*/
-
-		/* Was it the last one? */
-		if (lp->tx_n_in_use <= 0)
-			lp->tx_first_in_use = I82586NULL;
-		else {
-			/* Next one in the chain */
-			lp->tx_first_in_use += TXBLOCKZ;
-			if (lp->tx_first_in_use >=
-			    OFFSET_CU +
-			    NTXBLOCKS * TXBLOCKZ) lp->tx_first_in_use -=
-				    NTXBLOCKS * TXBLOCKZ;
-		}
-
-		/* Hack for reconfiguration */
-		if (tx_status == 0xFFFF)
-			continue;
-
-		/* Now, check status of the finished command */
-		if (tx_status & AC_SFLD_OK) {
-			int ncollisions;
-
-			lp->stats.tx_packets++;
-			ncollisions = tx_status & AC_SFLD_MAXCOL;
-			lp->stats.collisions += ncollisions;
-#ifdef DEBUG_TX_INFO
-			if (ncollisions > 0)
-				printk(KERN_DEBUG
-				       "%s: wv_complete(): tx completed after %d collisions.\n",
-				       dev->name, ncollisions);
-#endif
-		} else {
-			lp->stats.tx_errors++;
-			if (tx_status & AC_SFLD_S10) {
-				lp->stats.tx_carrier_errors++;
-#ifdef DEBUG_TX_FAIL
-				printk(KERN_DEBUG
-				       "%s: wv_complete(): tx error: no CS.\n",
-				       dev->name);
-#endif
-			}
-			if (tx_status & AC_SFLD_S9) {
-				lp->stats.tx_carrier_errors++;
-#ifdef DEBUG_TX_FAIL
-				printk(KERN_DEBUG
-				       "%s: wv_complete(): tx error: lost CTS.\n",
-				       dev->name);
-#endif
-			}
-			if (tx_status & AC_SFLD_S8) {
-				lp->stats.tx_fifo_errors++;
-#ifdef DEBUG_TX_FAIL
-				printk(KERN_DEBUG
-				       "%s: wv_complete(): tx error: slow DMA.\n",
-				       dev->name);
-#endif
-			}
-			if (tx_status & AC_SFLD_S6) {
-				lp->stats.tx_heartbeat_errors++;
-#ifdef DEBUG_TX_FAIL
-				printk(KERN_DEBUG
-				       "%s: wv_complete(): tx error: heart beat.\n",
-				       dev->name);
-#endif
-			}
-			if (tx_status & AC_SFLD_S5) {
-				lp->stats.tx_aborted_errors++;
-#ifdef DEBUG_TX_FAIL
-				printk(KERN_DEBUG
-				       "%s: wv_complete(): tx error: too many collisions.\n",
-				       dev->name);
-#endif
-			}
-		}
-
-#ifdef DEBUG_TX_INFO
-		printk(KERN_DEBUG
-		       "%s: wv_complete(): tx completed, tx_status 0x%04x\n",
-		       dev->name, tx_status);
-#endif
-	}
-
-#ifdef DEBUG_INTERRUPT_INFO
-	if (nreaped > 1)
-		printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n",
-		       dev->name, nreaped);
-#endif
-
-	/*
-	 * Inform upper layers.
-	 */
-	if (lp->tx_n_in_use < NTXBLOCKS - 1) {
-		netif_wake_queue(dev);
-	}
-#ifdef DEBUG_INTERRUPT_TRACE
-	printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name);
-#endif
-	return nreaped;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Reconfigure the i82586, or at least ask for it.
- * Because wv_82586_config uses a transmission buffer, we must do it
- * when we are sure that there is one left, so we do it now
- * or in wavelan_packet_xmit() (I can't find any better place,
- * wavelan_interrupt is not an option), so you may experience
- * delays sometimes.
- */
-static inline void wv_82586_reconfig(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long flags;
-
-	/* Arm the flag, will be cleard in wv_82586_config() */
-	lp->reconfig_82586 = 1;
-
-	/* Check if we can do it now ! */
-	if((netif_running(dev)) && !(netif_queue_stopped(dev))) {
-		wv_splhi(lp, &flags);
-		/* May fail */
-		wv_82586_config(dev);
-		wv_splx(lp, &flags);
-	}
-	else {
-#ifdef DEBUG_CONFIG_INFO
-		printk(KERN_DEBUG
-		       "%s: wv_82586_reconfig(): delayed (state = %lX)\n",
-			       dev->name, dev->state);
-#endif
-	}
-}
-
-/********************* DEBUG & INFO SUBROUTINES *********************/
-/*
- * This routine is used in the code to show information for debugging.
- * Most of the time, it dumps the contents of hardware structures.
- */
-
-#ifdef DEBUG_PSA_SHOW
-/*------------------------------------------------------------------*/
-/*
- * Print the formatted contents of the Parameter Storage Area.
- */
-static void wv_psa_show(psa_t * p)
-{
-	printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
-	printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
-	       p->psa_io_base_addr_1,
-	       p->psa_io_base_addr_2,
-	       p->psa_io_base_addr_3, p->psa_io_base_addr_4);
-	printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n",
-	       p->psa_rem_boot_addr_1,
-	       p->psa_rem_boot_addr_2, p->psa_rem_boot_addr_3);
-	printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
-	printk("psa_int_req_no: %d\n", p->psa_int_req_no);
-#ifdef DEBUG_SHOW_UNUSED
-	printk(KERN_DEBUG
-	       "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-	       p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2],
-	       p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5],
-	       p->psa_unused0[6]);
-#endif				/* DEBUG_SHOW_UNUSED */
-	printk(KERN_DEBUG
-	       "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1],
-	       p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3],
-	       p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]);
-	printk(KERN_DEBUG
-	       "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       p->psa_local_mac_addr[0], p->psa_local_mac_addr[1],
-	       p->psa_local_mac_addr[2], p->psa_local_mac_addr[3],
-	       p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]);
-	printk(KERN_DEBUG "psa_univ_local_sel: %d, ",
-	       p->psa_univ_local_sel);
-	printk("psa_comp_number: %d, ", p->psa_comp_number);
-	printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
-	printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ",
-	       p->psa_feature_select);
-	printk("psa_subband/decay_update_prm: %d\n", p->psa_subband);
-	printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr);
-	printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay);
-	printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0],
-	       p->psa_nwid[1]);
-	printk("psa_nwid_select: %d\n", p->psa_nwid_select);
-	printk(KERN_DEBUG "psa_encryption_select: %d, ",
-	       p->psa_encryption_select);
-	printk
-	    ("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
-	     p->psa_encryption_key[0], p->psa_encryption_key[1],
-	     p->psa_encryption_key[2], p->psa_encryption_key[3],
-	     p->psa_encryption_key[4], p->psa_encryption_key[5],
-	     p->psa_encryption_key[6], p->psa_encryption_key[7]);
-	printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width);
-	printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ",
-	       p->psa_call_code[0]);
-	printk
-	    ("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-	     p->psa_call_code[0], p->psa_call_code[1], p->psa_call_code[2],
-	     p->psa_call_code[3], p->psa_call_code[4], p->psa_call_code[5],
-	     p->psa_call_code[6], p->psa_call_code[7]);
-#ifdef DEBUG_SHOW_UNUSED
-	printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
-	       p->psa_reserved[0],
-	       p->psa_reserved[1], p->psa_reserved[2], p->psa_reserved[3]);
-#endif				/* DEBUG_SHOW_UNUSED */
-	printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
-	printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
-	printk("psa_crc_status: 0x%02x\n", p->psa_crc_status);
-}				/* wv_psa_show */
-#endif				/* DEBUG_PSA_SHOW */
-
-#ifdef DEBUG_MMC_SHOW
-/*------------------------------------------------------------------*/
-/*
- * Print the formatted status of the Modem Management Controller.
- * This function needs to be completed.
- */
-static void wv_mmc_show(device * dev)
-{
-	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;
-	mmr_t m;
-
-	/* Basic check */
-	if (hasr_read(ioaddr) & HASR_NO_CLK) {
-		printk(KERN_WARNING
-		       "%s: wv_mmc_show: modem not connected\n",
-		       dev->name);
-		return;
-	}
-
-	/* Read the mmc */
-	mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
-	mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m));
-	mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
-
-#ifdef WIRELESS_EXT		/* if wireless extension exists in the kernel */
-	/* Don't forget to update statistics */
-	lp->wstats.discard.nwid +=
-	    (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
-#endif				/* WIRELESS_EXT */
-
-	printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n");
-#ifdef DEBUG_SHOW_UNUSED
-	printk(KERN_DEBUG
-	       "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-	       m.mmr_unused0[0], m.mmr_unused0[1], m.mmr_unused0[2],
-	       m.mmr_unused0[3], m.mmr_unused0[4], m.mmr_unused0[5],
-	       m.mmr_unused0[6], m.mmr_unused0[7]);
-#endif				/* DEBUG_SHOW_UNUSED */
-	printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n",
-	       m.mmr_des_avail, m.mmr_des_status);
-#ifdef DEBUG_SHOW_UNUSED
-	printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
-	       m.mmr_unused1[0],
-	       m.mmr_unused1[1],
-	       m.mmr_unused1[2], m.mmr_unused1[3], m.mmr_unused1[4]);
-#endif				/* DEBUG_SHOW_UNUSED */
-	printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n",
-	       m.mmr_dce_status,
-	       (m.
-		mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ?
-	       "energy detected," : "",
-	       (m.
-		mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ?
-	       "loop test indicated," : "",
-	       (m.
-		mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ?
-	       "transmitter on," : "",
-	       (m.
-		mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ?
-	       "jabber timer expired," : "");
-	printk(KERN_DEBUG "Dsp ID: %02X\n", m.mmr_dsp_id);
-#ifdef DEBUG_SHOW_UNUSED
-	printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n",
-	       m.mmr_unused2[0], m.mmr_unused2[1]);
-#endif				/* DEBUG_SHOW_UNUSED */
-	printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n",
-	       (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l,
-	       (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l);
-	printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n",
-	       m.mmr_thr_pre_set & MMR_THR_PRE_SET,
-	       (m.
-		mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" :
-	       "below");
-	printk(KERN_DEBUG "signal_lvl: %d [%s], ",
-	       m.mmr_signal_lvl & MMR_SIGNAL_LVL,
-	       (m.
-		mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" :
-	       "no new msg");
-	printk("silence_lvl: %d [%s], ",
-	       m.mmr_silence_lvl & MMR_SILENCE_LVL,
-	       (m.
-		mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" :
-	       "no new update");
-	printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL,
-	       (m.
-		mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" :
-	       "Antenna 0");
-#ifdef DEBUG_SHOW_UNUSED
-	printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l);
-#endif				/* DEBUG_SHOW_UNUSED */
-}				/* wv_mmc_show */
-#endif				/* DEBUG_MMC_SHOW */
-
-#ifdef DEBUG_I82586_SHOW
-/*------------------------------------------------------------------*/
-/*
- * Print the last block of the i82586 memory.
- */
-static void wv_scb_show(unsigned long ioaddr)
-{
-	scb_t scb;
-
-	obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
-		   sizeof(scb));
-
-	printk(KERN_DEBUG "##### WaveLAN system control block: #####\n");
-
-	printk(KERN_DEBUG "status: ");
-	printk("stat 0x%x[%s%s%s%s] ",
-	       (scb.
-		scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA |
-			      SCB_ST_RNR)) >> 12,
-	       (scb.
-		scb_status & SCB_ST_CX) ? "command completion interrupt," :
-	       "", (scb.scb_status & SCB_ST_FR) ? "frame received," : "",
-	       (scb.
-		scb_status & SCB_ST_CNA) ? "command unit not active," : "",
-	       (scb.
-		scb_status & SCB_ST_RNR) ? "receiving unit not ready," :
-	       "");
-	printk("cus 0x%x[%s%s%s] ", (scb.scb_status & SCB_ST_CUS) >> 8,
-	       ((scb.scb_status & SCB_ST_CUS) ==
-		SCB_ST_CUS_IDLE) ? "idle" : "",
-	       ((scb.scb_status & SCB_ST_CUS) ==
-		SCB_ST_CUS_SUSP) ? "suspended" : "",
-	       ((scb.scb_status & SCB_ST_CUS) ==
-		SCB_ST_CUS_ACTV) ? "active" : "");
-	printk("rus 0x%x[%s%s%s%s]\n", (scb.scb_status & SCB_ST_RUS) >> 4,
-	       ((scb.scb_status & SCB_ST_RUS) ==
-		SCB_ST_RUS_IDLE) ? "idle" : "",
-	       ((scb.scb_status & SCB_ST_RUS) ==
-		SCB_ST_RUS_SUSP) ? "suspended" : "",
-	       ((scb.scb_status & SCB_ST_RUS) ==
-		SCB_ST_RUS_NRES) ? "no resources" : "",
-	       ((scb.scb_status & SCB_ST_RUS) ==
-		SCB_ST_RUS_RDY) ? "ready" : "");
-
-	printk(KERN_DEBUG "command: ");
-	printk("ack 0x%x[%s%s%s%s] ",
-	       (scb.
-		scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR |
-			       SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12,
-	       (scb.
-		scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "",
-	       (scb.
-		scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "",
-	       (scb.
-		scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "",
-	       (scb.
-		scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : "");
-	printk("cuc 0x%x[%s%s%s%s%s] ",
-	       (scb.scb_command & SCB_CMD_CUC) >> 8,
-	       ((scb.scb_command & SCB_CMD_CUC) ==
-		SCB_CMD_CUC_NOP) ? "nop" : "",
-	       ((scb.scb_command & SCB_CMD_CUC) ==
-		SCB_CMD_CUC_GO) ? "start cbl_offset" : "",
-	       ((scb.scb_command & SCB_CMD_CUC) ==
-		SCB_CMD_CUC_RES) ? "resume execution" : "",
-	       ((scb.scb_command & SCB_CMD_CUC) ==
-		SCB_CMD_CUC_SUS) ? "suspend execution" : "",
-	       ((scb.scb_command & SCB_CMD_CUC) ==
-		SCB_CMD_CUC_ABT) ? "abort execution" : "");
-	printk("ruc 0x%x[%s%s%s%s%s]\n",
-	       (scb.scb_command & SCB_CMD_RUC) >> 4,
-	       ((scb.scb_command & SCB_CMD_RUC) ==
-		SCB_CMD_RUC_NOP) ? "nop" : "",
-	       ((scb.scb_command & SCB_CMD_RUC) ==
-		SCB_CMD_RUC_GO) ? "start rfa_offset" : "",
-	       ((scb.scb_command & SCB_CMD_RUC) ==
-		SCB_CMD_RUC_RES) ? "resume reception" : "",
-	       ((scb.scb_command & SCB_CMD_RUC) ==
-		SCB_CMD_RUC_SUS) ? "suspend reception" : "",
-	       ((scb.scb_command & SCB_CMD_RUC) ==
-		SCB_CMD_RUC_ABT) ? "abort reception" : "");
-
-	printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset);
-	printk("rfa_offset 0x%x\n", scb.scb_rfa_offset);
-
-	printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs);
-	printk("alnerrs %d ", scb.scb_alnerrs);
-	printk("rscerrs %d ", scb.scb_rscerrs);
-	printk("ovrnerrs %d\n", scb.scb_ovrnerrs);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Print the formatted status of the i82586's receive unit.
- */
-static void wv_ru_show(device * dev)
-{
-	/* net_local *lp = (net_local *) dev->priv; */
-
-	printk(KERN_DEBUG
-	       "##### WaveLAN i82586 receiver unit status: #####\n");
-	printk(KERN_DEBUG "ru:");
-	/*
-	 * Not implemented yet
-	 */
-	printk("\n");
-}				/* wv_ru_show */
-
-/*------------------------------------------------------------------*/
-/*
- * Display info about one control block of the i82586 memory.
- */
-static void wv_cu_show_one(device * dev, net_local * lp, int i, u16 p)
-{
-	unsigned long ioaddr;
-	ac_tx_t actx;
-
-	ioaddr = dev->base_addr;
-
-	printk("%d: 0x%x:", i, p);
-
-	obram_read(ioaddr, p, (unsigned char *) &actx, sizeof(actx));
-	printk(" status=0x%x,", actx.tx_h.ac_status);
-	printk(" command=0x%x,", actx.tx_h.ac_command);
-
-	/*
-	   {
-	   tbd_t      tbd;
-
-	   obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd));
-	   printk(" tbd_status=0x%x,", tbd.tbd_status);
-	   }
-	 */
-
-	printk("|");
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Print status of the command unit of the i82586.
- */
-static void wv_cu_show(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned int i;
-	u16 p;
-
-	printk(KERN_DEBUG
-	       "##### WaveLAN i82586 command unit status: #####\n");
-
-	printk(KERN_DEBUG);
-	for (i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++) {
-		wv_cu_show_one(dev, lp, i, p);
-
-		p += TXBLOCKZ;
-		if (p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
-			p -= NTXBLOCKS * TXBLOCKZ;
-	}
-	printk("\n");
-}
-#endif				/* DEBUG_I82586_SHOW */
-
-#ifdef DEBUG_DEVICE_SHOW
-/*------------------------------------------------------------------*/
-/*
- * Print the formatted status of the WaveLAN PCMCIA device driver.
- */
-static void wv_dev_show(device * dev)
-{
-	printk(KERN_DEBUG "dev:");
-	printk(" state=%lX,", dev->state);
-	printk(" trans_start=%ld,", dev->trans_start);
-	printk(" flags=0x%x,", dev->flags);
-	printk("\n");
-}				/* wv_dev_show */
-
-/*------------------------------------------------------------------*/
-/*
- * Print the formatted status of the WaveLAN PCMCIA device driver's
- * private information.
- */
-static void wv_local_show(device * dev)
-{
-	net_local *lp;
-
-	lp = (net_local *) dev->priv;
-
-	printk(KERN_DEBUG "local:");
-	printk(" tx_n_in_use=%d,", lp->tx_n_in_use);
-	printk(" hacr=0x%x,", lp->hacr);
-	printk(" rx_head=0x%x,", lp->rx_head);
-	printk(" rx_last=0x%x,", lp->rx_last);
-	printk(" tx_first_free=0x%x,", lp->tx_first_free);
-	printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use);
-	printk("\n");
-}				/* wv_local_show */
-#endif				/* DEBUG_DEVICE_SHOW */
-
-#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO)
-/*------------------------------------------------------------------*/
-/*
- * Dump packet header (and content if necessary) on the screen
- */
-static inline void wv_packet_info(u8 * p,	/* Packet to dump */
-				  int length,	/* Length of the packet */
-				  char *msg1,	/* Name of the device */
-				  char *msg2)
-{				/* Name of the function */
-	int i;
-	int maxi;
-
-	printk(KERN_DEBUG
-	       "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
-	       msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
-	printk(KERN_DEBUG
-	       "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
-	       msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12],
-	       p[13]);
-
-#ifdef DEBUG_PACKET_DUMP
-
-	printk(KERN_DEBUG "data=\"");
-
-	if ((maxi = length) > DEBUG_PACKET_DUMP)
-		maxi = DEBUG_PACKET_DUMP;
-	for (i = 14; i < maxi; i++)
-		if (p[i] >= ' ' && p[i] <= '~')
-			printk(" %c", p[i]);
-		else
-			printk("%02X", p[i]);
-	if (maxi < length)
-		printk("..");
-	printk("\"\n");
-	printk(KERN_DEBUG "\n");
-#endif				/* DEBUG_PACKET_DUMP */
-}
-#endif				/* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */
-
-/*------------------------------------------------------------------*/
-/*
- * This is the information which is displayed by the driver at startup.
- * There are lots of flags for configuring it to your liking.
- */
-static inline void wv_init_info(device * dev)
-{
-	short ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;
-	psa_t psa;
-	int i;
-
-	/* Read the parameter storage area */
-	psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
-
-#ifdef DEBUG_PSA_SHOW
-	wv_psa_show(&psa);
-#endif
-#ifdef DEBUG_MMC_SHOW
-	wv_mmc_show(dev);
-#endif
-#ifdef DEBUG_I82586_SHOW
-	wv_cu_show(dev);
-#endif
-
-#ifdef DEBUG_BASIC_SHOW
-	/* Now, let's go for the basic stuff. */
-	printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
-	for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
-		printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
-	printk(", IRQ %d", dev->irq);
-
-	/* Print current network ID. */
-	if (psa.psa_nwid_select)
-		printk(", nwid 0x%02X-%02X", psa.psa_nwid[0],
-		       psa.psa_nwid[1]);
-	else
-		printk(", nwid off");
-
-	/* If 2.00 card */
-	if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
-	      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
-		unsigned short freq;
-
-		/* Ask the EEPROM to read the frequency from the first area. */
-		fee_read(ioaddr, 0x00, &freq, 1);
-
-		/* Print frequency */
-		printk(", 2.00, %ld", (freq >> 6) + 2400L);
-
-		/* Hack! */
-		if (freq & 0x20)
-			printk(".5");
-	} else {
-		printk(", PC");
-		switch (psa.psa_comp_number) {
-		case PSA_COMP_PC_AT_915:
-		case PSA_COMP_PC_AT_2400:
-			printk("-AT");
-			break;
-		case PSA_COMP_PC_MC_915:
-		case PSA_COMP_PC_MC_2400:
-			printk("-MC");
-			break;
-		case PSA_COMP_PCMCIA_915:
-			printk("MCIA");
-			break;
-		default:
-			printk("?");
-		}
-		printk(", ");
-		switch (psa.psa_subband) {
-		case PSA_SUBBAND_915:
-			printk("915");
-			break;
-		case PSA_SUBBAND_2425:
-			printk("2425");
-			break;
-		case PSA_SUBBAND_2460:
-			printk("2460");
-			break;
-		case PSA_SUBBAND_2484:
-			printk("2484");
-			break;
-		case PSA_SUBBAND_2430_5:
-			printk("2430.5");
-			break;
-		default:
-			printk("?");
-		}
-	}
-
-	printk(" MHz\n");
-#endif				/* DEBUG_BASIC_SHOW */
-
-#ifdef DEBUG_VERSION_SHOW
-	/* Print version information */
-	printk(KERN_NOTICE "%s", version);
-#endif
-}				/* wv_init_info */
-
-/********************* IOCTL, STATS & RECONFIG *********************/
-/*
- * We found here routines that are called by Linux on different
- * occasions after the configuration and not for transmitting data
- * These may be called when the user use ifconfig, /proc/net/dev
- * or wireless extensions
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Get the current Ethernet statistics. This may be called with the
- * card open or closed.
- * Used when the user read /proc/net/dev
- */
-static en_stats *wavelan_get_stats(device * dev)
-{
-#ifdef DEBUG_IOCTL_TRACE
-	printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
-#endif
-
-	return (&((net_local *) dev->priv)->stats);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Set or clear the multicast filter for this adaptor.
- * num_addrs == -1	Promiscuous mode, receive all packets
- * num_addrs == 0	Normal mode, clear multicast list
- * num_addrs > 0	Multicast mode, receive normal and MC packets,
- *			and do best-effort filtering.
- */
-static void wavelan_set_multicast_list(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-
-#ifdef DEBUG_IOCTL_TRACE
-	printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n",
-	       dev->name);
-#endif
-
-#ifdef DEBUG_IOCTL_INFO
-	printk(KERN_DEBUG
-	       "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n",
-	       dev->name, dev->flags, dev->mc_count);
-#endif
-
-	/* Are we asking for promiscuous mode,
-	 * or all multicast addresses (we don't have that!)
-	 * or too many multicast addresses for the hardware filter? */
-	if ((dev->flags & IFF_PROMISC) ||
-	    (dev->flags & IFF_ALLMULTI) ||
-	    (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) {
-		/*
-		 * Enable promiscuous mode: receive all packets.
-		 */
-		if (!lp->promiscuous) {
-			lp->promiscuous = 1;
-			lp->mc_count = 0;
-
-			wv_82586_reconfig(dev);
-
-			/* Tell the kernel that we are doing a really bad job. */
-			dev->flags |= IFF_PROMISC;
-		}
-	} else
-		/* Are there multicast addresses to send? */
-	if (dev->mc_list != (struct dev_mc_list *) NULL) {
-		/*
-		 * Disable promiscuous mode, but receive all packets
-		 * in multicast list
-		 */
-#ifdef MULTICAST_AVOID
-		if (lp->promiscuous || (dev->mc_count != lp->mc_count))
-#endif
-		{
-			lp->promiscuous = 0;
-			lp->mc_count = dev->mc_count;
-
-			wv_82586_reconfig(dev);
-		}
-	} else {
-		/*
-		 * Switch to normal mode: disable promiscuous mode and 
-		 * clear the multicast list.
-		 */
-		if (lp->promiscuous || lp->mc_count == 0) {
-			lp->promiscuous = 0;
-			lp->mc_count = 0;
-
-			wv_82586_reconfig(dev);
-		}
-	}
-#ifdef DEBUG_IOCTL_TRACE
-	printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n",
-	       dev->name);
-#endif
-}
-
-/*------------------------------------------------------------------*/
-/*
- * This function doesn't exist.
- * (Note : it was a nice way to test the reconfigure stuff...)
- */
-#ifdef SET_MAC_ADDRESS
-static int wavelan_set_mac_address(device * dev, void *addr)
-{
-	struct sockaddr *mac = addr;
-
-	/* Copy the address. */
-	memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
-
-	/* Reconfigure the beast. */
-	wv_82586_reconfig(dev);
-
-	return 0;
-}
-#endif				/* SET_MAC_ADDRESS */
-
-#ifdef WIRELESS_EXT		/* if wireless extensions exist in the kernel */
-
-/*------------------------------------------------------------------*/
-/*
- * Frequency setting (for hardware capable of it)
- * It's a bit complicated and you don't really want to look into it.
- * (called in wavelan_ioctl)
- */
-static inline int wv_set_frequency(unsigned long ioaddr,	/* I/O port of the card */
-				   iw_freq * frequency)
-{
-	const int BAND_NUM = 10;	/* Number of bands */
-	long freq = 0L;		/* offset to 2.4 GHz in .5 MHz */
-#ifdef DEBUG_IOCTL_INFO
-	int i;
-#endif
-
-	/* Setting by frequency */
-	/* Theoretically, you may set any frequency between
-	 * the two limits with a 0.5 MHz precision. In practice,
-	 * I don't want you to have trouble with local regulations.
-	 */
-	if ((frequency->e == 1) &&
-	    (frequency->m >= (int) 2.412e8)
-	    && (frequency->m <= (int) 2.487e8)) {
-		freq = ((frequency->m / 10000) - 24000L) / 5;
-	}
-
-	/* Setting by channel (same as wfreqsel) */
-	/* Warning: each channel is 22 MHz wide, so some of the channels
-	 * will interfere. */
-	if ((frequency->e == 0) && (frequency->m < BAND_NUM)) {
-		/* Get frequency offset. */
-		freq = channel_bands[frequency->m] >> 1;
-	}
-
-	/* Verify that the frequency is allowed. */
-	if (freq != 0L) {
-		u16 table[10];	/* Authorized frequency table */
-
-		/* Read the frequency table. */
-		fee_read(ioaddr, 0x71, table, 10);
-
-#ifdef DEBUG_IOCTL_INFO
-		printk(KERN_DEBUG "Frequency table: ");
-		for (i = 0; i < 10; i++) {
-			printk(" %04X", table[i]);
-		}
-		printk("\n");
-#endif
-
-		/* Look in the table to see whether the frequency is allowed. */
-		if (!(table[9 - ((freq - 24) / 16)] &
-		      (1 << ((freq - 24) % 16)))) return -EINVAL;	/* not allowed */
-	} else
-		return -EINVAL;
-
-	/* if we get a usable frequency */
-	if (freq != 0L) {
-		unsigned short area[16];
-		unsigned short dac[2];
-		unsigned short area_verify[16];
-		unsigned short dac_verify[2];
-		/* Corresponding gain (in the power adjust value table)
-		 * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
-		 * and WCIN062D.DOC, page 6.2.9. */
-		unsigned short power_limit[] = { 40, 80, 120, 160, 0 };
-		int power_band = 0;	/* Selected band */
-		unsigned short power_adjust;	/* Correct value */
-
-		/* Search for the gain. */
-		power_band = 0;
-		while ((freq > power_limit[power_band]) &&
-		       (power_limit[++power_band] != 0));
-
-		/* Read the first area. */
-		fee_read(ioaddr, 0x00, area, 16);
-
-		/* Read the DAC. */
-		fee_read(ioaddr, 0x60, dac, 2);
-
-		/* Read the new power adjust value. */
-		fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust,
-			 1);
-		if (power_band & 0x1)
-			power_adjust >>= 8;
-		else
-			power_adjust &= 0xFF;
-
-#ifdef DEBUG_IOCTL_INFO
-		printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
-		for (i = 0; i < 16; i++) {
-			printk(" %04X", area[i]);
-		}
-		printk("\n");
-
-		printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
-		       dac[0], dac[1]);
-#endif
-
-		/* Frequency offset (for info only) */
-		area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
-
-		/* Receiver Principle main divider coefficient */
-		area[3] = (freq >> 1) + 2400L - 352L;
-		area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
-
-		/* Transmitter Main divider coefficient */
-		area[13] = (freq >> 1) + 2400L;
-		area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
-
-		/* Other parts of the area are flags, bit streams or unused. */
-
-		/* Set the value in the DAC. */
-		dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
-		dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
-
-		/* Write the first area. */
-		fee_write(ioaddr, 0x00, area, 16);
-
-		/* Write the DAC. */
-		fee_write(ioaddr, 0x60, dac, 2);
-
-		/* We now should verify here that the writing of the EEPROM went OK. */
-
-		/* Reread the first area. */
-		fee_read(ioaddr, 0x00, area_verify, 16);
-
-		/* Reread the DAC. */
-		fee_read(ioaddr, 0x60, dac_verify, 2);
-
-		/* Compare. */
-		if (memcmp(area, area_verify, 16 * 2) ||
-		    memcmp(dac, dac_verify, 2 * 2)) {
-#ifdef DEBUG_IOCTL_ERROR
-			printk(KERN_INFO
-			       "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n");
-#endif
-			return -EOPNOTSUPP;
-		}
-
-		/* We must download the frequency parameters to the
-		 * synthesizers (from the EEPROM - area 1)
-		 * Note: as the EEPROM is automatically decremented, we set the end
-		 * if the area... */
-		mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F);
-		mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
-			MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
-
-		/* Wait until the download is finished. */
-		fee_wait(ioaddr, 100, 100);
-
-		/* We must now download the power adjust value (gain) to
-		 * the synthesizers (from the EEPROM - area 7 - DAC). */
-		mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
-		mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
-			MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
-
-		/* Wait for the download to finish. */
-		fee_wait(ioaddr, 100, 100);
-
-#ifdef DEBUG_IOCTL_INFO
-		/* Verification of what we have done */
-
-		printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
-		for (i = 0; i < 16; i++) {
-			printk(" %04X", area_verify[i]);
-		}
-		printk("\n");
-
-		printk(KERN_DEBUG "WaveLAN EEPROM DAC:  %04X %04X\n",
-		       dac_verify[0], dac_verify[1]);
-#endif
-
-		return 0;
-	} else
-		return -EINVAL;	/* Bah, never get there... */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Give the list of available frequencies.
- */
-static inline int wv_frequency_list(unsigned long ioaddr,	/* I/O port of the card */
-				    iw_freq * list,	/* List of frequencies to fill */
-				    int max)
-{				/* Maximum number of frequencies */
-	u16 table[10];	/* Authorized frequency table */
-	long freq = 0L;		/* offset to 2.4 GHz in .5 MHz + 12 MHz */
-	int i;			/* index in the table */
-	int c = 0;		/* Channel number */
-
-	/* Read the frequency table. */
-	fee_read(ioaddr, 0x71 /* frequency table */ , table, 10);
-
-	/* Check all frequencies. */
-	i = 0;
-	for (freq = 0; freq < 150; freq++)
-		/* Look in the table if the frequency is allowed */
-		if (table[9 - (freq / 16)] & (1 << (freq % 16))) {
-			/* Compute approximate channel number */
-			while ((((channel_bands[c] >> 1) - 24) < freq) &&
-			       (c < NELS(channel_bands)))
-				c++;
-			list[i].i = c;	/* Set the list index */
-
-			/* put in the list */
-			list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
-			list[i++].e = 1;
-
-			/* Check number. */
-			if (i >= max)
-				return (i);
-		}
-
-	return (i);
-}
-
-#ifdef WIRELESS_SPY
-/*------------------------------------------------------------------*/
-/*
- * Gather wireless spy statistics:  for each packet, compare the source
- * address with our list, and if they match, get the statistics.
- * Sorry, but this function really needs the wireless extensions.
- */
-static inline void wl_spy_gather(device * dev, u8 * mac,	/* MAC address */
-				 u8 * stats)
-{				/* Statistics to gather */
-	net_local *lp = (net_local *) dev->priv;
-	int i;
-
-	/* Check all addresses. */
-	for (i = 0; i < lp->spy_number; i++)
-		/* If match */
-		if (!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) {
-			/* Update statistics */
-			lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL;
-			lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL;
-			lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL;
-			lp->spy_stat[i].updated = 0x7;
-		}
-}
-#endif				/* WIRELESS_SPY */
-
-#ifdef HISTOGRAM
-/*------------------------------------------------------------------*/
-/*
- * This function calculates a histogram of the signal level.
- * As the noise is quite constant, it's like doing it on the SNR.
- * We have defined a set of interval (lp->his_range), and each time
- * the level goes in that interval, we increment the count (lp->his_sum).
- * With this histogram you may detect if one WaveLAN is really weak,
- * or you may also calculate the mean and standard deviation of the level.
- */
-static inline void wl_his_gather(device * dev, u8 * stats)
-{				/* Statistics to gather */
-	net_local *lp = (net_local *) dev->priv;
-	u8 level = stats[0] & MMR_SIGNAL_LVL;
-	int i;
-
-	/* Find the correct interval. */
-	i = 0;
-	while ((i < (lp->his_number - 1))
-	       && (level >= lp->his_range[i++]));
-
-	/* Increment interval counter. */
-	(lp->his_sum[i])++;
-}
-#endif				/* HISTOGRAM */
-
-/*------------------------------------------------------------------*/
-/*
- * Perform ioctl for configuration and information.
- * It is here that the wireless extensions are treated (iwconfig).
- */
-static int wavelan_ioctl(struct net_device *dev,	/* device on which the ioctl is applied */
-			 struct ifreq *rq,	/* data passed */
-			 int cmd)
-{				/* ioctl number */
-	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
-	struct iwreq *wrq = (struct iwreq *) rq;
-	psa_t psa;
-	mm_t m;
-	unsigned long flags;
-	int ret = 0;
-	int err = 0;
-
-#ifdef DEBUG_IOCTL_TRACE
-	printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name,
-	       cmd);
-#endif
-
-	/* Disable interrupts and save flags. */
-	wv_splhi(lp, &flags);
-	
-	/* Look what is the request */
-	switch (cmd) {
-		/* --------------- WIRELESS EXTENSIONS --------------- */
-
-	case SIOCGIWNAME:
-		strcpy(wrq->u.name, "WaveLAN");
-		break;
-
-	case SIOCSIWNWID:
-		/* Set NWID in WaveLAN. */
-		if (!wrq->u.nwid.disabled) {
-			/* Set NWID in psa */
-			psa.psa_nwid[0] =
-			    (wrq->u.nwid.value & 0xFF00) >> 8;
-			psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
-			psa.psa_nwid_select = 0x01;
-			psa_write(ioaddr, lp->hacr,
-				  (char *) psa.psa_nwid - (char *) &psa,
-				  (unsigned char *) psa.psa_nwid, 3);
-
-			/* Set NWID in mmc. */
-			m.w.mmw_netw_id_l = psa.psa_nwid[1];
-			m.w.mmw_netw_id_h = psa.psa_nwid[0];
-			mmc_write(ioaddr,
-				  (char *) &m.w.mmw_netw_id_l -
-				  (char *) &m,
-				  (unsigned char *) &m.w.mmw_netw_id_l, 2);
-			mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00);
-		} else {
-			/* Disable NWID in the psa. */
-			psa.psa_nwid_select = 0x00;
-			psa_write(ioaddr, lp->hacr,
-				  (char *) &psa.psa_nwid_select -
-				  (char *) &psa,
-				  (unsigned char *) &psa.psa_nwid_select,
-				  1);
-
-			/* Disable NWID in the mmc (no filtering). */
-			mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel),
-				MMW_LOOPT_SEL_DIS_NWID);
-		}
-		/* update the Wavelan checksum */
-		update_psa_checksum(dev, ioaddr, lp->hacr);
-		break;
-
-	case SIOCGIWNWID:
-		/* Read the NWID. */
-		psa_read(ioaddr, lp->hacr,
-			 (char *) psa.psa_nwid - (char *) &psa,
-			 (unsigned char *) psa.psa_nwid, 3);
-		wrq->u.nwid.value =
-		    (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
-		wrq->u.nwid.disabled = !(psa.psa_nwid_select);
-		wrq->u.nwid.fixed = 1;	/* Superfluous */
-		break;
-
-	case SIOCSIWFREQ:
-		/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
-		if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
-		      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
-			ret = wv_set_frequency(ioaddr, &(wrq->u.freq));
-		else
-			ret = -EOPNOTSUPP;
-		break;
-
-	case SIOCGIWFREQ:
-		/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
-		 * Does it work for everybody, especially old cards? */
-		if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
-		      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
-			unsigned short freq;
-
-			/* Ask the EEPROM to read the frequency from the first area. */
-			fee_read(ioaddr, 0x00, &freq, 1);
-			wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
-			wrq->u.freq.e = 1;
-		} else {
-			psa_read(ioaddr, lp->hacr,
-				 (char *) &psa.psa_subband - (char *) &psa,
-				 (unsigned char *) &psa.psa_subband, 1);
-
-			if (psa.psa_subband <= 4) {
-				wrq->u.freq.m =
-				    fixed_bands[psa.psa_subband];
-				wrq->u.freq.e = (psa.psa_subband != 0);
-			} else
-				ret = -EOPNOTSUPP;
-		}
-		break;
-
-	case SIOCSIWSENS:
-		/* Set the level threshold. */
-		/* We should complain loudly if wrq->u.sens.fixed = 0, because we
-		 * can't set auto mode... */
-		psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
-		psa_write(ioaddr, lp->hacr,
-			  (char *) &psa.psa_thr_pre_set - (char *) &psa,
-			  (unsigned char *) &psa.psa_thr_pre_set, 1);
-		/* update the Wavelan checksum */
-		update_psa_checksum(dev, ioaddr, lp->hacr);
-		mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set),
-			psa.psa_thr_pre_set);
-		break;
-
-	case SIOCGIWSENS:
-		/* Read the level threshold. */
-		psa_read(ioaddr, lp->hacr,
-			 (char *) &psa.psa_thr_pre_set - (char *) &psa,
-			 (unsigned char *) &psa.psa_thr_pre_set, 1);
-		wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
-		wrq->u.sens.fixed = 1;
-		break;
-
-	case SIOCSIWENCODE:
-		/* Set encryption key */
-		if (!mmc_encr(ioaddr)) {
-			ret = -EOPNOTSUPP;
-			break;
-		}
-
-		/* Basic checking... */
-		if (wrq->u.encoding.pointer != (caddr_t) 0) {
-			/* Check the size of the key */
-			if (wrq->u.encoding.length != 8) {
-				ret = -EINVAL;
-				break;
-			}
-
-			/* Copy the key in the driver */
-			wv_splx(lp, &flags);
-			err = copy_from_user(psa.psa_encryption_key,
-					     wrq->u.encoding.pointer,
-					     wrq->u.encoding.length);
-			wv_splhi(lp, &flags);
-			if (err) {
-				ret = -EFAULT;
-				break;
-			}
-
-			psa.psa_encryption_select = 1;
-			psa_write(ioaddr, lp->hacr,
-				  (char *) &psa.psa_encryption_select -
-				  (char *) &psa,
-				  (unsigned char *) &psa.
-				  psa_encryption_select, 8 + 1);
-
-			mmc_out(ioaddr, mmwoff(0, mmw_encr_enable),
-				MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
-			mmc_write(ioaddr, mmwoff(0, mmw_encr_key),
-				  (unsigned char *) &psa.
-				  psa_encryption_key, 8);
-		}
-
-		if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) {	/* disable encryption */
-			psa.psa_encryption_select = 0;
-			psa_write(ioaddr, lp->hacr,
-				  (char *) &psa.psa_encryption_select -
-				  (char *) &psa,
-				  (unsigned char *) &psa.
-				  psa_encryption_select, 1);
-
-			mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
-		}
-		/* update the Wavelan checksum */
-		update_psa_checksum(dev, ioaddr, lp->hacr);
-		break;
-
-	case SIOCGIWENCODE:
-		/* Read the encryption key */
-		if (!mmc_encr(ioaddr)) {
-			ret = -EOPNOTSUPP;
-			break;
-		}
-
-		/* only super-user can see encryption key */
-		if (!capable(CAP_NET_ADMIN)) {
-			ret = -EPERM;
-			break;
-		}
-
-		/* Basic checking... */
-		if (wrq->u.encoding.pointer != (caddr_t) 0) {
-			/* Verify the user buffer */
-			ret =
-			    verify_area(VERIFY_WRITE,
-					wrq->u.encoding.pointer, 8);
-			if (ret)
-				break;
-
-			psa_read(ioaddr, lp->hacr,
-				 (char *) &psa.psa_encryption_select -
-				 (char *) &psa,
-				 (unsigned char *) &psa.
-				 psa_encryption_select, 1 + 8);
-
-			/* encryption is enabled ? */
-			if (psa.psa_encryption_select)
-				wrq->u.encoding.flags = IW_ENCODE_ENABLED;
-			else
-				wrq->u.encoding.flags = IW_ENCODE_DISABLED;
-			wrq->u.encoding.flags |= mmc_encr(ioaddr);
-
-			/* Copy the key to the user buffer */
-			wrq->u.encoding.length = 8;
-			wv_splx(lp, &flags);
-			if (copy_to_user(wrq->u.encoding.pointer,
-					 psa.psa_encryption_key, 8))
-				ret = -EFAULT;
-			wv_splhi(lp, &flags);
-		}
-		break;
-
-	case SIOCGIWRANGE:
-		/* basic checking */
-		if (wrq->u.data.pointer != (caddr_t) 0) {
-			struct iw_range range;
-
-			/* Set the length (very important for backward
-			 * compatibility) */
-			wrq->u.data.length = sizeof(struct iw_range);
-
-			/* Set all the info we don't care or don't know
-			 * about to zero */
-			memset(&range, 0, sizeof(range));
-
-			/* Set the Wireless Extension versions */
-			range.we_version_compiled = WIRELESS_EXT;
-			range.we_version_source = 9;
-
-			/* Set information in the range struct.  */
-			range.throughput = 1.6 * 1000 * 1000;	/* don't argue on this ! */
-			range.min_nwid = 0x0000;
-			range.max_nwid = 0xFFFF;
-
-			/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
-			if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
-			      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
-				range.num_channels = 10;
-				range.num_frequency =
-				    wv_frequency_list(ioaddr, range.freq,
-						      IW_MAX_FREQUENCIES);
-			} else
-				range.num_channels = range.num_frequency =
-				    0;
-
-			range.sensitivity = 0x3F;
-			range.max_qual.qual = MMR_SGNL_QUAL;
-			range.max_qual.level = MMR_SIGNAL_LVL;
-			range.max_qual.noise = MMR_SILENCE_LVL;
-			range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
-			/* Need to get better values for those two */
-			range.avg_qual.level = 30;
-			range.avg_qual.noise = 8;
-
-			range.num_bitrates = 1;
-			range.bitrate[0] = 2000000;	/* 2 Mb/s */
-
-			/* Encryption supported ? */
-			if (mmc_encr(ioaddr)) {
-				range.encoding_size[0] = 8;	/* DES = 64 bits key */
-				range.num_encoding_sizes = 1;
-				range.max_encoding_tokens = 1;	/* Only one key possible */
-			} else {
-				range.num_encoding_sizes = 0;
-				range.max_encoding_tokens = 0;
-			}
-
-			/* Copy structure to the user buffer. */
-			wv_splx(lp, &flags);
-			if (copy_to_user(wrq->u.data.pointer,
-					 &range,
-					 sizeof(struct iw_range)))
-				ret = -EFAULT;
-			wv_splhi(lp, &flags);
-		}
-		break;
-
-	case SIOCGIWPRIV:
-		/* Basic checking */
-		if (wrq->u.data.pointer != (caddr_t) 0) {
-			struct iw_priv_args priv[] = {
-				/* { cmd,
-				     set_args,
-				     get_args,
-				     name } */
-				{ SIOCSIPQTHR,
-				  IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-				  0,
-				  "setqualthr" },
-				{ SIOCGIPQTHR,
-				  0,
-				  IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-				  "getqualthr" },
-				{ SIOCSIPHISTO,
-				  IW_PRIV_TYPE_BYTE | 16,
-				  0,
-				  "sethisto" },
-				{ SIOCGIPHISTO,
-				  0,
-				  IW_PRIV_TYPE_INT | 16,
-				 "gethisto" },
-			};
-
-			/* Set the number of available ioctls. */
-			wrq->u.data.length = 4;
-
-			/* Copy structure to the user buffer. */
-			wv_splx(lp, &flags);
-			if (copy_to_user(wrq->u.data.pointer,
-					      (u8 *) priv,
-					      sizeof(priv)))
-				ret = -EFAULT;
-			wv_splhi(lp, &flags);
-		}
-		break;
-
-#ifdef WIRELESS_SPY
-	case SIOCSIWSPY:
-		/* Set the spy list */
-
-		/* Check the number of addresses. */
-		if (wrq->u.data.length > IW_MAX_SPY) {
-			ret = -E2BIG;
-			break;
-		}
-		lp->spy_number = wrq->u.data.length;
-
-		/* Are there are addresses to copy? */
-		if (lp->spy_number > 0) {
-			struct sockaddr address[IW_MAX_SPY];
-			int i;
-
-			/* Copy addresses to the driver. */
-			wv_splx(lp, &flags);
-			err = copy_from_user(address,
-					     wrq->u.data.pointer,
-					     sizeof(struct sockaddr)
-					     * lp->spy_number);
-			wv_splhi(lp, &flags);
-			if (err) {
-				ret = -EFAULT;
-				break;
-			}
-
-			/* Copy addresses to the lp structure. */
-			for (i = 0; i < lp->spy_number; i++) {
-				memcpy(lp->spy_address[i],
-				       address[i].sa_data,
-				       WAVELAN_ADDR_SIZE);
-			}
-
-			/* Reset structure. */
-			memset(lp->spy_stat, 0x00,
-			       sizeof(iw_qual) * IW_MAX_SPY);
-
-#ifdef DEBUG_IOCTL_INFO
-			printk(KERN_DEBUG
-			       "SetSpy:  set of new addresses is: \n");
-			for (i = 0; i < wrq->u.data.length; i++)
-				printk(KERN_DEBUG
-				       "%02X:%02X:%02X:%02X:%02X:%02X \n",
-				       lp->spy_address[i][0],
-				       lp->spy_address[i][1],
-				       lp->spy_address[i][2],
-				       lp->spy_address[i][3],
-				       lp->spy_address[i][4],
-				       lp->spy_address[i][5]);
-#endif				/* DEBUG_IOCTL_INFO */
-		}
-
-		break;
-
-	case SIOCGIWSPY:
-		/* Get the spy list and spy stats. */
-
-		/* Set the number of addresses */
-		wrq->u.data.length = lp->spy_number;
-
-		/* Does the user want to have the addresses back? */
-		if ((lp->spy_number > 0)
-		    && (wrq->u.data.pointer != (caddr_t) 0)) {
-			struct sockaddr address[IW_MAX_SPY];
-			int i;
-
-			/* Copy addresses from the lp structure. */
-			for (i = 0; i < lp->spy_number; i++) {
-				memcpy(address[i].sa_data,
-				       lp->spy_address[i],
-				       WAVELAN_ADDR_SIZE);
-				address[i].sa_family = AF_UNIX;
-			}
-
-			/* Copy addresses to the user buffer. */
-			wv_splx(lp, &flags);
-			err = copy_to_user(wrq->u.data.pointer,
-					   address,
-					   sizeof(struct sockaddr)
-					   * lp->spy_number);
-
-			/* Copy stats to the user buffer (just after). */
-			err |= copy_to_user(wrq->u.data.pointer
-					    + (sizeof(struct sockaddr)
-					       * lp->spy_number),
-					    lp->spy_stat,
-					    sizeof(iw_qual) * lp->spy_number);
-			wv_splhi(lp, &flags);
-			if (err) {
-				ret = -EFAULT;
-				break;
-			}
-
-			/* Reset updated flags. */
-			for (i = 0; i < lp->spy_number; i++)
-				lp->spy_stat[i].updated = 0x0;
-		}
-		/* if(pointer != NULL) */
-		break;
-#endif				/* WIRELESS_SPY */
-
-		/* ------------------ PRIVATE IOCTL ------------------ */
-
-	case SIOCSIPQTHR:
-		if (!capable(CAP_NET_ADMIN)) {
-			ret = -EPERM;
-			break;
-		}
-		psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
-		psa_write(ioaddr, lp->hacr,
-			  (char *) &psa.psa_quality_thr - (char *) &psa,
-			  (unsigned char *) &psa.psa_quality_thr, 1);
-		/* update the Wavelan checksum */
-		update_psa_checksum(dev, ioaddr, lp->hacr);
-		mmc_out(ioaddr, mmwoff(0, mmw_quality_thr),
-			psa.psa_quality_thr);
-		break;
-
-	case SIOCGIPQTHR:
-		psa_read(ioaddr, lp->hacr,
-			 (char *) &psa.psa_quality_thr - (char *) &psa,
-			 (unsigned char *) &psa.psa_quality_thr, 1);
-		*(wrq->u.name) = psa.psa_quality_thr & 0x0F;
-		break;
-
-#ifdef HISTOGRAM
-	case SIOCSIPHISTO:
-		/* Verify that the user is root. */
-		if (!capable(CAP_NET_ADMIN)) {
-			ret = -EPERM;
-			break;
-		}
-
-		/* Check the number of intervals. */
-		if (wrq->u.data.length > 16) {
-			ret = -E2BIG;
-			break;
-		}
-		lp->his_number = wrq->u.data.length;
-
-		/* Are there addresses to copy? */
-		if (lp->his_number > 0) {
-			/* Copy interval ranges to the driver */
-			wv_splx(lp, &flags);
-			err = copy_from_user(lp->his_range,
-					     wrq->u.data.pointer,
-					     sizeof(char) * lp->his_number);
-			wv_splhi(lp, &flags);
-			if (err) {
-				ret = -EFAULT;
-				break;
-			}
-
-			/* Reset structure. */
-			memset(lp->his_sum, 0x00, sizeof(long) * 16);
-		}
-		break;
-
-	case SIOCGIPHISTO:
-		/* Set the number of intervals. */
-		wrq->u.data.length = lp->his_number;
-
-		/* Give back the distribution statistics */
-		if ((lp->his_number > 0)
-		    && (wrq->u.data.pointer != (caddr_t) 0)) {
-			/* Copy data to the user buffer. */
-			wv_splx(lp, &flags);
-			if (copy_to_user(wrq->u.data.pointer,
-					 lp->his_sum,
-					 sizeof(long) * lp->his_number);
-				ret = -EFAULT;
-			wv_splhi(lp, &flags);
-
-		}		/* if(pointer != NULL) */
-		break;
-#endif				/* HISTOGRAM */
-
-		/* ------------------- OTHER IOCTL ------------------- */
-
-	default:
-		ret = -EOPNOTSUPP;
-	}	/* switch (cmd) */
-
-	/* Enable interrupts and restore flags. */
-	wv_splx(lp, &flags);
-
-#ifdef DEBUG_IOCTL_TRACE
-	printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
-#endif
-	return ret;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Get wireless statistics.
- * Called by /proc/net/wireless
- */
-static iw_stats *wavelan_get_wireless_stats(device * dev)
-{
-	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;
-	mmr_t m;
-	iw_stats *wstats;
-	unsigned long flags;
-
-#ifdef DEBUG_IOCTL_TRACE
-	printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n",
-	       dev->name);
-#endif
-
-	/* Check */
-	if (lp == (net_local *) NULL)
-		return (iw_stats *) NULL;
-	
-	/* Disable interrupts and save flags. */
-	wv_splhi(lp, &flags);
-	
-	wstats = &lp->wstats;
-
-	/* Get data from the mmc. */
-	mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
-
-	mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
-	mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l,
-		 2);
-	mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set,
-		 4);
-
-	mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
-
-	/* Copy data to wireless stuff. */
-	wstats->status = m.mmr_dce_status & MMR_DCE_STATUS;
-	wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
-	wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
-	wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL;
-	wstats->qual.updated = (((m. mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) 
-			| ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) 
-			| ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5));
-	wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
-	wstats->discard.code = 0L;
-	wstats->discard.misc = 0L;
-
-	/* Enable interrupts and restore flags. */
-	wv_splx(lp, &flags);
-
-#ifdef DEBUG_IOCTL_TRACE
-	printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n",
-	       dev->name);
-#endif
-	return &lp->wstats;
-}
-#endif				/* WIRELESS_EXT */
-
-/************************* PACKET RECEPTION *************************/
-/*
- * This part deals with receiving the packets.
- * The interrupt handler gets an interrupt when a packet has been
- * successfully received and calls this part.
- */
-
-/*------------------------------------------------------------------*/
-/*
- * This routine does the actual copying of data (including the Ethernet
- * header structure) from the WaveLAN card to an sk_buff chain that
- * will be passed up to the network interface layer. NOTE: we
- * currently don't handle trailer protocols (neither does the rest of
- * the network interface), so if that is needed, it will (at least in
- * part) be added here.  The contents of the receive ring buffer are
- * copied to a message chain that is then passed to the kernel.
- *
- * Note: if any errors occur, the packet is "dropped on the floor".
- * (called by wv_packet_rcv())
- */
-static inline void
-wv_packet_read(device * dev, u16 buf_off, int sksize)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	struct sk_buff *skb;
-
-#ifdef DEBUG_RX_TRACE
-	printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n",
-	       dev->name, buf_off, sksize);
-#endif
-
-	/* Allocate buffer for the data */
-	if ((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL) {
-#ifdef DEBUG_RX_ERROR
-		printk(KERN_INFO
-		       "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n",
-		       dev->name, sksize);
-#endif
-		lp->stats.rx_dropped++;
-		return;
-	}
-
-	skb->dev = dev;
-
-	/* Copy the packet to the buffer. */
-	obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize);
-	skb->protocol = eth_type_trans(skb, dev);
-
-#ifdef DEBUG_RX_INFO
-	wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
-#endif				/* DEBUG_RX_INFO */
-
-	/* Statistics-gathering and associated stuff.
-	 * It seem a bit messy with all the define, but it's really simple... */
-#if defined(WIRELESS_SPY) || defined(HISTOGRAM)
-	if (
-#ifdef WIRELESS_SPY
-		   (lp->spy_number > 0) ||
-#endif				/* WIRELESS_SPY */
-#ifdef HISTOGRAM
-		   (lp->his_number > 0) ||
-#endif				/* HISTOGRAM */
-		   0) {
-		u8 stats[3];	/* signal level, noise level, signal quality */
-
-		/* Read signal level, silence level and signal quality bytes. */
-		/* Note: in the PCMCIA hardware, these are part of the frame.  It seems
-		 * that for the ISA hardware, it's nowhere to be found in the frame,
-		 * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
-		 * Any ideas?
-		 */
-		mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
-		mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
-		mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
-
-#ifdef DEBUG_RX_INFO
-		printk(KERN_DEBUG
-		       "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n",
-		       dev->name, stats[0] & 0x3F, stats[1] & 0x3F,
-		       stats[2] & 0x0F);
-#endif
-
-		/* Spying stuff */
-#ifdef WIRELESS_SPY
-		wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE,
-			      stats);
-#endif				/* WIRELESS_SPY */
-#ifdef HISTOGRAM
-		wl_his_gather(dev, stats);
-#endif				/* HISTOGRAM */
-	}
-#endif				/* defined(WIRELESS_SPY) || defined(HISTOGRAM) */
-
-	/*
-	 * Hand the packet to the network module.
-	 */
-	netif_rx(skb);
-
-	/* Keep statistics up to date */
-	dev->last_rx = jiffies;
-	lp->stats.rx_packets++;
-	lp->stats.rx_bytes += sksize;
-
-#ifdef DEBUG_RX_TRACE
-	printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name);
-#endif
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Transfer as many packets as we can
- * from the device RAM.
- * (called in wavelan_interrupt()).
- * Note : the spinlock is already grabbed for us.
- */
-static inline void wv_receive(device * dev)
-{
-	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;
-	fd_t fd;
-	rbd_t rbd;
-	int nreaped = 0;
-
-#ifdef DEBUG_RX_TRACE
-	printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name);
-#endif
-
-	/* Loop on each received packet. */
-	for (;;) {
-		obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd,
-			   sizeof(fd));
-
-		/* Note about the status :
-		 * It start up to be 0 (the value we set). Then, when the RU
-		 * grab the buffer to prepare for reception, it sets the
-		 * FD_STATUS_B flag. When the RU has finished receiving the
-		 * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate
-		 * completion and set the other flags to indicate the eventual
-		 * errors. FD_STATUS_OK indicates that the reception was OK.
-		 */
-
-		/* If the current frame is not complete, we have reached the end. */
-		if ((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
-			break;	/* This is how we exit the loop. */
-
-		nreaped++;
-
-		/* Check whether frame was correctly received. */
-		if ((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK) {
-			/* Does the frame contain a pointer to the data?  Let's check. */
-			if (fd.fd_rbd_offset != I82586NULL) {
-				/* Read the receive buffer descriptor */
-				obram_read(ioaddr, fd.fd_rbd_offset,
-					   (unsigned char *) &rbd,
-					   sizeof(rbd));
-
-#ifdef DEBUG_RX_ERROR
-				if ((rbd.rbd_status & RBD_STATUS_EOF) !=
-				    RBD_STATUS_EOF) printk(KERN_INFO
-							   "%s: wv_receive(): missing EOF flag.\n",
-							   dev->name);
-
-				if ((rbd.rbd_status & RBD_STATUS_F) !=
-				    RBD_STATUS_F) printk(KERN_INFO
-							 "%s: wv_receive(): missing F flag.\n",
-							 dev->name);
-#endif				/* DEBUG_RX_ERROR */
-
-				/* Read the packet and transmit to Linux */
-				wv_packet_read(dev, rbd.rbd_bufl,
-					       rbd.
-					       rbd_status &
-					       RBD_STATUS_ACNT);
-			}
-#ifdef DEBUG_RX_ERROR
-			else	/* if frame has no data */
-				printk(KERN_INFO
-				       "%s: wv_receive(): frame has no data.\n",
-				       dev->name);
-#endif
-		} else {	/* If reception was no successful */
-
-			lp->stats.rx_errors++;
-
-#ifdef DEBUG_RX_INFO
-			printk(KERN_DEBUG
-			       "%s: wv_receive(): frame not received successfully (%X).\n",
-			       dev->name, fd.fd_status);
-#endif
-
-#ifdef DEBUG_RX_ERROR
-			if ((fd.fd_status & FD_STATUS_S6) != 0)
-				printk(KERN_INFO
-				       "%s: wv_receive(): no EOF flag.\n",
-				       dev->name);
-#endif
-
-			if ((fd.fd_status & FD_STATUS_S7) != 0) {
-				lp->stats.rx_length_errors++;
-#ifdef DEBUG_RX_FAIL
-				printk(KERN_DEBUG
-				       "%s: wv_receive(): frame too short.\n",
-				       dev->name);
-#endif
-			}
-
-			if ((fd.fd_status & FD_STATUS_S8) != 0) {
-				lp->stats.rx_over_errors++;
-#ifdef DEBUG_RX_FAIL
-				printk(KERN_DEBUG
-				       "%s: wv_receive(): rx DMA overrun.\n",
-				       dev->name);
-#endif
-			}
-
-			if ((fd.fd_status & FD_STATUS_S9) != 0) {
-				lp->stats.rx_fifo_errors++;
-#ifdef DEBUG_RX_FAIL
-				printk(KERN_DEBUG
-				       "%s: wv_receive(): ran out of resources.\n",
-				       dev->name);
-#endif
-			}
-
-			if ((fd.fd_status & FD_STATUS_S10) != 0) {
-				lp->stats.rx_frame_errors++;
-#ifdef DEBUG_RX_FAIL
-				printk(KERN_DEBUG
-				       "%s: wv_receive(): alignment error.\n",
-				       dev->name);
-#endif
-			}
-
-			if ((fd.fd_status & FD_STATUS_S11) != 0) {
-				lp->stats.rx_crc_errors++;
-#ifdef DEBUG_RX_FAIL
-				printk(KERN_DEBUG
-				       "%s: wv_receive(): CRC error.\n",
-				       dev->name);
-#endif
-			}
-		}
-
-		fd.fd_status = 0;
-		obram_write(ioaddr, fdoff(lp->rx_head, fd_status),
-			    (unsigned char *) &fd.fd_status,
-			    sizeof(fd.fd_status));
-
-		fd.fd_command = FD_COMMAND_EL;
-		obram_write(ioaddr, fdoff(lp->rx_head, fd_command),
-			    (unsigned char *) &fd.fd_command,
-			    sizeof(fd.fd_command));
-
-		fd.fd_command = 0;
-		obram_write(ioaddr, fdoff(lp->rx_last, fd_command),
-			    (unsigned char *) &fd.fd_command,
-			    sizeof(fd.fd_command));
-
-		lp->rx_last = lp->rx_head;
-		lp->rx_head = fd.fd_link_offset;
-	}			/* for(;;) -> loop on all frames */
-
-#ifdef DEBUG_RX_INFO
-	if (nreaped > 1)
-		printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n",
-		       dev->name, nreaped);
-#endif
-#ifdef DEBUG_RX_TRACE
-	printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name);
-#endif
-}
-
-/*********************** PACKET TRANSMISSION ***********************/
-/*
- * This part deals with sending packets through the WaveLAN.
- *
- */
-
-/*------------------------------------------------------------------*/
-/*
- * This routine fills in the appropriate registers and memory
- * locations on the WaveLAN card and starts the card off on
- * the transmit.
- *
- * The principle:
- * Each block contains a transmit command, a NOP command,
- * a transmit block descriptor and a buffer.
- * The CU read the transmit block which point to the tbd,
- * read the tbd and the content of the buffer.
- * When it has finish with it, it goes to the next command
- * which in our case is the NOP. The NOP points on itself,
- * so the CU stop here.
- * When we add the next block, we modify the previous nop
- * to make it point on the new tx command.
- * Simple, isn't it ?
- *
- * (called in wavelan_packet_xmit())
- */
-static inline int wv_packet_write(device * dev, void *buf, short length)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	unsigned short txblock;
-	unsigned short txpred;
-	unsigned short tx_addr;
-	unsigned short nop_addr;
-	unsigned short tbd_addr;
-	unsigned short buf_addr;
-	ac_tx_t tx;
-	ac_nop_t nop;
-	tbd_t tbd;
-	int clen = length;
-	unsigned long flags;
-
-#ifdef DEBUG_TX_TRACE
-	printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name,
-	       length);
-#endif
-
-	/* Do we need some padding? */
-	if (clen < ETH_ZLEN)
-		clen = ETH_ZLEN;
-
-	wv_splhi(lp, &flags);
-
-	/* Check nothing bad has happened */
-	if (lp->tx_n_in_use == (NTXBLOCKS - 1)) {
-#ifdef DEBUG_TX_ERROR
-		printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n",
-		       dev->name);
-#endif
-		wv_splx(lp, &flags);
-		return 1;
-	}
-
-	/* Calculate addresses of next block and previous block. */
-	txblock = lp->tx_first_free;
-	txpred = txblock - TXBLOCKZ;
-	if (txpred < OFFSET_CU)
-		txpred += NTXBLOCKS * TXBLOCKZ;
-	lp->tx_first_free += TXBLOCKZ;
-	if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
-		lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
-
-	lp->tx_n_in_use++;
-
-	/* Calculate addresses of the different parts of the block. */
-	tx_addr = txblock;
-	nop_addr = tx_addr + sizeof(tx);
-	tbd_addr = nop_addr + sizeof(nop);
-	buf_addr = tbd_addr + sizeof(tbd);
-
-	/*
-	 * Transmit command
-	 */
-	tx.tx_h.ac_status = 0;
-	obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
-		    (unsigned char *) &tx.tx_h.ac_status,
-		    sizeof(tx.tx_h.ac_status));
-
-	/*
-	 * NOP command
-	 */
-	nop.nop_h.ac_status = 0;
-	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
-		    (unsigned char *) &nop.nop_h.ac_status,
-		    sizeof(nop.nop_h.ac_status));
-	nop.nop_h.ac_link = nop_addr;
-	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
-		    (unsigned char *) &nop.nop_h.ac_link,
-		    sizeof(nop.nop_h.ac_link));
-
-	/*
-	 * Transmit buffer descriptor
-	 */
-	tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen);
-	tbd.tbd_next_bd_offset = I82586NULL;
-	tbd.tbd_bufl = buf_addr;
-	tbd.tbd_bufh = 0;
-	obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd));
-
-	/*
-	 * Data
-	 */
-	obram_write(ioaddr, buf_addr, buf, length);
-
-	/*
-	 * Overwrite the predecessor NOP link
-	 * so that it points to this txblock.
-	 */
-	nop_addr = txpred + sizeof(tx);
-	nop.nop_h.ac_status = 0;
-	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
-		    (unsigned char *) &nop.nop_h.ac_status,
-		    sizeof(nop.nop_h.ac_status));
-	nop.nop_h.ac_link = txblock;
-	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
-		    (unsigned char *) &nop.nop_h.ac_link,
-		    sizeof(nop.nop_h.ac_link));
-
-	/* Keep stats up to date. */
-	lp->stats.tx_bytes += length;
-
-	if (lp->tx_first_in_use == I82586NULL)
-		lp->tx_first_in_use = txblock;
-
-	if (lp->tx_n_in_use < NTXBLOCKS - 1)
-		netif_wake_queue(dev);
-
-	wv_splx(lp, &flags);
-	
-#ifdef DEBUG_TX_INFO
-	wv_packet_info((u8 *) buf, length, dev->name,
-		       "wv_packet_write");
-#endif				/* DEBUG_TX_INFO */
-
-#ifdef DEBUG_TX_TRACE
-	printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
-#endif
-
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the harware is ready to accept
- * the packet.  We also prevent reentrance.  Then we call the function
- * to send the packet.
- */
-static int wavelan_packet_xmit(struct sk_buff *skb, device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long flags;
-
-#ifdef DEBUG_TX_TRACE
-	printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
-	       (unsigned) skb);
-#endif
-
-	/*
-	 * Block a timer-based transmit from overlapping.
-	 * In other words, prevent reentering this routine.
-	 */
-	netif_stop_queue(dev);
-
-	/* If somebody has asked to reconfigure the controller, 
-	 * we can do it now.
-	 */
-	if (lp->reconfig_82586) {
-		wv_splhi(lp, &flags);
-		wv_82586_config(dev);
-		wv_splx(lp, &flags);
-		/* Check that we can continue */
-		if (lp->tx_n_in_use == (NTXBLOCKS - 1))
-			return 1;
-	}
-#ifdef DEBUG_TX_ERROR
-	if (skb->next)
-		printk(KERN_INFO "skb has next\n");
-#endif
-
-	/* Write packet on the card */
-	if(wv_packet_write(dev, skb->data, skb->len))
-		return 1;	/* We failed */
-
-	dev_kfree_skb(skb);
-
-#ifdef DEBUG_TX_TRACE
-	printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
-#endif
-	return 0;
-}
-
-/*********************** HARDWARE CONFIGURATION ***********************/
-/*
- * This part does the real job of starting and configuring the hardware.
- */
-
-/*--------------------------------------------------------------------*/
-/*
- * Routine to initialize the Modem Management Controller.
- * (called by wv_hw_reset())
- */
-static inline int wv_mmc_init(device * dev)
-{
-	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;
-	psa_t psa;
-	mmw_t m;
-	int configured;
-
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
-#endif
-
-	/* Read the parameter storage area. */
-	psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
-
-#ifdef USE_PSA_CONFIG
-	configured = psa.psa_conf_status & 1;
-#else
-	configured = 0;
-#endif
-
-	/* Is the PSA is not configured */
-	if (!configured) {
-		/* User will be able to configure NWID later (with iwconfig). */
-		psa.psa_nwid[0] = 0;
-		psa.psa_nwid[1] = 0;
-
-		/* no NWID checking since NWID is not set */
-		psa.psa_nwid_select = 0;
-
-		/* Disable encryption */
-		psa.psa_encryption_select = 0;
-
-		/* Set to standard values:
-		 * 0x04 for AT,
-		 * 0x01 for MCA,
-		 * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
-		 */
-		if (psa.psa_comp_number & 1)
-			psa.psa_thr_pre_set = 0x01;
-		else
-			psa.psa_thr_pre_set = 0x04;
-		psa.psa_quality_thr = 0x03;
-
-		/* It is configured */
-		psa.psa_conf_status |= 1;
-
-#ifdef USE_PSA_CONFIG
-		/* Write the psa. */
-		psa_write(ioaddr, lp->hacr,
-			  (char *) psa.psa_nwid - (char *) &psa,
-			  (unsigned char *) psa.psa_nwid, 4);
-		psa_write(ioaddr, lp->hacr,
-			  (char *) &psa.psa_thr_pre_set - (char *) &psa,
-			  (unsigned char *) &psa.psa_thr_pre_set, 1);
-		psa_write(ioaddr, lp->hacr,
-			  (char *) &psa.psa_quality_thr - (char *) &psa,
-			  (unsigned char *) &psa.psa_quality_thr, 1);
-		psa_write(ioaddr, lp->hacr,
-			  (char *) &psa.psa_conf_status - (char *) &psa,
-			  (unsigned char *) &psa.psa_conf_status, 1);
-		/* update the Wavelan checksum */
-		update_psa_checksum(dev, ioaddr, lp->hacr);
-#endif
-	}
-
-	/* Zero the mmc structure. */
-	memset(&m, 0x00, sizeof(m));
-
-	/* Copy PSA info to the mmc. */
-	m.mmw_netw_id_l = psa.psa_nwid[1];
-	m.mmw_netw_id_h = psa.psa_nwid[0];
-
-	if (psa.psa_nwid_select & 1)
-		m.mmw_loopt_sel = 0x00;
-	else
-		m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID;
-
-	memcpy(&m.mmw_encr_key, &psa.psa_encryption_key,
-	       sizeof(m.mmw_encr_key));
-
-	if (psa.psa_encryption_select)
-		m.mmw_encr_enable =
-		    MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE;
-	else
-		m.mmw_encr_enable = 0;
-
-	m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
-	m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
-
-	/*
-	 * Set default modem control parameters.
-	 * See NCR document 407-0024326 Rev. A.
-	 */
-	m.mmw_jabber_enable = 0x01;
-	m.mmw_freeze = 0;
-	m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
-	m.mmw_ifs = 0x20;
-	m.mmw_mod_delay = 0x04;
-	m.mmw_jam_time = 0x38;
-
-	m.mmw_des_io_invert = 0;
-	m.mmw_decay_prm = 0;
-	m.mmw_decay_updat_prm = 0;
-
-	/* Write all info to MMC. */
-	mmc_write(ioaddr, 0, (u8 *) & m, sizeof(m));
-
-	/* The following code starts the modem of the 2.00 frequency
-	 * selectable cards at power on.  It's not strictly needed for the
-	 * following boots.
-	 * The original patch was by Joe Finney for the PCMCIA driver, but
-	 * I've cleaned it up a bit and added documentation.
-	 * Thanks to Loeke Brederveld from Lucent for the info.
-	 */
-
-	/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-	 * Does it work for everybody, especially old cards? */
-	/* Note: WFREQSEL verifies that it is able to read a sensible
-	 * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID
-	 * is 0xA (Xilinx version) or 0xB (Ariadne version).
-	 * My test is more crude but does work. */
-	if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
-	      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
-		/* We must download the frequency parameters to the
-		 * synthesizers (from the EEPROM - area 1)
-		 * Note: as the EEPROM is automatically decremented, we set the end
-		 * if the area... */
-		m.mmw_fee_addr = 0x0F;
-		m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
-		mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m,
-			  (unsigned char *) &m.mmw_fee_ctrl, 2);
-
-		/* Wait until the download is finished. */
-		fee_wait(ioaddr, 100, 100);
-
-#ifdef DEBUG_CONFIG_INFO
-		/* The frequency was in the last word downloaded. */
-		mmc_read(ioaddr, (char *) &m.mmw_fee_data_l - (char *) &m,
-			 (unsigned char *) &m.mmw_fee_data_l, 2);
-
-		/* Print some info for the user. */
-		printk(KERN_DEBUG
-		       "%s: WaveLAN 2.00 recognised (frequency select).  Current frequency = %ld\n",
-		       dev->name,
-		       ((m.
-			 mmw_fee_data_h << 4) | (m.mmw_fee_data_l >> 4)) *
-		       5 / 2 + 24000L);
-#endif
-
-		/* We must now download the power adjust value (gain) to
-		 * the synthesizers (from the EEPROM - area 7 - DAC). */
-		m.mmw_fee_addr = 0x61;
-		m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
-		mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m,
-			  (unsigned char *) &m.mmw_fee_ctrl, 2);
-
-		/* Wait until the download is finished. */
-	}
-	/* if 2.00 card */
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name);
-#endif
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Construct the fd and rbd structures.
- * Start the receive unit.
- * (called by wv_hw_reset())
- */
-static inline int wv_ru_start(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	u16 scb_cs;
-	fd_t fd;
-	rbd_t rbd;
-	u16 rx;
-	u16 rx_next;
-	int i;
-
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
-#endif
-
-	obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
-		   (unsigned char *) &scb_cs, sizeof(scb_cs));
-	if ((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY)
-		return 0;
-
-	lp->rx_head = OFFSET_RU;
-
-	for (i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next) {
-		rx_next =
-		    (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ;
-
-		fd.fd_status = 0;
-		fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0;
-		fd.fd_link_offset = rx_next;
-		fd.fd_rbd_offset = rx + sizeof(fd);
-		obram_write(ioaddr, rx, (unsigned char *) &fd, sizeof(fd));
-
-		rbd.rbd_status = 0;
-		rbd.rbd_next_rbd_offset = I82586NULL;
-		rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd);
-		rbd.rbd_bufh = 0;
-		rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ);
-		obram_write(ioaddr, rx + sizeof(fd),
-			    (unsigned char *) &rbd, sizeof(rbd));
-
-		lp->rx_last = rx;
-	}
-
-	obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset),
-		    (unsigned char *) &lp->rx_head, sizeof(lp->rx_head));
-
-	scb_cs = SCB_CMD_RUC_GO;
-	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
-		    (unsigned char *) &scb_cs, sizeof(scb_cs));
-
-	set_chan_attn(ioaddr, lp->hacr);
-
-	for (i = 1000; i > 0; i--) {
-		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
-			   (unsigned char *) &scb_cs, sizeof(scb_cs));
-		if (scb_cs == 0)
-			break;
-
-		udelay(10);
-	}
-
-	if (i <= 0) {
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_INFO
-		       "%s: wavelan_ru_start(): board not accepting command.\n",
-		       dev->name);
-#endif
-		return -1;
-	}
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
-#endif
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Initialise the transmit blocks.
- * Start the command unit executing the NOP
- * self-loop of the first transmit block.
- *
- * Here we create the list of send buffers used to transmit packets
- * between the PC and the command unit. For each buffer, we create a
- * buffer descriptor (pointing on the buffer), a transmit command
- * (pointing to the buffer descriptor) and a NOP command.
- * The transmit command is linked to the NOP, and the NOP to itself.
- * When we will have finished executing the transmit command, we will
- * then loop on the NOP. By releasing the NOP link to a new command,
- * we may send another buffer.
- *
- * (called by wv_hw_reset())
- */
-static inline int wv_cu_start(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	int i;
-	u16 txblock;
-	u16 first_nop;
-	u16 scb_cs;
-
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name);
-#endif
-
-	lp->tx_first_free = OFFSET_CU;
-	lp->tx_first_in_use = I82586NULL;
-
-	for (i = 0, txblock = OFFSET_CU;
-	     i < NTXBLOCKS; i++, txblock += TXBLOCKZ) {
-		ac_tx_t tx;
-		ac_nop_t nop;
-		tbd_t tbd;
-		unsigned short tx_addr;
-		unsigned short nop_addr;
-		unsigned short tbd_addr;
-		unsigned short buf_addr;
-
-		tx_addr = txblock;
-		nop_addr = tx_addr + sizeof(tx);
-		tbd_addr = nop_addr + sizeof(nop);
-		buf_addr = tbd_addr + sizeof(tbd);
-
-		tx.tx_h.ac_status = 0;
-		tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I;
-		tx.tx_h.ac_link = nop_addr;
-		tx.tx_tbd_offset = tbd_addr;
-		obram_write(ioaddr, tx_addr, (unsigned char *) &tx,
-			    sizeof(tx));
-
-		nop.nop_h.ac_status = 0;
-		nop.nop_h.ac_command = acmd_nop;
-		nop.nop_h.ac_link = nop_addr;
-		obram_write(ioaddr, nop_addr, (unsigned char *) &nop,
-			    sizeof(nop));
-
-		tbd.tbd_status = TBD_STATUS_EOF;
-		tbd.tbd_next_bd_offset = I82586NULL;
-		tbd.tbd_bufl = buf_addr;
-		tbd.tbd_bufh = 0;
-		obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd,
-			    sizeof(tbd));
-	}
-
-	first_nop =
-	    OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t);
-	obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset),
-		    (unsigned char *) &first_nop, sizeof(first_nop));
-
-	scb_cs = SCB_CMD_CUC_GO;
-	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
-		    (unsigned char *) &scb_cs, sizeof(scb_cs));
-
-	set_chan_attn(ioaddr, lp->hacr);
-
-	for (i = 1000; i > 0; i--) {
-		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
-			   (unsigned char *) &scb_cs, sizeof(scb_cs));
-		if (scb_cs == 0)
-			break;
-
-		udelay(10);
-	}
-
-	if (i <= 0) {
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_INFO
-		       "%s: wavelan_cu_start(): board not accepting command.\n",
-		       dev->name);
-#endif
-		return -1;
-	}
-
-	lp->tx_n_in_use = 0;
-	netif_start_queue(dev);
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name);
-#endif
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * This routine does a standard configuration of the WaveLAN 
- * controller (i82586).
- *
- * It initialises the scp, iscp and scb structure
- * The first two are just pointers to the next.
- * The last one is used for basic configuration and for basic
- * communication (interrupt status).
- *
- * (called by wv_hw_reset())
- */
-static inline int wv_82586_start(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	scp_t scp;		/* system configuration pointer */
-	iscp_t iscp;		/* intermediate scp */
-	scb_t scb;		/* system control block */
-	ach_t cb;		/* Action command header */
-	u8 zeroes[512];
-	int i;
-
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name);
-#endif
-
-	/*
-	 * Clear the onboard RAM.
-	 */
-	memset(&zeroes[0], 0x00, sizeof(zeroes));
-	for (i = 0; i < I82586_MEMZ; i += sizeof(zeroes))
-		obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes));
-
-	/*
-	 * Construct the command unit structures:
-	 * scp, iscp, scb, cb.
-	 */
-	memset(&scp, 0x00, sizeof(scp));
-	scp.scp_sysbus = SCP_SY_16BBUS;
-	scp.scp_iscpl = OFFSET_ISCP;
-	obram_write(ioaddr, OFFSET_SCP, (unsigned char *) &scp,
-		    sizeof(scp));
-
-	memset(&iscp, 0x00, sizeof(iscp));
-	iscp.iscp_busy = 1;
-	iscp.iscp_offset = OFFSET_SCB;
-	obram_write(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp,
-		    sizeof(iscp));
-
-	/* Our first command is to reset the i82586. */
-	memset(&scb, 0x00, sizeof(scb));
-	scb.scb_command = SCB_CMD_RESET;
-	scb.scb_cbl_offset = OFFSET_CU;
-	scb.scb_rfa_offset = OFFSET_RU;
-	obram_write(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
-		    sizeof(scb));
-
-	set_chan_attn(ioaddr, lp->hacr);
-
-	/* Wait for command to finish. */
-	for (i = 1000; i > 0; i--) {
-		obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp,
-			   sizeof(iscp));
-
-		if (iscp.iscp_busy == (unsigned short) 0)
-			break;
-
-		udelay(10);
-	}
-
-	if (i <= 0) {
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_INFO
-		       "%s: wv_82586_start(): iscp_busy timeout.\n",
-		       dev->name);
-#endif
-		return -1;
-	}
-
-	/* Check command completion. */
-	for (i = 15; i > 0; i--) {
-		obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
-			   sizeof(scb));
-
-		if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA))
-			break;
-
-		udelay(10);
-	}
-
-	if (i <= 0) {
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_INFO
-		       "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n",
-		       dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status);
-#endif
-		return -1;
-	}
-
-	wv_ack(dev);
-
-	/* Set the action command header. */
-	memset(&cb, 0x00, sizeof(cb));
-	cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose);
-	cb.ac_link = OFFSET_CU;
-	obram_write(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb));
-
-	if (wv_synchronous_cmd(dev, "diag()") == -1)
-		return -1;
-
-	obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb));
-	if (cb.ac_status & AC_SFLD_FAIL) {
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_INFO
-		       "%s: wv_82586_start(): i82586 Self Test failed.\n",
-		       dev->name);
-#endif
-		return -1;
-	}
-#ifdef DEBUG_I82586_SHOW
-	wv_scb_show(ioaddr);
-#endif
-
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name);
-#endif
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * This routine does a standard configuration of the WaveLAN
- * controller (i82586).
- *
- * This routine is a violent hack. We use the first free transmit block
- * to make our configuration. In the buffer area, we create the three
- * configuration commands (linked). We make the previous NOP point to
- * the beginning of the buffer instead of the tx command. After, we go
- * as usual to the NOP command.
- * Note that only the last command (mc_set) will generate an interrupt.
- *
- * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit())
- */
-static void wv_82586_config(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	unsigned short txblock;
-	unsigned short txpred;
-	unsigned short tx_addr;
-	unsigned short nop_addr;
-	unsigned short tbd_addr;
-	unsigned short cfg_addr;
-	unsigned short ias_addr;
-	unsigned short mcs_addr;
-	ac_tx_t tx;
-	ac_nop_t nop;
-	ac_cfg_t cfg;		/* Configure action */
-	ac_ias_t ias;		/* IA-setup action */
-	ac_mcs_t mcs;		/* Multicast setup */
-	struct dev_mc_list *dmi;
-
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name);
-#endif
-
-	/* Check nothing bad has happened */
-	if (lp->tx_n_in_use == (NTXBLOCKS - 1)) {
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_INFO "%s: wv_82586_config(): Tx queue full.\n",
-		       dev->name);
-#endif
-		return;
-	}
-
-	/* Calculate addresses of next block and previous block. */
-	txblock = lp->tx_first_free;
-	txpred = txblock - TXBLOCKZ;
-	if (txpred < OFFSET_CU)
-		txpred += NTXBLOCKS * TXBLOCKZ;
-	lp->tx_first_free += TXBLOCKZ;
-	if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
-		lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
-
-	lp->tx_n_in_use++;
-
-	/* Calculate addresses of the different parts of the block. */
-	tx_addr = txblock;
-	nop_addr = tx_addr + sizeof(tx);
-	tbd_addr = nop_addr + sizeof(nop);
-	cfg_addr = tbd_addr + sizeof(tbd_t);	/* beginning of the buffer */
-	ias_addr = cfg_addr + sizeof(cfg);
-	mcs_addr = ias_addr + sizeof(ias);
-
-	/*
-	 * Transmit command
-	 */
-	tx.tx_h.ac_status = 0xFFFF;	/* Fake completion value */
-	obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
-		    (unsigned char *) &tx.tx_h.ac_status,
-		    sizeof(tx.tx_h.ac_status));
-
-	/*
-	 * NOP command
-	 */
-	nop.nop_h.ac_status = 0;
-	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
-		    (unsigned char *) &nop.nop_h.ac_status,
-		    sizeof(nop.nop_h.ac_status));
-	nop.nop_h.ac_link = nop_addr;
-	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
-		    (unsigned char *) &nop.nop_h.ac_link,
-		    sizeof(nop.nop_h.ac_link));
-
-	/* Create a configure action. */
-	memset(&cfg, 0x00, sizeof(cfg));
-
-	/*
-	 * For Linux we invert AC_CFG_ALOC() so as to conform
-	 * to the way that net packets reach us from above.
-	 * (See also ac_tx_t.)
-	 *
-	 * Updated from Wavelan Manual WCIN085B
-	 */
-	cfg.cfg_byte_cnt =
-	    AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t));
-	cfg.cfg_fifolim = AC_CFG_FIFOLIM(4);
-	cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | AC_CFG_SRDY(0);
-	cfg.cfg_byte9 = AC_CFG_ELPBCK(0) |
-	    AC_CFG_ILPBCK(0) |
-	    AC_CFG_PRELEN(AC_CFG_PLEN_2) |
-	    AC_CFG_ALOC(1) | AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE);
-	cfg.cfg_byte10 = AC_CFG_BOFMET(1) |
-	    AC_CFG_ACR(6) | AC_CFG_LINPRIO(0);
-	cfg.cfg_ifs = 0x20;
-	cfg.cfg_slotl = 0x0C;
-	cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | AC_CFG_SLTTMHI(0);
-	cfg.cfg_byte14 = AC_CFG_FLGPAD(0) |
-	    AC_CFG_BTSTF(0) |
-	    AC_CFG_CRC16(0) |
-	    AC_CFG_NCRC(0) |
-	    AC_CFG_TNCRS(1) |
-	    AC_CFG_MANCH(0) |
-	    AC_CFG_BCDIS(0) | AC_CFG_PRM(lp->promiscuous);
-	cfg.cfg_byte15 = AC_CFG_ICDS(0) |
-	    AC_CFG_CDTF(0) | AC_CFG_ICSS(0) | AC_CFG_CSTF(0);
-/*
-  cfg.cfg_min_frm_len = AC_CFG_MNFRM(64);
-*/
-	cfg.cfg_min_frm_len = AC_CFG_MNFRM(8);
-
-	cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure);
-	cfg.cfg_h.ac_link = ias_addr;
-	obram_write(ioaddr, cfg_addr, (unsigned char *) &cfg, sizeof(cfg));
-
-	/* Set up the MAC address */
-	memset(&ias, 0x00, sizeof(ias));
-	ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup);
-	ias.ias_h.ac_link = mcs_addr;
-	memcpy(&ias.ias_addr[0], (unsigned char *) &dev->dev_addr[0],
-	       sizeof(ias.ias_addr));
-	obram_write(ioaddr, ias_addr, (unsigned char *) &ias, sizeof(ias));
-
-	/* Initialize adapter's Ethernet multicast addresses */
-	memset(&mcs, 0x00, sizeof(mcs));
-	mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup);
-	mcs.mcs_h.ac_link = nop_addr;
-	mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count;
-	obram_write(ioaddr, mcs_addr, (unsigned char *) &mcs, sizeof(mcs));
-
-	/* Any address to set? */
-	if (lp->mc_count) {
-		for (dmi = dev->mc_list; dmi; dmi = dmi->next)
-			outsw(PIOP1(ioaddr), (u16 *) dmi->dmi_addr,
-			      WAVELAN_ADDR_SIZE >> 1);
-
-#ifdef DEBUG_CONFIG_INFO
-		printk(KERN_DEBUG
-		       "%s: wv_82586_config(): set %d multicast addresses:\n",
-		       dev->name, lp->mc_count);
-		for (dmi = dev->mc_list; dmi; dmi = dmi->next)
-			printk(KERN_DEBUG
-			       " %02x:%02x:%02x:%02x:%02x:%02x\n",
-			       dmi->dmi_addr[0], dmi->dmi_addr[1],
-			       dmi->dmi_addr[2], dmi->dmi_addr[3],
-			       dmi->dmi_addr[4], dmi->dmi_addr[5]);
-#endif
-	}
-
-	/*
-	 * Overwrite the predecessor NOP link
-	 * so that it points to the configure action.
-	 */
-	nop_addr = txpred + sizeof(tx);
-	nop.nop_h.ac_status = 0;
-	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
-		    (unsigned char *) &nop.nop_h.ac_status,
-		    sizeof(nop.nop_h.ac_status));
-	nop.nop_h.ac_link = cfg_addr;
-	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
-		    (unsigned char *) &nop.nop_h.ac_link,
-		    sizeof(nop.nop_h.ac_link));
-
-	/* Job done, clear the flag */
-	lp->reconfig_82586 = 0;
-
-	if (lp->tx_first_in_use == I82586NULL)
-		lp->tx_first_in_use = txblock;
-
-	if (lp->tx_n_in_use == (NTXBLOCKS - 1))
-		netif_stop_queue(dev);
-
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name);
-#endif
-}
-
-/*------------------------------------------------------------------*/
-/*
- * This routine, called by wavelan_close(), gracefully stops the 
- * WaveLAN controller (i82586).
- * (called by wavelan_close())
- */
-static inline void wv_82586_stop(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	u16 scb_cmd;
-
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name);
-#endif
-
-	/* Suspend both command unit and receive unit. */
-	scb_cmd =
-	    (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC &
-					       SCB_CMD_RUC_SUS);
-	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
-		    (unsigned char *) &scb_cmd, sizeof(scb_cmd));
-	set_chan_attn(ioaddr, lp->hacr);
-
-	/* No more interrupts */
-	wv_ints_off(dev);
-
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name);
-#endif
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Totally reset the WaveLAN and restart it.
- * Performs the following actions:
- *	1. A power reset (reset DMA)
- *	2. Initialize the radio modem (using wv_mmc_init)
- *	3. Reset & Configure LAN controller (using wv_82586_start)
- *	4. Start the LAN controller's command unit
- *	5. Start the LAN controller's receive unit
- * (called by wavelan_interrupt(), wavelan_watchdog() & wavelan_open())
- */
-static int wv_hw_reset(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name,
-	       (unsigned int) dev);
-#endif
-
-	/* Increase the number of resets done. */
-	lp->nresets++;
-
-	wv_hacr_reset(ioaddr);
-	lp->hacr = HACR_DEFAULT;
-
-	if ((wv_mmc_init(dev) < 0) || (wv_82586_start(dev) < 0))
-		return -1;
-
-	/* Enable the card to send interrupts. */
-	wv_ints_on(dev);
-
-	/* Start card functions */
-	if (wv_cu_start(dev) < 0)
-		return -1;
-
-	/* Setup the controller and parameters */
-	wv_82586_config(dev);
-
-	/* Finish configuration with the receive unit */
-	if (wv_ru_start(dev) < 0)
-		return -1;
-
-#ifdef DEBUG_CONFIG_TRACE
-	printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name);
-#endif
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Check if there is a WaveLAN at the specific base address.
- * As a side effect, this reads the MAC address.
- * (called in wavelan_probe() and init_module())
- */
-static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac)
-{
-	int i;			/* Loop counter */
-
-	/* Check if the base address if available. */
-	if (check_region(ioaddr, sizeof(ha_t)))
-		return -EADDRINUSE;	/* ioaddr already used */
-
-	/* Reset host interface */
-	wv_hacr_reset(ioaddr);
-
-	/* Read the MAC address from the parameter storage area. */
-	psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr),
-		 mac, 6);
-
-	/*
-	 * Check the first three octets of the address for the manufacturer's code.
-	 * Note: if this can't find your WaveLAN card, you've got a
-	 * non-NCR/AT&T/Lucent ISA card.  See wavelan.p.h for detail on
-	 * how to configure your card.
-	 */
-	for (i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
-		if ((mac[0] == MAC_ADDRESSES[i][0]) &&
-		    (mac[1] == MAC_ADDRESSES[i][1]) &&
-		    (mac[2] == MAC_ADDRESSES[i][2]))
-			return 0;
-
-#ifdef DEBUG_CONFIG_INFO
-	printk(KERN_WARNING
-	       "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n",
-	       ioaddr, mac[0], mac[1], mac[2]);
-#endif
-	return -ENODEV;
-}
-
-/************************ INTERRUPT HANDLING ************************/
-
-/*
- * This function is the interrupt handler for the WaveLAN card. This
- * routine will be called whenever: 
- */
-static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	device *dev;
-	unsigned long ioaddr;
-	net_local *lp;
-	u16 hasr;
-	u16 status;
-	u16 ack_cmd;
-
-	dev = dev_id;
-
-#ifdef DEBUG_INTERRUPT_TRACE
-	printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
-#endif
-
-	lp = (net_local *) dev->priv;
-	ioaddr = dev->base_addr;
-
-#ifdef DEBUG_INTERRUPT_INFO
-	/* Check state of our spinlock */
-	if(spin_is_locked(&lp->spinlock))
-		printk(KERN_DEBUG
-		       "%s: wavelan_interrupt(): spinlock is already locked !!!\n",
-		       dev->name);
-#endif
-
-	/* Prevent reentrancy. We need to do that because we may have
-	 * multiple interrupt handler running concurrently.
-	 * It is safe because wv_splhi() disables interrupts before acquiring
-	 * the spinlock. */
-	spin_lock(&lp->spinlock);
-
-	/* Check modem interrupt */
-	if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) {
-		u8 dce_status;
-
-		/*
-		 * Interrupt from the modem management controller.
-		 * This will clear it -- ignored for now.
-		 */
-		mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status,
-			 sizeof(dce_status));
-#ifdef DEBUG_INTERRUPT_ERROR
-		printk(KERN_INFO
-		       "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n",
-		       dev->name, dce_status);
-#endif
-	}
-
-	/* Check if not controller interrupt */
-	if ((hasr & HASR_82586_INTR) == 0) {
-#ifdef DEBUG_INTERRUPT_ERROR
-		printk(KERN_INFO
-		       "%s: wavelan_interrupt(): interrupt not coming from i82586\n",
-		       dev->name);
-#endif
-		spin_unlock (&lp->spinlock);
-		return;
-	}
-
-	/* Read interrupt data. */
-	obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
-		   (unsigned char *) &status, sizeof(status));
-
-	/*
-	 * Acknowledge the interrupt(s).
-	 */
-	ack_cmd = status & SCB_ST_INT;
-	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
-		    (unsigned char *) &ack_cmd, sizeof(ack_cmd));
-	set_chan_attn(ioaddr, lp->hacr);
-
-#ifdef DEBUG_INTERRUPT_INFO
-	printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n",
-	       dev->name, status);
-#endif
-
-	/* Command completed. */
-	if ((status & SCB_ST_CX) == SCB_ST_CX) {
-#ifdef DEBUG_INTERRUPT_INFO
-		printk(KERN_DEBUG
-		       "%s: wavelan_interrupt(): command completed.\n",
-		       dev->name);
-#endif
-		wv_complete(dev, ioaddr, lp);
-	}
-
-	/* Frame received. */
-	if ((status & SCB_ST_FR) == SCB_ST_FR) {
-#ifdef DEBUG_INTERRUPT_INFO
-		printk(KERN_DEBUG
-		       "%s: wavelan_interrupt(): received packet.\n",
-		       dev->name);
-#endif
-		wv_receive(dev);
-	}
-
-	/* Check the state of the command unit. */
-	if (((status & SCB_ST_CNA) == SCB_ST_CNA) ||
-	    (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) &&
-	     (netif_running(dev)))) {
-#ifdef DEBUG_INTERRUPT_ERROR
-		printk(KERN_INFO
-		       "%s: wavelan_interrupt(): CU inactive -- restarting\n",
-		       dev->name);
-#endif
-		wv_hw_reset(dev);
-	}
-
-	/* Check the state of the command unit. */
-	if (((status & SCB_ST_RNR) == SCB_ST_RNR) ||
-	    (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) &&
-	     (netif_running(dev)))) {
-#ifdef DEBUG_INTERRUPT_ERROR
-		printk(KERN_INFO
-		       "%s: wavelan_interrupt(): RU not ready -- restarting\n",
-		       dev->name);
-#endif
-		wv_hw_reset(dev);
-	}
-
-	/* Release spinlock */
-	spin_unlock (&lp->spinlock);
-
-#ifdef DEBUG_INTERRUPT_TRACE
-	printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
-#endif
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Watchdog: when we start a transmission, a timer is set for us in the
- * kernel.  If the transmission completes, this timer is disabled. If
- * the timer expires, we are called and we try to unlock the hardware.
- */
-static void wavelan_watchdog(device *	dev)
-{
-	net_local *	lp = (net_local *)dev->priv;
-	u_long		ioaddr = dev->base_addr;
-	unsigned long	flags;
-	unsigned int	nreaped;
-
-#ifdef DEBUG_INTERRUPT_TRACE
-	printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
-#endif
-
-#ifdef DEBUG_INTERRUPT_ERROR
-	printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n",
-	       dev->name);
-#endif
-
-	/* Check that we came here for something */
-	if (lp->tx_n_in_use <= 0) {
-		return;
-	}
-
-	wv_splhi(lp, &flags);
-
-	/* Try to see if some buffers are not free (in case we missed
-	 * an interrupt */
-	nreaped = wv_complete(dev, ioaddr, lp);
-
-#ifdef DEBUG_INTERRUPT_INFO
-	printk(KERN_DEBUG
-	       "%s: wavelan_watchdog(): %d reaped, %d remain.\n",
-	       dev->name, nreaped, lp->tx_n_in_use);
-#endif
-
-#ifdef DEBUG_PSA_SHOW
-	{
-		psa_t psa;
-		psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
-		wv_psa_show(&psa);
-	}
-#endif
-#ifdef DEBUG_MMC_SHOW
-	wv_mmc_show(dev);
-#endif
-#ifdef DEBUG_I82586_SHOW
-	wv_cu_show(dev);
-#endif
-
-	/* If no buffer has been freed */
-	if (nreaped == 0) {
-#ifdef DEBUG_INTERRUPT_ERROR
-		printk(KERN_INFO
-		       "%s: wavelan_watchdog(): cleanup failed, trying reset\n",
-		       dev->name);
-#endif
-		wv_hw_reset(dev);
-	}
-
-	/* At this point, we should have some free Tx buffer ;-) */
-	if (lp->tx_n_in_use < NTXBLOCKS - 1)
-		netif_wake_queue(dev);
-
-	wv_splx(lp, &flags);
-	
-#ifdef DEBUG_INTERRUPT_TRACE
-	printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
-#endif
-}
-
-/********************* CONFIGURATION CALLBACKS *********************/
-/*
- * Here are the functions called by the Linux networking code (NET3)
- * for initialization, configuration and deinstallations of the 
- * WaveLAN ISA hardware.
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Configure and start up the WaveLAN PCMCIA adaptor.
- * Called by NET3 when it "opens" the device.
- */
-static int wavelan_open(device * dev)
-{
-	net_local *	lp = (net_local *)dev->priv;
-	unsigned long	flags;
-
-#ifdef DEBUG_CALLBACK_TRACE
-	printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
-	       (unsigned int) dev);
-#endif
-
-	/* Check irq */
-	if (dev->irq == 0) {
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n",
-		       dev->name);
-#endif
-		return -ENXIO;
-	}
-
-	if (request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0) 
-	{
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n",
-		       dev->name);
-#endif
-		return -EAGAIN;
-	}
-
-	wv_splhi(lp, &flags);
-	
-	if (wv_hw_reset(dev) != -1) {
-		netif_start_queue(dev);
-	} else {
-		free_irq(dev->irq, dev);
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_INFO
-		       "%s: wavelan_open(): impossible to start the card\n",
-		       dev->name);
-#endif
-		wv_splx(lp, &flags);
-		return -EAGAIN;
-	}
-	wv_splx(lp, &flags);
-	
-#ifdef DEBUG_CALLBACK_TRACE
-	printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
-#endif
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Shut down the WaveLAN ISA card.
- * Called by NET3 when it "closes" the device.
- */
-static int wavelan_close(device * dev)
-{
-	net_local *lp = (net_local *) dev->priv;
-	unsigned long flags;
-
-#ifdef DEBUG_CALLBACK_TRACE
-	printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
-	       (unsigned int) dev);
-#endif
-
-	netif_stop_queue(dev);
-
-	/*
-	 * Flush the Tx and disable Rx.
-	 */
-	wv_splhi(lp, &flags);
-	wv_82586_stop(dev);
-	wv_splx(lp, &flags);
-
-	free_irq(dev->irq, dev);
-
-#ifdef DEBUG_CALLBACK_TRACE
-	printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name);
-#endif
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Probe an I/O address, and if the WaveLAN is there configure the
- * device structure
- * (called by wavelan_probe() and via init_module()).
- */
-static int __init wavelan_config(device * dev)
-{
-	unsigned long ioaddr = dev->base_addr;
-	u8 irq_mask;
-	int irq;
-	net_local *lp;
-
-#ifdef DEBUG_CALLBACK_TRACE
-	printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n",
-	       dev->name, (unsigned int) dev, ioaddr);
-#endif
-
-	/* Check IRQ argument on command line. */
-	if (dev->irq != 0) {
-		irq_mask = wv_irq_to_psa(dev->irq);
-
-		if (irq_mask == 0) {
-#ifdef DEBUG_CONFIG_ERROR
-			printk(KERN_WARNING
-			       "%s: wavelan_config(): invalid IRQ %d ignored.\n",
-			       dev->name, dev->irq);
-#endif
-			dev->irq = 0;
-		} else {
-#ifdef DEBUG_CONFIG_INFO
-			printk(KERN_DEBUG
-			       "%s: wavelan_config(): changing IRQ to %d\n",
-			       dev->name, dev->irq);
-#endif
-			psa_write(ioaddr, HACR_DEFAULT,
-				  psaoff(0, psa_int_req_no), &irq_mask, 1);
-			/* update the Wavelan checksum */
-			update_psa_checksum(dev, ioaddr, HACR_DEFAULT);
-			wv_hacr_reset(ioaddr);
-		}
-	}
-
-	psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no),
-		 &irq_mask, 1);
-	if ((irq = wv_psa_to_irq(irq_mask)) == -1) {
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_INFO
-		       "%s: wavelan_config(): could not wavelan_map_irq(%d).\n",
-		       dev->name, irq_mask);
-#endif
-		return -EAGAIN;
-	}
-
-	dev->irq = irq;
-
-	if (!request_region(ioaddr, sizeof(ha_t), "wavelan"))
-		return -EBUSY;
-
-	dev->mem_start = 0x0000;
-	dev->mem_end = 0x0000;
-	dev->if_port = 0;
-
-	/* Initialize device structures */
-	dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL);
-	if (dev->priv == NULL) {
-		release_region(ioaddr, sizeof(ha_t));
-		return -ENOMEM;
-	}
-	memset(dev->priv, 0x00, sizeof(net_local));
-	lp = (net_local *) dev->priv;
-
-	/* Back link to the device structure. */
-	lp->dev = dev;
-	/* Add the device at the beginning of the linked list. */
-	lp->next = wavelan_list;
-	wavelan_list = lp;
-
-	lp->hacr = HACR_DEFAULT;
-
-	/* Multicast stuff */
-	lp->promiscuous = 0;
-	lp->mc_count = 0;
-
-	/* Init spinlock */
-	spin_lock_init(&lp->spinlock);
-
-	/*
-	 * Fill in the fields of the device structure
-	 * with generic Ethernet values.
-	 */
-	ether_setup(dev);
-
-	SET_MODULE_OWNER(dev);
-	dev->open = wavelan_open;
-	dev->stop = wavelan_close;
-	dev->hard_start_xmit = wavelan_packet_xmit;
-	dev->get_stats = wavelan_get_stats;
-	dev->set_multicast_list = &wavelan_set_multicast_list;
-        dev->tx_timeout		= &wavelan_watchdog;
-        dev->watchdog_timeo	= WATCHDOG_JIFFIES;
-#ifdef SET_MAC_ADDRESS
-	dev->set_mac_address = &wavelan_set_mac_address;
-#endif				/* SET_MAC_ADDRESS */
-
-#ifdef WIRELESS_EXT		/* if wireless extension exists in the kernel */
-	dev->do_ioctl = wavelan_ioctl;
-	dev->get_wireless_stats = wavelan_get_wireless_stats;
-#endif
-
-	dev->mtu = WAVELAN_MTU;
-
-	/* Display nice information. */
-	wv_init_info(dev);
-
-#ifdef DEBUG_CALLBACK_TRACE
-	printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name);
-#endif
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Check for a network adaptor of this type.  Return '0' iff one 
- * exists.  There seem to be different interpretations of
- * the initial value of dev->base_addr.
- * We follow the example in drivers/net/ne.c.
- * (called in "Space.c")
- */
-int __init wavelan_probe(device * dev)
-{
-	short base_addr;
-	mac_addr mac;		/* MAC address (check existence of WaveLAN) */
-	int i;
-	int r;
-
-#ifdef DEBUG_CALLBACK_TRACE
-	printk(KERN_DEBUG
-	       "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n",
-	       dev->name, (unsigned int) dev,
-	       (unsigned int) dev->base_addr);
-#endif
-
-#ifdef	STRUCT_CHECK
-	if (wv_struct_check() != (char *) NULL) {
-		printk(KERN_WARNING
-		       "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n",
-		       dev->name, wv_struct_check());
-		return -ENODEV;
-	}
-#endif				/* STRUCT_CHECK */
-
-	/* Check the value of the command line parameter for base address. */
-	base_addr = dev->base_addr;
-
-	/* Don't probe at all. */
-	if (base_addr < 0) {
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_WARNING
-		       "%s: wavelan_probe(): invalid base address\n",
-		       dev->name);
-#endif
-		return -ENXIO;
-	}
-
-	/* Check a single specified location. */
-	if (base_addr > 0x100) {
-		/* Check if there is something at this base address */
-		if ((r = wv_check_ioaddr(base_addr, mac)) == 0) {
-			memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
-			r = wavelan_config(dev);
-		}
-#ifdef DEBUG_CONFIG_INFO
-		if (r != 0)
-			printk(KERN_DEBUG
-			       "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n",
-			       dev->name, base_addr);
-#endif
-
-#ifdef DEBUG_CALLBACK_TRACE
-		printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name);
-#endif
-		return r;
-	}
-
-	/* Scan all possible addresses of the WaveLAN hardware. */
-	for (i = 0; i < NELS(iobase); i++) {
-		/* Check whether there is something at this base address. */
-		if (wv_check_ioaddr(iobase[i], mac) == 0) {
-			dev->base_addr = iobase[i];	/* Copy base address. */
-			memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
-			if (wavelan_config(dev) == 0) {
-#ifdef DEBUG_CALLBACK_TRACE
-				printk(KERN_DEBUG
-				       "%s: <-wavelan_probe()\n",
-				       dev->name);
-#endif
-				return 0;
-			}
-		}
-	}
-
-	/* We may have touched base_addr.  Another driver may not like it. */
-	dev->base_addr = base_addr;
-
-#ifdef DEBUG_CONFIG_INFO
-	printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n",
-	       dev->name);
-#endif
-
-	return -ENODEV;
-}
-
-/****************************** MODULE ******************************/
-/*
- * Module entry point: insertion and removal
- */
-
-#ifdef	MODULE
-/*------------------------------------------------------------------*/
-/*
- * Insertion of the module
- * I'm now quite proud of the multi-device support.
- */
-int init_module(void)
-{
-	mac_addr mac;		/* MAC address (check WaveLAN existence) */
-	int ret = -EIO;		/* Return error if no cards found */
-	int i;
-
-#ifdef DEBUG_MODULE_TRACE
-	printk(KERN_DEBUG "-> init_module()\n");
-#endif
-
-	/* If probing is asked */
-	if (io[0] == 0) {
-#ifdef DEBUG_CONFIG_ERROR
-		printk(KERN_WARNING
-		       "WaveLAN init_module(): doing device probing (bad !)\n");
-		printk(KERN_WARNING
-		       "Specify base addresses while loading module to correct the problem\n");
-#endif
-
-		/* Copy the basic set of address to be probed. */
-		for (i = 0; i < NELS(iobase); i++)
-			io[i] = iobase[i];
-	}
-
-
-	/* Loop on all possible base addresses. */
-	i = -1;
-	while ((io[++i] != 0) && (i < NELS(io))) {
-		/* Check if there is something at this base address. */
-		if (wv_check_ioaddr(io[i], mac) == 0) {
-			device *dev;
-
-			/* Create device and set basic arguments. */
-			dev =
-			    kmalloc(sizeof(struct net_device), GFP_KERNEL);
-			if (dev == NULL) {
-				ret = -ENOMEM;
-				break;
-			}
-			memset(dev, 0x00, sizeof(struct net_device));
-			memcpy(dev->name, name[i], IFNAMSIZ);	/* Copy name */
-			dev->base_addr = io[i];
-			dev->irq = irq[i];
-			dev->init = &wavelan_config;
-			memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
-
-			/* Try to create the device. */
-			if (register_netdev(dev) != 0) {
-				/* Deallocate everything. */
-				/* Note: if dev->priv is mallocated, there is no way to fail. */
-				kfree(dev);
-			} else {
-				/* If at least one device OK, we do not fail */
-				ret = 0;
-			}
-		}		/* if there is something at the address */
-	}			/* Loop on all addresses. */
-
-#ifdef DEBUG_CONFIG_ERROR
-	if (wavelan_list == (net_local *) NULL)
-		printk(KERN_WARNING
-		       "WaveLAN init_module(): no device found\n");
-#endif
-
-#ifdef DEBUG_MODULE_TRACE
-	printk(KERN_DEBUG "<- init_module()\n");
-#endif
-	return ret;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Removal of the module
- */
-void cleanup_module(void)
-{
-#ifdef DEBUG_MODULE_TRACE
-	printk(KERN_DEBUG "-> cleanup_module()\n");
-#endif
-
-	/* Loop on all devices and release them. */
-	while (wavelan_list != (net_local *) NULL) {
-		device *dev = wavelan_list->dev;
-
-#ifdef DEBUG_CONFIG_INFO
-		printk(KERN_DEBUG
-		       "%s: cleanup_module(): removing device at 0x%x\n",
-		       dev->name, (unsigned int) dev);
-#endif
-
-		/* Release the ioport region. */
-		release_region(dev->base_addr, sizeof(ha_t));
-
-		/* Definitely remove the device. */
-		unregister_netdev(dev);
-
-		/* Unlink the device. */
-		wavelan_list = wavelan_list->next;
-
-		/* Free pieces. */
-		kfree(dev->priv);
-		kfree(dev);
-	}
-
-#ifdef DEBUG_MODULE_TRACE
-	printk(KERN_DEBUG "<- cleanup_module()\n");
-#endif
-}
-#endif				/* MODULE */
-MODULE_LICENSE("GPL");
-
-/*
- * This software may only be used and distributed
- * according to the terms of the GNU General Public License.
- *
- * This software was developed as a component of the
- * Linux operating system.
- * It is based on other device drivers and information
- * either written or supplied by:
- *	Ajay Bakre (bakre@paul.rutgers.edu),
- *	Donald Becker (becker@scyld.com),
- *	Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com),
- *	Anders Klemets (klemets@it.kth.se),
- *	Vladimir V. Kolpakov (w@stier.koenig.ru),
- *	Marc Meertens (Marc.Meertens@Utrecht.NCR.com),
- *	Pauline Middelink (middelin@polyware.iaf.nl),
- *	Robert Morris (rtm@das.harvard.edu),
- *	Jean Tourrilhes (jt@hplb.hpl.hp.com),
- *	Girish Welling (welling@paul.rutgers.edu),
- *
- * Thanks go also to:
- *	James Ashton (jaa101@syseng.anu.edu.au),
- *	Alan Cox (alan@redhat.com),
- *	Allan Creighton (allanc@cs.usyd.edu.au),
- *	Matthew Geier (matthew@cs.usyd.edu.au),
- *	Remo di Giovanni (remo@cs.usyd.edu.au),
- *	Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de),
- *	Vipul Gupta (vgupta@cs.binghamton.edu),
- *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
- *	Tim Nicholson (tim@cs.usyd.edu.au),
- *	Ian Parkin (ian@cs.usyd.edu.au),
- *	John Rosenberg (johnr@cs.usyd.edu.au),
- *	George Rossi (george@phm.gov.au),
- *	Arthur Scott (arthur@cs.usyd.edu.au),
- *	Peter Storey,
- * for their assistance and advice.
- *
- * Please send bug reports, updates, comments to:
- *
- * Bruce Janson                                    Email:  bruce@cs.usyd.edu.au
- * Basser Department of Computer Science           Phone:  +61-2-9351-3423
- * University of Sydney, N.S.W., 2006, AUSTRALIA   Fax:    +61-2-9351-3838
- */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wavelan.h linux/drivers/net/wavelan.h
--- v2.5.2/linux/drivers/net/wavelan.h	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/wavelan.h	Wed Dec 31 16:00:00 1969
@@ -1,370 +0,0 @@
-/*
- *	WaveLAN ISA driver
- *
- *		Jean II - HPLB '96
- *
- * Reorganisation and extension of the driver.
- * Original copyright follows. See wavelan.p.h for details.
- *
- * This file contains the declarations for the WaveLAN hardware. Note that
- * the WaveLAN ISA includes a i82586 controller (see definitions in
- * file i82586.h).
- *
- * The main difference between the ISA hardware and the PCMCIA one is
- * the Ethernet controller (i82586 instead of i82593).
- * The i82586 allows multiple transmit buffers.  The PSA needs to be accessed
- * through the host interface.
- */
-
-#ifndef _WAVELAN_H
-#define	_WAVELAN_H
-
-/************************** MAGIC NUMBERS ***************************/
-
-/* Detection of the WaveLAN card is done by reading the MAC
- * address from the card and checking it.  If you have a non-AT&T
- * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson),
- * you might need to modify this part to accommodate your hardware.
- */
-static const char	MAC_ADDRESSES[][3] =
-{
-  { 0x08, 0x00, 0x0E },		/* AT&T WaveLAN (standard) & DEC RoamAbout */
-  { 0x08, 0x00, 0x6A },		/* AT&T WaveLAN (alternate) */
-  { 0x00, 0x00, 0xE1 },		/* Hitachi Wavelan */
-  { 0x00, 0x60, 0x1D }		/* Lucent Wavelan (another one) */
-  /* Add your card here and send me the patch! */
-};
-
-#define WAVELAN_ADDR_SIZE	6	/* Size of a MAC address */
-
-#define WAVELAN_MTU		1500	/* Maximum size of WaveLAN packet */
-
-#define	MAXDATAZ		(WAVELAN_ADDR_SIZE + WAVELAN_ADDR_SIZE + 2 + WAVELAN_MTU)
-
-/*
- * Constants used to convert channels to frequencies
- */
-
-/* Frequency available in the 2.0 modem, in units of 250 kHz
- * (as read in the offset register of the dac area).
- * Used to map channel numbers used by `wfreqsel' to frequencies
- */
-static const short	channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8,
-				    0xD0, 0xF0, 0xF8, 0x150 };
-
-/* Frequencies of the 1.0 modem (fixed frequencies).
- * Use to map the PSA `subband' to a frequency
- * Note : all frequencies apart from the first one need to be multiplied by 10
- */
-static const int	fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
-
-
-
-/*************************** PC INTERFACE ****************************/
-
-/*
- * Host Adaptor structure.
- * (base is board port address).
- */
-typedef union hacs_u	hacs_u;
-union hacs_u
-{
-	unsigned short	hu_command;		/* Command register */
-#define		HACR_RESET		0x0001	/* Reset board */
-#define		HACR_CA			0x0002	/* Set Channel Attention for 82586 */
-#define		HACR_16BITS		0x0004	/* 16-bit operation (0 => 8bits) */
-#define		HACR_OUT0		0x0008	/* General purpose output pin 0 */
-						/* not used - must be 1 */
-#define		HACR_OUT1		0x0010	/* General purpose output pin 1 */
-						/* not used - must be 1 */
-#define		HACR_82586_INT_ENABLE	0x0020	/* Enable 82586 interrupts */
-#define		HACR_MMC_INT_ENABLE	0x0040	/* Enable MMC interrupts */
-#define		HACR_INTR_CLR_ENABLE	0x0080	/* Enable interrupt status read/clear */
-	unsigned short	hu_status;		/* Status Register */
-#define		HASR_82586_INTR		0x0001	/* Interrupt request from 82586 */
-#define		HASR_MMC_INTR		0x0002	/* Interrupt request from MMC */
-#define		HASR_MMC_BUSY		0x0004	/* MMC busy indication */
-#define		HASR_PSA_BUSY		0x0008	/* LAN parameter storage area busy */
-};
-
-typedef struct ha_t	ha_t;
-struct ha_t
-{
-	hacs_u		ha_cs;		/* Command and status registers */
-#define 		ha_command	ha_cs.hu_command
-#define 		ha_status	ha_cs.hu_status
-	unsigned short	ha_mmcr;	/* Modem Management Ctrl Register */
-	unsigned short	ha_pior0;	/* Program I/O Address Register Port 0 */
-	unsigned short	ha_piop0;	/* Program I/O Port 0 */
-	unsigned short	ha_pior1;	/* Program I/O Address Register Port 1 */
-	unsigned short	ha_piop1;	/* Program I/O Port 1 */
-	unsigned short	ha_pior2;	/* Program I/O Address Register Port 2 */
-	unsigned short	ha_piop2;	/* Program I/O Port 2 */
-};
-
-#define HA_SIZE		16
-
-#define	hoff(p,f) 	(unsigned short)((void *)(&((ha_t *)((void *)0 + (p)))->f) - (void *)0)
-#define	HACR(p)		hoff(p, ha_command)
-#define	HASR(p)		hoff(p, ha_status)
-#define	MMCR(p)		hoff(p, ha_mmcr)
-#define	PIOR0(p)	hoff(p, ha_pior0)
-#define	PIOP0(p)	hoff(p, ha_piop0)
-#define	PIOR1(p)	hoff(p, ha_pior1)
-#define	PIOP1(p)	hoff(p, ha_piop1)
-#define	PIOR2(p)	hoff(p, ha_pior2)
-#define	PIOP2(p)	hoff(p, ha_piop2)
-
-/*
- * Program I/O Mode Register values.
- */
-#define STATIC_PIO		0	/* Mode 1: static mode */
-					/* RAM access ??? */
-#define AUTOINCR_PIO		1	/* Mode 2: auto increment mode */
-					/* RAM access ??? */
-#define AUTODECR_PIO		2	/* Mode 3: auto decrement mode */
-					/* RAM access ??? */
-#define PARAM_ACCESS_PIO	3	/* Mode 4: LAN parameter access mode */
-					/* Parameter access. */
-#define PIO_MASK		3	/* register mask */
-#define PIOM(cmd,piono)		((u_short)cmd << 10 << (piono * 2))
-
-#define	HACR_DEFAULT		(HACR_OUT0 | HACR_OUT1 | HACR_16BITS | PIOM(STATIC_PIO, 0) | PIOM(AUTOINCR_PIO, 1) | PIOM(PARAM_ACCESS_PIO, 2))
-#define	HACR_INTRON		(HACR_82586_INT_ENABLE | HACR_MMC_INT_ENABLE | HACR_INTR_CLR_ENABLE)
-
-/************************** MEMORY LAYOUT **************************/
-
-/*
- * Onboard 64 k RAM layout.
- * (Offsets from 0x0000.)
- */
-#define OFFSET_RU		0x0000		/* 75% memory */
-#define OFFSET_CU		0xC000		/* 25% memory */
-#define OFFSET_SCB		(OFFSET_ISCP - sizeof(scb_t))
-#define OFFSET_ISCP		(OFFSET_SCP - sizeof(iscp_t))
-#define OFFSET_SCP		I82586_SCP_ADDR
-
-#define	RXBLOCKZ		(sizeof(fd_t) + sizeof(rbd_t) + MAXDATAZ)
-#define	TXBLOCKZ		(sizeof(ac_tx_t) + sizeof(ac_nop_t) + sizeof(tbd_t) + MAXDATAZ)
-
-#define	NRXBLOCKS		((OFFSET_CU - OFFSET_RU) / RXBLOCKZ)
-#define	NTXBLOCKS		((OFFSET_SCB - OFFSET_CU) / TXBLOCKZ)
-
-/********************** PARAMETER STORAGE AREA **********************/
-
-/*
- * Parameter Storage Area (PSA).
- */
-typedef struct psa_t	psa_t;
-struct psa_t
-{
-  unsigned char	psa_io_base_addr_1;	/* [0x00] Base address 1 ??? */
-  unsigned char	psa_io_base_addr_2;	/* [0x01] Base address 2 */
-  unsigned char	psa_io_base_addr_3;	/* [0x02] Base address 3 */
-  unsigned char	psa_io_base_addr_4;	/* [0x03] Base address 4 */
-  unsigned char	psa_rem_boot_addr_1;	/* [0x04] Remote Boot Address 1 */
-  unsigned char	psa_rem_boot_addr_2;	/* [0x05] Remote Boot Address 2 */
-  unsigned char	psa_rem_boot_addr_3;	/* [0x06] Remote Boot Address 3 */
-  unsigned char	psa_holi_params;	/* [0x07] HOst Lan Interface (HOLI) Parameters */
-  unsigned char	psa_int_req_no;		/* [0x08] Interrupt Request Line */
-  unsigned char	psa_unused0[7];		/* [0x09-0x0F] unused */
-
-  unsigned char	psa_univ_mac_addr[WAVELAN_ADDR_SIZE];	/* [0x10-0x15] Universal (factory) MAC Address */
-  unsigned char	psa_local_mac_addr[WAVELAN_ADDR_SIZE];	/* [0x16-1B] Local MAC Address */
-  unsigned char	psa_univ_local_sel;	/* [0x1C] Universal Local Selection */
-#define		PSA_UNIVERSAL	0		/* Universal (factory) */
-#define		PSA_LOCAL	1		/* Local */
-  unsigned char	psa_comp_number;	/* [0x1D] Compatibility Number:	 */
-#define		PSA_COMP_PC_AT_915	0 	/* PC-AT 915 MHz 	 */
-#define		PSA_COMP_PC_MC_915	1 	/* PC-MC 915 MHz	 */
-#define		PSA_COMP_PC_AT_2400	2 	/* PC-AT 2.4 GHz	 */
-#define		PSA_COMP_PC_MC_2400	3 	/* PC-MC 2.4 GHz 	 */
-#define		PSA_COMP_PCMCIA_915	4 	/* PCMCIA 915 MHz or 2.0 */
-  unsigned char	psa_thr_pre_set;	/* [0x1E] Modem Threshold Preset */
-  unsigned char	psa_feature_select;	/* [0x1F] Call code required (1=on) */
-#define		PSA_FEATURE_CALL_CODE	0x01 	/* Call code required (Japan) */
-  unsigned char	psa_subband;		/* [0x20] Subband	  */
-#define		PSA_SUBBAND_915		0	/* 915 MHz or 2.0 */
-#define		PSA_SUBBAND_2425	1	/* 2425 MHz	  */
-#define		PSA_SUBBAND_2460	2	/* 2460 MHz	  */
-#define		PSA_SUBBAND_2484	3	/* 2484 MHz	  */
-#define		PSA_SUBBAND_2430_5	4	/* 2430.5 MHz	  */
-  unsigned char	psa_quality_thr;	/* [0x21] Modem Quality Threshold */
-  unsigned char	psa_mod_delay;		/* [0x22] Modem Delay (?) (reserved) */
-  unsigned char	psa_nwid[2];		/* [0x23-0x24] Network ID */
-  unsigned char	psa_nwid_select;	/* [0x25] Network ID Select On/Off */
-  unsigned char	psa_encryption_select;	/* [0x26] Encryption On/Off */
-  unsigned char	psa_encryption_key[8];	/* [0x27-0x2E] Encryption Key */
-  unsigned char	psa_databus_width;	/* [0x2F] AT bus width select 8/16 */
-  unsigned char	psa_call_code[8];	/* [0x30-0x37] (Japan) Call Code */
-  unsigned char	psa_nwid_prefix[2];	/* [0x38-0x39] Roaming domain */
-  unsigned char	psa_reserved[2];	/* [0x3A-0x3B] Reserved - fixed 00 */
-  unsigned char	psa_conf_status;	/* [0x3C] Conf Status, bit 0=1:config*/
-  unsigned char	psa_crc[2];		/* [0x3D] CRC-16 over PSA */
-  unsigned char	psa_crc_status;		/* [0x3F] CRC Valid Flag */
-};
-
-#define	PSA_SIZE	64
-
-/* Calculate offset of a field in the above structure.
- * Warning:  only even addresses are used. */
-#define	psaoff(p,f) 	((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL))
-
-/******************** MODEM MANAGEMENT INTERFACE ********************/
-
-/*
- * Modem Management Controller (MMC) write structure.
- */
-typedef struct mmw_t	mmw_t;
-struct mmw_t
-{
-  unsigned char	mmw_encr_key[8];	/* encryption key */
-  unsigned char	mmw_encr_enable;	/* Enable or disable encryption. */
-#define	MMW_ENCR_ENABLE_MODE	0x02	/* mode of security option */
-#define	MMW_ENCR_ENABLE_EN	0x01	/* Enable security option. */
-  unsigned char	mmw_unused0[1];		/* unused */
-  unsigned char	mmw_des_io_invert;	/* encryption option */
-#define	MMW_DES_IO_INVERT_RES	0x0F	/* reserved */
-#define	MMW_DES_IO_INVERT_CTRL	0xF0	/* control (?) (set to 0) */
-  unsigned char	mmw_unused1[5];		/* unused */
-  unsigned char	mmw_loopt_sel;		/* looptest selection */
-#define	MMW_LOOPT_SEL_DIS_NWID	0x40	/* Disable NWID filtering. */
-#define	MMW_LOOPT_SEL_INT	0x20	/* Activate Attention Request. */
-#define	MMW_LOOPT_SEL_LS	0x10	/* looptest, no collision avoidance */
-#define MMW_LOOPT_SEL_LT3A	0x08	/* looptest 3a */
-#define	MMW_LOOPT_SEL_LT3B	0x04	/* looptest 3b */
-#define	MMW_LOOPT_SEL_LT3C	0x02	/* looptest 3c */
-#define	MMW_LOOPT_SEL_LT3D	0x01	/* looptest 3d */
-  unsigned char	mmw_jabber_enable;	/* jabber timer enable */
-  /* Abort transmissions > 200 ms */
-  unsigned char	mmw_freeze;		/* freeze or unfreeze signal level */
-  /* 0 : signal level & qual updated for every new message, 1 : frozen */
-  unsigned char	mmw_anten_sel;		/* antenna selection */
-#define MMW_ANTEN_SEL_SEL	0x01	/* direct antenna selection */
-#define	MMW_ANTEN_SEL_ALG_EN	0x02	/* antenna selection algo. enable */
-  unsigned char	mmw_ifs;		/* inter frame spacing */
-  /* min time between transmission in bit periods (.5 us) - bit 0 ignored */
-  unsigned char	mmw_mod_delay;	 	/* modem delay (synchro) */
-  unsigned char	mmw_jam_time;		/* jamming time (after collision) */
-  unsigned char	mmw_unused2[1];		/* unused */
-  unsigned char	mmw_thr_pre_set;	/* level threshold preset */
-  /* Discard all packet with signal < this value (4) */
-  unsigned char	mmw_decay_prm;		/* decay parameters */
-  unsigned char	mmw_decay_updat_prm;	/* decay update parameters */
-  unsigned char	mmw_quality_thr;	/* quality (z-quotient) threshold */
-  /* Discard all packet with quality < this value (3) */
-  unsigned char	mmw_netw_id_l;		/* NWID low order byte */
-  unsigned char	mmw_netw_id_h;		/* NWID high order byte */
-  /* Network ID or Domain : create virtual net on the air */
-
-  /* 2.0 Hardware extension - frequency selection support */
-  unsigned char	mmw_mode_select;	/* for analog tests (set to 0) */
-  unsigned char	mmw_unused3[1];		/* unused */
-  unsigned char	mmw_fee_ctrl;		/* frequency EEPROM control */
-#define	MMW_FEE_CTRL_PRE	0x10	/* Enable protected instructions. */
-#define	MMW_FEE_CTRL_DWLD	0x08	/* Download EEPROM to mmc. */
-#define	MMW_FEE_CTRL_CMD	0x07	/* EEPROM commands:  */
-#define	MMW_FEE_CTRL_READ	0x06	/* Read */
-#define	MMW_FEE_CTRL_WREN	0x04	/* Write enable */
-#define	MMW_FEE_CTRL_WRITE	0x05	/* Write data to address. */
-#define	MMW_FEE_CTRL_WRALL	0x04	/* Write data to all addresses. */
-#define	MMW_FEE_CTRL_WDS	0x04	/* Write disable */
-#define	MMW_FEE_CTRL_PRREAD	0x16	/* Read addr from protect register */
-#define	MMW_FEE_CTRL_PREN	0x14	/* Protect register enable */
-#define	MMW_FEE_CTRL_PRCLEAR	0x17	/* Unprotect all registers. */
-#define	MMW_FEE_CTRL_PRWRITE	0x15	/* Write address in protect register */
-#define	MMW_FEE_CTRL_PRDS	0x14	/* Protect register disable */
-  /* Never issue the PRDS command:  it's irreversible! */
-
-  unsigned char	mmw_fee_addr;		/* EEPROM address */
-#define	MMW_FEE_ADDR_CHANNEL	0xF0	/* Select the channel. */
-#define	MMW_FEE_ADDR_OFFSET	0x0F	/* Offset in channel data */
-#define	MMW_FEE_ADDR_EN		0xC0	/* FEE_CTRL enable operations */
-#define	MMW_FEE_ADDR_DS		0x00	/* FEE_CTRL disable operations */
-#define	MMW_FEE_ADDR_ALL	0x40	/* FEE_CTRL all operations */
-#define	MMW_FEE_ADDR_CLEAR	0xFF	/* FEE_CTRL clear operations */
-
-  unsigned char	mmw_fee_data_l;		/* Write data to EEPROM. */
-  unsigned char	mmw_fee_data_h;		/* high octet */
-  unsigned char	mmw_ext_ant;		/* Setting for external antenna */
-#define	MMW_EXT_ANT_EXTANT	0x01	/* Select external antenna */
-#define	MMW_EXT_ANT_POL		0x02	/* Polarity of the antenna */
-#define	MMW_EXT_ANT_INTERNAL	0x00	/* Internal antenna */
-#define	MMW_EXT_ANT_EXTERNAL	0x03	/* External antenna */
-#define	MMW_EXT_ANT_IQ_TEST	0x1C	/* IQ test pattern (set to 0) */
-};
-
-#define	MMW_SIZE	37
-
-#define	mmwoff(p,f) 	(unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
-
-/*
- * Modem Management Controller (MMC) read structure.
- */
-typedef struct mmr_t	mmr_t;
-struct mmr_t
-{
-  unsigned char	mmr_unused0[8];		/* unused */
-  unsigned char	mmr_des_status;		/* encryption status */
-  unsigned char	mmr_des_avail;		/* encryption available (0x55 read) */
-#define	MMR_DES_AVAIL_DES	0x55		/* DES available */
-#define	MMR_DES_AVAIL_AES	0x33		/* AES (AT&T) available */
-  unsigned char	mmr_des_io_invert;	/* des I/O invert register */
-  unsigned char	mmr_unused1[5];		/* unused */
-  unsigned char	mmr_dce_status;		/* DCE status */
-#define	MMR_DCE_STATUS_RX_BUSY		0x01	/* receiver busy */
-#define	MMR_DCE_STATUS_LOOPT_IND	0x02	/* loop test indicated */
-#define	MMR_DCE_STATUS_TX_BUSY		0x04	/* transmitter on */
-#define	MMR_DCE_STATUS_JBR_EXPIRED	0x08	/* jabber timer expired */
-#define MMR_DCE_STATUS			0x0F	/* mask to get the bits */
-  unsigned char	mmr_dsp_id;		/* DSP ID (AA = Daedalus rev A) */
-  unsigned char	mmr_unused2[2];		/* unused */
-  unsigned char	mmr_correct_nwid_l;	/* # of correct NWIDs rxd (low) */
-  unsigned char	mmr_correct_nwid_h;	/* # of correct NWIDs rxd (high) */
-  /* Warning:  read high-order octet first! */
-  unsigned char	mmr_wrong_nwid_l;	/* # of wrong NWIDs rxd (low) */
-  unsigned char	mmr_wrong_nwid_h;	/* # of wrong NWIDs rxd (high) */
-  unsigned char	mmr_thr_pre_set;	/* level threshold preset */
-#define	MMR_THR_PRE_SET		0x3F		/* level threshold preset */
-#define	MMR_THR_PRE_SET_CUR	0x80		/* Current signal above it */
-  unsigned char	mmr_signal_lvl;		/* signal level */
-#define	MMR_SIGNAL_LVL		0x3F		/* signal level */
-#define	MMR_SIGNAL_LVL_VALID	0x80		/* Updated since last read */
-  unsigned char	mmr_silence_lvl;	/* silence level (noise) */
-#define	MMR_SILENCE_LVL		0x3F		/* silence level */
-#define	MMR_SILENCE_LVL_VALID	0x80		/* Updated since last read */
-  unsigned char	mmr_sgnl_qual;		/* signal quality */
-#define	MMR_SGNL_QUAL		0x0F		/* signal quality */
-#define	MMR_SGNL_QUAL_ANT	0x80		/* current antenna used */
-  unsigned char	mmr_netw_id_l;		/* NWID low order byte (?) */
-  unsigned char	mmr_unused3[3];		/* unused */
-
-  /* 2.0 Hardware extension - frequency selection support */
-  unsigned char	mmr_fee_status;		/* Status of frequency EEPROM */
-#define	MMR_FEE_STATUS_ID	0xF0		/* Modem revision ID */
-#define	MMR_FEE_STATUS_DWLD	0x08		/* Download in progress */
-#define	MMR_FEE_STATUS_BUSY	0x04		/* EEPROM busy */
-  unsigned char	mmr_unused4[1];		/* unused */
-  unsigned char	mmr_fee_data_l;		/* Read data from EEPROM (low) */
-  unsigned char	mmr_fee_data_h;		/* Read data from EEPROM (high) */
-};
-
-#define	MMR_SIZE	36
-
-#define	mmroff(p,f) 	(unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
-
-/* Make the two above structures one */
-typedef union mm_t
-{
-  struct mmw_t	w;	/* Write to the mmc */
-  struct mmr_t	r;	/* Read from the mmc */
-} mm_t;
-
-#endif /* _WAVELAN_H */
-
-/*
- * This software may only be used and distributed
- * according to the terms of the GNU General Public License.
- *
- * For more details, see wavelan.c.
- */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h
--- v2.5.2/linux/drivers/net/wavelan.p.h	Fri Oct 12 14:21:18 2001
+++ linux/drivers/net/wavelan.p.h	Wed Dec 31 16:00:00 1969
@@ -1,713 +0,0 @@
-/*
- *	WaveLAN ISA driver
- *
- *		Jean II - HPLB '96
- *
- * Reorganisation and extension of the driver.
- *
- * This file contains all definitions and declarations necessary for the
- * WaveLAN ISA driver.  This file is a private header, so it should
- * be included only in wavelan.c!
- */
-
-#ifndef WAVELAN_P_H
-#define WAVELAN_P_H
-
-/************************** DOCUMENTATION ***************************/
-/*
- * This driver provides a Linux interface to the WaveLAN ISA hardware.
- * The WaveLAN is a product of Lucent (http://www.wavelan.com/).
- * This division was formerly part of NCR and then AT&T.
- * WaveLANs are also distributed by DEC (RoamAbout DS) and Digital Ocean.
- *
- * To learn how to use this driver, read the NET3 HOWTO.
- * If you want to exploit the many other functionalities, read the comments
- * in the code.
- *
- * This driver is the result of the effort of many people (see below).
- */
-
-/* ------------------------ SPECIFIC NOTES ------------------------ */
-/*
- * Web page
- * --------
- *	I try to maintain a web page with the Wireless LAN Howto at :
- *	    http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
- *
- * SMP
- * ---
- *	We now are SMP compliant (I eventually fixed the remaining bugs).
- *	The driver has been tested on a dual P6-150 and survived my usual
- *	set of torture tests.
- *	Anyway, I spent enough time chasing interrupt re-entrancy during
- *	errors or reconfigure, and I designed the locked/unlocked sections
- *	of the driver with great care, and with the recent addition of
- *	the spinlock (thanks to the new API), we should be quite close to
- *	the truth.
- *	The SMP/IRQ locking is quite coarse and conservative (i.e. not fast),
- *	but better safe than sorry (especially at 2 Mb/s ;-).
- *
- *	I have also looked into disabling only our interrupt on the card
- *	(via HACR) instead of all interrupts in the processor (via cli),
- *	so that other driver are not impacted, and it look like it's
- *	possible, but it's very tricky to do right (full of races). As
- *	the gain would be mostly for SMP systems, it can wait...
- *
- * Debugging and options
- * ---------------------
- *	You will find below a set of '#define" allowing a very fine control
- *	on the driver behaviour and the debug messages printed.
- *	The main options are :
- *	o SET_PSA_CRC, to have your card correctly recognised by
- *	  an access point and the Point-to-Point diagnostic tool.
- *	o USE_PSA_CONFIG, to read configuration from the PSA (EEprom)
- *	  (otherwise we always start afresh with some defaults)
- *
- * wavelan.o is too darned big
- * ---------------------------
- *	That's true!  There is a very simple way to reduce the driver
- *	object by 33%!  Comment out the following line:
- *		#include <linux/wireless.h>
- *	Other compile options can also reduce the size of it...
- *
- * MAC address and hardware detection:
- * -----------------------------------
- *	The detection code for the WaveLAN checks that the first three
- *	octets of the MAC address fit the company code.  This type of
- *	detection works well for AT&T cards (because the AT&T code is
- *	hardcoded in wavelan.h), but of course will fail for other
- *	manufacturers.
- *
- *	If you are sure that your card is derived from the WaveLAN,
- *	here is the way to configure it:
- *	1) Get your MAC address
- *		a) With your card utilities (wfreqsel, instconf, etc.)
- *		b) With the driver:
- *			o compile the kernel with DEBUG_CONFIG_INFO enabled
- *			o Boot and look the card messages
- *	2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h)
- *	3) Compile and verify
- *	4) Send me the MAC code.  I will include it in the next version.
- *
- */
-
-/* --------------------- WIRELESS EXTENSIONS --------------------- */
-/*
- * This driver is the first to support "wireless extensions".
- * This set of extensions provides a standard way to control the wireless
- * characteristics of the hardware.  Applications such as mobile IP may
- * take advantage of it.
- *
- * You will need to enable the CONFIG_NET_RADIO define in the kernel
- * configuration to enable the wireless extensions (this is the one
- * giving access to the radio network device choice).
- *
- * It might also be a good idea as well to fetch the wireless tools to
- * configure the device and play a bit.
- */
-
-/* ---------------------------- FILES ---------------------------- */
-/*
- * wavelan.c:		actual code for the driver:  C functions
- *
- * wavelan.p.h:		private header:  local types and variables for driver
- *
- * wavelan.h:		description of the hardware interface and structs
- *
- * i82586.h:		description of the Ethernet controller
- */
-
-/* --------------------------- HISTORY --------------------------- */
-/*
- * This is based on information in the drivers' headers. It may not be
- * accurate, and I guarantee only my best effort.
- *
- * The history of the WaveLAN drivers is as complicated as the history of
- * the WaveLAN itself (NCR -> AT&T -> Lucent).
- *
- * It all started with Anders Klemets <klemets@paul.rutgers.edu>
- * writing a WaveLAN ISA driver for the Mach microkernel.  Girish
- * Welling <welling@paul.rutgers.edu> had also worked on it.
- * Keith Moore modified this for the PCMCIA hardware.
- * 
- * Robert Morris <rtm@das.harvard.edu> ported these two drivers to BSDI
- * and added specific PCMCIA support (there is currently no equivalent
- * of the PCMCIA package under BSD).
- *
- * Jim Binkley <jrb@cs.pdx.edu> ported both BSDI drivers to FreeBSD.
- *
- * Bruce Janson <bruce@cs.usyd.edu.au> ported the BSDI ISA driver to Linux.
- *
- * Anthony D. Joseph <adj@lcs.mit.edu> started to modify Bruce's driver
- * (with help of the BSDI PCMCIA driver) for PCMCIA.
- * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished this work.
- * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
- * 2.00 cards correctly (2.4 GHz with frequency selection).
- * David Hinds <dhinds@hyper.stanford.edu> integrated the whole in his
- * PCMCIA package (and bug corrections).
- *
- * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
- * patches to the PCMCIA driver.  Later, I added code in the ISA driver
- * for Wireless Extensions and full support of frequency selection
- * cards.  Then, I did the same to the PCMCIA driver, and did some
- * reorganisation.  Finally, I came back to the ISA driver to
- * upgrade it at the same level as the PCMCIA one and reorganise
- * the code.
- * Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me
- * much needed information on the WaveLAN hardware.
- */
-
-/* The original copyrights and literature mention others' names and
- * credits.  I don't know what their part in this development was.
- */
-
-/* By the way, for the copyright and legal stuff:
- * almost everybody wrote code under the GNU or BSD license (or similar),
- * and want their original copyright to remain somewhere in the
- * code (for myself, I go with the GPL).
- * Nobody wants to take responsibility for anything, except the fame.
- */
-
-/* --------------------------- CREDITS --------------------------- */
-/*
- * This software was developed as a component of the
- * Linux operating system.
- * It is based on other device drivers and information
- * either written or supplied by:
- *	Ajay Bakre <bakre@paul.rutgers.edu>,
- *	Donald Becker <becker@cesdis.gsfc.nasa.gov>,
- *	Loeke Brederveld <Loeke.Brederveld@Utrecht.NCR.com>,
- *	Brent Elphick <belphick@uwaterloo.ca>,
- *	Anders Klemets <klemets@it.kth.se>,
- *	Vladimir V. Kolpakov <w@stier.koenig.ru>,
- *	Marc Meertens <Marc.Meertens@Utrecht.NCR.com>,
- *	Pauline Middelink <middelin@polyware.iaf.nl>,
- *	Robert Morris <rtm@das.harvard.edu>,
- *	Jean Tourrilhes <jt@hpl.hp.com>,
- *	Girish Welling <welling@paul.rutgers.edu>,
- *	Clark Woodworth <clark@hiway1.exit109.com>
- *	Yongguang Zhang <ygz@isl.hrl.hac.com>
- *
- * Thanks go also to:
- *	James Ashton <jaa101@syseng.anu.edu.au>,
- *	Alan Cox <alan@redhat.com>,
- *	Allan Creighton <allanc@cs.usyd.edu.au>,
- *	Matthew Geier <matthew@cs.usyd.edu.au>,
- *	Remo di Giovanni <remo@cs.usyd.edu.au>,
- *	Eckhard Grah <grah@wrcs1.urz.uni-wuppertal.de>,
- *	Vipul Gupta <vgupta@cs.binghamton.edu>,
- *	Mark Hagan <mhagan@wtcpost.daytonoh.NCR.COM>,
- *	Tim Nicholson <tim@cs.usyd.edu.au>,
- *	Ian Parkin <ian@cs.usyd.edu.au>,
- *	John Rosenberg <johnr@cs.usyd.edu.au>,
- *	George Rossi <george@phm.gov.au>,
- *	Arthur Scott <arthur@cs.usyd.edu.au>,
- *	Stanislav Sinyagin <stas@isf.ru>
- *	and Peter Storey for their assistance and advice.
- *
- * Additional Credits:
- *
- *	My development has been done initially under Debian 1.1 (Linux 2.0.x)
- *	and now	under Debian 2.2, initially with an HP Vectra XP/60, and now
- *	an HP Vectra XP/90.
- *
- */
-
-/* ------------------------- IMPROVEMENTS ------------------------- */
-/*
- * I proudly present:
- *
- * Changes made in first pre-release:
- * ----------------------------------
- *	- reorganisation of the code, function name change
- *	- creation of private header (wavelan.p.h)
- *	- reorganised debug messages
- *	- more comments, history, etc.
- *	- mmc_init:  configure the PSA if not done
- *	- mmc_init:  correct default value of level threshold for PCMCIA
- *	- mmc_init:  2.00 detection better code for 2.00 initialization
- *	- better info at startup
- *	- IRQ setting (note:  this setting is permanent)
- *	- watchdog:  change strategy (and solve module removal problems)
- *	- add wireless extensions (ioctl and get_wireless_stats)
- *	  get/set nwid/frequency on fly, info for /proc/net/wireless
- *	- more wireless extensions:  SETSPY and GETSPY
- *	- make wireless extensions optional
- *	- private ioctl to set/get quality and level threshold, histogram
- *	- remove /proc/net/wavelan
- *	- suppress useless stuff from lp (net_local)
- *	- kernel 2.1 support (copy_to/from_user instead of memcpy_to/fromfs)
- *	- add message level (debug stuff in /var/adm/debug and errors not
- *	  displayed at console and still in /var/adm/messages)
- *	- multi device support
- *	- start fixing the probe (init code)
- *	- more inlines
- *	- man page
- *	- many other minor details and cleanups
- *
- * Changes made in second pre-release:
- * -----------------------------------
- *	- clean up init code (probe and module init)
- *	- better multiple device support (module)
- *	- name assignment (module)
- *
- * Changes made in third pre-release:
- * ----------------------------------
- *	- be more conservative on timers
- *	- preliminary support for multicast (I still lack some details)
- *
- * Changes made in fourth pre-release:
- * -----------------------------------
- *	- multicast (revisited and finished)
- *	- avoid reset in set_multicast_list (a really big hack)
- *	  if somebody could apply this code for other i82586 based drivers
- *	- share onboard memory 75% RU and 25% CU (instead of 50/50)
- *
- * Changes made for release in 2.1.15:
- * -----------------------------------
- *	- change the detection code for multi manufacturer code support
- *
- * Changes made for release in 2.1.17:
- * -----------------------------------
- *	- update to wireless extensions changes
- *	- silly bug in card initial configuration (psa_conf_status)
- *
- * Changes made for release in 2.1.27 & 2.0.30:
- * --------------------------------------------
- *	- small bug in debug code (probably not the last one...)
- *	- remove extern keyword for wavelan_probe()
- *	- level threshold is now a standard wireless extension (version 4 !)
- *	- modules parameters types (new module interface)
- *
- * Changes made for release in 2.1.36:
- * -----------------------------------
- *	- byte count stats (courtesy of David Hinds)
- *	- remove dev_tint stuff (courtesy of David Hinds)
- *	- encryption setting from Brent Elphick (thanks a lot!)
- *	- 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin)
- *
- * Other changes (not by me) :
- * -------------------------
- *	- Spelling and gramar "rectification".
- *
- * Changes made for release in 2.0.37 & 2.2.2 :
- * ------------------------------------------
- *	- Correct status in /proc/net/wireless
- *	- Set PSA CRC to make PtP diagnostic tool happy (Bob Gray)
- *	- Module init code don't fail if we found at least one card in
- *	  the address list (Karlis Peisenieks)
- *	- Missing parenthesis (Christopher Peterson)
- *	- Correct i82586 configuration parameters
- *	- Encryption initialisation bug (Robert McCormack)
- *	- New mac addresses detected in the probe
- *	- Increase watchdog for busy environments
- *
- * Changes made for release in 2.0.38 & 2.2.7 :
- * ------------------------------------------
- *	- Correct the reception logic to better report errors and avoid
- *	  sending bogus packet up the stack
- *	- Delay RU config to avoid corrupting first received packet
- *	- Change config completion code (to actually check something)
- *	- Avoid reading out of bound in skbuf to transmit
- *	- Rectify a lot of (useless) debugging code
- *	- Change the way to `#ifdef SET_PSA_CRC'
- *
- * Changes made for release in 2.2.11 & 2.3.13 :
- * -------------------------------------------
- *	- Change e-mail and web page addresses
- *	- Watchdog timer is now correctly expressed in HZ, not in jiffies
- *	- Add channel number to the list of frequencies in range
- *	- Add the (short) list of bit-rates in range
- *	- Developp a new sensitivity... (sens.value & sens.fixed)
- *
- * Changes made for release in 2.2.14 & 2.3.23 :
- * -------------------------------------------
- *	- Fix check for root permission (break instead of exit)
- *	- New nwid & encoding setting (Wireless Extension 9)
- *
- * Changes made for release in 2.3.49 :
- * ----------------------------------
- *	- Indentation reformating (Alan)
- *	- Update to new network API (softnet - 2.3.43) :
- *		o replace dev->tbusy (Alan)
- *		o replace dev->tstart (Alan)
- *		o remove dev->interrupt (Alan)
- *		o add SMP locking via spinlock in splxx (me)
- *		o add spinlock in interrupt handler (me)
- *		o use kernel watchdog instead of ours (me)
- *		o increase watchdog timeout (kernel is more sensitive) (me)
- *		o verify that all the changes make sense and work (me)
- *	- Fixup a potential gotcha when reconfiguring and thighten a bit
- *		the interactions with Tx queue.
- *
- * Changes made for release in 2.4.0 :
- * ---------------------------------
- *	- Fix spinlock stupid bugs that I left in. The driver is now SMP
- *		compliant and doesn't lockup at startup.
- *
- * Wishes & dreams:
- * ----------------
- *	- roaming (see Pcmcia driver)
- */
-
-/***************************** INCLUDES *****************************/
-
-#include	<linux/module.h>
-
-#include	<linux/kernel.h>
-#include	<linux/sched.h>
-#include	<linux/types.h>
-#include	<linux/fcntl.h>
-#include	<linux/interrupt.h>
-#include	<linux/stat.h>
-#include	<linux/ptrace.h>
-#include	<linux/ioport.h>
-#include	<linux/in.h>
-#include	<linux/string.h>
-#include	<linux/delay.h>
-#include	<asm/system.h>
-#include	<asm/bitops.h>
-#include	<asm/io.h>
-#include	<asm/dma.h>
-#include	<asm/uaccess.h>
-#include	<linux/errno.h>
-#include	<linux/netdevice.h>
-#include	<linux/etherdevice.h>
-#include	<linux/skbuff.h>
-#include	<linux/slab.h>
-#include	<linux/timer.h>
-#include	<linux/init.h>
-
-#include <linux/wireless.h>		/* Wireless extensions */
-
-/* WaveLAN declarations */
-#include	"i82586.h"
-#include	"wavelan.h"
-
-/************************** DRIVER OPTIONS **************************/
-/*
- * `#define' or `#undef' the following constant to change the behaviour
- * of the driver...
- */
-#undef SET_PSA_CRC		/* Calculate and set the CRC on PSA (slower) */
-#define USE_PSA_CONFIG		/* Use info from the PSA. */
-#undef STRUCT_CHECK		/* Verify padding of structures. */
-#undef EEPROM_IS_PROTECTED	/* doesn't seem to be necessary */
-#define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical). */
-#undef SET_MAC_ADDRESS		/* Experimental */
-
-#ifdef WIRELESS_EXT	/* If wireless extensions exist in the kernel */
-/* Warning:  this stuff will slow down the driver. */
-#define WIRELESS_SPY		/* Enable spying addresses. */
-#undef HISTOGRAM		/* Enable histogram of signal level. */
-#endif
-
-/****************************** DEBUG ******************************/
-
-#undef DEBUG_MODULE_TRACE	/* module insertion/removal */
-#undef DEBUG_CALLBACK_TRACE	/* calls made by Linux */
-#undef DEBUG_INTERRUPT_TRACE	/* calls to handler */
-#undef DEBUG_INTERRUPT_INFO	/* type of interrupt and so on */
-#define DEBUG_INTERRUPT_ERROR	/* problems */
-#undef DEBUG_CONFIG_TRACE	/* Trace the config functions. */
-#undef DEBUG_CONFIG_INFO	/* what's going on */
-#define DEBUG_CONFIG_ERROR	/* errors on configuration */
-#undef DEBUG_TX_TRACE		/* transmission calls */
-#undef DEBUG_TX_INFO		/* header of the transmitted packet */
-#undef DEBUG_TX_FAIL		/* Normal failure conditions */
-#define DEBUG_TX_ERROR		/* Unexpected conditions */
-#undef DEBUG_RX_TRACE		/* transmission calls */
-#undef DEBUG_RX_INFO		/* header of the received packet */
-#undef DEBUG_RX_FAIL		/* Normal failure conditions */
-#define DEBUG_RX_ERROR		/* Unexpected conditions */
-
-#undef DEBUG_PACKET_DUMP	/* Dump packet on the screen if defined to 32. */
-#undef DEBUG_IOCTL_TRACE	/* misc. call by Linux */
-#undef DEBUG_IOCTL_INFO		/* various debugging info */
-#define DEBUG_IOCTL_ERROR	/* what's going wrong */
-#define DEBUG_BASIC_SHOW	/* Show basic startup info. */
-#undef DEBUG_VERSION_SHOW	/* Print version info. */
-#undef DEBUG_PSA_SHOW		/* Dump PSA to screen. */
-#undef DEBUG_MMC_SHOW		/* Dump mmc to screen. */
-#undef DEBUG_SHOW_UNUSED	/* Show unused fields too. */
-#undef DEBUG_I82586_SHOW	/* Show i82586 status. */
-#undef DEBUG_DEVICE_SHOW	/* Show device parameters. */
-
-/************************ CONSTANTS & MACROS ************************/
-
-#ifdef DEBUG_VERSION_SHOW
-static const char	*version	= "wavelan.c : v23 (SMP + wireless extensions) 05/10/00\n";
-#endif
-
-/* Watchdog temporisation */
-#define	WATCHDOG_JIFFIES	(512*HZ/100)
-
-/* Macro to get the number of elements in an array */
-#define	NELS(a)				(sizeof(a) / sizeof(a[0]))
-
-/* ------------------------ PRIVATE IOCTL ------------------------ */
-
-#define SIOCSIPQTHR	SIOCIWFIRSTPRIV		/* Set quality threshold */
-#define SIOCGIPQTHR	SIOCIWFIRSTPRIV + 1	/* Get quality threshold */
-#define SIOCSIPLTHR	SIOCIWFIRSTPRIV + 2	/* Set level threshold */
-#define SIOCGIPLTHR	SIOCIWFIRSTPRIV + 3	/* Get level threshold */
-
-#define SIOCSIPHISTO	SIOCIWFIRSTPRIV + 6	/* Set histogram ranges */
-#define SIOCGIPHISTO	SIOCIWFIRSTPRIV + 7	/* Get histogram values */
-
-/****************************** TYPES ******************************/
-
-/* Shortcuts */
-typedef struct net_device		device;
-typedef struct net_device_stats	en_stats;
-typedef struct iw_statistics	iw_stats;
-typedef struct iw_quality	iw_qual;
-typedef struct iw_freq		iw_freq;
-typedef struct net_local	net_local;
-typedef struct timer_list	timer_list;
-
-/* Basic types */
-typedef u_char		mac_addr[WAVELAN_ADDR_SIZE];	/* Hardware address */
-
-/*
- * Static specific data for the interface.
- *
- * For each network interface, Linux keeps data in two structures:  "device"
- * keeps the generic data (same format for everybody) and "net_local" keeps
- * additional specific data.
- * Note that some of this specific data is in fact generic (en_stats, for
- * example).
- */
-struct net_local
-{
-  net_local *	next;		/* linked list of the devices */
-  device *	dev;		/* reverse link */
-  spinlock_t	spinlock;	/* Serialize access to the hardware (SMP) */
-  en_stats	stats;		/* Ethernet interface statistics */
-  int		nresets;	/* number of hardware resets */
-  u_char	reconfig_82586;	/* We need to reconfigure the controller. */
-  u_char	promiscuous;	/* promiscuous mode */
-  int		mc_count;	/* number of multicast addresses */
-  u_short	hacr;		/* current host interface state */
-
-  int		tx_n_in_use;
-  u_short	rx_head;
-  u_short	rx_last;
-  u_short	tx_first_free;
-  u_short	tx_first_in_use;
-
-#ifdef WIRELESS_EXT
-  iw_stats	wstats;		/* Wireless-specific statistics */
-#endif
-
-#ifdef WIRELESS_SPY
-  int		spy_number;			/* number of addresses to spy */
-  mac_addr	spy_address[IW_MAX_SPY];	/* the addresses to spy */
-  iw_qual	spy_stat[IW_MAX_SPY];		/* statistics gathered */
-#endif	/* WIRELESS_SPY */
-
-#ifdef HISTOGRAM
-  int		his_number;		/* number of intervals */
-  u_char	his_range[16];		/* boundaries of interval ]n-1; n] */
-  u_long	his_sum[16];		/* sum in interval */
-#endif	/* HISTOGRAM */
-};
-
-/**************************** PROTOTYPES ****************************/
-
-/* ----------------------- MISC. SUBROUTINES ------------------------ */
-static inline void
-	wv_splhi(net_local *,		/* Disable interrupts, lock driver */
-		 unsigned long *);	/* flags */
-static inline void
-	wv_splx(net_local *,		/* Enable interrupts, unlock driver */
-		unsigned long *);	/* flags */
-static u_char
-	wv_irq_to_psa(int);
-static int
-	wv_psa_to_irq(u_char);
-/* ------------------- HOST ADAPTER SUBROUTINES ------------------- */
-static inline u_short		/* data */
-	hasr_read(u_long);	/* Read the host interface:  base address */
-static inline void
-	hacr_write(u_long,	/* Write to host interface:  base address */
-		   u_short),	/* data */
-	hacr_write_slow(u_long,
-		   u_short),
-	set_chan_attn(u_long,	/* ioaddr */
-		      u_short),	/* hacr   */
-	wv_hacr_reset(u_long),	/* ioaddr */
-	wv_16_off(u_long,	/* ioaddr */
-		  u_short),	/* hacr   */
-	wv_16_on(u_long,	/* ioaddr */
-		 u_short),	/* hacr   */
-	wv_ints_off(device *),
-	wv_ints_on(device *);
-/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
-static void
-	psa_read(u_long,	/* Read the Parameter Storage Area. */
-		 u_short,	/* hacr */
-		 int,		/* offset in PSA */
-		 u_char *,	/* buffer to fill */
-		 int),		/* size to read */
-	psa_write(u_long, 	/* Write to the PSA. */
-		  u_short,	/* hacr */
-		  int,		/* offset in PSA */
-		  u_char *,	/* buffer in memory */
-		  int);		/* length of buffer */
-static inline void
-	mmc_out(u_long,		/* Write 1 byte to the Modem Manag Control. */
-		u_short,
-		u_char),
-	mmc_write(u_long,	/* Write n bytes to the MMC. */
-		  u_char,
-		  u_char *,
-		  int);
-static inline u_char		/* Read 1 byte from the MMC. */
-	mmc_in(u_long,
-	       u_short);
-static inline void
-	mmc_read(u_long,	/* Read n bytes from the MMC. */
-		 u_char,
-		 u_char *,
-		 int),
-	fee_wait(u_long,	/* Wait for frequency EEPROM:  base address */
-		 int,		/* base delay to wait for */
-		 int);		/* time to wait */
-static void
-	fee_read(u_long,	/* Read the frequency EEPROM:  base address */
-		 u_short,	/* destination offset */
-		 u_short *,	/* data buffer */
-		 int);		/* number of registers */
-/* ---------------------- I82586 SUBROUTINES ----------------------- */
-static /*inline*/ void
-	obram_read(u_long,	/* ioaddr */
-		   u_short,	/* o */
-		   u_char *,	/* b */
-		   int);	/* n */
-static inline void
-	obram_write(u_long,	/* ioaddr */
-		    u_short,	/* o */
-		    u_char *,	/* b */
-		    int);	/* n */
-static void
-	wv_ack(device *);
-static inline int
-	wv_synchronous_cmd(device *,
-			   const char *),
-	wv_config_complete(device *,
-			   u_long,
-			   net_local *);
-static int
-	wv_complete(device *,
-		    u_long,
-		    net_local *);
-static inline void
-	wv_82586_reconfig(device *);
-/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */
-#ifdef DEBUG_I82586_SHOW
-static void
-	wv_scb_show(unsigned short);
-#endif
-static inline void
-	wv_init_info(device *);	/* display startup info */
-/* ------------------- IOCTL, STATS & RECONFIG ------------------- */
-static en_stats	*
-	wavelan_get_stats(device *);	/* Give stats /proc/net/dev */
-static void
-	wavelan_set_multicast_list(device *);
-/* ----------------------- PACKET RECEPTION ----------------------- */
-static inline void
-	wv_packet_read(device *,	/* Read a packet from a frame. */
-		       u_short,
-		       int),
-	wv_receive(device *);	/* Read all packets waiting. */
-/* --------------------- PACKET TRANSMISSION --------------------- */
-static inline int
-	wv_packet_write(device *,	/* Write a packet to the Tx buffer. */
-			void *,
-			short);
-static int
-	wavelan_packet_xmit(struct sk_buff *,	/* Send a packet. */
-			    device *);
-/* -------------------- HARDWARE CONFIGURATION -------------------- */
-static inline int
-	wv_mmc_init(device *),		/* Initialize the modem. */
-	wv_ru_start(device *),		/* Start the i82586 receiver unit. */
-	wv_cu_start(device *),		/* Start the i82586 command unit. */
-	wv_82586_start(device *);	/* Start the i82586. */
-static void
-	wv_82586_config(device *);	/* Configure the i82586. */
-static inline void
-	wv_82586_stop(device *);
-static int
-	wv_hw_reset(device *),		/* Reset the WaveLAN hardware. */
-	wv_check_ioaddr(u_long,		/* ioaddr */
-			u_char *);	/* mac address (read) */
-/* ---------------------- INTERRUPT HANDLING ---------------------- */
-static void
-	wavelan_interrupt(int,		/* interrupt handler */
-			  void *,
-			  struct pt_regs *);
-static void
-	wavelan_watchdog(device *);	/* transmission watchdog */
-/* ------------------- CONFIGURATION CALLBACKS ------------------- */
-static int
-	wavelan_open(device *),		/* Open the device. */
-	wavelan_close(device *),	/* Close the device. */
-	wavelan_config(device *);	/* Configure one device. */
-extern int
-	wavelan_probe(device *);	/* See Space.c. */
-
-/**************************** VARIABLES ****************************/
-
-/*
- * This is the root of the linked list of WaveLAN drivers
- * It is use to verify that we don't reuse the same base address
- * for two different drivers and to clean up when removing the module.
- */
-static net_local *	wavelan_list	= (net_local *) NULL;
-
-/*
- * This table is used to translate the PSA value to IRQ number
- * and vice versa.
- */
-static u_char	irqvals[]	=
-{
-	   0,    0,    0, 0x01,
-	0x02, 0x04,    0, 0x08,
-	   0,    0, 0x10, 0x20,
-	0x40,    0,    0, 0x80,
-};
-
-/*
- * Table of the available I/O addresses (base addresses) for WaveLAN
- */
-static unsigned short	iobase[]	=
-{
-#if	0
-  /* Leave out 0x3C0 for now -- seems to clash with some video
-   * controllers.
-   * Leave out the others too -- we will always use 0x390 and leave
-   * 0x300 for the Ethernet device.
-   * Jean II:  0x3E0 is fine as well.
-   */
-  0x300, 0x390, 0x3E0, 0x3C0
-#endif	/* 0 */
-  0x390, 0x3E0
-};
-
-#ifdef	MODULE
-/* Parameters set by insmod */
-static int	io[4];
-static int	irq[4];
-static char	name[4][IFNAMSIZ];
-MODULE_PARM(io, "1-4i");
-MODULE_PARM(irq, "1-4i");
-MODULE_PARM(name, "1-4c" __MODULE_STRING(IFNAMSIZ));
-MODULE_PARM_DESC(io, "WaveLAN I/O base address(es),required");
-MODULE_PARM_DESC(irq, "WaveLAN IRQ number(s)");
-MODULE_PARM_DESC(name, "WaveLAN interface neme(s)");
-#endif	/* MODULE */
-
-#endif	/* WAVELAN_P_H */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/Config.help linux/drivers/net/wireless/Config.help
--- v2.5.2/linux/drivers/net/wireless/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/Config.help	Fri Jan 25 16:03:42 2002
@@ -0,0 +1,133 @@
+CONFIG_WAVELAN
+  The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is
+  a Radio LAN (wireless Ethernet-like Local Area Network) using the
+  radio frequencies 900 MHz and 2.4 GHz.
+
+  This driver support the ISA version of the WaveLAN card.  A separate
+  driver for the PCMCIA (PC-card) hardware is available in David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).
+
+  If you want to use an ISA WaveLAN card under Linux, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. Some more specific
+  information is contained in
+  <file:Documentation/networking/wavelan.txt> and in the source code
+  <file:drivers/net/wavelan.p.h>.
+
+  You will also need the wireless tools package available from
+  <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+  Please read the man pages contained therein.
+
+  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 wavelan.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_HERMES
+  A driver for 802.11b wireless cards based based on the "Hermes" or
+  Intersil HFA384x (Prism 2) MAC controller.  This includes the vast
+  majority of the PCMCIA 802.11b cards (which are nearly all rebadges)
+  - except for the Cisco/Aironet cards.  Cards supported include the
+  Apple Airport (not a PCMCIA card), WavelanIEEE/Orinoco,
+  Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya,
+  IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear
+  MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel
+  PRO/Wireless, and Symbol Spectrum24 High Rate amongst others.
+
+  This option includes the guts of the driver, but in order to
+  actually use a card you will also need to enable support for PCMCIA
+  Hermes cards, PLX9052 based PCI adaptors or the Apple Airport below.
+
+  You will also very likely also need the Wireless Tools in order to
+  configure your card and that /etc/pcmcia/wireless.opts works :
+  <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
+
+CONFIG_PLX_HERMES
+  Enable support for PCMCIA cards supported by the "Hermes" (aka
+  orinoco_cs) driver when used in PLX9052 based PCI adaptors.  These
+  adaptors are not a full PCMCIA controller but act as a more limited
+  PCI <-> PCMCIA bridge.  Several vendors sell such adaptors so that
+  802.11b PCMCIA cards can be used in desktop machines.  The Netgear
+  MA301 is such an adaptor.
+
+  Support for these adaptors is so far still incomplete and buggy.
+  You have been warned.
+
+CONFIG_PCMCIA_HERMES
+  A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
+  as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
+  EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and
+  others).  It should also be usable on various Prism II based cards
+  such as the Linksys, D-Link and Farallon Skyline.  It should also
+  work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  You also want to check out the PCMCIA-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  You will also very likely also need the Wireless Tools in order to
+  configure your card and that /etc/pcmcia/wireless.opts works:
+  <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+
+CONFIG_AIRO
+  This is the standard Linux driver to support Cisco/Aironet ISA and
+  PCI 802.11 wireless cards.
+  It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X
+  - with or without encryption) as well as card before the Cisco
+  aquisition (Aironet 4500, Aironet 4800, Aironet 4800B).
+
+  This driver support both the standard Linux Wireless Extensions
+  and Cisco proprietary API, so both the Linux Wireless Tools and the
+  Cisco Linux utilities can be used to configure the card.
+
+  The driver can be compiled as a module and will be named "airo.o".
+
+CONFIG_AIRO_CS
+  This is the standard Linux driver to support Cisco/Aironet PCMCIA
+  802.11 wireless cards.  This driver is the same as the Aironet
+  driver part of the Linux Pcmcia package.
+  It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X
+  - with or without encryption) as well as card before the Cisco
+  aquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also
+  supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom
+  802.11b cards.
+
+  This driver support both the standard Linux Wireless Extensions
+  and Cisco proprietary API, so both the Linux Wireless Tools and the
+  Cisco Linux utilities can be used to configure the card.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  You also want to check out the PCMCIA-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+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. This is essentially a Lucent Orinoco card with 
+  a non-standard interface
+
+CONFIG_PCMCIA_NETWAVE
+  Say Y here if you intend to attach this type of PCMCIA (PC-card)
+  wireless Ethernet networking card to your computer.
+
+  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 netwave_cs.o.  If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+  If unsure, say N.
+
+CONFIG_PCMCIA_WAVELAN
+  Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA
+  (PC-card) wireless Ethernet networking card to your computer.  This
+  driver is for the non-IEEE-802.11 Wavelan cards.
+
+  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 wavelan_cs.o.  If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+  If unsure, say N.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/Config.in linux/drivers/net/wireless/Config.in
--- v2.5.2/linux/drivers/net/wireless/Config.in	Tue Oct  9 15:13:03 2001
+++ linux/drivers/net/wireless/Config.in	Mon Jan 21 16:04:47 2002
@@ -2,6 +2,12 @@
 # Wireless LAN device configuration
 #
 
+comment 'Wireless ISA/PCI cards support' 
+
+# Good old obsolete Wavelan.
+tristate '  AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support' CONFIG_WAVELAN
+
+# 802.11b cards
 if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
    tristate '  Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards' CONFIG_AIRO
 fi
@@ -18,8 +24,13 @@
 
 # If Pcmcia is compiled in, offer Pcmcia cards...
 if [ "$CONFIG_PCMCIA" != "n" ]; then
-   comment 'Wireless Pcmcia cards support' 
+   comment 'Wireless Pcmcia/Cardbus cards support' 
+
+# Obsolete cards
+   dep_tristate '  Xircom Netwave AirSurfer Pcmcia wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA
+   dep_tristate '  AT&T/Lucent old Wavelan Pcmcia wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA
 
+# 802.11b cards
    dep_tristate '  Hermes PCMCIA card support' CONFIG_PCMCIA_HERMES $CONFIG_HERMES
    tristate '  Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards' CONFIG_AIRO_CS
 fi
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/Makefile linux/drivers/net/wireless/Makefile
--- v2.5.2/linux/drivers/net/wireless/Makefile	Tue Oct  9 15:13:03 2001
+++ linux/drivers/net/wireless/Makefile	Mon Jan 21 16:04:47 2002
@@ -14,6 +14,11 @@
 # Things that need to export symbols
 export-objs	:= airo.o orinoco.o hermes.o
 
+# Obsolete cards
+obj-$(CONFIG_WAVELAN)		+= wavelan.o
+obj-$(CONFIG_PCMCIA_NETWAVE)	+= netwave_cs.o
+obj-$(CONFIG_PCMCIA_WAVELAN)	+= wavelan_cs.o
+
 obj-$(CONFIG_HERMES)		+= orinoco.o hermes.o
 obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o
 obj-$(CONFIG_APPLE_AIRPORT)	+= airport.o
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/i82586.h linux/drivers/net/wireless/i82586.h
--- v2.5.2/linux/drivers/net/wireless/i82586.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/i82586.h	Tue Feb 13 13:15:05 2001
@@ -0,0 +1,413 @@
+/*
+ * Intel 82586 IEEE 802.3 Ethernet LAN Coprocessor.
+ *
+ * See:
+ *	Intel Microcommunications 1991
+ *	p1-1 to p1-37
+ *	Intel order No. 231658
+ *	ISBN 1-55512-119-5
+ *
+ *     Unfortunately, the above chapter mentions neither
+ * the System Configuration Pointer (SCP) nor the
+ * Intermediate System Configuration Pointer (ISCP),
+ * so we probably need to look elsewhere for the
+ * whole story -- some recommend the "Intel LAN
+ * Components manual" but I have neither a copy
+ * nor a full reference.  But "elsewhere" may be
+ * in the same publication...
+ *     The description of a later device, the
+ * "82596CA High-Performance 32-Bit Local Area Network
+ * Coprocessor", (ibid. p1-38 to p1-109) does mention
+ * the SCP and ISCP and also has an i82586 compatibility
+ * mode.  Even more useful is "AP-235 An 82586 Data Link
+ * Driver" (ibid. p1-337 to p1-417).
+ */
+
+#define	I82586_MEMZ	(64 * 1024)
+
+#define	I82586_SCP_ADDR	(I82586_MEMZ - sizeof(scp_t))
+
+#define	ADDR_LEN	6
+#define	I82586NULL	0xFFFF
+
+#define	toff(t,p,f) 	(unsigned short)((void *)(&((t *)((void *)0 + (p)))->f) - (void *)0)
+
+/*
+ * System Configuration Pointer (SCP).
+ */
+typedef struct scp_t	scp_t;
+struct scp_t
+{
+	unsigned short	scp_sysbus;	/* 82586 bus width:	*/
+#define		SCP_SY_16BBUS	(0x0 << 0)	/* 16 bits */
+#define		SCP_SY_8BBUS	(0x1 << 0)	/*  8 bits. */
+	unsigned short	scp_junk[2];	/* Unused */
+	unsigned short	scp_iscpl;	/* lower 16 bits of ISCP_ADDR */
+	unsigned short	scp_iscph;	/* upper 16 bits of ISCP_ADDR */
+};
+
+/*
+ * Intermediate System Configuration Pointer (ISCP).
+ */
+typedef struct iscp_t	iscp_t;
+struct iscp_t
+{
+	unsigned short	iscp_busy;	/* set by CPU before first CA,	*/
+					/* cleared by 82586 after read.	*/
+	unsigned short	iscp_offset;	/* offset of SCB		*/
+	unsigned short	iscp_basel;	/* base of SCB			*/
+	unsigned short	iscp_baseh;	/*  "				*/
+};
+
+/*
+ * System Control Block (SCB).
+ *	The 82586 writes its status to scb_status and then
+ *	raises an interrupt to alert the CPU.
+ *	The CPU writes a command to scb_command and
+ *	then issues a Channel Attention (CA) to alert the 82586.
+ */
+typedef struct scb_t	scb_t;
+struct scb_t
+{
+	unsigned short	scb_status;	/* Status of 82586		*/
+#define		SCB_ST_INT	(0xF << 12)	/* Some of:		*/
+#define		SCB_ST_CX	(0x1 << 15)	/* Cmd completed	*/
+#define		SCB_ST_FR	(0x1 << 14)	/* Frame received	*/
+#define		SCB_ST_CNA	(0x1 << 13)	/* Cmd unit not active	*/
+#define		SCB_ST_RNR	(0x1 << 12)	/* Rcv unit not ready	*/
+#define		SCB_ST_JUNK0	(0x1 << 11)	/* 0			*/
+#define		SCB_ST_CUS	(0x7 <<  8)	/* Cmd unit status	*/
+#define			SCB_ST_CUS_IDLE	(0 << 8)	/* Idle		*/
+#define			SCB_ST_CUS_SUSP	(1 << 8)	/* Suspended	*/
+#define			SCB_ST_CUS_ACTV	(2 << 8)	/* Active	*/
+#define		SCB_ST_JUNK1	(0x1 <<  7)	/* 0			*/
+#define		SCB_ST_RUS	(0x7 <<  4)	/* Rcv unit status	*/
+#define			SCB_ST_RUS_IDLE	(0 << 4)	/* Idle		*/
+#define			SCB_ST_RUS_SUSP	(1 << 4)	/* Suspended	*/
+#define			SCB_ST_RUS_NRES	(2 << 4)	/* No resources	*/
+#define			SCB_ST_RUS_RDY	(4 << 4)	/* Ready	*/
+	unsigned short	scb_command;	/* Next command			*/
+#define		SCB_CMD_ACK_CX	(0x1 << 15)	/* Ack cmd completion	*/
+#define		SCB_CMD_ACK_FR	(0x1 << 14)	/* Ack frame received	*/
+#define		SCB_CMD_ACK_CNA	(0x1 << 13)	/* Ack CU not active	*/
+#define		SCB_CMD_ACK_RNR	(0x1 << 12)	/* Ack RU not ready	*/
+#define		SCB_CMD_JUNKX	(0x1 << 11)	/* Unused		*/
+#define		SCB_CMD_CUC	(0x7 <<  8)	/* Command Unit command	*/
+#define			SCB_CMD_CUC_NOP	(0 << 8)	/* Nop		*/
+#define			SCB_CMD_CUC_GO	(1 << 8)	/* Start cbl_offset */
+#define			SCB_CMD_CUC_RES	(2 << 8)	/* Resume execution */
+#define			SCB_CMD_CUC_SUS	(3 << 8)	/* Suspend   "	*/
+#define			SCB_CMD_CUC_ABT	(4 << 8)	/* Abort     "	*/
+#define		SCB_CMD_RESET	(0x1 <<  7)	/* Reset chip (hardware) */
+#define		SCB_CMD_RUC	(0x7 <<  4)	/* Receive Unit command	*/
+#define			SCB_CMD_RUC_NOP	(0 << 4)	/* Nop		*/
+#define			SCB_CMD_RUC_GO	(1 << 4)	/* Start rfa_offset */
+#define			SCB_CMD_RUC_RES	(2 << 4)	/* Resume reception */
+#define			SCB_CMD_RUC_SUS	(3 << 4)	/* Suspend   "	*/
+#define			SCB_CMD_RUC_ABT	(4 << 4)	/* Abort     "	*/
+	unsigned short	scb_cbl_offset;	/* Offset of first command unit	*/
+					/* Action Command		*/
+	unsigned short	scb_rfa_offset;	/* Offset of first Receive	*/
+					/* Frame Descriptor in the	*/
+					/* Receive Frame Area		*/
+	unsigned short	scb_crcerrs;	/* Properly aligned frames	*/
+					/* received with a CRC error	*/
+	unsigned short	scb_alnerrs;	/* Misaligned frames received	*/
+					/* with a CRC error		*/
+	unsigned short	scb_rscerrs;	/* Frames lost due to no space	*/
+	unsigned short	scb_ovrnerrs;	/* Frames lost due to slow bus	*/
+};
+
+#define	scboff(p,f) 	toff(scb_t, p, f)
+
+/*
+ * The eight Action Commands.
+ */
+typedef enum acmd_e	acmd_e;
+enum acmd_e
+{
+	acmd_nop	= 0,	/* Do nothing				*/
+	acmd_ia_setup	= 1,	/* Load an (ethernet) address into the	*/
+				/* 82586				*/
+	acmd_configure	= 2,	/* Update the 82586 operating parameters */
+	acmd_mc_setup	= 3,	/* Load a list of (ethernet) multicast	*/
+				/* addresses into the 82586		*/
+	acmd_transmit	= 4,	/* Transmit a frame			*/
+	acmd_tdr	= 5,	/* Perform a Time Domain Reflectometer	*/
+				/* test on the serial link		*/
+	acmd_dump	= 6,	/* Copy 82586 registers to memory	*/
+	acmd_diagnose	= 7,	/* Run an internal self test		*/
+};
+
+/*
+ * Generic Action Command header.
+ */
+typedef struct ach_t	ach_t;
+struct ach_t
+{
+	unsigned short	ac_status;		/* Command status:	*/
+#define		AC_SFLD_C	(0x1 << 15)	/* Command completed	*/
+#define		AC_SFLD_B	(0x1 << 14)	/* Busy executing	*/
+#define		AC_SFLD_OK	(0x1 << 13)	/* Completed error free	*/
+#define		AC_SFLD_A	(0x1 << 12)	/* Command aborted	*/
+#define		AC_SFLD_FAIL	(0x1 << 11)	/* Selftest failed	*/
+#define		AC_SFLD_S10	(0x1 << 10)	/* No carrier sense	*/
+						/* during transmission	*/
+#define		AC_SFLD_S9	(0x1 <<  9)	/* Tx unsuccessful:	*/
+						/* (stopped) lost CTS	*/
+#define		AC_SFLD_S8	(0x1 <<  8)	/* Tx unsuccessful:	*/
+						/* (stopped) slow DMA	*/
+#define		AC_SFLD_S7	(0x1 <<  7)	/* Tx deferred:		*/
+						/* other link traffic	*/
+#define		AC_SFLD_S6	(0x1 <<  6)	/* Heart Beat: collision */
+						/* detect after last tx	*/
+#define		AC_SFLD_S5	(0x1 <<  5)	/* Tx stopped:		*/
+						/* excessive collisions	*/
+#define		AC_SFLD_MAXCOL	(0xF <<  0)	/* Collision count  	*/
+	unsigned short	ac_command;		/* Command specifier:	*/
+#define		AC_CFLD_EL	(0x1 << 15)	/* End of command list	*/
+#define		AC_CFLD_S	(0x1 << 14)	/* Suspend on completion */
+#define		AC_CFLD_I	(0x1 << 13)	/* Interrupt on completion */
+#define		AC_CFLD_CMD	(0x7 <<  0)	/* acmd_e		*/
+	unsigned short	ac_link;		/* Next Action Command	*/
+};
+
+#define	acoff(p,f) 	toff(ach_t, p, f)
+
+/*
+ * The Nop Action Command.
+ */
+typedef struct ac_nop_t	ac_nop_t;
+struct ac_nop_t
+{
+	ach_t	nop_h;
+};
+
+/*
+ * The IA-Setup Action Command.
+ */
+typedef struct ac_ias_t	ac_ias_t;
+struct ac_ias_t
+{
+	ach_t		ias_h;
+	unsigned char	ias_addr[ADDR_LEN]; /* The (ethernet) address	*/
+};
+
+/*
+ * The Configure Action Command.
+ */
+typedef struct ac_cfg_t	ac_cfg_t;
+struct ac_cfg_t
+{
+	ach_t		cfg_h;
+	unsigned char	cfg_byte_cnt;	/* Size foll data: 4-12	*/
+#define	AC_CFG_BYTE_CNT(v)	(((v) & 0xF) << 0)
+	unsigned char	cfg_fifolim;	/* FIFO threshold	*/
+#define	AC_CFG_FIFOLIM(v)	(((v) & 0xF) << 0)
+	unsigned char	cfg_byte8;
+#define	AC_CFG_SAV_BF(v) 	(((v) & 0x1) << 7)	/* Save rxd bad frames	*/
+#define	AC_CFG_SRDY(v) 		(((v) & 0x1) << 6)	/* SRDY/ARDY pin means	*/
+							/* external sync.	*/
+	unsigned char	cfg_byte9;
+#define	AC_CFG_ELPBCK(v)	(((v) & 0x1) << 7)	/* External loopback	*/
+#define	AC_CFG_ILPBCK(v)	(((v) & 0x1) << 6)	/* Internal loopback	*/
+#define	AC_CFG_PRELEN(v)	(((v) & 0x3) << 4)	/* Preamble length	*/
+#define		AC_CFG_PLEN_2		0		/*  2 bytes	*/
+#define		AC_CFG_PLEN_4		1		/*  4 bytes	*/
+#define		AC_CFG_PLEN_8		2		/*  8 bytes	*/
+#define		AC_CFG_PLEN_16		3		/* 16 bytes	*/
+#define	AC_CFG_ALOC(v)		(((v) & 0x1) << 3)	/* Addr/len data is	*/
+							/* explicit in buffers	*/
+#define	AC_CFG_ADDRLEN(v)	(((v) & 0x7) << 0)	/* Bytes per address	*/
+	unsigned char	cfg_byte10;
+#define	AC_CFG_BOFMET(v)	(((v) & 0x1) << 7)	/* Use alternate expo.	*/
+							/* backoff method	*/
+#define	AC_CFG_ACR(v)		(((v) & 0x7) << 4)	/* Accelerated cont. res. */
+#define	AC_CFG_LINPRIO(v)	(((v) & 0x7) << 0)	/* Linear priority	*/
+	unsigned char	cfg_ifs;	/* Interframe spacing		*/
+	unsigned char	cfg_slotl;	/* Slot time (low byte)		*/
+	unsigned char	cfg_byte13;
+#define	AC_CFG_RETRYNUM(v)	(((v) & 0xF) << 4)	/* Max. collision retry	*/
+#define	AC_CFG_SLTTMHI(v)	(((v) & 0x7) << 0)	/* Slot time (high bits) */
+	unsigned char	cfg_byte14;
+#define	AC_CFG_FLGPAD(v)	(((v) & 0x1) << 7)	/* Pad with HDLC flags	*/
+#define	AC_CFG_BTSTF(v)		(((v) & 0x1) << 6)	/* Do HDLC bitstuffing	*/
+#define	AC_CFG_CRC16(v)		(((v) & 0x1) << 5)	/* 16 bit CCITT CRC	*/
+#define	AC_CFG_NCRC(v)		(((v) & 0x1) << 4)	/* Insert no CRC	*/
+#define	AC_CFG_TNCRS(v)		(((v) & 0x1) << 3)	/* Tx even if no carrier */
+#define	AC_CFG_MANCH(v)		(((v) & 0x1) << 2)	/* Manchester coding	*/
+#define	AC_CFG_BCDIS(v)		(((v) & 0x1) << 1)	/* Disable broadcast	*/
+#define	AC_CFG_PRM(v)		(((v) & 0x1) << 0)	/* Promiscuous mode	*/
+	unsigned char	cfg_byte15;
+#define	AC_CFG_ICDS(v)		(((v) & 0x1) << 7)	/* Internal collision	*/
+							/* detect source	*/
+#define	AC_CFG_CDTF(v)		(((v) & 0x7) << 4)	/* Collision detect	*/
+							/* filter in bit times	*/
+#define	AC_CFG_ICSS(v)		(((v) & 0x1) << 3)	/* Internal carrier	*/
+							/* sense source		*/
+#define	AC_CFG_CSTF(v)		(((v) & 0x7) << 0)	/* Carrier sense	*/
+							/* filter in bit times	*/
+	unsigned short	cfg_min_frm_len;
+#define	AC_CFG_MNFRM(v)		(((v) & 0xFF) << 0)	/* Min. bytes/frame (<= 255) */
+};
+
+/*
+ * The MC-Setup Action Command.
+ */
+typedef struct ac_mcs_t	ac_mcs_t;
+struct ac_mcs_t
+{
+	ach_t		mcs_h;
+	unsigned short	mcs_cnt;	/* No. of bytes of MC addresses	*/
+#if 0
+	unsigned char	mcs_data[ADDR_LEN]; /* The first MC address ..	*/
+	...
+#endif
+};
+
+#define I82586_MAX_MULTICAST_ADDRESSES	128	/* Hardware hashed filter */
+
+/*
+ * The Transmit Action Command.
+ */
+typedef struct ac_tx_t	ac_tx_t;
+struct ac_tx_t
+{
+	ach_t		tx_h;
+	unsigned short	tx_tbd_offset;	/* Address of list of buffers.	*/
+#if	0
+Linux packets are passed down with the destination MAC address
+and length/type field already prepended to the data,
+so we do not need to insert it.  Consistent with this
+we must also set the AC_CFG_ALOC(..) flag during the
+ac_cfg_t action command.
+	unsigned char	tx_addr[ADDR_LEN]; /* The frame dest. address	*/
+	unsigned short	tx_length;	/* The frame length		*/
+#endif	/* 0 */
+};
+
+/*
+ * The Time Domain Reflectometer Action Command.
+ */
+typedef struct ac_tdr_t	ac_tdr_t;
+struct ac_tdr_t
+{
+	ach_t		tdr_h;
+	unsigned short	tdr_result;	/* Result.	*/
+#define		AC_TDR_LNK_OK	(0x1 << 15)	/* No link problem	*/
+#define		AC_TDR_XCVR_PRB	(0x1 << 14)	/* Txcvr cable problem	*/
+#define		AC_TDR_ET_OPN	(0x1 << 13)	/* Open on the link	*/
+#define		AC_TDR_ET_SRT	(0x1 << 12)	/* Short on the link	*/
+#define		AC_TDR_TIME	(0x7FF << 0)	/* Distance to problem	*/
+						/* site	in transmit	*/
+						/* clock cycles		*/
+};
+
+/*
+ * The Dump Action Command.
+ */
+typedef struct ac_dmp_t	ac_dmp_t;
+struct ac_dmp_t
+{
+	ach_t		dmp_h;
+	unsigned short	dmp_offset;	/* Result.	*/
+};
+
+/*
+ * Size of the result of the dump command.
+ */
+#define	DUMPBYTES	170
+
+/*
+ * The Diagnose Action Command.
+ */
+typedef struct ac_dgn_t	ac_dgn_t;
+struct ac_dgn_t
+{
+	ach_t		dgn_h;
+};
+
+/*
+ * Transmit Buffer Descriptor (TBD).
+ */
+typedef struct tbd_t	tbd_t;
+struct tbd_t
+{
+	unsigned short	tbd_status;		/* Written by the CPU	*/
+#define		TBD_STATUS_EOF	(0x1 << 15)	/* This TBD is the	*/
+						/* last for this frame	*/
+#define		TBD_STATUS_ACNT	(0x3FFF << 0)	/* Actual count of data	*/
+						/* bytes in this buffer	*/
+	unsigned short	tbd_next_bd_offset;	/* Next in list		*/
+	unsigned short	tbd_bufl;		/* Buffer address (low)	*/
+	unsigned short	tbd_bufh;		/*    "	     "	(high)	*/
+};
+
+/*
+ * Receive Buffer Descriptor (RBD).
+ */
+typedef struct rbd_t	rbd_t;
+struct rbd_t
+{
+	unsigned short	rbd_status;		/* Written by the 82586	*/
+#define		RBD_STATUS_EOF	(0x1 << 15)	/* This RBD is the	*/
+						/* last for this frame	*/
+#define		RBD_STATUS_F	(0x1 << 14)	/* ACNT field is valid	*/
+#define		RBD_STATUS_ACNT	(0x3FFF << 0)	/* Actual no. of data	*/
+						/* bytes in this buffer	*/
+	unsigned short	rbd_next_rbd_offset;	/* Next rbd in list	*/
+	unsigned short	rbd_bufl;		/* Data pointer (low)	*/
+	unsigned short	rbd_bufh;		/*  "	   "    (high)	*/
+	unsigned short	rbd_el_size;		/* EL+Data buf. size	*/
+#define		RBD_EL	(0x1 << 15)		/* This BD is the	*/
+						/* last in the list	*/
+#define		RBD_SIZE (0x3FFF << 0)		/* No. of bytes the	*/
+						/* buffer can hold	*/
+};
+
+#define	rbdoff(p,f) 	toff(rbd_t, p, f)
+
+/*
+ * Frame Descriptor (FD).
+ */
+typedef struct fd_t	fd_t;
+struct fd_t
+{
+	unsigned short	fd_status;		/* Written by the 82586	*/
+#define		FD_STATUS_C	(0x1 << 15)	/* Completed storing frame */
+#define		FD_STATUS_B	(0x1 << 14)	/* FD was consumed by RU */
+#define		FD_STATUS_OK	(0x1 << 13)	/* Frame rxd successfully */
+#define		FD_STATUS_S11	(0x1 << 11)	/* CRC error		*/
+#define		FD_STATUS_S10	(0x1 << 10)	/* Alignment error	*/
+#define		FD_STATUS_S9	(0x1 <<  9)	/* Ran out of resources	*/
+#define		FD_STATUS_S8	(0x1 <<  8)	/* Rx DMA overrun	*/
+#define		FD_STATUS_S7	(0x1 <<  7)	/* Frame too short	*/
+#define		FD_STATUS_S6	(0x1 <<  6)	/* No EOF flag		*/
+	unsigned short	fd_command;		/* Command		*/
+#define		FD_COMMAND_EL	(0x1 << 15)	/* Last FD in list	*/
+#define		FD_COMMAND_S	(0x1 << 14)	/* Suspend RU after rx	*/
+	unsigned short	fd_link_offset;		/* Next FD		*/
+	unsigned short	fd_rbd_offset;		/* First RBD (data)	*/
+						/* Prepared by CPU,	*/
+						/* updated by 82586	*/
+#if	0
+I think the rest is unused since we
+have set AC_CFG_ALOC(..).  However, just
+in case, we leave the space.
+#endif	/* 0 */
+	unsigned char	fd_dest[ADDR_LEN];	/* Destination address	*/
+						/* Written by 82586	*/
+	unsigned char	fd_src[ADDR_LEN];	/* Source address	*/
+						/* Written by 82586	*/
+	unsigned short	fd_length;		/* Frame length or type	*/
+						/* Written by 82586	*/
+};
+
+#define	fdoff(p,f) 	toff(fd_t, p, f)
+
+/*
+ * This software may only be used and distributed
+ * according to the terms of the GNU General Public License.
+ *
+ * For more details, see wavelan.c.
+ */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/i82593.h linux/drivers/net/wireless/i82593.h
--- v2.5.2/linux/drivers/net/wireless/i82593.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/i82593.h	Fri Mar  2 11:02:15 2001
@@ -0,0 +1,224 @@
+/*
+ * Definitions for Intel 82593 CSMA/CD Core LAN Controller
+ * The definitions are taken from the 1992 users manual with Intel
+ * order number 297125-001.
+ *
+ * /usr/src/pc/RCS/i82593.h,v 1.1 1996/07/17 15:23:12 root Exp
+ *
+ * Copyright 1994, Anders Klemets <klemets@it.kth.se>
+ *
+ * This software may be freely distributed for noncommercial purposes
+ * as long as this notice is retained.
+ * 
+ * HISTORY
+ * i82593.h,v
+ * Revision 1.1  1996/07/17 15:23:12  root
+ * Initial revision
+ *
+ * Revision 1.3  1995/04/05  15:13:58  adj
+ * Initial alpha release
+ *
+ * Revision 1.2  1994/06/16  23:57:31  klemets
+ * Mirrored all the fields in the configuration block.
+ *
+ * Revision 1.1  1994/06/02  20:25:34  klemets
+ * Initial revision
+ *
+ *
+ */
+#ifndef	_I82593_H
+#define	_I82593_H
+
+/* Intel 82593 CSMA/CD Core LAN Controller */
+
+/* Port 0 Command Register definitions */
+
+/* Execution operations */
+#define OP0_NOP			0	/* CHNL = 0 */
+#define OP0_SWIT_TO_PORT_1	0	/* CHNL = 1 */
+#define OP0_IA_SETUP		1
+#define OP0_CONFIGURE		2
+#define OP0_MC_SETUP		3
+#define OP0_TRANSMIT		4
+#define OP0_TDR			5
+#define OP0_DUMP		6
+#define OP0_DIAGNOSE		7
+#define OP0_TRANSMIT_NO_CRC	9
+#define OP0_RETRANSMIT		12
+#define OP0_ABORT		13
+/* Reception operations */
+#define OP0_RCV_ENABLE		8
+#define OP0_RCV_DISABLE		10
+#define OP0_STOP_RCV		11
+/* Status pointer control operations */
+#define OP0_FIX_PTR		15	/* CHNL = 1 */
+#define OP0_RLS_PTR		15	/* CHNL = 0 */
+#define OP0_RESET		14
+
+#define CR0_CHNL		(1 << 4)	/* 0=Channel 0, 1=Channel 1 */
+#define CR0_STATUS_0		0x00
+#define CR0_STATUS_1		0x20
+#define CR0_STATUS_2		0x40
+#define CR0_STATUS_3		0x60
+#define CR0_INT_ACK		(1 << 7)	/* 0=No ack, 1=acknowledge */
+
+/* Port 0 Status Register definitions */
+
+#define SR0_NO_RESULT		0		/* dummy */
+#define SR0_EVENT_MASK		0x0f
+#define SR0_IA_SETUP_DONE	1
+#define SR0_CONFIGURE_DONE	2
+#define SR0_MC_SETUP_DONE	3
+#define SR0_TRANSMIT_DONE	4
+#define SR0_TDR_DONE		5
+#define SR0_DUMP_DONE		6
+#define SR0_DIAGNOSE_PASSED	7
+#define SR0_TRANSMIT_NO_CRC_DONE 9
+#define SR0_RETRANSMIT_DONE	12
+#define SR0_EXECUTION_ABORTED	13
+#define SR0_END_OF_FRAME	8
+#define SR0_RECEPTION_ABORTED	10
+#define SR0_DIAGNOSE_FAILED	15
+#define SR0_STOP_REG_HIT	11
+
+#define SR0_CHNL		(1 << 4)
+#define SR0_EXECUTION		(1 << 5)
+#define SR0_RECEPTION		(1 << 6)
+#define SR0_INTERRUPT		(1 << 7)
+#define SR0_BOTH_RX_TX		(SR0_EXECUTION | SR0_RECEPTION)
+
+#define SR3_EXEC_STATE_MASK	0x03
+#define SR3_EXEC_IDLE		0
+#define SR3_TX_ABORT_IN_PROGRESS 1
+#define SR3_EXEC_ACTIVE		2
+#define SR3_ABORT_IN_PROGRESS	3
+#define SR3_EXEC_CHNL		(1 << 2)
+#define SR3_STP_ON_NO_RSRC	(1 << 3)
+#define SR3_RCVING_NO_RSRC	(1 << 4)
+#define SR3_RCV_STATE_MASK	0x60
+#define SR3_RCV_IDLE		0x00
+#define SR3_RCV_READY		0x20
+#define SR3_RCV_ACTIVE		0x40
+#define SR3_RCV_STOP_IN_PROG	0x60
+#define SR3_RCV_CHNL		(1 << 7)
+
+/* Port 1 Command Register definitions */
+
+#define OP1_NOP			0
+#define OP1_SWIT_TO_PORT_0	1
+#define OP1_INT_DISABLE		2
+#define OP1_INT_ENABLE		3
+#define OP1_SET_TS		5
+#define OP1_RST_TS		7
+#define OP1_POWER_DOWN		8
+#define OP1_RESET_RING_MNGMT	11
+#define OP1_RESET		14
+#define OP1_SEL_RST		15
+
+#define CR1_STATUS_4		0x00
+#define CR1_STATUS_5		0x20
+#define CR1_STATUS_6		0x40
+#define CR1_STOP_REG_UPDATE	(1 << 7)
+
+/* Receive frame status bits */
+
+#define	RX_RCLD			(1 << 0)
+#define RX_IA_MATCH		(1 << 1)
+#define	RX_NO_AD_MATCH		(1 << 2)
+#define RX_NO_SFD		(1 << 3)
+#define RX_SRT_FRM		(1 << 7)
+#define RX_OVRRUN		(1 << 8)
+#define RX_ALG_ERR		(1 << 10)
+#define RX_CRC_ERR		(1 << 11)
+#define RX_LEN_ERR		(1 << 12)
+#define RX_RCV_OK		(1 << 13)
+#define RX_TYP_LEN		(1 << 15)
+
+/* Transmit status bits */
+
+#define TX_NCOL_MASK		0x0f
+#define TX_FRTL			(1 << 4)
+#define TX_MAX_COL		(1 << 5)
+#define TX_HRT_BEAT		(1 << 6)
+#define TX_DEFER		(1 << 7)
+#define TX_UND_RUN		(1 << 8)
+#define TX_LOST_CTS		(1 << 9)
+#define TX_LOST_CRS		(1 << 10)
+#define TX_LTCOL		(1 << 11)
+#define TX_OK			(1 << 13)
+#define TX_COLL			(1 << 15)
+
+struct i82593_conf_block {
+  u_char fifo_limit : 4,
+  	 forgnesi   : 1,
+  	 fifo_32    : 1,
+  	 d6mod      : 1,
+  	 throttle_enb : 1;
+  u_char throttle   : 6,
+	 cntrxint   : 1,
+	 contin	    : 1;
+  u_char addr_len   : 3,
+  	 acloc 	    : 1,
+ 	 preamb_len : 2,
+  	 loopback   : 2;
+  u_char lin_prio   : 3,
+	 tbofstop   : 1,
+	 exp_prio   : 3,
+	 bof_met    : 1;
+  u_char	    : 4,
+	 ifrm_spc   : 4;
+  u_char	    : 5,
+	 slottim_low : 3;
+  u_char slottim_hi : 3,
+		    : 1,
+	 max_retr   : 4;
+  u_char prmisc     : 1,
+	 bc_dis     : 1,
+  		    : 1,
+	 crs_1	    : 1,
+	 nocrc_ins  : 1,
+	 crc_1632   : 1,
+  	 	    : 1,
+  	 crs_cdt    : 1;
+  u_char cs_filter  : 3,
+	 crs_src    : 1,
+	 cd_filter  : 3,
+		    : 1;
+  u_char	    : 2,
+  	 min_fr_len : 6;
+  u_char lng_typ    : 1,
+	 lng_fld    : 1,
+	 rxcrc_xf   : 1,
+	 artx	    : 1,
+	 sarec	    : 1,
+	 tx_jabber  : 1,	/* why is this called max_len in the manual? */
+	 hash_1	    : 1,
+  	 lbpkpol    : 1;
+  u_char	    : 6,
+  	 fdx	    : 1,
+  	  	    : 1;
+  u_char dummy_6    : 6,	/* supposed to be ones */
+  	 mult_ia    : 1,
+  	 dis_bof    : 1;
+  u_char dummy_1    : 1,	/* supposed to be one */
+	 tx_ifs_retrig : 2,
+	 mc_all     : 1,
+	 rcv_mon    : 2,
+	 frag_acpt  : 1,
+  	 tstrttrs   : 1;
+  u_char fretx	    : 1,
+	 runt_eop   : 1,
+	 hw_sw_pin  : 1,
+	 big_endn   : 1,
+	 syncrqs    : 1,
+	 sttlen     : 1,
+	 tx_eop     : 1,
+  	 rx_eop	    : 1;
+  u_char rbuf_size  : 5,
+	 rcvstop    : 1,
+  	 	    : 2;
+};
+
+#define I82593_MAX_MULTICAST_ADDRESSES	128	/* Hardware hashed filter */
+
+#endif /* _I82593_H */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/netwave_cs.c linux/drivers/net/wireless/netwave_cs.c
--- v2.5.2/linux/drivers/net/wireless/netwave_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/netwave_cs.c	Mon Jan 21 16:04:47 2002
@@ -0,0 +1,1600 @@
+/*********************************************************************
+ *                
+ * Filename:      netwave_cs.c
+ * Version:       0.4.1
+ * Description:   Netwave AirSurfer Wireless LAN PC Card driver
+ * Status:        Experimental.
+ * Authors:       John Markus Bjørndalen <johnm@cs.uit.no>
+ *                Dag Brattli <dagb@cs.uit.no>
+ *                David Hinds <dahinds@users.sourceforge.net>
+ * Created at:    A long time ago!
+ * Modified at:   Mon Nov 10 11:54:37 1997
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1997 University of Tromsø, Norway
+ *
+ * Revision History:
+ *
+ *   08-Nov-97 15:14:47   John Markus Bjørndalen <johnm@cs.uit.no>
+ *    - Fixed some bugs in netwave_rx and cleaned it up a bit. 
+ *      (One of the bugs would have destroyed packets when receiving
+ *      multiple packets per interrupt). 
+ *    - Cleaned up parts of newave_hw_xmit. 
+ *    - A few general cleanups. 
+ *   24-Oct-97 13:17:36   Dag Brattli <dagb@cs.uit.no>
+ *    - Fixed netwave_rx receive function (got updated docs)
+ *   Others:
+ *    - Changed name from xircnw to netwave, take a look at 
+ *      http://www.netwave-wireless.com
+ *    - Some reorganizing of the code
+ *    - Removed possible race condition between interrupt handler and transmit
+ *      function
+ *    - Started to add wireless extensions, but still needs some coding
+ *    - Added watchdog for better handling of transmission timeouts 
+ *      (hopefully this works better)
+ ********************************************************************/
+
+/* To have statistics (just packets sent) define this */
+#undef NETWAVE_STATS
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#ifdef CONFIG_NET_RADIO
+#include <linux/wireless.h>
+#endif
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/mem_op.h>
+
+#define NETWAVE_REGOFF         0x8000
+/* The Netwave IO registers, offsets to iobase */
+#define NETWAVE_REG_COR        0x0
+#define NETWAVE_REG_CCSR       0x2
+#define NETWAVE_REG_ASR        0x4
+#define NETWAVE_REG_IMR        0xa
+#define NETWAVE_REG_PMR        0xc
+#define NETWAVE_REG_IOLOW      0x6
+#define NETWAVE_REG_IOHI       0x7
+#define NETWAVE_REG_IOCONTROL  0x8
+#define NETWAVE_REG_DATA       0xf
+/* The Netwave Extended IO registers, offsets to RamBase */
+#define NETWAVE_EREG_ASCC      0x114
+#define NETWAVE_EREG_RSER      0x120
+#define NETWAVE_EREG_RSERW     0x124
+#define NETWAVE_EREG_TSER      0x130
+#define NETWAVE_EREG_TSERW     0x134
+#define NETWAVE_EREG_CB        0x100
+#define NETWAVE_EREG_SPCQ      0x154
+#define NETWAVE_EREG_SPU       0x155
+#define NETWAVE_EREG_LIF       0x14e
+#define NETWAVE_EREG_ISPLQ     0x156
+#define NETWAVE_EREG_HHC       0x158
+#define NETWAVE_EREG_NI        0x16e
+#define NETWAVE_EREG_MHS       0x16b
+#define NETWAVE_EREG_TDP       0x140
+#define NETWAVE_EREG_RDP       0x150
+#define NETWAVE_EREG_PA        0x160
+#define NETWAVE_EREG_EC        0x180
+#define NETWAVE_EREG_CRBP      0x17a
+#define NETWAVE_EREG_ARW       0x166
+
+/*
+ * Commands used in the extended command buffer
+ * NETWAVE_EREG_CB (0x100-0x10F) 
+ */
+#define NETWAVE_CMD_NOP        0x00
+#define NETWAVE_CMD_SRC        0x01
+#define NETWAVE_CMD_STC        0x02
+#define NETWAVE_CMD_AMA        0x03
+#define NETWAVE_CMD_DMA        0x04
+#define NETWAVE_CMD_SAMA       0x05
+#define NETWAVE_CMD_ER         0x06
+#define NETWAVE_CMD_DR         0x07
+#define NETWAVE_CMD_TL         0x08
+#define NETWAVE_CMD_SRP        0x09
+#define NETWAVE_CMD_SSK        0x0a
+#define NETWAVE_CMD_SMD        0x0b
+#define NETWAVE_CMD_SAPD       0x0c
+#define NETWAVE_CMD_SSS        0x11
+/* End of Command marker */
+#define NETWAVE_CMD_EOC        0x00
+
+/* ASR register bits */
+#define NETWAVE_ASR_RXRDY   0x80
+#define NETWAVE_ASR_TXBA    0x01
+
+#define TX_TIMEOUT		((32*HZ)/100)
+
+static const unsigned int imrConfRFU1 = 0x10; /* RFU interrupt mask, keep high */
+static const unsigned int imrConfIENA = 0x02; /* Interrupt enable */
+
+static const unsigned int corConfIENA   = 0x01; /* Interrupt enable */
+static const unsigned int corConfLVLREQ = 0x40; /* Keep high */
+
+static const unsigned int rxConfRxEna  = 0x80; /* Receive Enable */
+static const unsigned int rxConfMAC    = 0x20; /* MAC host receive mode*/ 
+static const unsigned int rxConfPro    = 0x10; /* Promiscuous */
+static const unsigned int rxConfAMP    = 0x08; /* Accept Multicast Packets */
+static const unsigned int rxConfBcast  = 0x04; /* Accept Broadcast Packets */
+
+static const unsigned int txConfTxEna  = 0x80; /* Transmit Enable */
+static const unsigned int txConfMAC    = 0x20; /* Host sends MAC mode */
+static const unsigned int txConfEUD    = 0x10; /* Enable Uni-Data packets */
+static const unsigned int txConfKey    = 0x02; /* Scramble data packets */
+static const unsigned int txConfLoop   = 0x01; /* Loopback mode */
+
+/*
+   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+*/
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"netwave_cs.c 0.3.0 Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n";
+#else
+#define DEBUG(n, args...)
+#endif
+
+static dev_info_t dev_info = "netwave_cs";
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Choose the domain, default is 0x100 */
+static u_int  domain = 0x100;
+
+/* Scramble key, range from 0x0 to 0xffff.  
+ * 0x0 is no scrambling. 
+ */
+static u_int  scramble_key = 0x0;
+
+/* Shared memory speed, in ns. The documentation states that 
+ * the card should not be read faster than every 400ns. 
+ * This timing should be provided by the HBA. If it becomes a 
+ * problem, try setting mem_speed to 400. 
+ */
+static int mem_speed;
+
+/* Bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(domain, "i");
+MODULE_PARM(scramble_key, "i");
+MODULE_PARM(mem_speed, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+/* PCMCIA (Card Services) related functions */
+static void netwave_release(u_long arg);     /* Card removal */
+static int  netwave_event(event_t event, int priority, 
+					      event_callback_args_t *args);
+static void netwave_pcmcia_config(dev_link_t *arg); /* Runs after card 
+													   insertion */
+static dev_link_t *netwave_attach(void);     /* Create instance */
+static void netwave_detach(dev_link_t *);    /* Destroy instance */
+static void netwave_flush_stale_links(void);	     /* Destroy all staled instances */
+
+/* Hardware configuration */
+static void netwave_doreset(ioaddr_t iobase, u_char* ramBase);
+static void netwave_reset(struct net_device *dev);
+
+/* Misc device stuff */
+static int netwave_open(struct net_device *dev);  /* Open the device */
+static int netwave_close(struct net_device *dev); /* Close the device */
+static int netwave_config(struct net_device *dev, struct ifmap *map);
+
+/* Packet transmission and Packet reception */
+static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev);
+static int netwave_rx( struct net_device *dev);
+
+/* Interrupt routines */
+static void netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void netwave_watchdog(struct net_device *);
+
+/* Statistics */
+static void update_stats(struct net_device *dev);
+static struct net_device_stats *netwave_get_stats(struct net_device *dev);
+
+/* Wireless extensions */
+#ifdef WIRELESS_EXT
+static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev);
+#endif
+static int netwave_ioctl(struct net_device *, struct ifreq *, int);
+
+static void set_multicast_list(struct net_device *dev);
+
+/*
+   A linked list of "instances" of the skeleton device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+
+   You may not want to use a linked list for this -- for example, the
+   memory card driver uses an array of dev_link_t pointers, where minor
+   device numbers are used to derive the corresponding array index.
+*/
+static dev_link_t *dev_list;
+
+/*
+   A dev_link_t structure has fields for most things that are needed
+   to keep track of a socket, but there will usually be some device
+   specific information that also needs to be kept track of.  The
+   'priv' pointer in a dev_link_t structure can be used to point to
+   a device-specific private data structure, like this.
+
+   A driver needs to provide a dev_node_t structure for each device
+   on a card.  In some cases, there is only one device per card (for
+   example, ethernet cards, modems).  In other cases, there may be
+   many actual or logical devices (SCSI adapters, memory cards with
+   multiple partitions).  The dev_node_t structures need to be kept
+   in a linked list starting at the 'dev' field of a dev_link_t
+   structure.  We allocate them in the card's private data structure,
+   because they generally can't be allocated dynamically.
+*/
+
+/* Wireless Extension Backward compatibility - Jean II
+ * If the new wireless device private ioctl range is not defined,
+ * default to standard device private ioctl range */
+#ifndef SIOCIWFIRSTPRIV
+#define SIOCIWFIRSTPRIV	SIOCDEVPRIVATE
+#endif /* SIOCIWFIRSTPRIV */
+
+#define SIOCGIPSNAP	SIOCIWFIRSTPRIV		/* Site Survey Snapshot */
+/*#define SIOCGIPQTHR	SIOCIWFIRSTPRIV + 1*/
+
+#define MAX_ESA 10
+
+typedef struct net_addr {
+    u_char addr48[6];
+} net_addr;
+
+struct site_survey {
+    u_short length;
+    u_char  struct_revision;
+    u_char  roaming_state;
+	
+    u_char  sp_existsFlag;
+    u_char  sp_link_quality;
+    u_char  sp_max_link_quality;
+    u_char  linkQualityGoodFairBoundary;
+    u_char  linkQualityFairPoorBoundary;
+    u_char  sp_utilization;
+    u_char  sp_goodness;
+    u_char  sp_hotheadcount;
+    u_char  roaming_condition;
+	
+    net_addr sp;
+    u_char   numAPs;
+    net_addr nearByAccessPoints[MAX_ESA];
+};	
+   
+typedef struct netwave_private {
+    dev_link_t link;
+    struct net_device      dev;
+    dev_node_t node;
+    u_char     *ramBase;
+    int        timeoutCounter;
+    int        lastExec;
+    struct timer_list      watchdog;	/* To avoid blocking state */
+    struct site_survey     nss;
+    struct net_device_stats stats;
+#ifdef WIRELESS_EXT
+    struct iw_statistics   iw_stats;    /* Wireless stats */
+#endif
+} netwave_private;
+
+#ifdef NETWAVE_STATS
+static struct net_device_stats *netwave_get_stats(struct net_device *dev);
+#endif
+
+/*
+ * The Netwave card is little-endian, so won't work for big endian
+ * systems.
+ */
+static inline unsigned short get_uint16(u_char* staddr) 
+{
+    return readw(staddr); /* Return only 16 bits */
+}
+
+static inline short get_int16(u_char* staddr)
+{
+    return readw(staddr);
+}
+
+/**************************************************************************/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/* 
+ * Wait until the WOC (Write Operation Complete) bit in the 
+ * ASR (Adapter Status Register) is asserted. 
+ * This should have aborted if it takes too long time. 
+ */
+static inline void wait_WOC(unsigned int iobase)
+{
+    /* Spin lock */
+    while ((inb(iobase + NETWAVE_REG_ASR) & 0x8) != 0x8) ; 
+}
+
+#ifdef WIRELESS_EXT
+static void netwave_snapshot(netwave_private *priv, u_char *ramBase, 
+			     ioaddr_t iobase) { 
+    u_short resultBuffer;
+
+    /* if time since last snapshot is > 1 sec. (100 jiffies?)  then take 
+     * new snapshot, else return cached data. This is the recommended rate.  
+     */
+    if ( jiffies - priv->lastExec > 100) { 
+	/* Take site survey  snapshot */ 
+	/*printk( KERN_DEBUG "Taking new snapshot. %ld\n", jiffies -
+	  priv->lastExec); */
+	wait_WOC(iobase); 
+	writeb(NETWAVE_CMD_SSS, ramBase + NETWAVE_EREG_CB + 0); 
+	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); 
+	wait_WOC(iobase); 
+
+	/* Get result and copy to cach */ 
+	resultBuffer = readw(ramBase + NETWAVE_EREG_CRBP); 
+	copy_from_pc( &priv->nss, ramBase+resultBuffer, 
+		      sizeof(struct site_survey)); 
+    } 
+}
+#endif
+
+#ifdef WIRELESS_EXT
+/*
+ * Function netwave_get_wireless_stats (dev)
+ *
+ *    Wireless extensions statistics
+ *
+ */
+static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev)
+{	
+    unsigned long flags;
+    ioaddr_t iobase = dev->base_addr;
+    netwave_private *priv = (netwave_private *) dev->priv;
+    u_char *ramBase = priv->ramBase;
+    struct iw_statistics* wstats;
+	
+    wstats = &priv->iw_stats;
+
+    save_flags(flags);
+    cli();
+	
+    netwave_snapshot( priv, ramBase, iobase);
+
+    wstats->status = priv->nss.roaming_state;
+    wstats->qual.qual = readb( ramBase + NETWAVE_EREG_SPCQ); 
+    wstats->qual.level = readb( ramBase + NETWAVE_EREG_ISPLQ);
+    wstats->qual.noise = readb( ramBase + NETWAVE_EREG_SPU) & 0x3f;
+    wstats->discard.nwid = 0L;
+    wstats->discard.code = 0L;
+    wstats->discard.misc = 0L;
+
+    restore_flags(flags);
+    
+    return &priv->iw_stats;
+}
+#endif
+
+/*
+ * Function netwave_attach (void)
+ *
+ *     Creates an "instance" of the driver, allocating local data 
+ *     structures for one device.  The device is registered with Card 
+ *     Services.
+ *
+ *     The dev_link structure is initialized, but we don't actually
+ *     configure the card at this point -- we wait until we receive a
+ *     card insertion event.
+ */
+static dev_link_t *netwave_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    struct net_device *dev;
+    netwave_private *priv;
+    int i, ret;
+    
+    DEBUG(0, "netwave_attach()\n");
+    
+    /* Perform some cleanup */
+    netwave_flush_stale_links();
+
+    /* Initialize the dev_link_t structure */
+    priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+    if (!priv) return NULL;
+    memset(priv, 0, sizeof(*priv));
+    link = &priv->link; dev = &priv->dev;
+    link->priv = dev->priv = priv;
+    link->release.function = &netwave_release;
+    link->release.data = (u_long)link;
+	
+    /* The io structure describes IO port mapping */
+    link->io.NumPorts1 = 16;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+    /* link->io.NumPorts2 = 16; 
+       link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; */
+    link->io.IOAddrLines = 5;
+    
+    /* Interrupt setup */
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = &netwave_interrupt;
+    
+    /* General socket configuration */
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.ConfigIndex = 1;
+    link->conf.Present = PRESENT_OPTION;
+
+    /* Netwave specific entries in the device structure */
+    dev->hard_start_xmit = &netwave_start_xmit;
+    dev->set_config = &netwave_config;
+    dev->get_stats  = &netwave_get_stats;
+    dev->set_multicast_list = &set_multicast_list;
+    /* wireless extensions */
+#ifdef WIRELESS_EXT
+    dev->get_wireless_stats = &netwave_get_wireless_stats;
+#endif
+    dev->do_ioctl = &netwave_ioctl;
+
+    dev->tx_timeout = &netwave_watchdog;
+    dev->watchdog_timeo = TX_TIMEOUT;
+
+    ether_setup(dev);
+    dev->open = &netwave_open;
+    dev->stop = &netwave_close;
+    link->irq.Instance = dev;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &netwave_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != 0) {
+	cs_error(link->handle, RegisterClient, ret);
+	netwave_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* netwave_attach */
+
+/*
+ * Function netwave_detach (link)
+ *
+ *    This deletes a driver "instance".  The device is de-registered
+ *    with Card Services.  If it has been released, all local data
+ *    structures are freed.  Otherwise, the structures will be freed
+ *    when the device is released.
+ */
+static void netwave_detach(dev_link_t *link)
+{
+    netwave_private *priv = link->priv;
+    dev_link_t **linkp;
+
+    DEBUG(0, "netwave_detach(0x%p)\n", link);
+  
+    /*
+	  If the device is currently configured and active, we won't
+	  actually delete it yet.  Instead, it is marked so that when
+	  the release() function is called, that will trigger a proper
+	  detach().
+	*/
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	netwave_release((u_long) link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    DEBUG(1, "netwave_cs: detach postponed, '%s' still "
+		  "locked\n", link->dev->dev_name);
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+	
+    /* Break the link with Card Services */
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+      {
+	DEBUG(1, "netwave_cs: detach fail, '%s' not in list\n",
+	      link->dev->dev_name);
+	return;
+      }
+
+    /* Unlink device structure, free pieces */
+    *linkp = link->next;
+    if (link->dev)
+	unregister_netdev(&priv->dev);
+    kfree(priv);
+    
+} /* netwave_detach */
+
+/*
+ * Function netwave_flush_stale_links (void)
+ *
+ *    This deletes all driver "instances" that need to be deleted.
+ *    Sometimes, netwave_detach can't be performed following a call from
+ *    cardmgr (device still open) and the device is put in a STALE_LINK
+ *    state.
+ *    This function is in charge of making the cleanup...
+ */
+static void netwave_flush_stale_links(void)
+{
+    dev_link_t *	link;		/* Current node in linked list */
+    dev_link_t *	next;		/* Next node in linked list */
+
+    DEBUG(1, "netwave_flush_stale_links(0x%p)\n", dev_list);
+
+    /* Go through the list */
+    for (link = dev_list; link; link = next) {
+        next = link->next;
+        /* Check if in need of being removed */
+        if(link->state & DEV_STALE_LINK)
+	    netwave_detach(link);
+    }
+} /* netwave_flush_stale_links */
+
+/*
+ * Function netwave_ioctl (dev, rq, cmd)
+ *
+ *     Perform ioctl : config & info stuff
+ *     This is the stuff that are treated the wireless extensions (iwconfig)
+ *
+ */
+static int netwave_ioctl(struct net_device *dev, /* ioctl device */
+			 struct ifreq *rq,	 /* Data passed */
+			 int	cmd)	     /* Ioctl number */
+{
+    unsigned long flags;
+    int			ret = 0;
+#ifdef WIRELESS_EXT
+    ioaddr_t iobase = dev->base_addr;
+    netwave_private *priv = (netwave_private *) dev->priv;
+    u_char *ramBase = priv->ramBase;
+    struct iwreq *wrq = (struct iwreq *) rq;
+#endif
+	
+    DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd);
+	
+    /* Disable interrupts & save flags */
+    save_flags(flags);
+    cli();
+
+    /* Look what is the request */
+    switch(cmd) {
+	/* --------------- WIRELESS EXTENSIONS --------------- */
+#ifdef WIRELESS_EXT
+    case SIOCGIWNAME:
+	/* Get name */
+	strcpy(wrq->u.name, "Netwave");
+	break;
+    case SIOCSIWNWID:
+	/* Set domain */
+#if WIRELESS_EXT > 8
+	if(!wrq->u.nwid.disabled) {
+	    domain = wrq->u.nwid.value;
+#else	/* WIRELESS_EXT > 8 */
+	if(wrq->u.nwid.on) {
+	    domain = wrq->u.nwid.nwid;
+#endif	/* WIRELESS_EXT > 8 */
+	    printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", 
+		    (domain >> 8) & 0x01, domain & 0xff);
+	    wait_WOC(iobase);
+	    writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0);
+	    writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+	    writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2);
+	    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	} break;
+    case SIOCGIWNWID:
+	/* Read domain*/
+#if WIRELESS_EXT > 8
+	wrq->u.nwid.value = domain;
+	wrq->u.nwid.disabled = 0;
+	wrq->u.nwid.fixed = 1;
+#else	/* WIRELESS_EXT > 8 */
+	wrq->u.nwid.nwid = domain;
+	wrq->u.nwid.on = 1;
+#endif	/* WIRELESS_EXT > 8 */
+	break;
+#if WIRELESS_EXT > 8	/* Note : The API did change... */
+    case SIOCGIWENCODE:
+	/* Get scramble key */
+	if(wrq->u.encoding.pointer != (caddr_t) 0)
+	  {
+	    char	key[2];
+	    key[1] = scramble_key & 0xff;
+	    key[0] = (scramble_key>>8) & 0xff;
+	    wrq->u.encoding.flags = IW_ENCODE_ENABLED;
+	    wrq->u.encoding.length = 2;
+	    if(copy_to_user(wrq->u.encoding.pointer, key, 2))
+	      ret = -EFAULT;
+	  }
+	break;
+    case SIOCSIWENCODE:
+	/* Set  scramble key */
+	if(wrq->u.encoding.pointer != (caddr_t) 0)
+	  {
+	    char	key[2];
+	    if(copy_from_user(key, wrq->u.encoding.pointer, 2))
+	      {
+		ret = -EFAULT;
+		break;
+	      }
+	    scramble_key = (key[0] << 8) | key[1];
+	    wait_WOC(iobase);
+	    writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
+	    writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+	    writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
+	    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	  }
+	break;
+    case SIOCGIWMODE:
+      /* Mode of operation */
+	if(domain & 0x100)
+	  wrq->u.mode = IW_MODE_INFRA;
+	else
+	  wrq->u.mode = IW_MODE_ADHOC;
+      break;
+#else /* WIRELESS_EXT > 8 */
+    case SIOCGIWENCODE:
+	/* Get scramble key */
+	wrq->u.encoding.code = scramble_key;
+	wrq->u.encoding.method = 1;
+	break;
+    case SIOCSIWENCODE:
+	/* Set  scramble key */
+	scramble_key = wrq->u.encoding.code;
+	wait_WOC(iobase);
+	writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
+	writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+	writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
+	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	break;
+#endif /* WIRELESS_EXT > 8 */
+   case SIOCGIWRANGE:
+       /* Basic checking... */
+       if(wrq->u.data.pointer != (caddr_t) 0) {
+	   struct iw_range	range;
+		   
+	   /* Set the length (very important for backward compatibility) */
+	   wrq->u.data.length = sizeof(struct iw_range);
+
+	   /* Set all the info we don't care or don't know about to zero */
+	   memset(&range, 0, sizeof(range));
+
+#if WIRELESS_EXT > 10
+	   /* Set the Wireless Extension versions */
+	   range.we_version_compiled = WIRELESS_EXT;
+	   range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#endif /* WIRELESS_EXT > 10 */
+		   
+	   /* Set information in the range struct */
+	   range.throughput = 450 * 1000;	/* don't argue on this ! */
+	   range.min_nwid = 0x0000;
+	   range.max_nwid = 0x01FF;
+
+	   range.num_channels = range.num_frequency = 0;
+		   
+	   range.sensitivity = 0x3F;
+	   range.max_qual.qual = 255;
+	   range.max_qual.level = 255;
+	   range.max_qual.noise = 0;
+		   
+#if WIRELESS_EXT > 7
+	   range.num_bitrates = 1;
+	   range.bitrate[0] = 1000000;	/* 1 Mb/s */
+#endif /* WIRELESS_EXT > 7 */
+
+#if WIRELESS_EXT > 8
+	   range.encoding_size[0] = 2;		/* 16 bits scrambling */
+	   range.num_encoding_sizes = 1;
+	   range.max_encoding_tokens = 1;	/* Only one key possible */
+#endif /* WIRELESS_EXT > 8 */
+
+	   /* Copy structure to the user buffer */
+	   if(copy_to_user(wrq->u.data.pointer, &range,
+			sizeof(struct iw_range)))
+	     ret = -EFAULT;
+       }
+       break;
+    case SIOCGIWPRIV:
+	/* Basic checking... */
+	if(wrq->u.data.pointer != (caddr_t) 0) {
+	    struct iw_priv_args	priv[] =
+	    {	/* cmd,		set_args,	get_args,	name */
+		{ SIOCGIPSNAP, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 0, 
+		  sizeof(struct site_survey), 
+		  "getsitesurvey" },
+	    };
+			
+	    /* Set the number of ioctl available */
+	    wrq->u.data.length = 1;
+			
+	    /* Copy structure to the user buffer */
+	    if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
+			 sizeof(priv)))
+	      ret = -EFAULT;
+	} 
+	break;
+    case SIOCGIPSNAP:
+	if(wrq->u.data.pointer != (caddr_t) 0) {
+	    /* Take snapshot of environment */
+	    netwave_snapshot( priv, ramBase, iobase);
+	    wrq->u.data.length = priv->nss.length;
+	    /* Copy structure to the user buffer */
+	    if(copy_to_user(wrq->u.data.pointer, 
+			 (u_char *) &priv->nss,
+			 sizeof( struct site_survey)))
+	      {
+		printk(KERN_DEBUG "Bad buffer!\n");
+		break;
+	      }
+
+	    priv->lastExec = jiffies;
+	}
+	break;
+#endif
+    default:
+	ret = -EOPNOTSUPP;
+    }
+	
+    /* ReEnable interrupts & restore flags */
+    restore_flags(flags);
+    
+    return ret;
+}
+
+/*
+ * Function netwave_pcmcia_config (link)
+ *
+ *     netwave_pcmcia_config() is scheduled to run after a CARD_INSERTION 
+ *     event is received, to configure the PCMCIA socket, and to make the
+ *     device available to the system. 
+ *
+ */
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void netwave_pcmcia_config(dev_link_t *link) {
+    client_handle_t handle = link->handle;
+    netwave_private *priv = link->priv;
+    struct net_device *dev = &priv->dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    int i, j, last_ret, last_fn;
+    u_char buf[64];
+    win_req_t req;
+    memreq_t mem;
+    u_char *ramBase = NULL;
+
+    DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link);
+
+    /*
+      This reads the card's CONFIG tuple to find its configuration
+      registers.
+    */
+    tuple.Attributes = 0;
+    tuple.TupleData = (cisdata_t *) buf;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /*
+     *  Try allocating IO ports.  This tries a few fixed addresses.
+     *  If you want, you can also read the card's config table to
+     *  pick addresses -- see the serial driver for an example.
+     */
+    for (i = j = 0x0; j < 0x400; j += 0x20) {
+	link->io.BasePort1 = j ^ 0x300;
+	i = CardServices(RequestIO, link->handle, &link->io);
+	if (i == CS_SUCCESS) break;
+    }
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestIO, i);
+	goto failed;
+    }
+
+    /*
+     *  Now allocate an interrupt line.  Note that this does not
+     *  actually assign a handler to the interrupt.
+     */
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+
+    /*
+     *  This actually configures the PCMCIA socket -- setting up
+     *  the I/O windows and the interrupt mapping.
+     */
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+    /*
+     *  Allocate a 32K memory window.  Note that the dev_link_t
+     *  structure provides space for one window handle -- if your
+     *  device needs several windows, you'll need to keep track of
+     *  the handles in your private data structure, link->priv.
+     */
+    DEBUG(1, "Setting mem speed of %d\n", mem_speed);
+
+    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+    req.Base = 0; req.Size = 0x8000;
+    req.AccessSpeed = mem_speed;
+    link->win = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &link->win, &req);
+    mem.CardOffset = 0x20000; mem.Page = 0; 
+    CS_CHECK(MapMemPage, link->win, &mem);
+
+    /* Store base address of the common window frame */
+    ramBase = ioremap(req.Base, 0x8000);
+    ((netwave_private*)dev->priv)->ramBase = ramBase;
+
+    dev->irq = link->irq.AssignedIRQ;
+    dev->base_addr = link->io.BasePort1;
+    if (register_netdev(dev) != 0) {
+	printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n");
+	goto failed;
+    }
+
+    strcpy(priv->node.dev_name, dev->name);
+    link->dev = &priv->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    /* Reset card before reading physical address */
+    netwave_doreset(dev->base_addr, ramBase);
+
+    /* Read the ethernet address and fill in the Netwave registers. */
+    for (i = 0; i < 6; i++) 
+	dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i);
+
+    printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx id "
+	   "%c%c, hw_addr ", dev->name, dev->base_addr, dev->irq,
+	   (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI),
+	   (int) readb(ramBase+NETWAVE_EREG_NI+1));
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+
+    /* get revision words */
+    printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", 
+	   get_uint16(ramBase + NETWAVE_EREG_ARW),
+	   get_uint16(ramBase + NETWAVE_EREG_ARW+2));
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    netwave_release((u_long)link);
+} /* netwave_pcmcia_config */
+
+/*
+ * Function netwave_release (arg)
+ *
+ *    After a card is removed, netwave_release() will unregister the net
+ *    device, and release the PCMCIA configuration.  If the device is
+ *    still open, this will be postponed until it is closed.
+ */
+static void netwave_release(u_long arg) {
+    dev_link_t *link = (dev_link_t *)arg;
+    netwave_private *priv = link->priv;
+
+    DEBUG(0, "netwave_release(0x%p)\n", link);
+
+    /*
+      If the device is currently in use, we won't release until it
+      is actually closed.
+      */
+    if (link->open) {
+	printk(KERN_DEBUG "netwave_cs: release postponed, '%s' still open\n",
+	       link->dev->dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    /* Don't bother checking to see if these succeed or not */
+    if (link->win) {
+	iounmap(priv->ramBase);
+	CardServices(ReleaseWindow, link->win);
+    }
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+    link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG);
+
+} /* netwave_release */
+
+/*
+ * Function netwave_event (event, priority, args)
+ *
+ *    The card status event handler.  Mostly, this schedules other
+ *    stuff to run after an event is received.  A CARD_REMOVAL event
+ *    also sets some flags to discourage the net drivers from trying
+ *    to talk to the card any more.
+ *
+ *    When a CARD_REMOVAL event is received, we immediately set a flag
+ *    to block future accesses to this device.  All the functions that
+ *    actually access the device should check this flag to make sure
+ *    the card is still present.
+ *
+ */
+static int netwave_event(event_t event, int priority,
+			 event_callback_args_t *args) {
+    dev_link_t *link = args->client_data;
+    netwave_private *priv = link->priv;
+    struct net_device *dev = &priv->dev;
+	
+    DEBUG(1, "netwave_event(0x%06x)\n", event);
+  
+    switch (event) {
+    case CS_EVENT_REGISTRATION_COMPLETE:
+	DEBUG(0, "netwave_cs: registration complete\n");
+	break;
+
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    netif_device_detach(dev);
+	    mod_timer(&link->release, jiffies + HZ/20);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	netwave_pcmcia_config( link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG) {
+	    if (link->open)
+		netif_device_detach(dev);
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (link->open) {
+		netwave_reset(dev);
+		netif_device_attach(dev);
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* netwave_event */
+
+/*
+ * Function netwave_doreset (ioBase, ramBase)
+ *
+ *    Proper hardware reset of the card.
+ */
+static void netwave_doreset(ioaddr_t ioBase, u_char* ramBase) {
+    /* Reset card */
+    wait_WOC(ioBase);
+    outb(0x80, ioBase + NETWAVE_REG_PMR);
+    writeb(0x08, ramBase + NETWAVE_EREG_ASCC); /* Bit 3 is WOC */
+    outb(0x0, ioBase + NETWAVE_REG_PMR); /* release reset */
+}
+
+/*
+ * Function netwave_reset (dev)
+ *
+ *    Reset and restore all of the netwave registers 
+ */
+static void netwave_reset(struct net_device *dev) {
+    /* u_char state; */
+    netwave_private *priv = (netwave_private*) dev->priv;
+    u_char *ramBase = priv->ramBase;
+    ioaddr_t iobase = dev->base_addr;
+
+    DEBUG(0, "netwave_reset: Done with hardware reset\n");
+
+    priv->timeoutCounter = 0;
+
+    /* Reset card */
+    netwave_doreset(iobase, ramBase);
+    printk(KERN_DEBUG "netwave_reset: Done with hardware reset\n");
+	
+    /* Write a NOP to check the card */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_NOP, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
+	
+    /* Set receive conf */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(rxConfRxEna + rxConfBcast, ramBase + NETWAVE_EREG_CB + 1);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
+    
+    /* Set transmit conf */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_STC, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(txConfTxEna, ramBase + NETWAVE_EREG_CB + 1);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
+    
+    /* Now set the MU Domain */
+    printk(KERN_DEBUG "Setting domain to 0x%x%02x\n", (domain >> 8) & 0x01, domain & 0xff);
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(domain & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+    writeb((domain>>8) & 0x01, ramBase + NETWAVE_EREG_CB + 2);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	
+    /* Set scramble key */
+    printk(KERN_DEBUG "Setting scramble key to 0x%x\n", scramble_key);
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+    writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+
+    /* Enable interrupts, bit 4 high to keep unused
+     * source from interrupting us, bit 2 high to 
+     * set interrupt enable, 567 to enable TxDN, 
+     * RxErr and RxRdy
+     */
+    wait_WOC(iobase);
+    outb(imrConfIENA+imrConfRFU1, iobase + NETWAVE_REG_IMR);
+
+    /* Hent 4 bytes fra 0x170. Skal vaere 0a,29,88,36
+     * waitWOC
+     * skriv 80 til d000:3688
+     * sjekk om det ble 80
+     */
+    
+    /* Enable Receiver */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_ER, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
+	
+    /* Set the IENA bit in COR */
+    wait_WOC(iobase);
+    outb(corConfIENA + corConfLVLREQ, iobase + NETWAVE_REG_COR);
+}
+
+/*
+ * Function netwave_config (dev, map)
+ *
+ *    Configure device, this work is done by netwave_pcmcia_config when a
+ *    card is inserted
+ */
+static int netwave_config(struct net_device *dev, struct ifmap *map) {
+    return 0; 
+}
+
+/*
+ * Function netwave_hw_xmit (data, len, dev)    
+ */
+static int netwave_hw_xmit(unsigned char* data, int len,
+			   struct net_device* dev) {
+    unsigned long flags;
+    unsigned int TxFreeList,
+	         curBuff,
+	         MaxData, 
+                 DataOffset;
+    int tmpcount; 
+	
+    netwave_private *priv = (netwave_private *) dev->priv;
+    u_char* ramBase = priv->ramBase;
+    ioaddr_t iobase = dev->base_addr;
+
+    /* Disable interrupts & save flags */
+    save_flags(flags);
+    cli();
+
+    /* Check if there are transmit buffers available */
+    wait_WOC(iobase);
+    if ((inb(iobase+NETWAVE_REG_ASR) & NETWAVE_ASR_TXBA) == 0) {
+	/* No buffers available */
+	printk(KERN_DEBUG "netwave_hw_xmit: %s - no xmit buffers available.\n",
+	       dev->name);
+	restore_flags(flags);
+	return 1;
+    }
+
+    priv->stats.tx_bytes += len;
+
+    DEBUG(3, "Transmitting with SPCQ %x SPU %x LIF %x ISPLQ %x\n",
+	  readb(ramBase + NETWAVE_EREG_SPCQ),
+	  readb(ramBase + NETWAVE_EREG_SPU),
+	  readb(ramBase + NETWAVE_EREG_LIF),
+	  readb(ramBase + NETWAVE_EREG_ISPLQ));
+
+    /* Now try to insert it into the adapters free memory */
+    wait_WOC(iobase);
+    TxFreeList = get_uint16(ramBase + NETWAVE_EREG_TDP);
+    MaxData    = get_uint16(ramBase + NETWAVE_EREG_TDP+2);
+    DataOffset = get_uint16(ramBase + NETWAVE_EREG_TDP+4);
+	
+    DEBUG(3, "TxFreeList %x, MaxData %x, DataOffset %x\n",
+	  TxFreeList, MaxData, DataOffset);
+
+    /* Copy packet to the adapter fragment buffers */
+    curBuff = TxFreeList; 
+    tmpcount = 0; 
+    while (tmpcount < len) {
+	int tmplen = len - tmpcount; 
+	copy_to_pc(ramBase + curBuff + DataOffset, data + tmpcount, 
+		   (tmplen < MaxData) ? tmplen : MaxData);
+	tmpcount += MaxData;
+			
+	/* Advance to next buffer */
+	curBuff = get_uint16(ramBase + curBuff);
+    }
+    
+    /* Now issue transmit list */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_TL, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(len & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+    writeb((len>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+
+    restore_flags( flags);
+    return 0;
+}
+
+static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+	/* This flag indicate that the hardware can't perform a transmission.
+	 * Theoritically, NET3 check it before sending a packet to the driver,
+	 * but in fact it never do that and pool continuously.
+	 * As the watchdog will abort too long transmissions, we are quite safe...
+	 */
+
+    netif_stop_queue(dev);
+
+    {
+	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned char* buf = skb->data;
+	
+	if (netwave_hw_xmit( buf, length, dev) == 1) {
+	    /* Some error, let's make them call us another time? */
+	    netif_start_queue(dev);
+	}
+	dev->trans_start = jiffies;
+    }
+    dev_kfree_skb(skb);
+    
+    return 0;
+} /* netwave_start_xmit */
+
+/*
+ * Function netwave_interrupt (irq, dev_id, regs)
+ *
+ *    This function is the interrupt handler for the Netwave card. This
+ *    routine will be called whenever: 
+ *	  1. A packet is received.
+ *	  2. A packet has successfully been transferred and the unit is
+ *	     ready to transmit another packet.
+ *	  3. A command has completed execution.
+ */
+static void netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) {
+    ioaddr_t iobase;
+    u_char *ramBase;
+    struct net_device *dev = (struct net_device *)dev_id;
+    struct netwave_private *priv = dev->priv;
+    dev_link_t *link = &priv->link;
+    int i;
+    
+    if (!netif_device_present(dev))
+	return;
+    
+    iobase = dev->base_addr;
+    ramBase = priv->ramBase;
+	
+    /* Now find what caused the interrupt, check while interrupts ready */
+    for (i = 0; i < 10; i++) {
+	u_char status;
+		
+	wait_WOC(iobase);	
+	if (!(inb(iobase+NETWAVE_REG_CCSR) & 0x02))
+	    break; /* None of the interrupt sources asserted */
+	
+        status = inb(iobase + NETWAVE_REG_ASR);
+		
+	if (!DEV_OK(link)) {
+	    DEBUG(1, "netwave_interrupt: Interrupt with status 0x%x "
+		  "from removed or suspended card!\n", status);
+	    break;
+	}
+		
+	/* RxRdy */
+	if (status & 0x80) {
+	    netwave_rx(dev);
+	    /* wait_WOC(iobase); */
+	    /* RxRdy cannot be reset directly by the host */
+	}
+	/* RxErr */
+	if (status & 0x40) {
+	    u_char rser;
+			
+	    rser = readb(ramBase + NETWAVE_EREG_RSER);			
+	    
+	    if (rser & 0x04) {
+		++priv->stats.rx_dropped; 
+		++priv->stats.rx_crc_errors;
+	    }
+	    if (rser & 0x02)
+		++priv->stats.rx_frame_errors;
+			
+	    /* Clear the RxErr bit in RSER. RSER+4 is the
+	     * write part. Also clear the RxCRC (0x04) and 
+	     * RxBig (0x02) bits if present */
+	    wait_WOC(iobase);
+	    writeb(0x40 | (rser & 0x06), ramBase + NETWAVE_EREG_RSER + 4);
+
+	    /* Write bit 6 high to ASCC to clear RxErr in ASR,
+	     * WOC must be set first! 
+	     */
+	    wait_WOC(iobase);
+	    writeb(0x40, ramBase + NETWAVE_EREG_ASCC);
+
+	    /* Remember to count up priv->stats on error packets */
+	    ++priv->stats.rx_errors;
+	}
+	/* TxDN */
+	if (status & 0x20) {
+	    int txStatus;
+
+	    txStatus = readb(ramBase + NETWAVE_EREG_TSER);
+	    DEBUG(3, "Transmit done. TSER = %x id %x\n", 
+		  txStatus, readb(ramBase + NETWAVE_EREG_TSER + 1));
+	    
+	    if (txStatus & 0x20) {
+		/* Transmitting was okay, clear bits */
+		wait_WOC(iobase);
+		writeb(0x2f, ramBase + NETWAVE_EREG_TSER + 4);
+		++priv->stats.tx_packets;
+	    }
+			
+	    if (txStatus & 0xd0) {
+		if (txStatus & 0x80) {
+		    ++priv->stats.collisions; /* Because of /proc/net/dev*/
+		    /* ++priv->stats.tx_aborted_errors; */
+		    /* printk("Collision. %ld\n", jiffies - dev->trans_start); */
+		}
+		if (txStatus & 0x40) 
+		    ++priv->stats.tx_carrier_errors;
+		/* 0x80 TxGU Transmit giveup - nine times and no luck
+		 * 0x40 TxNOAP No access point. Discarded packet.
+		 * 0x10 TxErr Transmit error. Always set when 
+		 *      TxGU and TxNOAP is set. (Those are the only ones
+		 *      to set TxErr).
+		 */
+		DEBUG(3, "netwave_interrupt: TxDN with error status %x\n", 
+		      txStatus);
+		
+		/* Clear out TxGU, TxNOAP, TxErr and TxTrys */
+		wait_WOC(iobase);
+		writeb(0xdf & txStatus, ramBase+NETWAVE_EREG_TSER+4);
+		++priv->stats.tx_errors;
+	    }
+	    DEBUG(3, "New status is TSER %x ASR %x\n",
+		  readb(ramBase + NETWAVE_EREG_TSER),
+		  inb(iobase + NETWAVE_REG_ASR));
+
+	    netif_wake_queue(dev);
+	}
+	/* TxBA, this would trigger on all error packets received */
+	/* if (status & 0x01) {
+	   DEBUG(4, "Transmit buffers available, %x\n", status);
+	   }
+	   */
+    }
+} /* netwave_interrupt */
+
+/*
+ * Function netwave_watchdog (a)
+ *
+ *    Watchdog : when we start a transmission, we set a timer in the
+ *    kernel.  If the transmission complete, this timer is disabled. If
+ *    it expire, we reset the card.
+ *
+ */
+static void netwave_watchdog(struct net_device *dev) {
+
+    DEBUG(1, "%s: netwave_watchdog: watchdog timer expired\n", dev->name);
+    netwave_reset(dev);
+    dev->trans_start = jiffies;
+    netif_wake_queue(dev);
+} /* netwave_watchdog */
+
+static struct net_device_stats *netwave_get_stats(struct net_device *dev) {
+    netwave_private *priv = (netwave_private*)dev->priv;
+
+    update_stats(dev);
+
+    DEBUG(2, "netwave: SPCQ %x SPU %x LIF %x ISPLQ %x MHS %x rxtx %x"
+	  " %x tx %x %x %x %x\n", 
+	  readb(priv->ramBase + NETWAVE_EREG_SPCQ),
+	  readb(priv->ramBase + NETWAVE_EREG_SPU),
+	  readb(priv->ramBase + NETWAVE_EREG_LIF),
+	  readb(priv->ramBase + NETWAVE_EREG_ISPLQ),
+	  readb(priv->ramBase + NETWAVE_EREG_MHS),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0xe),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0xf),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x18),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x19),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x1a),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x1b));
+
+    return &priv->stats;
+}
+
+static void update_stats(struct net_device *dev) {
+    unsigned long flags;
+
+    save_flags(flags);
+    cli();
+
+/*     netwave_private *priv = (netwave_private*) dev->priv;
+    priv->stats.rx_packets = readb(priv->ramBase + 0x18e); 
+    priv->stats.tx_packets = readb(priv->ramBase + 0x18f); */
+
+    restore_flags(flags);
+}
+
+static int netwave_rx(struct net_device *dev) {
+    netwave_private *priv = (netwave_private*)(dev->priv);
+    u_char *ramBase = priv->ramBase;
+    ioaddr_t iobase = dev->base_addr;
+    u_char rxStatus;
+    struct sk_buff *skb = NULL;
+    unsigned int curBuffer,
+		rcvList;
+    int rcvLen;
+    int tmpcount = 0;
+    int dataCount, dataOffset;
+    int i;
+    u_char *ptr;
+	
+    DEBUG(3, "xinw_rx: Receiving ... \n");
+
+    /* Receive max 10 packets for now. */
+    for (i = 0; i < 10; i++) {
+	/* Any packets? */
+	wait_WOC(iobase);
+	rxStatus = readb(ramBase + NETWAVE_EREG_RSER);		
+	if ( !( rxStatus & 0x80)) /* No more packets */
+	    break;
+		
+	/* Check if multicast/broadcast or other */
+	/* multicast = (rxStatus & 0x20);  */
+		
+	/* The receive list pointer and length of the packet */
+	wait_WOC(iobase);
+	rcvLen  = get_int16( ramBase + NETWAVE_EREG_RDP);
+	rcvList = get_uint16( ramBase + NETWAVE_EREG_RDP + 2);
+		
+	if (rcvLen < 0) {
+	    printk(KERN_DEBUG "netwave_rx: Receive packet with len %d\n", 
+		   rcvLen);
+	    return 0;
+	}
+		
+	skb = dev_alloc_skb(rcvLen+5);
+	if (skb == NULL) {
+	    DEBUG(1, "netwave_rx: Could not allocate an sk_buff of "
+		  "length %d\n", rcvLen);
+	    ++priv->stats.rx_dropped; 
+	    /* Tell the adapter to skip the packet */
+	    wait_WOC(iobase);
+	    writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0);
+	    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
+	    return 0;
+	}
+
+	skb_reserve( skb, 2);  /* Align IP on 16 byte */
+	skb_put( skb, rcvLen);
+	skb->dev = dev;
+
+	/* Copy packet fragments to the skb data area */
+	ptr = (u_char*) skb->data;
+	curBuffer = rcvList;
+	tmpcount = 0; 
+	while ( tmpcount < rcvLen) {
+	    /* Get length and offset of current buffer */
+	    dataCount  = get_uint16( ramBase+curBuffer+2);
+	    dataOffset = get_uint16( ramBase+curBuffer+4);
+		
+	    copy_from_pc( ptr + tmpcount,
+			  ramBase+curBuffer+dataOffset, dataCount);
+
+	    tmpcount += dataCount;
+		
+	    /* Point to next buffer */
+	    curBuffer = get_uint16(ramBase + curBuffer);
+	}
+	
+	skb->protocol = eth_type_trans(skb,dev);
+	/* Queue packet for network layer */
+	netif_rx(skb);
+
+	dev->last_rx = jiffies;
+	priv->stats.rx_packets++;
+	priv->stats.rx_bytes += rcvLen;
+
+	/* Got the packet, tell the adapter to skip it */
+	wait_WOC(iobase);
+	writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0);
+	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
+	DEBUG(3, "Packet reception ok\n");
+    }
+    return 0;
+}
+
+static int netwave_open(struct net_device *dev) {
+    netwave_private *priv = dev->priv;
+    dev_link_t *link = &priv->link;
+
+    DEBUG(1, "netwave_open: starting.\n");
+    
+    if (!DEV_OK(link))
+	return -ENODEV;
+
+    link->open++;
+    MOD_INC_USE_COUNT;
+
+    netif_start_queue(dev);
+    netwave_reset(dev);
+	
+    return 0;
+}
+
+static int netwave_close(struct net_device *dev) {
+    netwave_private *priv = (netwave_private *)dev->priv;
+    dev_link_t *link = &priv->link;
+
+    DEBUG(1, "netwave_close: finishing.\n");
+
+    link->open--;
+    netif_stop_queue(dev);
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
+	
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+static int __init init_netwave_cs(void) {
+    servinfo_t serv;
+
+    DEBUG(0, "%s\n", version);
+
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk("netwave_cs: Card Services release does not match!\n");
+	return -1;
+    }
+ 
+    register_pccard_driver(&dev_info, &netwave_attach, &netwave_detach);
+	
+    return 0;
+}
+
+static void __exit exit_netwave_cs(void) {
+    DEBUG(1, "netwave_cs: unloading\n");
+
+    unregister_pccard_driver(&dev_info);
+
+    /* Do some cleanup of the device list */
+    netwave_flush_stale_links();
+    if(dev_list != NULL)	/* Critical situation */
+        printk("netwave_cs: devices remaining when removing module\n");
+}
+
+module_init(init_netwave_cs);
+module_exit(exit_netwave_cs);
+
+/* Set or clear the multicast filter for this adaptor.
+   num_addrs == -1	Promiscuous mode, receive all packets
+   num_addrs == 0	Normal mode, clear multicast list
+   num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+   best-effort filtering.
+ */
+static void set_multicast_list(struct net_device *dev)
+{
+    ioaddr_t iobase = dev->base_addr;
+    u_char* ramBase = ((netwave_private*) dev->priv)->ramBase;
+    u_char  rcvMode = 0;
+   
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 2) {
+	static int old;
+	if (old != dev->mc_count) {
+	    old = dev->mc_count;
+	    DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
+		  dev->name, dev->mc_count);
+	}
+    }
+#endif
+	
+    if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) {
+	/* Multicast Mode */
+	rcvMode = rxConfRxEna + rxConfAMP + rxConfBcast;
+    } else if (dev->flags & IFF_PROMISC) {
+	/* Promiscous mode */
+	rcvMode = rxConfRxEna + rxConfPro + rxConfAMP + rxConfBcast;
+    } else {
+	/* Normal mode */
+	rcvMode = rxConfRxEna + rxConfBcast;
+    }
+	
+    /* printk("netwave set_multicast_list: rcvMode to %x\n", rcvMode);*/
+    /* Now set receive mode */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(rcvMode, ramBase + NETWAVE_EREG_CB + 1);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
+}
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/todo.txt linux/drivers/net/wireless/todo.txt
--- v2.5.2/linux/drivers/net/wireless/todo.txt	Mon May  7 19:42:14 2001
+++ linux/drivers/net/wireless/todo.txt	Mon Jan 21 16:04:47 2002
@@ -4,21 +4,26 @@
 1) Bring other kernel Wireless LAN drivers here
 	Already done :
 	 o hermes.c/orinoco.c	-> Wavelan IEEE driver + Airport driver
-	Drivers I have control over :
+	 o airo.c/airo_cs.c	-> Ben's Aironet driver
 	 o wavelan.c		-> old Wavelan ISA driver
-	 o wavelan_cs.c		-> old Wavelan Pcmcia driver (warning : header)
+	 o wavelan_cs.c		-> old Wavelan Pcmcia driver
 	 o netwave_cs.c		-> Netwave Pcmcia driver
 	Drivers likely to go :
 	 o ray_cs.c		-> Raytheon/Aviator driver (maintainer MIA)
 	Drivers I have absolutely no control over :
 	 o arlan.c		-> old Aironet Arlan 655 (need to ask Elmer)
 	 o aironet4500_xxx.c	-> Elmer's Aironet driver (need to ask Elmer)
-	 o airo.c/airo_cs.c	-> Ben's Aironet driver (not yet in kernel)
 	 o strip.c		-> Metricom's stuff. Not a wlan. Hum...
 
 	ETA : Kernel 2.5.X
 
 2) Bring new Wireless LAN driver not yet in the kernel there
 	See my web page for details
+
+3) Misc
+	o Mark wavelan, wavelan_cs, netwave_cs drivers as obsolete
+	o Maybe arlan.c, ray_cs.c and strip.c also deserve to be obsolete
+	o Use new Probe/module stuff in wavelan.c
+	o New Wireless Extension API (pending)
 
 	Jean II
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/wavelan.c linux/drivers/net/wireless/wavelan.c
--- v2.5.2/linux/drivers/net/wireless/wavelan.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/wavelan.c	Wed Jan  9 14:54:38 2002
@@ -0,0 +1,4342 @@
+/*
+ *	WaveLAN ISA driver
+ *
+ *		Jean II - HPLB '96
+ *
+ * Reorganisation and extension of the driver.
+ * Original copyright follows (also see the end of this file).
+ * See wavelan.p.h for details.
+ *
+ *
+ *
+ * AT&T GIS (nee NCR) WaveLAN card:
+ *	An Ethernet-like radio transceiver
+ *	controlled by an Intel 82586 coprocessor.
+ */
+
+#include "wavelan.p.h"		/* Private header */
+
+/************************* MISC SUBROUTINES **************************/
+/*
+ * Subroutines which won't fit in one of the following category
+ * (WaveLAN modem or i82586)
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for disabling interrupts and locking the driver.
+ * (note : inline, so optimised away)
+ */
+static inline void wv_splhi(net_local *		lp,
+			    unsigned long *	pflags)
+{
+	spin_lock_irqsave(&lp->spinlock, *pflags);
+	/* Note : above does the cli(); itself */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for re-enabling interrupts and un-locking the driver.
+ */
+static inline void wv_splx(net_local *		lp,
+			   unsigned long *	pflags)
+{
+	spin_unlock_irqrestore(&lp->spinlock, *pflags);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Translate irq number to PSA irq parameter
+ */
+static u8 wv_irq_to_psa(int irq)
+{
+	if (irq < 0 || irq >= NELS(irqvals))
+		return 0;
+
+	return irqvals[irq];
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Translate PSA irq parameter to irq number 
+ */
+static int __init wv_psa_to_irq(u8 irqval)
+{
+	int irq;
+
+	for (irq = 0; irq < NELS(irqvals); irq++)
+		if (irqvals[irq] == irqval)
+			return irq;
+
+	return -1;
+}
+
+#ifdef STRUCT_CHECK
+/*------------------------------------------------------------------*/
+/*
+ * Sanity routine to verify the sizes of the various WaveLAN interface
+ * structures.
+ */
+static char *wv_struct_check(void)
+{
+#define	SC(t,s,n)	if (sizeof(t) != s) return(n);
+
+	SC(psa_t, PSA_SIZE, "psa_t");
+	SC(mmw_t, MMW_SIZE, "mmw_t");
+	SC(mmr_t, MMR_SIZE, "mmr_t");
+	SC(ha_t, HA_SIZE, "ha_t");
+
+#undef	SC
+
+	return ((char *) NULL);
+}				/* wv_struct_check */
+#endif				/* STRUCT_CHECK */
+
+/********************* HOST ADAPTER SUBROUTINES *********************/
+/*
+ * Useful subroutines to manage the WaveLAN ISA interface
+ *
+ * One major difference with the PCMCIA hardware (except the port mapping)
+ * is that we have to keep the state of the Host Control Register
+ * because of the interrupt enable & bus size flags.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read from card's Host Adaptor Status Register.
+ */
+static inline u16 hasr_read(unsigned long ioaddr)
+{
+	return (inw(HASR(ioaddr)));
+}				/* hasr_read */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write to card's Host Adapter Command Register.
+ */
+static inline void hacr_write(unsigned long ioaddr, u16 hacr)
+{
+	outw(hacr, HACR(ioaddr));
+}				/* hacr_write */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write to card's Host Adapter Command Register. Include a delay for
+ * those times when it is needed.
+ */
+static inline void hacr_write_slow(unsigned long ioaddr, u16 hacr)
+{
+	hacr_write(ioaddr, hacr);
+	/* delay might only be needed sometimes */
+	mdelay(1);
+}				/* hacr_write_slow */
+
+/*------------------------------------------------------------------*/
+/*
+ * Set the channel attention bit.
+ */
+static inline void set_chan_attn(unsigned long ioaddr, u16 hacr)
+{
+	hacr_write(ioaddr, hacr | HACR_CA);
+}				/* set_chan_attn */
+
+/*------------------------------------------------------------------*/
+/*
+ * Reset, and then set host adaptor into default mode.
+ */
+static inline void wv_hacr_reset(unsigned long ioaddr)
+{
+	hacr_write_slow(ioaddr, HACR_RESET);
+	hacr_write(ioaddr, HACR_DEFAULT);
+}				/* wv_hacr_reset */
+
+/*------------------------------------------------------------------*/
+/*
+ * Set the I/O transfer over the ISA bus to 8-bit mode
+ */
+static inline void wv_16_off(unsigned long ioaddr, u16 hacr)
+{
+	hacr &= ~HACR_16BITS;
+	hacr_write(ioaddr, hacr);
+}				/* wv_16_off */
+
+/*------------------------------------------------------------------*/
+/*
+ * Set the I/O transfer over the ISA bus to 8-bit mode
+ */
+static inline void wv_16_on(unsigned long ioaddr, u16 hacr)
+{
+	hacr |= HACR_16BITS;
+	hacr_write(ioaddr, hacr);
+}				/* wv_16_on */
+
+/*------------------------------------------------------------------*/
+/*
+ * Disable interrupts on the WaveLAN hardware.
+ * (called by wv_82586_stop())
+ */
+static inline void wv_ints_off(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	
+	lp->hacr &= ~HACR_INTRON;
+	hacr_write(ioaddr, lp->hacr);
+}				/* wv_ints_off */
+
+/*------------------------------------------------------------------*/
+/*
+ * Enable interrupts on the WaveLAN hardware.
+ * (called by wv_hw_reset())
+ */
+static inline void wv_ints_on(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+
+	lp->hacr |= HACR_INTRON;
+	hacr_write(ioaddr, lp->hacr);
+}				/* wv_ints_on */
+
+/******************* MODEM MANAGEMENT SUBROUTINES *******************/
+/*
+ * Useful subroutines to manage the modem of the WaveLAN
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read the Parameter Storage Area from the WaveLAN card's memory
+ */
+/*
+ * Read bytes from the PSA.
+ */
+static void psa_read(unsigned long ioaddr, u16 hacr, int o,	/* offset in PSA */
+		     u8 * b,	/* buffer to fill */
+		     int n)
+{				/* size to read */
+	wv_16_off(ioaddr, hacr);
+
+	while (n-- > 0) {
+		outw(o, PIOR2(ioaddr));
+		o++;
+		*b++ = inb(PIOP2(ioaddr));
+	}
+
+	wv_16_on(ioaddr, hacr);
+}				/* psa_read */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write the Parameter Storage Area to the WaveLAN card's memory.
+ */
+static void psa_write(unsigned long ioaddr, u16 hacr, int o,	/* Offset in PSA */
+		      u8 * b,	/* Buffer in memory */
+		      int n)
+{				/* Length of buffer */
+	int count = 0;
+
+	wv_16_off(ioaddr, hacr);
+
+	while (n-- > 0) {
+		outw(o, PIOR2(ioaddr));
+		o++;
+
+		outb(*b, PIOP2(ioaddr));
+		b++;
+
+		/* Wait for the memory to finish its write cycle */
+		count = 0;
+		while ((count++ < 100) &&
+		       (hasr_read(ioaddr) & HASR_PSA_BUSY)) mdelay(1);
+	}
+
+	wv_16_on(ioaddr, hacr);
+}				/* psa_write */
+
+#ifdef SET_PSA_CRC
+/*------------------------------------------------------------------*/
+/*
+ * Calculate the PSA CRC
+ * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code
+ * NOTE: By specifying a length including the CRC position the
+ * returned value should be zero. (i.e. a correct checksum in the PSA)
+ *
+ * The Windows drivers don't use the CRC, but the AP and the PtP tool
+ * depend on it.
+ */
+static inline u16 psa_crc(u8 * psa,	/* The PSA */
+			      int size)
+{				/* Number of short for CRC */
+	int byte_cnt;		/* Loop on the PSA */
+	u16 crc_bytes = 0;	/* Data in the PSA */
+	int bit_cnt;		/* Loop on the bits of the short */
+
+	for (byte_cnt = 0; byte_cnt < size; byte_cnt++) {
+		crc_bytes ^= psa[byte_cnt];	/* Its an xor */
+
+		for (bit_cnt = 1; bit_cnt < 9; bit_cnt++) {
+			if (crc_bytes & 0x0001)
+				crc_bytes = (crc_bytes >> 1) ^ 0xA001;
+			else
+				crc_bytes >>= 1;
+		}
+	}
+
+	return crc_bytes;
+}				/* psa_crc */
+#endif				/* SET_PSA_CRC */
+
+/*------------------------------------------------------------------*/
+/*
+ * update the checksum field in the Wavelan's PSA
+ */
+static void update_psa_checksum(device * dev, unsigned long ioaddr, u16 hacr)
+{
+#ifdef SET_PSA_CRC
+	psa_t psa;
+	u16 crc;
+
+	/* read the parameter storage area */
+	psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa));
+
+	/* update the checksum */
+	crc = psa_crc((unsigned char *) &psa,
+		      sizeof(psa) - sizeof(psa.psa_crc[0]) -
+		      sizeof(psa.psa_crc[1])
+		      - sizeof(psa.psa_crc_status));
+
+	psa.psa_crc[0] = crc & 0xFF;
+	psa.psa_crc[1] = (crc & 0xFF00) >> 8;
+
+	/* Write it ! */
+	psa_write(ioaddr, hacr, (char *) &psa.psa_crc - (char *) &psa,
+		  (unsigned char *) &psa.psa_crc, 2);
+
+#ifdef DEBUG_IOCTL_INFO
+	printk(KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n",
+	       dev->name, psa.psa_crc[0], psa.psa_crc[1]);
+
+	/* Check again (luxury !) */
+	crc = psa_crc((unsigned char *) &psa,
+		      sizeof(psa) - sizeof(psa.psa_crc_status));
+
+	if (crc != 0)
+		printk(KERN_WARNING
+		       "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n",
+		       dev->name);
+#endif				/* DEBUG_IOCTL_INFO */
+#endif				/* SET_PSA_CRC */
+}				/* update_psa_checksum */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write 1 byte to the MMC.
+ */
+static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d)
+{
+	/* Wait for MMC to go idle */
+	while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
+
+	outw((u16) (((u16) d << 8) | (o << 1) | 1), MMCR(ioaddr));
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to write bytes to the Modem Management Controller.
+ * We start at the end because it is the way it should be!
+ */
+static inline void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n)
+{
+	o += n;
+	b += n;
+
+	while (n-- > 0)
+		mmc_out(ioaddr, --o, *(--b));
+}				/* mmc_write */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read a byte from the MMC.
+ * Optimised version for 1 byte, avoid using memory.
+ */
+static inline u8 mmc_in(unsigned long ioaddr, u16 o)
+{
+	while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
+	outw(o << 1, MMCR(ioaddr));
+
+	while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
+	return (u8) (inw(MMCR(ioaddr)) >> 8);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to read bytes from the Modem Management Controller.
+ * The implementation is complicated by a lack of address lines,
+ * which prevents decoding of the low-order bit.
+ * (code has just been moved in the above function)
+ * We start at the end because it is the way it should be!
+ */
+static inline void mmc_read(unsigned long ioaddr, u8 o, u8 * b, int n)
+{
+	o += n;
+	b += n;
+
+	while (n-- > 0)
+		*(--b) = mmc_in(ioaddr, --o);
+}				/* mmc_read */
+
+/*------------------------------------------------------------------*/
+/*
+ * Get the type of encryption available.
+ */
+static inline int mmc_encr(unsigned long ioaddr)
+{				/* I/O port of the card */
+	int temp;
+
+	temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail));
+	if ((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES))
+		return 0;
+	else
+		return temp;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wait for the frequency EEPROM to complete a command.
+ * I hope this one will be optimally inlined.
+ */
+static inline void fee_wait(unsigned long ioaddr,	/* I/O port of the card */
+			    int delay,	/* Base delay to wait for */
+			    int number)
+{				/* Number of time to wait */
+	int count = 0;		/* Wait only a limited time */
+
+	while ((count++ < number) &&
+	       (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+		MMR_FEE_STATUS_BUSY)) udelay(delay);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Read bytes from the Frequency EEPROM (frequency select cards).
+ */
+static void fee_read(unsigned long ioaddr,	/* I/O port of the card */
+		     u16 o,	/* destination offset */
+		     u16 * b,	/* data buffer */
+		     int n)
+{				/* number of registers */
+	b += n;			/* Position at the end of the area */
+
+	/* Write the address */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
+
+	/* Loop on all buffer */
+	while (n-- > 0) {
+		/* Write the read command */
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
+			MMW_FEE_CTRL_READ);
+
+		/* Wait until EEPROM is ready (should be quick). */
+		fee_wait(ioaddr, 10, 100);
+
+		/* Read the value. */
+		*--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) |
+			mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
+	}
+}
+
+#ifdef WIRELESS_EXT		/* if the wireless extension exists in the kernel */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write bytes from the Frequency EEPROM (frequency select cards).
+ * This is a bit complicated, because the frequency EEPROM has to
+ * be unprotected and the write enabled.
+ * Jean II
+ */
+static void fee_write(unsigned long ioaddr,	/* I/O port of the card */
+		      u16 o,	/* destination offset */
+		      u16 * b,	/* data buffer */
+		      int n)
+{				/* number of registers */
+	b += n;			/* Position at the end of the area. */
+
+#ifdef EEPROM_IS_PROTECTED	/* disabled */
+#ifdef DOESNT_SEEM_TO_WORK	/* disabled */
+	/* Ask to read the protected register */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD);
+
+	fee_wait(ioaddr, 10, 100);
+
+	/* Read the protected register. */
+	printk("Protected 2:  %02X-%02X\n",
+	       mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
+	       mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
+#endif				/* DOESNT_SEEM_TO_WORK */
+
+	/* Enable protected register. */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
+
+	fee_wait(ioaddr, 10, 100);
+
+	/* Unprotect area. */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
+#ifdef DOESNT_SEEM_TO_WORK	/* disabled */
+	/* or use: */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
+#endif				/* DOESNT_SEEM_TO_WORK */
+
+	fee_wait(ioaddr, 10, 100);
+#endif				/* EEPROM_IS_PROTECTED */
+
+	/* Write enable. */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
+
+	fee_wait(ioaddr, 10, 100);
+
+	/* Write the EEPROM address. */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
+
+	/* Loop on all buffer */
+	while (n-- > 0) {
+		/* Write the value. */
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
+
+		/* Write the write command. */
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
+			MMW_FEE_CTRL_WRITE);
+
+		/* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */
+		mdelay(10);
+		fee_wait(ioaddr, 10, 100);
+	}
+
+	/* Write disable. */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
+
+	fee_wait(ioaddr, 10, 100);
+
+#ifdef EEPROM_IS_PROTECTED	/* disabled */
+	/* Reprotect EEPROM. */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00);
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
+
+	fee_wait(ioaddr, 10, 100);
+#endif				/* EEPROM_IS_PROTECTED */
+}
+#endif				/* WIRELESS_EXT */
+
+/************************ I82586 SUBROUTINES *************************/
+/*
+ * Useful subroutines to manage the Ethernet controller
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read bytes from the on-board RAM.
+ * Why does inlining this function make it fail?
+ */
+static /*inline */ void obram_read(unsigned long ioaddr,
+				   u16 o, u8 * b, int n)
+{
+	outw(o, PIOR1(ioaddr));
+	insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Write bytes to the on-board RAM.
+ */
+static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n)
+{
+	outw(o, PIOR1(ioaddr));
+	outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Acknowledge the reading of the status issued by the i82586.
+ */
+static void wv_ack(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	u16 scb_cs;
+	int i;
+
+	obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
+		   (unsigned char *) &scb_cs, sizeof(scb_cs));
+	scb_cs &= SCB_ST_INT;
+
+	if (scb_cs == 0)
+		return;
+
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+		    (unsigned char *) &scb_cs, sizeof(scb_cs));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 1000; i > 0; i--) {
+		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
+			   (unsigned char *) &scb_cs, sizeof(scb_cs));
+		if (scb_cs == 0)
+			break;
+
+		udelay(10);
+	}
+	udelay(100);
+
+#ifdef DEBUG_CONFIG_ERROR
+	if (i <= 0)
+		printk(KERN_INFO
+		       "%s: wv_ack(): board not accepting command.\n",
+		       dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set channel attention bit and busy wait until command has
+ * completed, then acknowledge completion of the command.
+ */
+static inline int wv_synchronous_cmd(device * dev, const char *str)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	u16 scb_cmd;
+	ach_t cb;
+	int i;
+
+	scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO;
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+		    (unsigned char *) &scb_cmd, sizeof(scb_cmd));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 1000; i > 0; i--) {
+		obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb,
+			   sizeof(cb));
+		if (cb.ac_status & AC_SFLD_C)
+			break;
+
+		udelay(10);
+	}
+	udelay(100);
+
+	if (i <= 0 || !(cb.ac_status & AC_SFLD_OK)) {
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_INFO "%s: %s failed; status = 0x%x\n",
+		       dev->name, str, cb.ac_status);
+#endif
+#ifdef DEBUG_I82586_SHOW
+		wv_scb_show(ioaddr);
+#endif
+		return -1;
+	}
+
+	/* Ack the status */
+	wv_ack(dev);
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Configuration commands completion interrupt.
+ * Check if done, and if OK.
+ */
+static inline int
+wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp)
+{
+	unsigned short mcs_addr;
+	unsigned short status;
+	int ret;
+
+#ifdef DEBUG_INTERRUPT_TRACE
+	printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name);
+#endif
+
+	mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t)
+	    + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t);
+
+	/* Read the status of the last command (set mc list). */
+	obram_read(ioaddr, acoff(mcs_addr, ac_status),
+		   (unsigned char *) &status, sizeof(status));
+
+	/* If not completed -> exit */
+	if ((status & AC_SFLD_C) == 0)
+		ret = 0;	/* Not ready to be scrapped */
+	else {
+#ifdef DEBUG_CONFIG_ERROR
+		unsigned short cfg_addr;
+		unsigned short ias_addr;
+
+		/* Check mc_config command */
+		if ((status & AC_SFLD_OK) != AC_SFLD_OK)
+			printk(KERN_INFO
+			       "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n",
+			       dev->name, status);
+
+		/* check ia-config command */
+		ias_addr = mcs_addr - sizeof(ac_ias_t);
+		obram_read(ioaddr, acoff(ias_addr, ac_status),
+			   (unsigned char *) &status, sizeof(status));
+		if ((status & AC_SFLD_OK) != AC_SFLD_OK)
+			printk(KERN_INFO
+			       "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n",
+			       dev->name, status);
+
+		/* Check config command. */
+		cfg_addr = ias_addr - sizeof(ac_cfg_t);
+		obram_read(ioaddr, acoff(cfg_addr, ac_status),
+			   (unsigned char *) &status, sizeof(status));
+		if ((status & AC_SFLD_OK) != AC_SFLD_OK)
+			printk(KERN_INFO
+			       "%s: wv_config_complete(): configure failed; status = 0x%x\n",
+			       dev->name, status);
+#endif	/* DEBUG_CONFIG_ERROR */
+
+		ret = 1;	/* Ready to be scrapped */
+	}
+
+#ifdef DEBUG_INTERRUPT_TRACE
+	printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name,
+	       ret);
+#endif
+	return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Command completion interrupt.
+ * Reclaim as many freed tx buffers as we can.
+ * (called in wavelan_interrupt()).
+ * Note : the spinlock is already grabbed for us.
+ */
+static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp)
+{
+	int nreaped = 0;
+
+#ifdef DEBUG_INTERRUPT_TRACE
+	printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name);
+#endif
+
+	/* Loop on all the transmit buffers */
+	while (lp->tx_first_in_use != I82586NULL) {
+		unsigned short tx_status;
+
+		/* Read the first transmit buffer */
+		obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status),
+			   (unsigned char *) &tx_status,
+			   sizeof(tx_status));
+
+		/* If not completed -> exit */
+		if ((tx_status & AC_SFLD_C) == 0)
+			break;
+
+		/* Hack for reconfiguration */
+		if (tx_status == 0xFFFF)
+			if (!wv_config_complete(dev, ioaddr, lp))
+				break;	/* Not completed */
+
+		/* We now remove this buffer */
+		nreaped++;
+		--lp->tx_n_in_use;
+
+/*
+if (lp->tx_n_in_use > 0)
+	printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);
+*/
+
+		/* Was it the last one? */
+		if (lp->tx_n_in_use <= 0)
+			lp->tx_first_in_use = I82586NULL;
+		else {
+			/* Next one in the chain */
+			lp->tx_first_in_use += TXBLOCKZ;
+			if (lp->tx_first_in_use >=
+			    OFFSET_CU +
+			    NTXBLOCKS * TXBLOCKZ) lp->tx_first_in_use -=
+				    NTXBLOCKS * TXBLOCKZ;
+		}
+
+		/* Hack for reconfiguration */
+		if (tx_status == 0xFFFF)
+			continue;
+
+		/* Now, check status of the finished command */
+		if (tx_status & AC_SFLD_OK) {
+			int ncollisions;
+
+			lp->stats.tx_packets++;
+			ncollisions = tx_status & AC_SFLD_MAXCOL;
+			lp->stats.collisions += ncollisions;
+#ifdef DEBUG_TX_INFO
+			if (ncollisions > 0)
+				printk(KERN_DEBUG
+				       "%s: wv_complete(): tx completed after %d collisions.\n",
+				       dev->name, ncollisions);
+#endif
+		} else {
+			lp->stats.tx_errors++;
+			if (tx_status & AC_SFLD_S10) {
+				lp->stats.tx_carrier_errors++;
+#ifdef DEBUG_TX_FAIL
+				printk(KERN_DEBUG
+				       "%s: wv_complete(): tx error: no CS.\n",
+				       dev->name);
+#endif
+			}
+			if (tx_status & AC_SFLD_S9) {
+				lp->stats.tx_carrier_errors++;
+#ifdef DEBUG_TX_FAIL
+				printk(KERN_DEBUG
+				       "%s: wv_complete(): tx error: lost CTS.\n",
+				       dev->name);
+#endif
+			}
+			if (tx_status & AC_SFLD_S8) {
+				lp->stats.tx_fifo_errors++;
+#ifdef DEBUG_TX_FAIL
+				printk(KERN_DEBUG
+				       "%s: wv_complete(): tx error: slow DMA.\n",
+				       dev->name);
+#endif
+			}
+			if (tx_status & AC_SFLD_S6) {
+				lp->stats.tx_heartbeat_errors++;
+#ifdef DEBUG_TX_FAIL
+				printk(KERN_DEBUG
+				       "%s: wv_complete(): tx error: heart beat.\n",
+				       dev->name);
+#endif
+			}
+			if (tx_status & AC_SFLD_S5) {
+				lp->stats.tx_aborted_errors++;
+#ifdef DEBUG_TX_FAIL
+				printk(KERN_DEBUG
+				       "%s: wv_complete(): tx error: too many collisions.\n",
+				       dev->name);
+#endif
+			}
+		}
+
+#ifdef DEBUG_TX_INFO
+		printk(KERN_DEBUG
+		       "%s: wv_complete(): tx completed, tx_status 0x%04x\n",
+		       dev->name, tx_status);
+#endif
+	}
+
+#ifdef DEBUG_INTERRUPT_INFO
+	if (nreaped > 1)
+		printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n",
+		       dev->name, nreaped);
+#endif
+
+	/*
+	 * Inform upper layers.
+	 */
+	if (lp->tx_n_in_use < NTXBLOCKS - 1) {
+		netif_wake_queue(dev);
+	}
+#ifdef DEBUG_INTERRUPT_TRACE
+	printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name);
+#endif
+	return nreaped;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Reconfigure the i82586, or at least ask for it.
+ * Because wv_82586_config uses a transmission buffer, we must do it
+ * when we are sure that there is one left, so we do it now
+ * or in wavelan_packet_xmit() (I can't find any better place,
+ * wavelan_interrupt is not an option), so you may experience
+ * delays sometimes.
+ */
+static inline void wv_82586_reconfig(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long flags;
+
+	/* Arm the flag, will be cleard in wv_82586_config() */
+	lp->reconfig_82586 = 1;
+
+	/* Check if we can do it now ! */
+	if((netif_running(dev)) && !(netif_queue_stopped(dev))) {
+		wv_splhi(lp, &flags);
+		/* May fail */
+		wv_82586_config(dev);
+		wv_splx(lp, &flags);
+	}
+	else {
+#ifdef DEBUG_CONFIG_INFO
+		printk(KERN_DEBUG
+		       "%s: wv_82586_reconfig(): delayed (state = %lX)\n",
+			       dev->name, dev->state);
+#endif
+	}
+}
+
+/********************* DEBUG & INFO SUBROUTINES *********************/
+/*
+ * This routine is used in the code to show information for debugging.
+ * Most of the time, it dumps the contents of hardware structures.
+ */
+
+#ifdef DEBUG_PSA_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted contents of the Parameter Storage Area.
+ */
+static void wv_psa_show(psa_t * p)
+{
+	printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
+	printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
+	       p->psa_io_base_addr_1,
+	       p->psa_io_base_addr_2,
+	       p->psa_io_base_addr_3, p->psa_io_base_addr_4);
+	printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n",
+	       p->psa_rem_boot_addr_1,
+	       p->psa_rem_boot_addr_2, p->psa_rem_boot_addr_3);
+	printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
+	printk("psa_int_req_no: %d\n", p->psa_int_req_no);
+#ifdef DEBUG_SHOW_UNUSED
+	printk(KERN_DEBUG
+	       "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	       p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2],
+	       p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5],
+	       p->psa_unused0[6]);
+#endif				/* DEBUG_SHOW_UNUSED */
+	printk(KERN_DEBUG
+	       "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1],
+	       p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3],
+	       p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]);
+	printk(KERN_DEBUG
+	       "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       p->psa_local_mac_addr[0], p->psa_local_mac_addr[1],
+	       p->psa_local_mac_addr[2], p->psa_local_mac_addr[3],
+	       p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]);
+	printk(KERN_DEBUG "psa_univ_local_sel: %d, ",
+	       p->psa_univ_local_sel);
+	printk("psa_comp_number: %d, ", p->psa_comp_number);
+	printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
+	printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ",
+	       p->psa_feature_select);
+	printk("psa_subband/decay_update_prm: %d\n", p->psa_subband);
+	printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr);
+	printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay);
+	printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0],
+	       p->psa_nwid[1]);
+	printk("psa_nwid_select: %d\n", p->psa_nwid_select);
+	printk(KERN_DEBUG "psa_encryption_select: %d, ",
+	       p->psa_encryption_select);
+	printk
+	    ("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+	     p->psa_encryption_key[0], p->psa_encryption_key[1],
+	     p->psa_encryption_key[2], p->psa_encryption_key[3],
+	     p->psa_encryption_key[4], p->psa_encryption_key[5],
+	     p->psa_encryption_key[6], p->psa_encryption_key[7]);
+	printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width);
+	printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ",
+	       p->psa_call_code[0]);
+	printk
+	    ("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	     p->psa_call_code[0], p->psa_call_code[1], p->psa_call_code[2],
+	     p->psa_call_code[3], p->psa_call_code[4], p->psa_call_code[5],
+	     p->psa_call_code[6], p->psa_call_code[7]);
+#ifdef DEBUG_SHOW_UNUSED
+	printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
+	       p->psa_reserved[0],
+	       p->psa_reserved[1], p->psa_reserved[2], p->psa_reserved[3]);
+#endif				/* DEBUG_SHOW_UNUSED */
+	printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
+	printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
+	printk("psa_crc_status: 0x%02x\n", p->psa_crc_status);
+}				/* wv_psa_show */
+#endif				/* DEBUG_PSA_SHOW */
+
+#ifdef DEBUG_MMC_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the Modem Management Controller.
+ * This function needs to be completed.
+ */
+static void wv_mmc_show(device * dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;
+	mmr_t m;
+
+	/* Basic check */
+	if (hasr_read(ioaddr) & HASR_NO_CLK) {
+		printk(KERN_WARNING
+		       "%s: wv_mmc_show: modem not connected\n",
+		       dev->name);
+		return;
+	}
+
+	/* Read the mmc */
+	mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
+	mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m));
+	mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
+
+#ifdef WIRELESS_EXT		/* if wireless extension exists in the kernel */
+	/* Don't forget to update statistics */
+	lp->wstats.discard.nwid +=
+	    (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+#endif				/* WIRELESS_EXT */
+
+	printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n");
+#ifdef DEBUG_SHOW_UNUSED
+	printk(KERN_DEBUG
+	       "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	       m.mmr_unused0[0], m.mmr_unused0[1], m.mmr_unused0[2],
+	       m.mmr_unused0[3], m.mmr_unused0[4], m.mmr_unused0[5],
+	       m.mmr_unused0[6], m.mmr_unused0[7]);
+#endif				/* DEBUG_SHOW_UNUSED */
+	printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n",
+	       m.mmr_des_avail, m.mmr_des_status);
+#ifdef DEBUG_SHOW_UNUSED
+	printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
+	       m.mmr_unused1[0],
+	       m.mmr_unused1[1],
+	       m.mmr_unused1[2], m.mmr_unused1[3], m.mmr_unused1[4]);
+#endif				/* DEBUG_SHOW_UNUSED */
+	printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n",
+	       m.mmr_dce_status,
+	       (m.
+		mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ?
+	       "energy detected," : "",
+	       (m.
+		mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ?
+	       "loop test indicated," : "",
+	       (m.
+		mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ?
+	       "transmitter on," : "",
+	       (m.
+		mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ?
+	       "jabber timer expired," : "");
+	printk(KERN_DEBUG "Dsp ID: %02X\n", m.mmr_dsp_id);
+#ifdef DEBUG_SHOW_UNUSED
+	printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n",
+	       m.mmr_unused2[0], m.mmr_unused2[1]);
+#endif				/* DEBUG_SHOW_UNUSED */
+	printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n",
+	       (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l,
+	       (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l);
+	printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n",
+	       m.mmr_thr_pre_set & MMR_THR_PRE_SET,
+	       (m.
+		mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" :
+	       "below");
+	printk(KERN_DEBUG "signal_lvl: %d [%s], ",
+	       m.mmr_signal_lvl & MMR_SIGNAL_LVL,
+	       (m.
+		mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" :
+	       "no new msg");
+	printk("silence_lvl: %d [%s], ",
+	       m.mmr_silence_lvl & MMR_SILENCE_LVL,
+	       (m.
+		mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" :
+	       "no new update");
+	printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL,
+	       (m.
+		mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" :
+	       "Antenna 0");
+#ifdef DEBUG_SHOW_UNUSED
+	printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l);
+#endif				/* DEBUG_SHOW_UNUSED */
+}				/* wv_mmc_show */
+#endif				/* DEBUG_MMC_SHOW */
+
+#ifdef DEBUG_I82586_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the last block of the i82586 memory.
+ */
+static void wv_scb_show(unsigned long ioaddr)
+{
+	scb_t scb;
+
+	obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
+		   sizeof(scb));
+
+	printk(KERN_DEBUG "##### WaveLAN system control block: #####\n");
+
+	printk(KERN_DEBUG "status: ");
+	printk("stat 0x%x[%s%s%s%s] ",
+	       (scb.
+		scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA |
+			      SCB_ST_RNR)) >> 12,
+	       (scb.
+		scb_status & SCB_ST_CX) ? "command completion interrupt," :
+	       "", (scb.scb_status & SCB_ST_FR) ? "frame received," : "",
+	       (scb.
+		scb_status & SCB_ST_CNA) ? "command unit not active," : "",
+	       (scb.
+		scb_status & SCB_ST_RNR) ? "receiving unit not ready," :
+	       "");
+	printk("cus 0x%x[%s%s%s] ", (scb.scb_status & SCB_ST_CUS) >> 8,
+	       ((scb.scb_status & SCB_ST_CUS) ==
+		SCB_ST_CUS_IDLE) ? "idle" : "",
+	       ((scb.scb_status & SCB_ST_CUS) ==
+		SCB_ST_CUS_SUSP) ? "suspended" : "",
+	       ((scb.scb_status & SCB_ST_CUS) ==
+		SCB_ST_CUS_ACTV) ? "active" : "");
+	printk("rus 0x%x[%s%s%s%s]\n", (scb.scb_status & SCB_ST_RUS) >> 4,
+	       ((scb.scb_status & SCB_ST_RUS) ==
+		SCB_ST_RUS_IDLE) ? "idle" : "",
+	       ((scb.scb_status & SCB_ST_RUS) ==
+		SCB_ST_RUS_SUSP) ? "suspended" : "",
+	       ((scb.scb_status & SCB_ST_RUS) ==
+		SCB_ST_RUS_NRES) ? "no resources" : "",
+	       ((scb.scb_status & SCB_ST_RUS) ==
+		SCB_ST_RUS_RDY) ? "ready" : "");
+
+	printk(KERN_DEBUG "command: ");
+	printk("ack 0x%x[%s%s%s%s] ",
+	       (scb.
+		scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR |
+			       SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12,
+	       (scb.
+		scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "",
+	       (scb.
+		scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "",
+	       (scb.
+		scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "",
+	       (scb.
+		scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : "");
+	printk("cuc 0x%x[%s%s%s%s%s] ",
+	       (scb.scb_command & SCB_CMD_CUC) >> 8,
+	       ((scb.scb_command & SCB_CMD_CUC) ==
+		SCB_CMD_CUC_NOP) ? "nop" : "",
+	       ((scb.scb_command & SCB_CMD_CUC) ==
+		SCB_CMD_CUC_GO) ? "start cbl_offset" : "",
+	       ((scb.scb_command & SCB_CMD_CUC) ==
+		SCB_CMD_CUC_RES) ? "resume execution" : "",
+	       ((scb.scb_command & SCB_CMD_CUC) ==
+		SCB_CMD_CUC_SUS) ? "suspend execution" : "",
+	       ((scb.scb_command & SCB_CMD_CUC) ==
+		SCB_CMD_CUC_ABT) ? "abort execution" : "");
+	printk("ruc 0x%x[%s%s%s%s%s]\n",
+	       (scb.scb_command & SCB_CMD_RUC) >> 4,
+	       ((scb.scb_command & SCB_CMD_RUC) ==
+		SCB_CMD_RUC_NOP) ? "nop" : "",
+	       ((scb.scb_command & SCB_CMD_RUC) ==
+		SCB_CMD_RUC_GO) ? "start rfa_offset" : "",
+	       ((scb.scb_command & SCB_CMD_RUC) ==
+		SCB_CMD_RUC_RES) ? "resume reception" : "",
+	       ((scb.scb_command & SCB_CMD_RUC) ==
+		SCB_CMD_RUC_SUS) ? "suspend reception" : "",
+	       ((scb.scb_command & SCB_CMD_RUC) ==
+		SCB_CMD_RUC_ABT) ? "abort reception" : "");
+
+	printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset);
+	printk("rfa_offset 0x%x\n", scb.scb_rfa_offset);
+
+	printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs);
+	printk("alnerrs %d ", scb.scb_alnerrs);
+	printk("rscerrs %d ", scb.scb_rscerrs);
+	printk("ovrnerrs %d\n", scb.scb_ovrnerrs);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the i82586's receive unit.
+ */
+static void wv_ru_show(device * dev)
+{
+	/* net_local *lp = (net_local *) dev->priv; */
+
+	printk(KERN_DEBUG
+	       "##### WaveLAN i82586 receiver unit status: #####\n");
+	printk(KERN_DEBUG "ru:");
+	/*
+	 * Not implemented yet
+	 */
+	printk("\n");
+}				/* wv_ru_show */
+
+/*------------------------------------------------------------------*/
+/*
+ * Display info about one control block of the i82586 memory.
+ */
+static void wv_cu_show_one(device * dev, net_local * lp, int i, u16 p)
+{
+	unsigned long ioaddr;
+	ac_tx_t actx;
+
+	ioaddr = dev->base_addr;
+
+	printk("%d: 0x%x:", i, p);
+
+	obram_read(ioaddr, p, (unsigned char *) &actx, sizeof(actx));
+	printk(" status=0x%x,", actx.tx_h.ac_status);
+	printk(" command=0x%x,", actx.tx_h.ac_command);
+
+	/*
+	   {
+	   tbd_t      tbd;
+
+	   obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd));
+	   printk(" tbd_status=0x%x,", tbd.tbd_status);
+	   }
+	 */
+
+	printk("|");
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Print status of the command unit of the i82586.
+ */
+static void wv_cu_show(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned int i;
+	u16 p;
+
+	printk(KERN_DEBUG
+	       "##### WaveLAN i82586 command unit status: #####\n");
+
+	printk(KERN_DEBUG);
+	for (i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++) {
+		wv_cu_show_one(dev, lp, i, p);
+
+		p += TXBLOCKZ;
+		if (p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
+			p -= NTXBLOCKS * TXBLOCKZ;
+	}
+	printk("\n");
+}
+#endif				/* DEBUG_I82586_SHOW */
+
+#ifdef DEBUG_DEVICE_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the WaveLAN PCMCIA device driver.
+ */
+static void wv_dev_show(device * dev)
+{
+	printk(KERN_DEBUG "dev:");
+	printk(" state=%lX,", dev->state);
+	printk(" trans_start=%ld,", dev->trans_start);
+	printk(" flags=0x%x,", dev->flags);
+	printk("\n");
+}				/* wv_dev_show */
+
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the WaveLAN PCMCIA device driver's
+ * private information.
+ */
+static void wv_local_show(device * dev)
+{
+	net_local *lp;
+
+	lp = (net_local *) dev->priv;
+
+	printk(KERN_DEBUG "local:");
+	printk(" tx_n_in_use=%d,", lp->tx_n_in_use);
+	printk(" hacr=0x%x,", lp->hacr);
+	printk(" rx_head=0x%x,", lp->rx_head);
+	printk(" rx_last=0x%x,", lp->rx_last);
+	printk(" tx_first_free=0x%x,", lp->tx_first_free);
+	printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use);
+	printk("\n");
+}				/* wv_local_show */
+#endif				/* DEBUG_DEVICE_SHOW */
+
+#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO)
+/*------------------------------------------------------------------*/
+/*
+ * Dump packet header (and content if necessary) on the screen
+ */
+static inline void wv_packet_info(u8 * p,	/* Packet to dump */
+				  int length,	/* Length of the packet */
+				  char *msg1,	/* Name of the device */
+				  char *msg2)
+{				/* Name of the function */
+	int i;
+	int maxi;
+
+	printk(KERN_DEBUG
+	       "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
+	       msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
+	printk(KERN_DEBUG
+	       "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
+	       msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12],
+	       p[13]);
+
+#ifdef DEBUG_PACKET_DUMP
+
+	printk(KERN_DEBUG "data=\"");
+
+	if ((maxi = length) > DEBUG_PACKET_DUMP)
+		maxi = DEBUG_PACKET_DUMP;
+	for (i = 14; i < maxi; i++)
+		if (p[i] >= ' ' && p[i] <= '~')
+			printk(" %c", p[i]);
+		else
+			printk("%02X", p[i]);
+	if (maxi < length)
+		printk("..");
+	printk("\"\n");
+	printk(KERN_DEBUG "\n");
+#endif				/* DEBUG_PACKET_DUMP */
+}
+#endif				/* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */
+
+/*------------------------------------------------------------------*/
+/*
+ * This is the information which is displayed by the driver at startup.
+ * There are lots of flags for configuring it to your liking.
+ */
+static inline void wv_init_info(device * dev)
+{
+	short ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;
+	psa_t psa;
+	int i;
+
+	/* Read the parameter storage area */
+	psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
+
+#ifdef DEBUG_PSA_SHOW
+	wv_psa_show(&psa);
+#endif
+#ifdef DEBUG_MMC_SHOW
+	wv_mmc_show(dev);
+#endif
+#ifdef DEBUG_I82586_SHOW
+	wv_cu_show(dev);
+#endif
+
+#ifdef DEBUG_BASIC_SHOW
+	/* Now, let's go for the basic stuff. */
+	printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
+	for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
+		printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
+	printk(", IRQ %d", dev->irq);
+
+	/* Print current network ID. */
+	if (psa.psa_nwid_select)
+		printk(", nwid 0x%02X-%02X", psa.psa_nwid[0],
+		       psa.psa_nwid[1]);
+	else
+		printk(", nwid off");
+
+	/* If 2.00 card */
+	if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+	      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+		unsigned short freq;
+
+		/* Ask the EEPROM to read the frequency from the first area. */
+		fee_read(ioaddr, 0x00, &freq, 1);
+
+		/* Print frequency */
+		printk(", 2.00, %ld", (freq >> 6) + 2400L);
+
+		/* Hack! */
+		if (freq & 0x20)
+			printk(".5");
+	} else {
+		printk(", PC");
+		switch (psa.psa_comp_number) {
+		case PSA_COMP_PC_AT_915:
+		case PSA_COMP_PC_AT_2400:
+			printk("-AT");
+			break;
+		case PSA_COMP_PC_MC_915:
+		case PSA_COMP_PC_MC_2400:
+			printk("-MC");
+			break;
+		case PSA_COMP_PCMCIA_915:
+			printk("MCIA");
+			break;
+		default:
+			printk("?");
+		}
+		printk(", ");
+		switch (psa.psa_subband) {
+		case PSA_SUBBAND_915:
+			printk("915");
+			break;
+		case PSA_SUBBAND_2425:
+			printk("2425");
+			break;
+		case PSA_SUBBAND_2460:
+			printk("2460");
+			break;
+		case PSA_SUBBAND_2484:
+			printk("2484");
+			break;
+		case PSA_SUBBAND_2430_5:
+			printk("2430.5");
+			break;
+		default:
+			printk("?");
+		}
+	}
+
+	printk(" MHz\n");
+#endif				/* DEBUG_BASIC_SHOW */
+
+#ifdef DEBUG_VERSION_SHOW
+	/* Print version information */
+	printk(KERN_NOTICE "%s", version);
+#endif
+}				/* wv_init_info */
+
+/********************* IOCTL, STATS & RECONFIG *********************/
+/*
+ * We found here routines that are called by Linux on different
+ * occasions after the configuration and not for transmitting data
+ * These may be called when the user use ifconfig, /proc/net/dev
+ * or wireless extensions
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Get the current Ethernet statistics. This may be called with the
+ * card open or closed.
+ * Used when the user read /proc/net/dev
+ */
+static en_stats *wavelan_get_stats(device * dev)
+{
+#ifdef DEBUG_IOCTL_TRACE
+	printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
+#endif
+
+	return (&((net_local *) dev->priv)->stats);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1	Promiscuous mode, receive all packets
+ * num_addrs == 0	Normal mode, clear multicast list
+ * num_addrs > 0	Multicast mode, receive normal and MC packets,
+ *			and do best-effort filtering.
+ */
+static void wavelan_set_multicast_list(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+
+#ifdef DEBUG_IOCTL_TRACE
+	printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n",
+	       dev->name);
+#endif
+
+#ifdef DEBUG_IOCTL_INFO
+	printk(KERN_DEBUG
+	       "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n",
+	       dev->name, dev->flags, dev->mc_count);
+#endif
+
+	/* Are we asking for promiscuous mode,
+	 * or all multicast addresses (we don't have that!)
+	 * or too many multicast addresses for the hardware filter? */
+	if ((dev->flags & IFF_PROMISC) ||
+	    (dev->flags & IFF_ALLMULTI) ||
+	    (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) {
+		/*
+		 * Enable promiscuous mode: receive all packets.
+		 */
+		if (!lp->promiscuous) {
+			lp->promiscuous = 1;
+			lp->mc_count = 0;
+
+			wv_82586_reconfig(dev);
+
+			/* Tell the kernel that we are doing a really bad job. */
+			dev->flags |= IFF_PROMISC;
+		}
+	} else
+		/* Are there multicast addresses to send? */
+	if (dev->mc_list != (struct dev_mc_list *) NULL) {
+		/*
+		 * Disable promiscuous mode, but receive all packets
+		 * in multicast list
+		 */
+#ifdef MULTICAST_AVOID
+		if (lp->promiscuous || (dev->mc_count != lp->mc_count))
+#endif
+		{
+			lp->promiscuous = 0;
+			lp->mc_count = dev->mc_count;
+
+			wv_82586_reconfig(dev);
+		}
+	} else {
+		/*
+		 * Switch to normal mode: disable promiscuous mode and 
+		 * clear the multicast list.
+		 */
+		if (lp->promiscuous || lp->mc_count == 0) {
+			lp->promiscuous = 0;
+			lp->mc_count = 0;
+
+			wv_82586_reconfig(dev);
+		}
+	}
+#ifdef DEBUG_IOCTL_TRACE
+	printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n",
+	       dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This function doesn't exist.
+ * (Note : it was a nice way to test the reconfigure stuff...)
+ */
+#ifdef SET_MAC_ADDRESS
+static int wavelan_set_mac_address(device * dev, void *addr)
+{
+	struct sockaddr *mac = addr;
+
+	/* Copy the address. */
+	memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
+
+	/* Reconfigure the beast. */
+	wv_82586_reconfig(dev);
+
+	return 0;
+}
+#endif				/* SET_MAC_ADDRESS */
+
+#ifdef WIRELESS_EXT		/* if wireless extensions exist in the kernel */
+
+/*------------------------------------------------------------------*/
+/*
+ * Frequency setting (for hardware capable of it)
+ * It's a bit complicated and you don't really want to look into it.
+ * (called in wavelan_ioctl)
+ */
+static inline int wv_set_frequency(unsigned long ioaddr,	/* I/O port of the card */
+				   iw_freq * frequency)
+{
+	const int BAND_NUM = 10;	/* Number of bands */
+	long freq = 0L;		/* offset to 2.4 GHz in .5 MHz */
+#ifdef DEBUG_IOCTL_INFO
+	int i;
+#endif
+
+	/* Setting by frequency */
+	/* Theoretically, you may set any frequency between
+	 * the two limits with a 0.5 MHz precision. In practice,
+	 * I don't want you to have trouble with local regulations.
+	 */
+	if ((frequency->e == 1) &&
+	    (frequency->m >= (int) 2.412e8)
+	    && (frequency->m <= (int) 2.487e8)) {
+		freq = ((frequency->m / 10000) - 24000L) / 5;
+	}
+
+	/* Setting by channel (same as wfreqsel) */
+	/* Warning: each channel is 22 MHz wide, so some of the channels
+	 * will interfere. */
+	if ((frequency->e == 0) && (frequency->m < BAND_NUM)) {
+		/* Get frequency offset. */
+		freq = channel_bands[frequency->m] >> 1;
+	}
+
+	/* Verify that the frequency is allowed. */
+	if (freq != 0L) {
+		u16 table[10];	/* Authorized frequency table */
+
+		/* Read the frequency table. */
+		fee_read(ioaddr, 0x71, table, 10);
+
+#ifdef DEBUG_IOCTL_INFO
+		printk(KERN_DEBUG "Frequency table: ");
+		for (i = 0; i < 10; i++) {
+			printk(" %04X", table[i]);
+		}
+		printk("\n");
+#endif
+
+		/* Look in the table to see whether the frequency is allowed. */
+		if (!(table[9 - ((freq - 24) / 16)] &
+		      (1 << ((freq - 24) % 16)))) return -EINVAL;	/* not allowed */
+	} else
+		return -EINVAL;
+
+	/* if we get a usable frequency */
+	if (freq != 0L) {
+		unsigned short area[16];
+		unsigned short dac[2];
+		unsigned short area_verify[16];
+		unsigned short dac_verify[2];
+		/* Corresponding gain (in the power adjust value table)
+		 * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
+		 * and WCIN062D.DOC, page 6.2.9. */
+		unsigned short power_limit[] = { 40, 80, 120, 160, 0 };
+		int power_band = 0;	/* Selected band */
+		unsigned short power_adjust;	/* Correct value */
+
+		/* Search for the gain. */
+		power_band = 0;
+		while ((freq > power_limit[power_band]) &&
+		       (power_limit[++power_band] != 0));
+
+		/* Read the first area. */
+		fee_read(ioaddr, 0x00, area, 16);
+
+		/* Read the DAC. */
+		fee_read(ioaddr, 0x60, dac, 2);
+
+		/* Read the new power adjust value. */
+		fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust,
+			 1);
+		if (power_band & 0x1)
+			power_adjust >>= 8;
+		else
+			power_adjust &= 0xFF;
+
+#ifdef DEBUG_IOCTL_INFO
+		printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
+		for (i = 0; i < 16; i++) {
+			printk(" %04X", area[i]);
+		}
+		printk("\n");
+
+		printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
+		       dac[0], dac[1]);
+#endif
+
+		/* Frequency offset (for info only) */
+		area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
+
+		/* Receiver Principle main divider coefficient */
+		area[3] = (freq >> 1) + 2400L - 352L;
+		area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
+
+		/* Transmitter Main divider coefficient */
+		area[13] = (freq >> 1) + 2400L;
+		area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
+
+		/* Other parts of the area are flags, bit streams or unused. */
+
+		/* Set the value in the DAC. */
+		dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
+		dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
+
+		/* Write the first area. */
+		fee_write(ioaddr, 0x00, area, 16);
+
+		/* Write the DAC. */
+		fee_write(ioaddr, 0x60, dac, 2);
+
+		/* We now should verify here that the writing of the EEPROM went OK. */
+
+		/* Reread the first area. */
+		fee_read(ioaddr, 0x00, area_verify, 16);
+
+		/* Reread the DAC. */
+		fee_read(ioaddr, 0x60, dac_verify, 2);
+
+		/* Compare. */
+		if (memcmp(area, area_verify, 16 * 2) ||
+		    memcmp(dac, dac_verify, 2 * 2)) {
+#ifdef DEBUG_IOCTL_ERROR
+			printk(KERN_INFO
+			       "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n");
+#endif
+			return -EOPNOTSUPP;
+		}
+
+		/* We must download the frequency parameters to the
+		 * synthesizers (from the EEPROM - area 1)
+		 * Note: as the EEPROM is automatically decremented, we set the end
+		 * if the area... */
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F);
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
+			MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
+
+		/* Wait until the download is finished. */
+		fee_wait(ioaddr, 100, 100);
+
+		/* We must now download the power adjust value (gain) to
+		 * the synthesizers (from the EEPROM - area 7 - DAC). */
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
+			MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
+
+		/* Wait for the download to finish. */
+		fee_wait(ioaddr, 100, 100);
+
+#ifdef DEBUG_IOCTL_INFO
+		/* Verification of what we have done */
+
+		printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
+		for (i = 0; i < 16; i++) {
+			printk(" %04X", area_verify[i]);
+		}
+		printk("\n");
+
+		printk(KERN_DEBUG "WaveLAN EEPROM DAC:  %04X %04X\n",
+		       dac_verify[0], dac_verify[1]);
+#endif
+
+		return 0;
+	} else
+		return -EINVAL;	/* Bah, never get there... */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Give the list of available frequencies.
+ */
+static inline int wv_frequency_list(unsigned long ioaddr,	/* I/O port of the card */
+				    iw_freq * list,	/* List of frequencies to fill */
+				    int max)
+{				/* Maximum number of frequencies */
+	u16 table[10];	/* Authorized frequency table */
+	long freq = 0L;		/* offset to 2.4 GHz in .5 MHz + 12 MHz */
+	int i;			/* index in the table */
+	int c = 0;		/* Channel number */
+
+	/* Read the frequency table. */
+	fee_read(ioaddr, 0x71 /* frequency table */ , table, 10);
+
+	/* Check all frequencies. */
+	i = 0;
+	for (freq = 0; freq < 150; freq++)
+		/* Look in the table if the frequency is allowed */
+		if (table[9 - (freq / 16)] & (1 << (freq % 16))) {
+			/* Compute approximate channel number */
+			while ((((channel_bands[c] >> 1) - 24) < freq) &&
+			       (c < NELS(channel_bands)))
+				c++;
+			list[i].i = c;	/* Set the list index */
+
+			/* put in the list */
+			list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
+			list[i++].e = 1;
+
+			/* Check number. */
+			if (i >= max)
+				return (i);
+		}
+
+	return (i);
+}
+
+#ifdef WIRELESS_SPY
+/*------------------------------------------------------------------*/
+/*
+ * Gather wireless spy statistics:  for each packet, compare the source
+ * address with our list, and if they match, get the statistics.
+ * Sorry, but this function really needs the wireless extensions.
+ */
+static inline void wl_spy_gather(device * dev, u8 * mac,	/* MAC address */
+				 u8 * stats)
+{				/* Statistics to gather */
+	net_local *lp = (net_local *) dev->priv;
+	int i;
+
+	/* Check all addresses. */
+	for (i = 0; i < lp->spy_number; i++)
+		/* If match */
+		if (!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) {
+			/* Update statistics */
+			lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL;
+			lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL;
+			lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL;
+			lp->spy_stat[i].updated = 0x7;
+		}
+}
+#endif				/* WIRELESS_SPY */
+
+#ifdef HISTOGRAM
+/*------------------------------------------------------------------*/
+/*
+ * This function calculates a histogram of the signal level.
+ * As the noise is quite constant, it's like doing it on the SNR.
+ * We have defined a set of interval (lp->his_range), and each time
+ * the level goes in that interval, we increment the count (lp->his_sum).
+ * With this histogram you may detect if one WaveLAN is really weak,
+ * or you may also calculate the mean and standard deviation of the level.
+ */
+static inline void wl_his_gather(device * dev, u8 * stats)
+{				/* Statistics to gather */
+	net_local *lp = (net_local *) dev->priv;
+	u8 level = stats[0] & MMR_SIGNAL_LVL;
+	int i;
+
+	/* Find the correct interval. */
+	i = 0;
+	while ((i < (lp->his_number - 1))
+	       && (level >= lp->his_range[i++]));
+
+	/* Increment interval counter. */
+	(lp->his_sum[i])++;
+}
+#endif				/* HISTOGRAM */
+
+/*------------------------------------------------------------------*/
+/*
+ * Perform ioctl for configuration and information.
+ * It is here that the wireless extensions are treated (iwconfig).
+ */
+static int wavelan_ioctl(struct net_device *dev,	/* device on which the ioctl is applied */
+			 struct ifreq *rq,	/* data passed */
+			 int cmd)
+{				/* ioctl number */
+	unsigned long ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	struct iwreq *wrq = (struct iwreq *) rq;
+	psa_t psa;
+	mm_t m;
+	unsigned long flags;
+	int ret = 0;
+	int err = 0;
+
+#ifdef DEBUG_IOCTL_TRACE
+	printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name,
+	       cmd);
+#endif
+
+	/* Disable interrupts and save flags. */
+	wv_splhi(lp, &flags);
+	
+	/* Look what is the request */
+	switch (cmd) {
+		/* --------------- WIRELESS EXTENSIONS --------------- */
+
+	case SIOCGIWNAME:
+		strcpy(wrq->u.name, "WaveLAN");
+		break;
+
+	case SIOCSIWNWID:
+		/* Set NWID in WaveLAN. */
+		if (!wrq->u.nwid.disabled) {
+			/* Set NWID in psa */
+			psa.psa_nwid[0] =
+			    (wrq->u.nwid.value & 0xFF00) >> 8;
+			psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
+			psa.psa_nwid_select = 0x01;
+			psa_write(ioaddr, lp->hacr,
+				  (char *) psa.psa_nwid - (char *) &psa,
+				  (unsigned char *) psa.psa_nwid, 3);
+
+			/* Set NWID in mmc. */
+			m.w.mmw_netw_id_l = psa.psa_nwid[1];
+			m.w.mmw_netw_id_h = psa.psa_nwid[0];
+			mmc_write(ioaddr,
+				  (char *) &m.w.mmw_netw_id_l -
+				  (char *) &m,
+				  (unsigned char *) &m.w.mmw_netw_id_l, 2);
+			mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00);
+		} else {
+			/* Disable NWID in the psa. */
+			psa.psa_nwid_select = 0x00;
+			psa_write(ioaddr, lp->hacr,
+				  (char *) &psa.psa_nwid_select -
+				  (char *) &psa,
+				  (unsigned char *) &psa.psa_nwid_select,
+				  1);
+
+			/* Disable NWID in the mmc (no filtering). */
+			mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel),
+				MMW_LOOPT_SEL_DIS_NWID);
+		}
+		/* update the Wavelan checksum */
+		update_psa_checksum(dev, ioaddr, lp->hacr);
+		break;
+
+	case SIOCGIWNWID:
+		/* Read the NWID. */
+		psa_read(ioaddr, lp->hacr,
+			 (char *) psa.psa_nwid - (char *) &psa,
+			 (unsigned char *) psa.psa_nwid, 3);
+		wrq->u.nwid.value =
+		    (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+		wrq->u.nwid.disabled = !(psa.psa_nwid_select);
+		wrq->u.nwid.fixed = 1;	/* Superfluous */
+		break;
+
+	case SIOCSIWFREQ:
+		/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
+		if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+		      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+			ret = wv_set_frequency(ioaddr, &(wrq->u.freq));
+		else
+			ret = -EOPNOTSUPP;
+		break;
+
+	case SIOCGIWFREQ:
+		/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
+		 * Does it work for everybody, especially old cards? */
+		if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+		      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+			unsigned short freq;
+
+			/* Ask the EEPROM to read the frequency from the first area. */
+			fee_read(ioaddr, 0x00, &freq, 1);
+			wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
+			wrq->u.freq.e = 1;
+		} else {
+			psa_read(ioaddr, lp->hacr,
+				 (char *) &psa.psa_subband - (char *) &psa,
+				 (unsigned char *) &psa.psa_subband, 1);
+
+			if (psa.psa_subband <= 4) {
+				wrq->u.freq.m =
+				    fixed_bands[psa.psa_subband];
+				wrq->u.freq.e = (psa.psa_subband != 0);
+			} else
+				ret = -EOPNOTSUPP;
+		}
+		break;
+
+	case SIOCSIWSENS:
+		/* Set the level threshold. */
+		/* We should complain loudly if wrq->u.sens.fixed = 0, because we
+		 * can't set auto mode... */
+		psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
+		psa_write(ioaddr, lp->hacr,
+			  (char *) &psa.psa_thr_pre_set - (char *) &psa,
+			  (unsigned char *) &psa.psa_thr_pre_set, 1);
+		/* update the Wavelan checksum */
+		update_psa_checksum(dev, ioaddr, lp->hacr);
+		mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set),
+			psa.psa_thr_pre_set);
+		break;
+
+	case SIOCGIWSENS:
+		/* Read the level threshold. */
+		psa_read(ioaddr, lp->hacr,
+			 (char *) &psa.psa_thr_pre_set - (char *) &psa,
+			 (unsigned char *) &psa.psa_thr_pre_set, 1);
+		wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
+		wrq->u.sens.fixed = 1;
+		break;
+
+	case SIOCSIWENCODE:
+		/* Set encryption key */
+		if (!mmc_encr(ioaddr)) {
+			ret = -EOPNOTSUPP;
+			break;
+		}
+
+		/* Basic checking... */
+		if (wrq->u.encoding.pointer != (caddr_t) 0) {
+			/* Check the size of the key */
+			if (wrq->u.encoding.length != 8) {
+				ret = -EINVAL;
+				break;
+			}
+
+			/* Copy the key in the driver */
+			wv_splx(lp, &flags);
+			err = copy_from_user(psa.psa_encryption_key,
+					     wrq->u.encoding.pointer,
+					     wrq->u.encoding.length);
+			wv_splhi(lp, &flags);
+			if (err) {
+				ret = -EFAULT;
+				break;
+			}
+
+			psa.psa_encryption_select = 1;
+			psa_write(ioaddr, lp->hacr,
+				  (char *) &psa.psa_encryption_select -
+				  (char *) &psa,
+				  (unsigned char *) &psa.
+				  psa_encryption_select, 8 + 1);
+
+			mmc_out(ioaddr, mmwoff(0, mmw_encr_enable),
+				MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
+			mmc_write(ioaddr, mmwoff(0, mmw_encr_key),
+				  (unsigned char *) &psa.
+				  psa_encryption_key, 8);
+		}
+
+		if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) {	/* disable encryption */
+			psa.psa_encryption_select = 0;
+			psa_write(ioaddr, lp->hacr,
+				  (char *) &psa.psa_encryption_select -
+				  (char *) &psa,
+				  (unsigned char *) &psa.
+				  psa_encryption_select, 1);
+
+			mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
+		}
+		/* update the Wavelan checksum */
+		update_psa_checksum(dev, ioaddr, lp->hacr);
+		break;
+
+	case SIOCGIWENCODE:
+		/* Read the encryption key */
+		if (!mmc_encr(ioaddr)) {
+			ret = -EOPNOTSUPP;
+			break;
+		}
+
+		/* only super-user can see encryption key */
+		if (!capable(CAP_NET_ADMIN)) {
+			ret = -EPERM;
+			break;
+		}
+
+		/* Basic checking... */
+		if (wrq->u.encoding.pointer != (caddr_t) 0) {
+			/* Verify the user buffer */
+			ret =
+			    verify_area(VERIFY_WRITE,
+					wrq->u.encoding.pointer, 8);
+			if (ret)
+				break;
+
+			psa_read(ioaddr, lp->hacr,
+				 (char *) &psa.psa_encryption_select -
+				 (char *) &psa,
+				 (unsigned char *) &psa.
+				 psa_encryption_select, 1 + 8);
+
+			/* encryption is enabled ? */
+			if (psa.psa_encryption_select)
+				wrq->u.encoding.flags = IW_ENCODE_ENABLED;
+			else
+				wrq->u.encoding.flags = IW_ENCODE_DISABLED;
+			wrq->u.encoding.flags |= mmc_encr(ioaddr);
+
+			/* Copy the key to the user buffer */
+			wrq->u.encoding.length = 8;
+			wv_splx(lp, &flags);
+			if (copy_to_user(wrq->u.encoding.pointer,
+					 psa.psa_encryption_key, 8))
+				ret = -EFAULT;
+			wv_splhi(lp, &flags);
+		}
+		break;
+
+	case SIOCGIWRANGE:
+		/* basic checking */
+		if (wrq->u.data.pointer != (caddr_t) 0) {
+			struct iw_range range;
+
+			/* Set the length (very important for backward
+			 * compatibility) */
+			wrq->u.data.length = sizeof(struct iw_range);
+
+			/* Set all the info we don't care or don't know
+			 * about to zero */
+			memset(&range, 0, sizeof(range));
+
+			/* Set the Wireless Extension versions */
+			range.we_version_compiled = WIRELESS_EXT;
+			range.we_version_source = 9;
+
+			/* Set information in the range struct.  */
+			range.throughput = 1.6 * 1000 * 1000;	/* don't argue on this ! */
+			range.min_nwid = 0x0000;
+			range.max_nwid = 0xFFFF;
+
+			/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
+			if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+			      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+				range.num_channels = 10;
+				range.num_frequency =
+				    wv_frequency_list(ioaddr, range.freq,
+						      IW_MAX_FREQUENCIES);
+			} else
+				range.num_channels = range.num_frequency =
+				    0;
+
+			range.sensitivity = 0x3F;
+			range.max_qual.qual = MMR_SGNL_QUAL;
+			range.max_qual.level = MMR_SIGNAL_LVL;
+			range.max_qual.noise = MMR_SILENCE_LVL;
+			range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
+			/* Need to get better values for those two */
+			range.avg_qual.level = 30;
+			range.avg_qual.noise = 8;
+
+			range.num_bitrates = 1;
+			range.bitrate[0] = 2000000;	/* 2 Mb/s */
+
+			/* Encryption supported ? */
+			if (mmc_encr(ioaddr)) {
+				range.encoding_size[0] = 8;	/* DES = 64 bits key */
+				range.num_encoding_sizes = 1;
+				range.max_encoding_tokens = 1;	/* Only one key possible */
+			} else {
+				range.num_encoding_sizes = 0;
+				range.max_encoding_tokens = 0;
+			}
+
+			/* Copy structure to the user buffer. */
+			wv_splx(lp, &flags);
+			if (copy_to_user(wrq->u.data.pointer,
+					 &range,
+					 sizeof(struct iw_range)))
+				ret = -EFAULT;
+			wv_splhi(lp, &flags);
+		}
+		break;
+
+	case SIOCGIWPRIV:
+		/* Basic checking */
+		if (wrq->u.data.pointer != (caddr_t) 0) {
+			struct iw_priv_args priv[] = {
+				/* { cmd,
+				     set_args,
+				     get_args,
+				     name } */
+				{ SIOCSIPQTHR,
+				  IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+				  0,
+				  "setqualthr" },
+				{ SIOCGIPQTHR,
+				  0,
+				  IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+				  "getqualthr" },
+				{ SIOCSIPHISTO,
+				  IW_PRIV_TYPE_BYTE | 16,
+				  0,
+				  "sethisto" },
+				{ SIOCGIPHISTO,
+				  0,
+				  IW_PRIV_TYPE_INT | 16,
+				 "gethisto" },
+			};
+
+			/* Set the number of available ioctls. */
+			wrq->u.data.length = 4;
+
+			/* Copy structure to the user buffer. */
+			wv_splx(lp, &flags);
+			if (copy_to_user(wrq->u.data.pointer,
+					      (u8 *) priv,
+					      sizeof(priv)))
+				ret = -EFAULT;
+			wv_splhi(lp, &flags);
+		}
+		break;
+
+#ifdef WIRELESS_SPY
+	case SIOCSIWSPY:
+		/* Set the spy list */
+
+		/* Check the number of addresses. */
+		if (wrq->u.data.length > IW_MAX_SPY) {
+			ret = -E2BIG;
+			break;
+		}
+		lp->spy_number = wrq->u.data.length;
+
+		/* Are there are addresses to copy? */
+		if (lp->spy_number > 0) {
+			struct sockaddr address[IW_MAX_SPY];
+			int i;
+
+			/* Copy addresses to the driver. */
+			wv_splx(lp, &flags);
+			err = copy_from_user(address,
+					     wrq->u.data.pointer,
+					     sizeof(struct sockaddr)
+					     * lp->spy_number);
+			wv_splhi(lp, &flags);
+			if (err) {
+				ret = -EFAULT;
+				break;
+			}
+
+			/* Copy addresses to the lp structure. */
+			for (i = 0; i < lp->spy_number; i++) {
+				memcpy(lp->spy_address[i],
+				       address[i].sa_data,
+				       WAVELAN_ADDR_SIZE);
+			}
+
+			/* Reset structure. */
+			memset(lp->spy_stat, 0x00,
+			       sizeof(iw_qual) * IW_MAX_SPY);
+
+#ifdef DEBUG_IOCTL_INFO
+			printk(KERN_DEBUG
+			       "SetSpy:  set of new addresses is: \n");
+			for (i = 0; i < wrq->u.data.length; i++)
+				printk(KERN_DEBUG
+				       "%02X:%02X:%02X:%02X:%02X:%02X \n",
+				       lp->spy_address[i][0],
+				       lp->spy_address[i][1],
+				       lp->spy_address[i][2],
+				       lp->spy_address[i][3],
+				       lp->spy_address[i][4],
+				       lp->spy_address[i][5]);
+#endif				/* DEBUG_IOCTL_INFO */
+		}
+
+		break;
+
+	case SIOCGIWSPY:
+		/* Get the spy list and spy stats. */
+
+		/* Set the number of addresses */
+		wrq->u.data.length = lp->spy_number;
+
+		/* Does the user want to have the addresses back? */
+		if ((lp->spy_number > 0)
+		    && (wrq->u.data.pointer != (caddr_t) 0)) {
+			struct sockaddr address[IW_MAX_SPY];
+			int i;
+
+			/* Copy addresses from the lp structure. */
+			for (i = 0; i < lp->spy_number; i++) {
+				memcpy(address[i].sa_data,
+				       lp->spy_address[i],
+				       WAVELAN_ADDR_SIZE);
+				address[i].sa_family = AF_UNIX;
+			}
+
+			/* Copy addresses to the user buffer. */
+			wv_splx(lp, &flags);
+			err = copy_to_user(wrq->u.data.pointer,
+					   address,
+					   sizeof(struct sockaddr)
+					   * lp->spy_number);
+
+			/* Copy stats to the user buffer (just after). */
+			err |= copy_to_user(wrq->u.data.pointer
+					    + (sizeof(struct sockaddr)
+					       * lp->spy_number),
+					    lp->spy_stat,
+					    sizeof(iw_qual) * lp->spy_number);
+			wv_splhi(lp, &flags);
+			if (err) {
+				ret = -EFAULT;
+				break;
+			}
+
+			/* Reset updated flags. */
+			for (i = 0; i < lp->spy_number; i++)
+				lp->spy_stat[i].updated = 0x0;
+		}
+		/* if(pointer != NULL) */
+		break;
+#endif				/* WIRELESS_SPY */
+
+		/* ------------------ PRIVATE IOCTL ------------------ */
+
+	case SIOCSIPQTHR:
+		if (!capable(CAP_NET_ADMIN)) {
+			ret = -EPERM;
+			break;
+		}
+		psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
+		psa_write(ioaddr, lp->hacr,
+			  (char *) &psa.psa_quality_thr - (char *) &psa,
+			  (unsigned char *) &psa.psa_quality_thr, 1);
+		/* update the Wavelan checksum */
+		update_psa_checksum(dev, ioaddr, lp->hacr);
+		mmc_out(ioaddr, mmwoff(0, mmw_quality_thr),
+			psa.psa_quality_thr);
+		break;
+
+	case SIOCGIPQTHR:
+		psa_read(ioaddr, lp->hacr,
+			 (char *) &psa.psa_quality_thr - (char *) &psa,
+			 (unsigned char *) &psa.psa_quality_thr, 1);
+		*(wrq->u.name) = psa.psa_quality_thr & 0x0F;
+		break;
+
+#ifdef HISTOGRAM
+	case SIOCSIPHISTO:
+		/* Verify that the user is root. */
+		if (!capable(CAP_NET_ADMIN)) {
+			ret = -EPERM;
+			break;
+		}
+
+		/* Check the number of intervals. */
+		if (wrq->u.data.length > 16) {
+			ret = -E2BIG;
+			break;
+		}
+		lp->his_number = wrq->u.data.length;
+
+		/* Are there addresses to copy? */
+		if (lp->his_number > 0) {
+			/* Copy interval ranges to the driver */
+			wv_splx(lp, &flags);
+			err = copy_from_user(lp->his_range,
+					     wrq->u.data.pointer,
+					     sizeof(char) * lp->his_number);
+			wv_splhi(lp, &flags);
+			if (err) {
+				ret = -EFAULT;
+				break;
+			}
+
+			/* Reset structure. */
+			memset(lp->his_sum, 0x00, sizeof(long) * 16);
+		}
+		break;
+
+	case SIOCGIPHISTO:
+		/* Set the number of intervals. */
+		wrq->u.data.length = lp->his_number;
+
+		/* Give back the distribution statistics */
+		if ((lp->his_number > 0)
+		    && (wrq->u.data.pointer != (caddr_t) 0)) {
+			/* Copy data to the user buffer. */
+			wv_splx(lp, &flags);
+			if (copy_to_user(wrq->u.data.pointer,
+					 lp->his_sum,
+					 sizeof(long) * lp->his_number);
+				ret = -EFAULT;
+			wv_splhi(lp, &flags);
+
+		}		/* if(pointer != NULL) */
+		break;
+#endif				/* HISTOGRAM */
+
+		/* ------------------- OTHER IOCTL ------------------- */
+
+	default:
+		ret = -EOPNOTSUPP;
+	}	/* switch (cmd) */
+
+	/* Enable interrupts and restore flags. */
+	wv_splx(lp, &flags);
+
+#ifdef DEBUG_IOCTL_TRACE
+	printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
+#endif
+	return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get wireless statistics.
+ * Called by /proc/net/wireless
+ */
+static iw_stats *wavelan_get_wireless_stats(device * dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;
+	mmr_t m;
+	iw_stats *wstats;
+	unsigned long flags;
+
+#ifdef DEBUG_IOCTL_TRACE
+	printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n",
+	       dev->name);
+#endif
+
+	/* Check */
+	if (lp == (net_local *) NULL)
+		return (iw_stats *) NULL;
+	
+	/* Disable interrupts and save flags. */
+	wv_splhi(lp, &flags);
+	
+	wstats = &lp->wstats;
+
+	/* Get data from the mmc. */
+	mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
+
+	mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
+	mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l,
+		 2);
+	mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set,
+		 4);
+
+	mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
+
+	/* Copy data to wireless stuff. */
+	wstats->status = m.mmr_dce_status & MMR_DCE_STATUS;
+	wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
+	wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
+	wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL;
+	wstats->qual.updated = (((m. mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) 
+			| ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) 
+			| ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5));
+	wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+	wstats->discard.code = 0L;
+	wstats->discard.misc = 0L;
+
+	/* Enable interrupts and restore flags. */
+	wv_splx(lp, &flags);
+
+#ifdef DEBUG_IOCTL_TRACE
+	printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n",
+	       dev->name);
+#endif
+	return &lp->wstats;
+}
+#endif				/* WIRELESS_EXT */
+
+/************************* PACKET RECEPTION *************************/
+/*
+ * This part deals with receiving the packets.
+ * The interrupt handler gets an interrupt when a packet has been
+ * successfully received and calls this part.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine does the actual copying of data (including the Ethernet
+ * header structure) from the WaveLAN card to an sk_buff chain that
+ * will be passed up to the network interface layer. NOTE: we
+ * currently don't handle trailer protocols (neither does the rest of
+ * the network interface), so if that is needed, it will (at least in
+ * part) be added here.  The contents of the receive ring buffer are
+ * copied to a message chain that is then passed to the kernel.
+ *
+ * Note: if any errors occur, the packet is "dropped on the floor".
+ * (called by wv_packet_rcv())
+ */
+static inline void
+wv_packet_read(device * dev, u16 buf_off, int sksize)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	struct sk_buff *skb;
+
+#ifdef DEBUG_RX_TRACE
+	printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n",
+	       dev->name, buf_off, sksize);
+#endif
+
+	/* Allocate buffer for the data */
+	if ((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL) {
+#ifdef DEBUG_RX_ERROR
+		printk(KERN_INFO
+		       "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n",
+		       dev->name, sksize);
+#endif
+		lp->stats.rx_dropped++;
+		return;
+	}
+
+	skb->dev = dev;
+
+	/* Copy the packet to the buffer. */
+	obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize);
+	skb->protocol = eth_type_trans(skb, dev);
+
+#ifdef DEBUG_RX_INFO
+	wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
+#endif				/* DEBUG_RX_INFO */
+
+	/* Statistics-gathering and associated stuff.
+	 * It seem a bit messy with all the define, but it's really simple... */
+#if defined(WIRELESS_SPY) || defined(HISTOGRAM)
+	if (
+#ifdef WIRELESS_SPY
+		   (lp->spy_number > 0) ||
+#endif				/* WIRELESS_SPY */
+#ifdef HISTOGRAM
+		   (lp->his_number > 0) ||
+#endif				/* HISTOGRAM */
+		   0) {
+		u8 stats[3];	/* signal level, noise level, signal quality */
+
+		/* Read signal level, silence level and signal quality bytes. */
+		/* Note: in the PCMCIA hardware, these are part of the frame.  It seems
+		 * that for the ISA hardware, it's nowhere to be found in the frame,
+		 * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
+		 * Any ideas?
+		 */
+		mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
+		mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
+		mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
+
+#ifdef DEBUG_RX_INFO
+		printk(KERN_DEBUG
+		       "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n",
+		       dev->name, stats[0] & 0x3F, stats[1] & 0x3F,
+		       stats[2] & 0x0F);
+#endif
+
+		/* Spying stuff */
+#ifdef WIRELESS_SPY
+		wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE,
+			      stats);
+#endif				/* WIRELESS_SPY */
+#ifdef HISTOGRAM
+		wl_his_gather(dev, stats);
+#endif				/* HISTOGRAM */
+	}
+#endif				/* defined(WIRELESS_SPY) || defined(HISTOGRAM) */
+
+	/*
+	 * Hand the packet to the network module.
+	 */
+	netif_rx(skb);
+
+	/* Keep statistics up to date */
+	dev->last_rx = jiffies;
+	lp->stats.rx_packets++;
+	lp->stats.rx_bytes += sksize;
+
+#ifdef DEBUG_RX_TRACE
+	printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Transfer as many packets as we can
+ * from the device RAM.
+ * (called in wavelan_interrupt()).
+ * Note : the spinlock is already grabbed for us.
+ */
+static inline void wv_receive(device * dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;
+	fd_t fd;
+	rbd_t rbd;
+	int nreaped = 0;
+
+#ifdef DEBUG_RX_TRACE
+	printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name);
+#endif
+
+	/* Loop on each received packet. */
+	for (;;) {
+		obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd,
+			   sizeof(fd));
+
+		/* Note about the status :
+		 * It start up to be 0 (the value we set). Then, when the RU
+		 * grab the buffer to prepare for reception, it sets the
+		 * FD_STATUS_B flag. When the RU has finished receiving the
+		 * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate
+		 * completion and set the other flags to indicate the eventual
+		 * errors. FD_STATUS_OK indicates that the reception was OK.
+		 */
+
+		/* If the current frame is not complete, we have reached the end. */
+		if ((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
+			break;	/* This is how we exit the loop. */
+
+		nreaped++;
+
+		/* Check whether frame was correctly received. */
+		if ((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK) {
+			/* Does the frame contain a pointer to the data?  Let's check. */
+			if (fd.fd_rbd_offset != I82586NULL) {
+				/* Read the receive buffer descriptor */
+				obram_read(ioaddr, fd.fd_rbd_offset,
+					   (unsigned char *) &rbd,
+					   sizeof(rbd));
+
+#ifdef DEBUG_RX_ERROR
+				if ((rbd.rbd_status & RBD_STATUS_EOF) !=
+				    RBD_STATUS_EOF) printk(KERN_INFO
+							   "%s: wv_receive(): missing EOF flag.\n",
+							   dev->name);
+
+				if ((rbd.rbd_status & RBD_STATUS_F) !=
+				    RBD_STATUS_F) printk(KERN_INFO
+							 "%s: wv_receive(): missing F flag.\n",
+							 dev->name);
+#endif				/* DEBUG_RX_ERROR */
+
+				/* Read the packet and transmit to Linux */
+				wv_packet_read(dev, rbd.rbd_bufl,
+					       rbd.
+					       rbd_status &
+					       RBD_STATUS_ACNT);
+			}
+#ifdef DEBUG_RX_ERROR
+			else	/* if frame has no data */
+				printk(KERN_INFO
+				       "%s: wv_receive(): frame has no data.\n",
+				       dev->name);
+#endif
+		} else {	/* If reception was no successful */
+
+			lp->stats.rx_errors++;
+
+#ifdef DEBUG_RX_INFO
+			printk(KERN_DEBUG
+			       "%s: wv_receive(): frame not received successfully (%X).\n",
+			       dev->name, fd.fd_status);
+#endif
+
+#ifdef DEBUG_RX_ERROR
+			if ((fd.fd_status & FD_STATUS_S6) != 0)
+				printk(KERN_INFO
+				       "%s: wv_receive(): no EOF flag.\n",
+				       dev->name);
+#endif
+
+			if ((fd.fd_status & FD_STATUS_S7) != 0) {
+				lp->stats.rx_length_errors++;
+#ifdef DEBUG_RX_FAIL
+				printk(KERN_DEBUG
+				       "%s: wv_receive(): frame too short.\n",
+				       dev->name);
+#endif
+			}
+
+			if ((fd.fd_status & FD_STATUS_S8) != 0) {
+				lp->stats.rx_over_errors++;
+#ifdef DEBUG_RX_FAIL
+				printk(KERN_DEBUG
+				       "%s: wv_receive(): rx DMA overrun.\n",
+				       dev->name);
+#endif
+			}
+
+			if ((fd.fd_status & FD_STATUS_S9) != 0) {
+				lp->stats.rx_fifo_errors++;
+#ifdef DEBUG_RX_FAIL
+				printk(KERN_DEBUG
+				       "%s: wv_receive(): ran out of resources.\n",
+				       dev->name);
+#endif
+			}
+
+			if ((fd.fd_status & FD_STATUS_S10) != 0) {
+				lp->stats.rx_frame_errors++;
+#ifdef DEBUG_RX_FAIL
+				printk(KERN_DEBUG
+				       "%s: wv_receive(): alignment error.\n",
+				       dev->name);
+#endif
+			}
+
+			if ((fd.fd_status & FD_STATUS_S11) != 0) {
+				lp->stats.rx_crc_errors++;
+#ifdef DEBUG_RX_FAIL
+				printk(KERN_DEBUG
+				       "%s: wv_receive(): CRC error.\n",
+				       dev->name);
+#endif
+			}
+		}
+
+		fd.fd_status = 0;
+		obram_write(ioaddr, fdoff(lp->rx_head, fd_status),
+			    (unsigned char *) &fd.fd_status,
+			    sizeof(fd.fd_status));
+
+		fd.fd_command = FD_COMMAND_EL;
+		obram_write(ioaddr, fdoff(lp->rx_head, fd_command),
+			    (unsigned char *) &fd.fd_command,
+			    sizeof(fd.fd_command));
+
+		fd.fd_command = 0;
+		obram_write(ioaddr, fdoff(lp->rx_last, fd_command),
+			    (unsigned char *) &fd.fd_command,
+			    sizeof(fd.fd_command));
+
+		lp->rx_last = lp->rx_head;
+		lp->rx_head = fd.fd_link_offset;
+	}			/* for(;;) -> loop on all frames */
+
+#ifdef DEBUG_RX_INFO
+	if (nreaped > 1)
+		printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n",
+		       dev->name, nreaped);
+#endif
+#ifdef DEBUG_RX_TRACE
+	printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name);
+#endif
+}
+
+/*********************** PACKET TRANSMISSION ***********************/
+/*
+ * This part deals with sending packets through the WaveLAN.
+ *
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine fills in the appropriate registers and memory
+ * locations on the WaveLAN card and starts the card off on
+ * the transmit.
+ *
+ * The principle:
+ * Each block contains a transmit command, a NOP command,
+ * a transmit block descriptor and a buffer.
+ * The CU read the transmit block which point to the tbd,
+ * read the tbd and the content of the buffer.
+ * When it has finish with it, it goes to the next command
+ * which in our case is the NOP. The NOP points on itself,
+ * so the CU stop here.
+ * When we add the next block, we modify the previous nop
+ * to make it point on the new tx command.
+ * Simple, isn't it ?
+ *
+ * (called in wavelan_packet_xmit())
+ */
+static inline int wv_packet_write(device * dev, void *buf, short length)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	unsigned short txblock;
+	unsigned short txpred;
+	unsigned short tx_addr;
+	unsigned short nop_addr;
+	unsigned short tbd_addr;
+	unsigned short buf_addr;
+	ac_tx_t tx;
+	ac_nop_t nop;
+	tbd_t tbd;
+	int clen = length;
+	unsigned long flags;
+
+#ifdef DEBUG_TX_TRACE
+	printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name,
+	       length);
+#endif
+
+	/* Do we need some padding? */
+	if (clen < ETH_ZLEN)
+		clen = ETH_ZLEN;
+
+	wv_splhi(lp, &flags);
+
+	/* Check nothing bad has happened */
+	if (lp->tx_n_in_use == (NTXBLOCKS - 1)) {
+#ifdef DEBUG_TX_ERROR
+		printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n",
+		       dev->name);
+#endif
+		wv_splx(lp, &flags);
+		return 1;
+	}
+
+	/* Calculate addresses of next block and previous block. */
+	txblock = lp->tx_first_free;
+	txpred = txblock - TXBLOCKZ;
+	if (txpred < OFFSET_CU)
+		txpred += NTXBLOCKS * TXBLOCKZ;
+	lp->tx_first_free += TXBLOCKZ;
+	if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
+		lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
+
+	lp->tx_n_in_use++;
+
+	/* Calculate addresses of the different parts of the block. */
+	tx_addr = txblock;
+	nop_addr = tx_addr + sizeof(tx);
+	tbd_addr = nop_addr + sizeof(nop);
+	buf_addr = tbd_addr + sizeof(tbd);
+
+	/*
+	 * Transmit command
+	 */
+	tx.tx_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
+		    (unsigned char *) &tx.tx_h.ac_status,
+		    sizeof(tx.tx_h.ac_status));
+
+	/*
+	 * NOP command
+	 */
+	nop.nop_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
+		    (unsigned char *) &nop.nop_h.ac_status,
+		    sizeof(nop.nop_h.ac_status));
+	nop.nop_h.ac_link = nop_addr;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
+		    (unsigned char *) &nop.nop_h.ac_link,
+		    sizeof(nop.nop_h.ac_link));
+
+	/*
+	 * Transmit buffer descriptor
+	 */
+	tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen);
+	tbd.tbd_next_bd_offset = I82586NULL;
+	tbd.tbd_bufl = buf_addr;
+	tbd.tbd_bufh = 0;
+	obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd));
+
+	/*
+	 * Data
+	 */
+	obram_write(ioaddr, buf_addr, buf, length);
+
+	/*
+	 * Overwrite the predecessor NOP link
+	 * so that it points to this txblock.
+	 */
+	nop_addr = txpred + sizeof(tx);
+	nop.nop_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
+		    (unsigned char *) &nop.nop_h.ac_status,
+		    sizeof(nop.nop_h.ac_status));
+	nop.nop_h.ac_link = txblock;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
+		    (unsigned char *) &nop.nop_h.ac_link,
+		    sizeof(nop.nop_h.ac_link));
+
+	/* Keep stats up to date. */
+	lp->stats.tx_bytes += length;
+
+	if (lp->tx_first_in_use == I82586NULL)
+		lp->tx_first_in_use = txblock;
+
+	if (lp->tx_n_in_use < NTXBLOCKS - 1)
+		netif_wake_queue(dev);
+
+	wv_splx(lp, &flags);
+	
+#ifdef DEBUG_TX_INFO
+	wv_packet_info((u8 *) buf, length, dev->name,
+		       "wv_packet_write");
+#endif				/* DEBUG_TX_INFO */
+
+#ifdef DEBUG_TX_TRACE
+	printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
+#endif
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine is called when we want to send a packet (NET3 callback)
+ * In this routine, we check if the harware is ready to accept
+ * the packet.  We also prevent reentrance.  Then we call the function
+ * to send the packet.
+ */
+static int wavelan_packet_xmit(struct sk_buff *skb, device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long flags;
+
+#ifdef DEBUG_TX_TRACE
+	printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+	       (unsigned) skb);
+#endif
+
+	/*
+	 * Block a timer-based transmit from overlapping.
+	 * In other words, prevent reentering this routine.
+	 */
+	netif_stop_queue(dev);
+
+	/* If somebody has asked to reconfigure the controller, 
+	 * we can do it now.
+	 */
+	if (lp->reconfig_82586) {
+		wv_splhi(lp, &flags);
+		wv_82586_config(dev);
+		wv_splx(lp, &flags);
+		/* Check that we can continue */
+		if (lp->tx_n_in_use == (NTXBLOCKS - 1))
+			return 1;
+	}
+#ifdef DEBUG_TX_ERROR
+	if (skb->next)
+		printk(KERN_INFO "skb has next\n");
+#endif
+
+	/* Write packet on the card */
+	if(wv_packet_write(dev, skb->data, skb->len))
+		return 1;	/* We failed */
+
+	dev_kfree_skb(skb);
+
+#ifdef DEBUG_TX_TRACE
+	printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+#endif
+	return 0;
+}
+
+/*********************** HARDWARE CONFIGURATION ***********************/
+/*
+ * This part does the real job of starting and configuring the hardware.
+ */
+
+/*--------------------------------------------------------------------*/
+/*
+ * Routine to initialize the Modem Management Controller.
+ * (called by wv_hw_reset())
+ */
+static inline int wv_mmc_init(device * dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;
+	psa_t psa;
+	mmw_t m;
+	int configured;
+
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
+#endif
+
+	/* Read the parameter storage area. */
+	psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
+
+#ifdef USE_PSA_CONFIG
+	configured = psa.psa_conf_status & 1;
+#else
+	configured = 0;
+#endif
+
+	/* Is the PSA is not configured */
+	if (!configured) {
+		/* User will be able to configure NWID later (with iwconfig). */
+		psa.psa_nwid[0] = 0;
+		psa.psa_nwid[1] = 0;
+
+		/* no NWID checking since NWID is not set */
+		psa.psa_nwid_select = 0;
+
+		/* Disable encryption */
+		psa.psa_encryption_select = 0;
+
+		/* Set to standard values:
+		 * 0x04 for AT,
+		 * 0x01 for MCA,
+		 * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
+		 */
+		if (psa.psa_comp_number & 1)
+			psa.psa_thr_pre_set = 0x01;
+		else
+			psa.psa_thr_pre_set = 0x04;
+		psa.psa_quality_thr = 0x03;
+
+		/* It is configured */
+		psa.psa_conf_status |= 1;
+
+#ifdef USE_PSA_CONFIG
+		/* Write the psa. */
+		psa_write(ioaddr, lp->hacr,
+			  (char *) psa.psa_nwid - (char *) &psa,
+			  (unsigned char *) psa.psa_nwid, 4);
+		psa_write(ioaddr, lp->hacr,
+			  (char *) &psa.psa_thr_pre_set - (char *) &psa,
+			  (unsigned char *) &psa.psa_thr_pre_set, 1);
+		psa_write(ioaddr, lp->hacr,
+			  (char *) &psa.psa_quality_thr - (char *) &psa,
+			  (unsigned char *) &psa.psa_quality_thr, 1);
+		psa_write(ioaddr, lp->hacr,
+			  (char *) &psa.psa_conf_status - (char *) &psa,
+			  (unsigned char *) &psa.psa_conf_status, 1);
+		/* update the Wavelan checksum */
+		update_psa_checksum(dev, ioaddr, lp->hacr);
+#endif
+	}
+
+	/* Zero the mmc structure. */
+	memset(&m, 0x00, sizeof(m));
+
+	/* Copy PSA info to the mmc. */
+	m.mmw_netw_id_l = psa.psa_nwid[1];
+	m.mmw_netw_id_h = psa.psa_nwid[0];
+
+	if (psa.psa_nwid_select & 1)
+		m.mmw_loopt_sel = 0x00;
+	else
+		m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID;
+
+	memcpy(&m.mmw_encr_key, &psa.psa_encryption_key,
+	       sizeof(m.mmw_encr_key));
+
+	if (psa.psa_encryption_select)
+		m.mmw_encr_enable =
+		    MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE;
+	else
+		m.mmw_encr_enable = 0;
+
+	m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
+	m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
+
+	/*
+	 * Set default modem control parameters.
+	 * See NCR document 407-0024326 Rev. A.
+	 */
+	m.mmw_jabber_enable = 0x01;
+	m.mmw_freeze = 0;
+	m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
+	m.mmw_ifs = 0x20;
+	m.mmw_mod_delay = 0x04;
+	m.mmw_jam_time = 0x38;
+
+	m.mmw_des_io_invert = 0;
+	m.mmw_decay_prm = 0;
+	m.mmw_decay_updat_prm = 0;
+
+	/* Write all info to MMC. */
+	mmc_write(ioaddr, 0, (u8 *) & m, sizeof(m));
+
+	/* The following code starts the modem of the 2.00 frequency
+	 * selectable cards at power on.  It's not strictly needed for the
+	 * following boots.
+	 * The original patch was by Joe Finney for the PCMCIA driver, but
+	 * I've cleaned it up a bit and added documentation.
+	 * Thanks to Loeke Brederveld from Lucent for the info.
+	 */
+
+	/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
+	 * Does it work for everybody, especially old cards? */
+	/* Note: WFREQSEL verifies that it is able to read a sensible
+	 * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID
+	 * is 0xA (Xilinx version) or 0xB (Ariadne version).
+	 * My test is more crude but does work. */
+	if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+	      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+		/* We must download the frequency parameters to the
+		 * synthesizers (from the EEPROM - area 1)
+		 * Note: as the EEPROM is automatically decremented, we set the end
+		 * if the area... */
+		m.mmw_fee_addr = 0x0F;
+		m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
+		mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m,
+			  (unsigned char *) &m.mmw_fee_ctrl, 2);
+
+		/* Wait until the download is finished. */
+		fee_wait(ioaddr, 100, 100);
+
+#ifdef DEBUG_CONFIG_INFO
+		/* The frequency was in the last word downloaded. */
+		mmc_read(ioaddr, (char *) &m.mmw_fee_data_l - (char *) &m,
+			 (unsigned char *) &m.mmw_fee_data_l, 2);
+
+		/* Print some info for the user. */
+		printk(KERN_DEBUG
+		       "%s: WaveLAN 2.00 recognised (frequency select).  Current frequency = %ld\n",
+		       dev->name,
+		       ((m.
+			 mmw_fee_data_h << 4) | (m.mmw_fee_data_l >> 4)) *
+		       5 / 2 + 24000L);
+#endif
+
+		/* We must now download the power adjust value (gain) to
+		 * the synthesizers (from the EEPROM - area 7 - DAC). */
+		m.mmw_fee_addr = 0x61;
+		m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
+		mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m,
+			  (unsigned char *) &m.mmw_fee_ctrl, 2);
+
+		/* Wait until the download is finished. */
+	}
+	/* if 2.00 card */
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name);
+#endif
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Construct the fd and rbd structures.
+ * Start the receive unit.
+ * (called by wv_hw_reset())
+ */
+static inline int wv_ru_start(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	u16 scb_cs;
+	fd_t fd;
+	rbd_t rbd;
+	u16 rx;
+	u16 rx_next;
+	int i;
+
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
+#endif
+
+	obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
+		   (unsigned char *) &scb_cs, sizeof(scb_cs));
+	if ((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY)
+		return 0;
+
+	lp->rx_head = OFFSET_RU;
+
+	for (i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next) {
+		rx_next =
+		    (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ;
+
+		fd.fd_status = 0;
+		fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0;
+		fd.fd_link_offset = rx_next;
+		fd.fd_rbd_offset = rx + sizeof(fd);
+		obram_write(ioaddr, rx, (unsigned char *) &fd, sizeof(fd));
+
+		rbd.rbd_status = 0;
+		rbd.rbd_next_rbd_offset = I82586NULL;
+		rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd);
+		rbd.rbd_bufh = 0;
+		rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ);
+		obram_write(ioaddr, rx + sizeof(fd),
+			    (unsigned char *) &rbd, sizeof(rbd));
+
+		lp->rx_last = rx;
+	}
+
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset),
+		    (unsigned char *) &lp->rx_head, sizeof(lp->rx_head));
+
+	scb_cs = SCB_CMD_RUC_GO;
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+		    (unsigned char *) &scb_cs, sizeof(scb_cs));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 1000; i > 0; i--) {
+		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
+			   (unsigned char *) &scb_cs, sizeof(scb_cs));
+		if (scb_cs == 0)
+			break;
+
+		udelay(10);
+	}
+
+	if (i <= 0) {
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_INFO
+		       "%s: wavelan_ru_start(): board not accepting command.\n",
+		       dev->name);
+#endif
+		return -1;
+	}
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
+#endif
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Initialise the transmit blocks.
+ * Start the command unit executing the NOP
+ * self-loop of the first transmit block.
+ *
+ * Here we create the list of send buffers used to transmit packets
+ * between the PC and the command unit. For each buffer, we create a
+ * buffer descriptor (pointing on the buffer), a transmit command
+ * (pointing to the buffer descriptor) and a NOP command.
+ * The transmit command is linked to the NOP, and the NOP to itself.
+ * When we will have finished executing the transmit command, we will
+ * then loop on the NOP. By releasing the NOP link to a new command,
+ * we may send another buffer.
+ *
+ * (called by wv_hw_reset())
+ */
+static inline int wv_cu_start(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	int i;
+	u16 txblock;
+	u16 first_nop;
+	u16 scb_cs;
+
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name);
+#endif
+
+	lp->tx_first_free = OFFSET_CU;
+	lp->tx_first_in_use = I82586NULL;
+
+	for (i = 0, txblock = OFFSET_CU;
+	     i < NTXBLOCKS; i++, txblock += TXBLOCKZ) {
+		ac_tx_t tx;
+		ac_nop_t nop;
+		tbd_t tbd;
+		unsigned short tx_addr;
+		unsigned short nop_addr;
+		unsigned short tbd_addr;
+		unsigned short buf_addr;
+
+		tx_addr = txblock;
+		nop_addr = tx_addr + sizeof(tx);
+		tbd_addr = nop_addr + sizeof(nop);
+		buf_addr = tbd_addr + sizeof(tbd);
+
+		tx.tx_h.ac_status = 0;
+		tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I;
+		tx.tx_h.ac_link = nop_addr;
+		tx.tx_tbd_offset = tbd_addr;
+		obram_write(ioaddr, tx_addr, (unsigned char *) &tx,
+			    sizeof(tx));
+
+		nop.nop_h.ac_status = 0;
+		nop.nop_h.ac_command = acmd_nop;
+		nop.nop_h.ac_link = nop_addr;
+		obram_write(ioaddr, nop_addr, (unsigned char *) &nop,
+			    sizeof(nop));
+
+		tbd.tbd_status = TBD_STATUS_EOF;
+		tbd.tbd_next_bd_offset = I82586NULL;
+		tbd.tbd_bufl = buf_addr;
+		tbd.tbd_bufh = 0;
+		obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd,
+			    sizeof(tbd));
+	}
+
+	first_nop =
+	    OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t);
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset),
+		    (unsigned char *) &first_nop, sizeof(first_nop));
+
+	scb_cs = SCB_CMD_CUC_GO;
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+		    (unsigned char *) &scb_cs, sizeof(scb_cs));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 1000; i > 0; i--) {
+		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
+			   (unsigned char *) &scb_cs, sizeof(scb_cs));
+		if (scb_cs == 0)
+			break;
+
+		udelay(10);
+	}
+
+	if (i <= 0) {
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_INFO
+		       "%s: wavelan_cu_start(): board not accepting command.\n",
+		       dev->name);
+#endif
+		return -1;
+	}
+
+	lp->tx_n_in_use = 0;
+	netif_start_queue(dev);
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name);
+#endif
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine does a standard configuration of the WaveLAN 
+ * controller (i82586).
+ *
+ * It initialises the scp, iscp and scb structure
+ * The first two are just pointers to the next.
+ * The last one is used for basic configuration and for basic
+ * communication (interrupt status).
+ *
+ * (called by wv_hw_reset())
+ */
+static inline int wv_82586_start(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	scp_t scp;		/* system configuration pointer */
+	iscp_t iscp;		/* intermediate scp */
+	scb_t scb;		/* system control block */
+	ach_t cb;		/* Action command header */
+	u8 zeroes[512];
+	int i;
+
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name);
+#endif
+
+	/*
+	 * Clear the onboard RAM.
+	 */
+	memset(&zeroes[0], 0x00, sizeof(zeroes));
+	for (i = 0; i < I82586_MEMZ; i += sizeof(zeroes))
+		obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes));
+
+	/*
+	 * Construct the command unit structures:
+	 * scp, iscp, scb, cb.
+	 */
+	memset(&scp, 0x00, sizeof(scp));
+	scp.scp_sysbus = SCP_SY_16BBUS;
+	scp.scp_iscpl = OFFSET_ISCP;
+	obram_write(ioaddr, OFFSET_SCP, (unsigned char *) &scp,
+		    sizeof(scp));
+
+	memset(&iscp, 0x00, sizeof(iscp));
+	iscp.iscp_busy = 1;
+	iscp.iscp_offset = OFFSET_SCB;
+	obram_write(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp,
+		    sizeof(iscp));
+
+	/* Our first command is to reset the i82586. */
+	memset(&scb, 0x00, sizeof(scb));
+	scb.scb_command = SCB_CMD_RESET;
+	scb.scb_cbl_offset = OFFSET_CU;
+	scb.scb_rfa_offset = OFFSET_RU;
+	obram_write(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
+		    sizeof(scb));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	/* Wait for command to finish. */
+	for (i = 1000; i > 0; i--) {
+		obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp,
+			   sizeof(iscp));
+
+		if (iscp.iscp_busy == (unsigned short) 0)
+			break;
+
+		udelay(10);
+	}
+
+	if (i <= 0) {
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_INFO
+		       "%s: wv_82586_start(): iscp_busy timeout.\n",
+		       dev->name);
+#endif
+		return -1;
+	}
+
+	/* Check command completion. */
+	for (i = 15; i > 0; i--) {
+		obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
+			   sizeof(scb));
+
+		if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA))
+			break;
+
+		udelay(10);
+	}
+
+	if (i <= 0) {
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_INFO
+		       "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n",
+		       dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status);
+#endif
+		return -1;
+	}
+
+	wv_ack(dev);
+
+	/* Set the action command header. */
+	memset(&cb, 0x00, sizeof(cb));
+	cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose);
+	cb.ac_link = OFFSET_CU;
+	obram_write(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb));
+
+	if (wv_synchronous_cmd(dev, "diag()") == -1)
+		return -1;
+
+	obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb));
+	if (cb.ac_status & AC_SFLD_FAIL) {
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_INFO
+		       "%s: wv_82586_start(): i82586 Self Test failed.\n",
+		       dev->name);
+#endif
+		return -1;
+	}
+#ifdef DEBUG_I82586_SHOW
+	wv_scb_show(ioaddr);
+#endif
+
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name);
+#endif
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine does a standard configuration of the WaveLAN
+ * controller (i82586).
+ *
+ * This routine is a violent hack. We use the first free transmit block
+ * to make our configuration. In the buffer area, we create the three
+ * configuration commands (linked). We make the previous NOP point to
+ * the beginning of the buffer instead of the tx command. After, we go
+ * as usual to the NOP command.
+ * Note that only the last command (mc_set) will generate an interrupt.
+ *
+ * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit())
+ */
+static void wv_82586_config(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	unsigned short txblock;
+	unsigned short txpred;
+	unsigned short tx_addr;
+	unsigned short nop_addr;
+	unsigned short tbd_addr;
+	unsigned short cfg_addr;
+	unsigned short ias_addr;
+	unsigned short mcs_addr;
+	ac_tx_t tx;
+	ac_nop_t nop;
+	ac_cfg_t cfg;		/* Configure action */
+	ac_ias_t ias;		/* IA-setup action */
+	ac_mcs_t mcs;		/* Multicast setup */
+	struct dev_mc_list *dmi;
+
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name);
+#endif
+
+	/* Check nothing bad has happened */
+	if (lp->tx_n_in_use == (NTXBLOCKS - 1)) {
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_INFO "%s: wv_82586_config(): Tx queue full.\n",
+		       dev->name);
+#endif
+		return;
+	}
+
+	/* Calculate addresses of next block and previous block. */
+	txblock = lp->tx_first_free;
+	txpred = txblock - TXBLOCKZ;
+	if (txpred < OFFSET_CU)
+		txpred += NTXBLOCKS * TXBLOCKZ;
+	lp->tx_first_free += TXBLOCKZ;
+	if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
+		lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
+
+	lp->tx_n_in_use++;
+
+	/* Calculate addresses of the different parts of the block. */
+	tx_addr = txblock;
+	nop_addr = tx_addr + sizeof(tx);
+	tbd_addr = nop_addr + sizeof(nop);
+	cfg_addr = tbd_addr + sizeof(tbd_t);	/* beginning of the buffer */
+	ias_addr = cfg_addr + sizeof(cfg);
+	mcs_addr = ias_addr + sizeof(ias);
+
+	/*
+	 * Transmit command
+	 */
+	tx.tx_h.ac_status = 0xFFFF;	/* Fake completion value */
+	obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
+		    (unsigned char *) &tx.tx_h.ac_status,
+		    sizeof(tx.tx_h.ac_status));
+
+	/*
+	 * NOP command
+	 */
+	nop.nop_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
+		    (unsigned char *) &nop.nop_h.ac_status,
+		    sizeof(nop.nop_h.ac_status));
+	nop.nop_h.ac_link = nop_addr;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
+		    (unsigned char *) &nop.nop_h.ac_link,
+		    sizeof(nop.nop_h.ac_link));
+
+	/* Create a configure action. */
+	memset(&cfg, 0x00, sizeof(cfg));
+
+	/*
+	 * For Linux we invert AC_CFG_ALOC() so as to conform
+	 * to the way that net packets reach us from above.
+	 * (See also ac_tx_t.)
+	 *
+	 * Updated from Wavelan Manual WCIN085B
+	 */
+	cfg.cfg_byte_cnt =
+	    AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t));
+	cfg.cfg_fifolim = AC_CFG_FIFOLIM(4);
+	cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | AC_CFG_SRDY(0);
+	cfg.cfg_byte9 = AC_CFG_ELPBCK(0) |
+	    AC_CFG_ILPBCK(0) |
+	    AC_CFG_PRELEN(AC_CFG_PLEN_2) |
+	    AC_CFG_ALOC(1) | AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE);
+	cfg.cfg_byte10 = AC_CFG_BOFMET(1) |
+	    AC_CFG_ACR(6) | AC_CFG_LINPRIO(0);
+	cfg.cfg_ifs = 0x20;
+	cfg.cfg_slotl = 0x0C;
+	cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | AC_CFG_SLTTMHI(0);
+	cfg.cfg_byte14 = AC_CFG_FLGPAD(0) |
+	    AC_CFG_BTSTF(0) |
+	    AC_CFG_CRC16(0) |
+	    AC_CFG_NCRC(0) |
+	    AC_CFG_TNCRS(1) |
+	    AC_CFG_MANCH(0) |
+	    AC_CFG_BCDIS(0) | AC_CFG_PRM(lp->promiscuous);
+	cfg.cfg_byte15 = AC_CFG_ICDS(0) |
+	    AC_CFG_CDTF(0) | AC_CFG_ICSS(0) | AC_CFG_CSTF(0);
+/*
+  cfg.cfg_min_frm_len = AC_CFG_MNFRM(64);
+*/
+	cfg.cfg_min_frm_len = AC_CFG_MNFRM(8);
+
+	cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure);
+	cfg.cfg_h.ac_link = ias_addr;
+	obram_write(ioaddr, cfg_addr, (unsigned char *) &cfg, sizeof(cfg));
+
+	/* Set up the MAC address */
+	memset(&ias, 0x00, sizeof(ias));
+	ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup);
+	ias.ias_h.ac_link = mcs_addr;
+	memcpy(&ias.ias_addr[0], (unsigned char *) &dev->dev_addr[0],
+	       sizeof(ias.ias_addr));
+	obram_write(ioaddr, ias_addr, (unsigned char *) &ias, sizeof(ias));
+
+	/* Initialize adapter's Ethernet multicast addresses */
+	memset(&mcs, 0x00, sizeof(mcs));
+	mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup);
+	mcs.mcs_h.ac_link = nop_addr;
+	mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count;
+	obram_write(ioaddr, mcs_addr, (unsigned char *) &mcs, sizeof(mcs));
+
+	/* Any address to set? */
+	if (lp->mc_count) {
+		for (dmi = dev->mc_list; dmi; dmi = dmi->next)
+			outsw(PIOP1(ioaddr), (u16 *) dmi->dmi_addr,
+			      WAVELAN_ADDR_SIZE >> 1);
+
+#ifdef DEBUG_CONFIG_INFO
+		printk(KERN_DEBUG
+		       "%s: wv_82586_config(): set %d multicast addresses:\n",
+		       dev->name, lp->mc_count);
+		for (dmi = dev->mc_list; dmi; dmi = dmi->next)
+			printk(KERN_DEBUG
+			       " %02x:%02x:%02x:%02x:%02x:%02x\n",
+			       dmi->dmi_addr[0], dmi->dmi_addr[1],
+			       dmi->dmi_addr[2], dmi->dmi_addr[3],
+			       dmi->dmi_addr[4], dmi->dmi_addr[5]);
+#endif
+	}
+
+	/*
+	 * Overwrite the predecessor NOP link
+	 * so that it points to the configure action.
+	 */
+	nop_addr = txpred + sizeof(tx);
+	nop.nop_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
+		    (unsigned char *) &nop.nop_h.ac_status,
+		    sizeof(nop.nop_h.ac_status));
+	nop.nop_h.ac_link = cfg_addr;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
+		    (unsigned char *) &nop.nop_h.ac_link,
+		    sizeof(nop.nop_h.ac_link));
+
+	/* Job done, clear the flag */
+	lp->reconfig_82586 = 0;
+
+	if (lp->tx_first_in_use == I82586NULL)
+		lp->tx_first_in_use = txblock;
+
+	if (lp->tx_n_in_use == (NTXBLOCKS - 1))
+		netif_stop_queue(dev);
+
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine, called by wavelan_close(), gracefully stops the 
+ * WaveLAN controller (i82586).
+ * (called by wavelan_close())
+ */
+static inline void wv_82586_stop(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	u16 scb_cmd;
+
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name);
+#endif
+
+	/* Suspend both command unit and receive unit. */
+	scb_cmd =
+	    (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC &
+					       SCB_CMD_RUC_SUS);
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+		    (unsigned char *) &scb_cmd, sizeof(scb_cmd));
+	set_chan_attn(ioaddr, lp->hacr);
+
+	/* No more interrupts */
+	wv_ints_off(dev);
+
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Totally reset the WaveLAN and restart it.
+ * Performs the following actions:
+ *	1. A power reset (reset DMA)
+ *	2. Initialize the radio modem (using wv_mmc_init)
+ *	3. Reset & Configure LAN controller (using wv_82586_start)
+ *	4. Start the LAN controller's command unit
+ *	5. Start the LAN controller's receive unit
+ * (called by wavelan_interrupt(), wavelan_watchdog() & wavelan_open())
+ */
+static int wv_hw_reset(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name,
+	       (unsigned int) dev);
+#endif
+
+	/* Increase the number of resets done. */
+	lp->nresets++;
+
+	wv_hacr_reset(ioaddr);
+	lp->hacr = HACR_DEFAULT;
+
+	if ((wv_mmc_init(dev) < 0) || (wv_82586_start(dev) < 0))
+		return -1;
+
+	/* Enable the card to send interrupts. */
+	wv_ints_on(dev);
+
+	/* Start card functions */
+	if (wv_cu_start(dev) < 0)
+		return -1;
+
+	/* Setup the controller and parameters */
+	wv_82586_config(dev);
+
+	/* Finish configuration with the receive unit */
+	if (wv_ru_start(dev) < 0)
+		return -1;
+
+#ifdef DEBUG_CONFIG_TRACE
+	printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name);
+#endif
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Check if there is a WaveLAN at the specific base address.
+ * As a side effect, this reads the MAC address.
+ * (called in wavelan_probe() and init_module())
+ */
+static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac)
+{
+	int i;			/* Loop counter */
+
+	/* Check if the base address if available. */
+	if (check_region(ioaddr, sizeof(ha_t)))
+		return -EADDRINUSE;	/* ioaddr already used */
+
+	/* Reset host interface */
+	wv_hacr_reset(ioaddr);
+
+	/* Read the MAC address from the parameter storage area. */
+	psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr),
+		 mac, 6);
+
+	/*
+	 * Check the first three octets of the address for the manufacturer's code.
+	 * Note: if this can't find your WaveLAN card, you've got a
+	 * non-NCR/AT&T/Lucent ISA card.  See wavelan.p.h for detail on
+	 * how to configure your card.
+	 */
+	for (i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
+		if ((mac[0] == MAC_ADDRESSES[i][0]) &&
+		    (mac[1] == MAC_ADDRESSES[i][1]) &&
+		    (mac[2] == MAC_ADDRESSES[i][2]))
+			return 0;
+
+#ifdef DEBUG_CONFIG_INFO
+	printk(KERN_WARNING
+	       "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n",
+	       ioaddr, mac[0], mac[1], mac[2]);
+#endif
+	return -ENODEV;
+}
+
+/************************ INTERRUPT HANDLING ************************/
+
+/*
+ * This function is the interrupt handler for the WaveLAN card. This
+ * routine will be called whenever: 
+ */
+static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	device *dev;
+	unsigned long ioaddr;
+	net_local *lp;
+	u16 hasr;
+	u16 status;
+	u16 ack_cmd;
+
+	dev = dev_id;
+
+#ifdef DEBUG_INTERRUPT_TRACE
+	printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
+#endif
+
+	lp = (net_local *) dev->priv;
+	ioaddr = dev->base_addr;
+
+#ifdef DEBUG_INTERRUPT_INFO
+	/* Check state of our spinlock */
+	if(spin_is_locked(&lp->spinlock))
+		printk(KERN_DEBUG
+		       "%s: wavelan_interrupt(): spinlock is already locked !!!\n",
+		       dev->name);
+#endif
+
+	/* Prevent reentrancy. We need to do that because we may have
+	 * multiple interrupt handler running concurrently.
+	 * It is safe because wv_splhi() disables interrupts before acquiring
+	 * the spinlock. */
+	spin_lock(&lp->spinlock);
+
+	/* Check modem interrupt */
+	if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) {
+		u8 dce_status;
+
+		/*
+		 * Interrupt from the modem management controller.
+		 * This will clear it -- ignored for now.
+		 */
+		mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status,
+			 sizeof(dce_status));
+#ifdef DEBUG_INTERRUPT_ERROR
+		printk(KERN_INFO
+		       "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n",
+		       dev->name, dce_status);
+#endif
+	}
+
+	/* Check if not controller interrupt */
+	if ((hasr & HASR_82586_INTR) == 0) {
+#ifdef DEBUG_INTERRUPT_ERROR
+		printk(KERN_INFO
+		       "%s: wavelan_interrupt(): interrupt not coming from i82586\n",
+		       dev->name);
+#endif
+		spin_unlock (&lp->spinlock);
+		return;
+	}
+
+	/* Read interrupt data. */
+	obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
+		   (unsigned char *) &status, sizeof(status));
+
+	/*
+	 * Acknowledge the interrupt(s).
+	 */
+	ack_cmd = status & SCB_ST_INT;
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+		    (unsigned char *) &ack_cmd, sizeof(ack_cmd));
+	set_chan_attn(ioaddr, lp->hacr);
+
+#ifdef DEBUG_INTERRUPT_INFO
+	printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n",
+	       dev->name, status);
+#endif
+
+	/* Command completed. */
+	if ((status & SCB_ST_CX) == SCB_ST_CX) {
+#ifdef DEBUG_INTERRUPT_INFO
+		printk(KERN_DEBUG
+		       "%s: wavelan_interrupt(): command completed.\n",
+		       dev->name);
+#endif
+		wv_complete(dev, ioaddr, lp);
+	}
+
+	/* Frame received. */
+	if ((status & SCB_ST_FR) == SCB_ST_FR) {
+#ifdef DEBUG_INTERRUPT_INFO
+		printk(KERN_DEBUG
+		       "%s: wavelan_interrupt(): received packet.\n",
+		       dev->name);
+#endif
+		wv_receive(dev);
+	}
+
+	/* Check the state of the command unit. */
+	if (((status & SCB_ST_CNA) == SCB_ST_CNA) ||
+	    (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) &&
+	     (netif_running(dev)))) {
+#ifdef DEBUG_INTERRUPT_ERROR
+		printk(KERN_INFO
+		       "%s: wavelan_interrupt(): CU inactive -- restarting\n",
+		       dev->name);
+#endif
+		wv_hw_reset(dev);
+	}
+
+	/* Check the state of the command unit. */
+	if (((status & SCB_ST_RNR) == SCB_ST_RNR) ||
+	    (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) &&
+	     (netif_running(dev)))) {
+#ifdef DEBUG_INTERRUPT_ERROR
+		printk(KERN_INFO
+		       "%s: wavelan_interrupt(): RU not ready -- restarting\n",
+		       dev->name);
+#endif
+		wv_hw_reset(dev);
+	}
+
+	/* Release spinlock */
+	spin_unlock (&lp->spinlock);
+
+#ifdef DEBUG_INTERRUPT_TRACE
+	printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Watchdog: when we start a transmission, a timer is set for us in the
+ * kernel.  If the transmission completes, this timer is disabled. If
+ * the timer expires, we are called and we try to unlock the hardware.
+ */
+static void wavelan_watchdog(device *	dev)
+{
+	net_local *	lp = (net_local *)dev->priv;
+	u_long		ioaddr = dev->base_addr;
+	unsigned long	flags;
+	unsigned int	nreaped;
+
+#ifdef DEBUG_INTERRUPT_TRACE
+	printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
+#endif
+
+#ifdef DEBUG_INTERRUPT_ERROR
+	printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n",
+	       dev->name);
+#endif
+
+	/* Check that we came here for something */
+	if (lp->tx_n_in_use <= 0) {
+		return;
+	}
+
+	wv_splhi(lp, &flags);
+
+	/* Try to see if some buffers are not free (in case we missed
+	 * an interrupt */
+	nreaped = wv_complete(dev, ioaddr, lp);
+
+#ifdef DEBUG_INTERRUPT_INFO
+	printk(KERN_DEBUG
+	       "%s: wavelan_watchdog(): %d reaped, %d remain.\n",
+	       dev->name, nreaped, lp->tx_n_in_use);
+#endif
+
+#ifdef DEBUG_PSA_SHOW
+	{
+		psa_t psa;
+		psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+		wv_psa_show(&psa);
+	}
+#endif
+#ifdef DEBUG_MMC_SHOW
+	wv_mmc_show(dev);
+#endif
+#ifdef DEBUG_I82586_SHOW
+	wv_cu_show(dev);
+#endif
+
+	/* If no buffer has been freed */
+	if (nreaped == 0) {
+#ifdef DEBUG_INTERRUPT_ERROR
+		printk(KERN_INFO
+		       "%s: wavelan_watchdog(): cleanup failed, trying reset\n",
+		       dev->name);
+#endif
+		wv_hw_reset(dev);
+	}
+
+	/* At this point, we should have some free Tx buffer ;-) */
+	if (lp->tx_n_in_use < NTXBLOCKS - 1)
+		netif_wake_queue(dev);
+
+	wv_splx(lp, &flags);
+	
+#ifdef DEBUG_INTERRUPT_TRACE
+	printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
+#endif
+}
+
+/********************* CONFIGURATION CALLBACKS *********************/
+/*
+ * Here are the functions called by the Linux networking code (NET3)
+ * for initialization, configuration and deinstallations of the 
+ * WaveLAN ISA hardware.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Configure and start up the WaveLAN PCMCIA adaptor.
+ * Called by NET3 when it "opens" the device.
+ */
+static int wavelan_open(device * dev)
+{
+	net_local *	lp = (net_local *)dev->priv;
+	unsigned long	flags;
+
+#ifdef DEBUG_CALLBACK_TRACE
+	printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
+	       (unsigned int) dev);
+#endif
+
+	/* Check irq */
+	if (dev->irq == 0) {
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n",
+		       dev->name);
+#endif
+		return -ENXIO;
+	}
+
+	if (request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0) 
+	{
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n",
+		       dev->name);
+#endif
+		return -EAGAIN;
+	}
+
+	wv_splhi(lp, &flags);
+	
+	if (wv_hw_reset(dev) != -1) {
+		netif_start_queue(dev);
+	} else {
+		free_irq(dev->irq, dev);
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_INFO
+		       "%s: wavelan_open(): impossible to start the card\n",
+		       dev->name);
+#endif
+		wv_splx(lp, &flags);
+		return -EAGAIN;
+	}
+	wv_splx(lp, &flags);
+	
+#ifdef DEBUG_CALLBACK_TRACE
+	printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
+#endif
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Shut down the WaveLAN ISA card.
+ * Called by NET3 when it "closes" the device.
+ */
+static int wavelan_close(device * dev)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long flags;
+
+#ifdef DEBUG_CALLBACK_TRACE
+	printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
+	       (unsigned int) dev);
+#endif
+
+	netif_stop_queue(dev);
+
+	/*
+	 * Flush the Tx and disable Rx.
+	 */
+	wv_splhi(lp, &flags);
+	wv_82586_stop(dev);
+	wv_splx(lp, &flags);
+
+	free_irq(dev->irq, dev);
+
+#ifdef DEBUG_CALLBACK_TRACE
+	printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name);
+#endif
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Probe an I/O address, and if the WaveLAN is there configure the
+ * device structure
+ * (called by wavelan_probe() and via init_module()).
+ */
+static int __init wavelan_config(device * dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	u8 irq_mask;
+	int irq;
+	net_local *lp;
+
+#ifdef DEBUG_CALLBACK_TRACE
+	printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n",
+	       dev->name, (unsigned int) dev, ioaddr);
+#endif
+
+	/* Check IRQ argument on command line. */
+	if (dev->irq != 0) {
+		irq_mask = wv_irq_to_psa(dev->irq);
+
+		if (irq_mask == 0) {
+#ifdef DEBUG_CONFIG_ERROR
+			printk(KERN_WARNING
+			       "%s: wavelan_config(): invalid IRQ %d ignored.\n",
+			       dev->name, dev->irq);
+#endif
+			dev->irq = 0;
+		} else {
+#ifdef DEBUG_CONFIG_INFO
+			printk(KERN_DEBUG
+			       "%s: wavelan_config(): changing IRQ to %d\n",
+			       dev->name, dev->irq);
+#endif
+			psa_write(ioaddr, HACR_DEFAULT,
+				  psaoff(0, psa_int_req_no), &irq_mask, 1);
+			/* update the Wavelan checksum */
+			update_psa_checksum(dev, ioaddr, HACR_DEFAULT);
+			wv_hacr_reset(ioaddr);
+		}
+	}
+
+	psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no),
+		 &irq_mask, 1);
+	if ((irq = wv_psa_to_irq(irq_mask)) == -1) {
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_INFO
+		       "%s: wavelan_config(): could not wavelan_map_irq(%d).\n",
+		       dev->name, irq_mask);
+#endif
+		return -EAGAIN;
+	}
+
+	dev->irq = irq;
+
+	if (!request_region(ioaddr, sizeof(ha_t), "wavelan"))
+		return -EBUSY;
+
+	dev->mem_start = 0x0000;
+	dev->mem_end = 0x0000;
+	dev->if_port = 0;
+
+	/* Initialize device structures */
+	dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL);
+	if (dev->priv == NULL) {
+		release_region(ioaddr, sizeof(ha_t));
+		return -ENOMEM;
+	}
+	memset(dev->priv, 0x00, sizeof(net_local));
+	lp = (net_local *) dev->priv;
+
+	/* Back link to the device structure. */
+	lp->dev = dev;
+	/* Add the device at the beginning of the linked list. */
+	lp->next = wavelan_list;
+	wavelan_list = lp;
+
+	lp->hacr = HACR_DEFAULT;
+
+	/* Multicast stuff */
+	lp->promiscuous = 0;
+	lp->mc_count = 0;
+
+	/* Init spinlock */
+	spin_lock_init(&lp->spinlock);
+
+	/*
+	 * Fill in the fields of the device structure
+	 * with generic Ethernet values.
+	 */
+	ether_setup(dev);
+
+	SET_MODULE_OWNER(dev);
+	dev->open = wavelan_open;
+	dev->stop = wavelan_close;
+	dev->hard_start_xmit = wavelan_packet_xmit;
+	dev->get_stats = wavelan_get_stats;
+	dev->set_multicast_list = &wavelan_set_multicast_list;
+        dev->tx_timeout		= &wavelan_watchdog;
+        dev->watchdog_timeo	= WATCHDOG_JIFFIES;
+#ifdef SET_MAC_ADDRESS
+	dev->set_mac_address = &wavelan_set_mac_address;
+#endif				/* SET_MAC_ADDRESS */
+
+#ifdef WIRELESS_EXT		/* if wireless extension exists in the kernel */
+	dev->do_ioctl = wavelan_ioctl;
+	dev->get_wireless_stats = wavelan_get_wireless_stats;
+#endif
+
+	dev->mtu = WAVELAN_MTU;
+
+	/* Display nice information. */
+	wv_init_info(dev);
+
+#ifdef DEBUG_CALLBACK_TRACE
+	printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name);
+#endif
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Check for a network adaptor of this type.  Return '0' iff one 
+ * exists.  There seem to be different interpretations of
+ * the initial value of dev->base_addr.
+ * We follow the example in drivers/net/ne.c.
+ * (called in "Space.c")
+ */
+int __init wavelan_probe(device * dev)
+{
+	short base_addr;
+	mac_addr mac;		/* MAC address (check existence of WaveLAN) */
+	int i;
+	int r;
+
+#ifdef DEBUG_CALLBACK_TRACE
+	printk(KERN_DEBUG
+	       "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n",
+	       dev->name, (unsigned int) dev,
+	       (unsigned int) dev->base_addr);
+#endif
+
+#ifdef	STRUCT_CHECK
+	if (wv_struct_check() != (char *) NULL) {
+		printk(KERN_WARNING
+		       "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n",
+		       dev->name, wv_struct_check());
+		return -ENODEV;
+	}
+#endif				/* STRUCT_CHECK */
+
+	/* Check the value of the command line parameter for base address. */
+	base_addr = dev->base_addr;
+
+	/* Don't probe at all. */
+	if (base_addr < 0) {
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_WARNING
+		       "%s: wavelan_probe(): invalid base address\n",
+		       dev->name);
+#endif
+		return -ENXIO;
+	}
+
+	/* Check a single specified location. */
+	if (base_addr > 0x100) {
+		/* Check if there is something at this base address */
+		if ((r = wv_check_ioaddr(base_addr, mac)) == 0) {
+			memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
+			r = wavelan_config(dev);
+		}
+#ifdef DEBUG_CONFIG_INFO
+		if (r != 0)
+			printk(KERN_DEBUG
+			       "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n",
+			       dev->name, base_addr);
+#endif
+
+#ifdef DEBUG_CALLBACK_TRACE
+		printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name);
+#endif
+		return r;
+	}
+
+	/* Scan all possible addresses of the WaveLAN hardware. */
+	for (i = 0; i < NELS(iobase); i++) {
+		/* Check whether there is something at this base address. */
+		if (wv_check_ioaddr(iobase[i], mac) == 0) {
+			dev->base_addr = iobase[i];	/* Copy base address. */
+			memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
+			if (wavelan_config(dev) == 0) {
+#ifdef DEBUG_CALLBACK_TRACE
+				printk(KERN_DEBUG
+				       "%s: <-wavelan_probe()\n",
+				       dev->name);
+#endif
+				return 0;
+			}
+		}
+	}
+
+	/* We may have touched base_addr.  Another driver may not like it. */
+	dev->base_addr = base_addr;
+
+#ifdef DEBUG_CONFIG_INFO
+	printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n",
+	       dev->name);
+#endif
+
+	return -ENODEV;
+}
+
+/****************************** MODULE ******************************/
+/*
+ * Module entry point: insertion and removal
+ */
+
+#ifdef	MODULE
+/*------------------------------------------------------------------*/
+/*
+ * Insertion of the module
+ * I'm now quite proud of the multi-device support.
+ */
+int init_module(void)
+{
+	mac_addr mac;		/* MAC address (check WaveLAN existence) */
+	int ret = -EIO;		/* Return error if no cards found */
+	int i;
+
+#ifdef DEBUG_MODULE_TRACE
+	printk(KERN_DEBUG "-> init_module()\n");
+#endif
+
+	/* If probing is asked */
+	if (io[0] == 0) {
+#ifdef DEBUG_CONFIG_ERROR
+		printk(KERN_WARNING
+		       "WaveLAN init_module(): doing device probing (bad !)\n");
+		printk(KERN_WARNING
+		       "Specify base addresses while loading module to correct the problem\n");
+#endif
+
+		/* Copy the basic set of address to be probed. */
+		for (i = 0; i < NELS(iobase); i++)
+			io[i] = iobase[i];
+	}
+
+
+	/* Loop on all possible base addresses. */
+	i = -1;
+	while ((io[++i] != 0) && (i < NELS(io))) {
+		/* Check if there is something at this base address. */
+		if (wv_check_ioaddr(io[i], mac) == 0) {
+			device *dev;
+
+			/* Create device and set basic arguments. */
+			dev =
+			    kmalloc(sizeof(struct net_device), GFP_KERNEL);
+			if (dev == NULL) {
+				ret = -ENOMEM;
+				break;
+			}
+			memset(dev, 0x00, sizeof(struct net_device));
+			memcpy(dev->name, name[i], IFNAMSIZ);	/* Copy name */
+			dev->base_addr = io[i];
+			dev->irq = irq[i];
+			dev->init = &wavelan_config;
+			memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
+
+			/* Try to create the device. */
+			if (register_netdev(dev) != 0) {
+				/* Deallocate everything. */
+				/* Note: if dev->priv is mallocated, there is no way to fail. */
+				kfree(dev);
+			} else {
+				/* If at least one device OK, we do not fail */
+				ret = 0;
+			}
+		}		/* if there is something at the address */
+	}			/* Loop on all addresses. */
+
+#ifdef DEBUG_CONFIG_ERROR
+	if (wavelan_list == (net_local *) NULL)
+		printk(KERN_WARNING
+		       "WaveLAN init_module(): no device found\n");
+#endif
+
+#ifdef DEBUG_MODULE_TRACE
+	printk(KERN_DEBUG "<- init_module()\n");
+#endif
+	return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Removal of the module
+ */
+void cleanup_module(void)
+{
+#ifdef DEBUG_MODULE_TRACE
+	printk(KERN_DEBUG "-> cleanup_module()\n");
+#endif
+
+	/* Loop on all devices and release them. */
+	while (wavelan_list != (net_local *) NULL) {
+		device *dev = wavelan_list->dev;
+
+#ifdef DEBUG_CONFIG_INFO
+		printk(KERN_DEBUG
+		       "%s: cleanup_module(): removing device at 0x%x\n",
+		       dev->name, (unsigned int) dev);
+#endif
+
+		/* Release the ioport region. */
+		release_region(dev->base_addr, sizeof(ha_t));
+
+		/* Definitely remove the device. */
+		unregister_netdev(dev);
+
+		/* Unlink the device. */
+		wavelan_list = wavelan_list->next;
+
+		/* Free pieces. */
+		kfree(dev->priv);
+		kfree(dev);
+	}
+
+#ifdef DEBUG_MODULE_TRACE
+	printk(KERN_DEBUG "<- cleanup_module()\n");
+#endif
+}
+#endif				/* MODULE */
+MODULE_LICENSE("GPL");
+
+/*
+ * This software may only be used and distributed
+ * according to the terms of the GNU General Public License.
+ *
+ * This software was developed as a component of the
+ * Linux operating system.
+ * It is based on other device drivers and information
+ * either written or supplied by:
+ *	Ajay Bakre (bakre@paul.rutgers.edu),
+ *	Donald Becker (becker@scyld.com),
+ *	Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com),
+ *	Anders Klemets (klemets@it.kth.se),
+ *	Vladimir V. Kolpakov (w@stier.koenig.ru),
+ *	Marc Meertens (Marc.Meertens@Utrecht.NCR.com),
+ *	Pauline Middelink (middelin@polyware.iaf.nl),
+ *	Robert Morris (rtm@das.harvard.edu),
+ *	Jean Tourrilhes (jt@hplb.hpl.hp.com),
+ *	Girish Welling (welling@paul.rutgers.edu),
+ *
+ * Thanks go also to:
+ *	James Ashton (jaa101@syseng.anu.edu.au),
+ *	Alan Cox (alan@redhat.com),
+ *	Allan Creighton (allanc@cs.usyd.edu.au),
+ *	Matthew Geier (matthew@cs.usyd.edu.au),
+ *	Remo di Giovanni (remo@cs.usyd.edu.au),
+ *	Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de),
+ *	Vipul Gupta (vgupta@cs.binghamton.edu),
+ *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
+ *	Tim Nicholson (tim@cs.usyd.edu.au),
+ *	Ian Parkin (ian@cs.usyd.edu.au),
+ *	John Rosenberg (johnr@cs.usyd.edu.au),
+ *	George Rossi (george@phm.gov.au),
+ *	Arthur Scott (arthur@cs.usyd.edu.au),
+ *	Peter Storey,
+ * for their assistance and advice.
+ *
+ * Please send bug reports, updates, comments to:
+ *
+ * Bruce Janson                                    Email:  bruce@cs.usyd.edu.au
+ * Basser Department of Computer Science           Phone:  +61-2-9351-3423
+ * University of Sydney, N.S.W., 2006, AUSTRALIA   Fax:    +61-2-9351-3838
+ */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/wavelan.h linux/drivers/net/wireless/wavelan.h
--- v2.5.2/linux/drivers/net/wireless/wavelan.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/wavelan.h	Tue Feb 13 13:15:05 2001
@@ -0,0 +1,370 @@
+/*
+ *	WaveLAN ISA driver
+ *
+ *		Jean II - HPLB '96
+ *
+ * Reorganisation and extension of the driver.
+ * Original copyright follows. See wavelan.p.h for details.
+ *
+ * This file contains the declarations for the WaveLAN hardware. Note that
+ * the WaveLAN ISA includes a i82586 controller (see definitions in
+ * file i82586.h).
+ *
+ * The main difference between the ISA hardware and the PCMCIA one is
+ * the Ethernet controller (i82586 instead of i82593).
+ * The i82586 allows multiple transmit buffers.  The PSA needs to be accessed
+ * through the host interface.
+ */
+
+#ifndef _WAVELAN_H
+#define	_WAVELAN_H
+
+/************************** MAGIC NUMBERS ***************************/
+
+/* Detection of the WaveLAN card is done by reading the MAC
+ * address from the card and checking it.  If you have a non-AT&T
+ * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson),
+ * you might need to modify this part to accommodate your hardware.
+ */
+static const char	MAC_ADDRESSES[][3] =
+{
+  { 0x08, 0x00, 0x0E },		/* AT&T WaveLAN (standard) & DEC RoamAbout */
+  { 0x08, 0x00, 0x6A },		/* AT&T WaveLAN (alternate) */
+  { 0x00, 0x00, 0xE1 },		/* Hitachi Wavelan */
+  { 0x00, 0x60, 0x1D }		/* Lucent Wavelan (another one) */
+  /* Add your card here and send me the patch! */
+};
+
+#define WAVELAN_ADDR_SIZE	6	/* Size of a MAC address */
+
+#define WAVELAN_MTU		1500	/* Maximum size of WaveLAN packet */
+
+#define	MAXDATAZ		(WAVELAN_ADDR_SIZE + WAVELAN_ADDR_SIZE + 2 + WAVELAN_MTU)
+
+/*
+ * Constants used to convert channels to frequencies
+ */
+
+/* Frequency available in the 2.0 modem, in units of 250 kHz
+ * (as read in the offset register of the dac area).
+ * Used to map channel numbers used by `wfreqsel' to frequencies
+ */
+static const short	channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8,
+				    0xD0, 0xF0, 0xF8, 0x150 };
+
+/* Frequencies of the 1.0 modem (fixed frequencies).
+ * Use to map the PSA `subband' to a frequency
+ * Note : all frequencies apart from the first one need to be multiplied by 10
+ */
+static const int	fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
+
+
+
+/*************************** PC INTERFACE ****************************/
+
+/*
+ * Host Adaptor structure.
+ * (base is board port address).
+ */
+typedef union hacs_u	hacs_u;
+union hacs_u
+{
+	unsigned short	hu_command;		/* Command register */
+#define		HACR_RESET		0x0001	/* Reset board */
+#define		HACR_CA			0x0002	/* Set Channel Attention for 82586 */
+#define		HACR_16BITS		0x0004	/* 16-bit operation (0 => 8bits) */
+#define		HACR_OUT0		0x0008	/* General purpose output pin 0 */
+						/* not used - must be 1 */
+#define		HACR_OUT1		0x0010	/* General purpose output pin 1 */
+						/* not used - must be 1 */
+#define		HACR_82586_INT_ENABLE	0x0020	/* Enable 82586 interrupts */
+#define		HACR_MMC_INT_ENABLE	0x0040	/* Enable MMC interrupts */
+#define		HACR_INTR_CLR_ENABLE	0x0080	/* Enable interrupt status read/clear */
+	unsigned short	hu_status;		/* Status Register */
+#define		HASR_82586_INTR		0x0001	/* Interrupt request from 82586 */
+#define		HASR_MMC_INTR		0x0002	/* Interrupt request from MMC */
+#define		HASR_MMC_BUSY		0x0004	/* MMC busy indication */
+#define		HASR_PSA_BUSY		0x0008	/* LAN parameter storage area busy */
+};
+
+typedef struct ha_t	ha_t;
+struct ha_t
+{
+	hacs_u		ha_cs;		/* Command and status registers */
+#define 		ha_command	ha_cs.hu_command
+#define 		ha_status	ha_cs.hu_status
+	unsigned short	ha_mmcr;	/* Modem Management Ctrl Register */
+	unsigned short	ha_pior0;	/* Program I/O Address Register Port 0 */
+	unsigned short	ha_piop0;	/* Program I/O Port 0 */
+	unsigned short	ha_pior1;	/* Program I/O Address Register Port 1 */
+	unsigned short	ha_piop1;	/* Program I/O Port 1 */
+	unsigned short	ha_pior2;	/* Program I/O Address Register Port 2 */
+	unsigned short	ha_piop2;	/* Program I/O Port 2 */
+};
+
+#define HA_SIZE		16
+
+#define	hoff(p,f) 	(unsigned short)((void *)(&((ha_t *)((void *)0 + (p)))->f) - (void *)0)
+#define	HACR(p)		hoff(p, ha_command)
+#define	HASR(p)		hoff(p, ha_status)
+#define	MMCR(p)		hoff(p, ha_mmcr)
+#define	PIOR0(p)	hoff(p, ha_pior0)
+#define	PIOP0(p)	hoff(p, ha_piop0)
+#define	PIOR1(p)	hoff(p, ha_pior1)
+#define	PIOP1(p)	hoff(p, ha_piop1)
+#define	PIOR2(p)	hoff(p, ha_pior2)
+#define	PIOP2(p)	hoff(p, ha_piop2)
+
+/*
+ * Program I/O Mode Register values.
+ */
+#define STATIC_PIO		0	/* Mode 1: static mode */
+					/* RAM access ??? */
+#define AUTOINCR_PIO		1	/* Mode 2: auto increment mode */
+					/* RAM access ??? */
+#define AUTODECR_PIO		2	/* Mode 3: auto decrement mode */
+					/* RAM access ??? */
+#define PARAM_ACCESS_PIO	3	/* Mode 4: LAN parameter access mode */
+					/* Parameter access. */
+#define PIO_MASK		3	/* register mask */
+#define PIOM(cmd,piono)		((u_short)cmd << 10 << (piono * 2))
+
+#define	HACR_DEFAULT		(HACR_OUT0 | HACR_OUT1 | HACR_16BITS | PIOM(STATIC_PIO, 0) | PIOM(AUTOINCR_PIO, 1) | PIOM(PARAM_ACCESS_PIO, 2))
+#define	HACR_INTRON		(HACR_82586_INT_ENABLE | HACR_MMC_INT_ENABLE | HACR_INTR_CLR_ENABLE)
+
+/************************** MEMORY LAYOUT **************************/
+
+/*
+ * Onboard 64 k RAM layout.
+ * (Offsets from 0x0000.)
+ */
+#define OFFSET_RU		0x0000		/* 75% memory */
+#define OFFSET_CU		0xC000		/* 25% memory */
+#define OFFSET_SCB		(OFFSET_ISCP - sizeof(scb_t))
+#define OFFSET_ISCP		(OFFSET_SCP - sizeof(iscp_t))
+#define OFFSET_SCP		I82586_SCP_ADDR
+
+#define	RXBLOCKZ		(sizeof(fd_t) + sizeof(rbd_t) + MAXDATAZ)
+#define	TXBLOCKZ		(sizeof(ac_tx_t) + sizeof(ac_nop_t) + sizeof(tbd_t) + MAXDATAZ)
+
+#define	NRXBLOCKS		((OFFSET_CU - OFFSET_RU) / RXBLOCKZ)
+#define	NTXBLOCKS		((OFFSET_SCB - OFFSET_CU) / TXBLOCKZ)
+
+/********************** PARAMETER STORAGE AREA **********************/
+
+/*
+ * Parameter Storage Area (PSA).
+ */
+typedef struct psa_t	psa_t;
+struct psa_t
+{
+  unsigned char	psa_io_base_addr_1;	/* [0x00] Base address 1 ??? */
+  unsigned char	psa_io_base_addr_2;	/* [0x01] Base address 2 */
+  unsigned char	psa_io_base_addr_3;	/* [0x02] Base address 3 */
+  unsigned char	psa_io_base_addr_4;	/* [0x03] Base address 4 */
+  unsigned char	psa_rem_boot_addr_1;	/* [0x04] Remote Boot Address 1 */
+  unsigned char	psa_rem_boot_addr_2;	/* [0x05] Remote Boot Address 2 */
+  unsigned char	psa_rem_boot_addr_3;	/* [0x06] Remote Boot Address 3 */
+  unsigned char	psa_holi_params;	/* [0x07] HOst Lan Interface (HOLI) Parameters */
+  unsigned char	psa_int_req_no;		/* [0x08] Interrupt Request Line */
+  unsigned char	psa_unused0[7];		/* [0x09-0x0F] unused */
+
+  unsigned char	psa_univ_mac_addr[WAVELAN_ADDR_SIZE];	/* [0x10-0x15] Universal (factory) MAC Address */
+  unsigned char	psa_local_mac_addr[WAVELAN_ADDR_SIZE];	/* [0x16-1B] Local MAC Address */
+  unsigned char	psa_univ_local_sel;	/* [0x1C] Universal Local Selection */
+#define		PSA_UNIVERSAL	0		/* Universal (factory) */
+#define		PSA_LOCAL	1		/* Local */
+  unsigned char	psa_comp_number;	/* [0x1D] Compatibility Number:	 */
+#define		PSA_COMP_PC_AT_915	0 	/* PC-AT 915 MHz 	 */
+#define		PSA_COMP_PC_MC_915	1 	/* PC-MC 915 MHz	 */
+#define		PSA_COMP_PC_AT_2400	2 	/* PC-AT 2.4 GHz	 */
+#define		PSA_COMP_PC_MC_2400	3 	/* PC-MC 2.4 GHz 	 */
+#define		PSA_COMP_PCMCIA_915	4 	/* PCMCIA 915 MHz or 2.0 */
+  unsigned char	psa_thr_pre_set;	/* [0x1E] Modem Threshold Preset */
+  unsigned char	psa_feature_select;	/* [0x1F] Call code required (1=on) */
+#define		PSA_FEATURE_CALL_CODE	0x01 	/* Call code required (Japan) */
+  unsigned char	psa_subband;		/* [0x20] Subband	  */
+#define		PSA_SUBBAND_915		0	/* 915 MHz or 2.0 */
+#define		PSA_SUBBAND_2425	1	/* 2425 MHz	  */
+#define		PSA_SUBBAND_2460	2	/* 2460 MHz	  */
+#define		PSA_SUBBAND_2484	3	/* 2484 MHz	  */
+#define		PSA_SUBBAND_2430_5	4	/* 2430.5 MHz	  */
+  unsigned char	psa_quality_thr;	/* [0x21] Modem Quality Threshold */
+  unsigned char	psa_mod_delay;		/* [0x22] Modem Delay (?) (reserved) */
+  unsigned char	psa_nwid[2];		/* [0x23-0x24] Network ID */
+  unsigned char	psa_nwid_select;	/* [0x25] Network ID Select On/Off */
+  unsigned char	psa_encryption_select;	/* [0x26] Encryption On/Off */
+  unsigned char	psa_encryption_key[8];	/* [0x27-0x2E] Encryption Key */
+  unsigned char	psa_databus_width;	/* [0x2F] AT bus width select 8/16 */
+  unsigned char	psa_call_code[8];	/* [0x30-0x37] (Japan) Call Code */
+  unsigned char	psa_nwid_prefix[2];	/* [0x38-0x39] Roaming domain */
+  unsigned char	psa_reserved[2];	/* [0x3A-0x3B] Reserved - fixed 00 */
+  unsigned char	psa_conf_status;	/* [0x3C] Conf Status, bit 0=1:config*/
+  unsigned char	psa_crc[2];		/* [0x3D] CRC-16 over PSA */
+  unsigned char	psa_crc_status;		/* [0x3F] CRC Valid Flag */
+};
+
+#define	PSA_SIZE	64
+
+/* Calculate offset of a field in the above structure.
+ * Warning:  only even addresses are used. */
+#define	psaoff(p,f) 	((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL))
+
+/******************** MODEM MANAGEMENT INTERFACE ********************/
+
+/*
+ * Modem Management Controller (MMC) write structure.
+ */
+typedef struct mmw_t	mmw_t;
+struct mmw_t
+{
+  unsigned char	mmw_encr_key[8];	/* encryption key */
+  unsigned char	mmw_encr_enable;	/* Enable or disable encryption. */
+#define	MMW_ENCR_ENABLE_MODE	0x02	/* mode of security option */
+#define	MMW_ENCR_ENABLE_EN	0x01	/* Enable security option. */
+  unsigned char	mmw_unused0[1];		/* unused */
+  unsigned char	mmw_des_io_invert;	/* encryption option */
+#define	MMW_DES_IO_INVERT_RES	0x0F	/* reserved */
+#define	MMW_DES_IO_INVERT_CTRL	0xF0	/* control (?) (set to 0) */
+  unsigned char	mmw_unused1[5];		/* unused */
+  unsigned char	mmw_loopt_sel;		/* looptest selection */
+#define	MMW_LOOPT_SEL_DIS_NWID	0x40	/* Disable NWID filtering. */
+#define	MMW_LOOPT_SEL_INT	0x20	/* Activate Attention Request. */
+#define	MMW_LOOPT_SEL_LS	0x10	/* looptest, no collision avoidance */
+#define MMW_LOOPT_SEL_LT3A	0x08	/* looptest 3a */
+#define	MMW_LOOPT_SEL_LT3B	0x04	/* looptest 3b */
+#define	MMW_LOOPT_SEL_LT3C	0x02	/* looptest 3c */
+#define	MMW_LOOPT_SEL_LT3D	0x01	/* looptest 3d */
+  unsigned char	mmw_jabber_enable;	/* jabber timer enable */
+  /* Abort transmissions > 200 ms */
+  unsigned char	mmw_freeze;		/* freeze or unfreeze signal level */
+  /* 0 : signal level & qual updated for every new message, 1 : frozen */
+  unsigned char	mmw_anten_sel;		/* antenna selection */
+#define MMW_ANTEN_SEL_SEL	0x01	/* direct antenna selection */
+#define	MMW_ANTEN_SEL_ALG_EN	0x02	/* antenna selection algo. enable */
+  unsigned char	mmw_ifs;		/* inter frame spacing */
+  /* min time between transmission in bit periods (.5 us) - bit 0 ignored */
+  unsigned char	mmw_mod_delay;	 	/* modem delay (synchro) */
+  unsigned char	mmw_jam_time;		/* jamming time (after collision) */
+  unsigned char	mmw_unused2[1];		/* unused */
+  unsigned char	mmw_thr_pre_set;	/* level threshold preset */
+  /* Discard all packet with signal < this value (4) */
+  unsigned char	mmw_decay_prm;		/* decay parameters */
+  unsigned char	mmw_decay_updat_prm;	/* decay update parameters */
+  unsigned char	mmw_quality_thr;	/* quality (z-quotient) threshold */
+  /* Discard all packet with quality < this value (3) */
+  unsigned char	mmw_netw_id_l;		/* NWID low order byte */
+  unsigned char	mmw_netw_id_h;		/* NWID high order byte */
+  /* Network ID or Domain : create virtual net on the air */
+
+  /* 2.0 Hardware extension - frequency selection support */
+  unsigned char	mmw_mode_select;	/* for analog tests (set to 0) */
+  unsigned char	mmw_unused3[1];		/* unused */
+  unsigned char	mmw_fee_ctrl;		/* frequency EEPROM control */
+#define	MMW_FEE_CTRL_PRE	0x10	/* Enable protected instructions. */
+#define	MMW_FEE_CTRL_DWLD	0x08	/* Download EEPROM to mmc. */
+#define	MMW_FEE_CTRL_CMD	0x07	/* EEPROM commands:  */
+#define	MMW_FEE_CTRL_READ	0x06	/* Read */
+#define	MMW_FEE_CTRL_WREN	0x04	/* Write enable */
+#define	MMW_FEE_CTRL_WRITE	0x05	/* Write data to address. */
+#define	MMW_FEE_CTRL_WRALL	0x04	/* Write data to all addresses. */
+#define	MMW_FEE_CTRL_WDS	0x04	/* Write disable */
+#define	MMW_FEE_CTRL_PRREAD	0x16	/* Read addr from protect register */
+#define	MMW_FEE_CTRL_PREN	0x14	/* Protect register enable */
+#define	MMW_FEE_CTRL_PRCLEAR	0x17	/* Unprotect all registers. */
+#define	MMW_FEE_CTRL_PRWRITE	0x15	/* Write address in protect register */
+#define	MMW_FEE_CTRL_PRDS	0x14	/* Protect register disable */
+  /* Never issue the PRDS command:  it's irreversible! */
+
+  unsigned char	mmw_fee_addr;		/* EEPROM address */
+#define	MMW_FEE_ADDR_CHANNEL	0xF0	/* Select the channel. */
+#define	MMW_FEE_ADDR_OFFSET	0x0F	/* Offset in channel data */
+#define	MMW_FEE_ADDR_EN		0xC0	/* FEE_CTRL enable operations */
+#define	MMW_FEE_ADDR_DS		0x00	/* FEE_CTRL disable operations */
+#define	MMW_FEE_ADDR_ALL	0x40	/* FEE_CTRL all operations */
+#define	MMW_FEE_ADDR_CLEAR	0xFF	/* FEE_CTRL clear operations */
+
+  unsigned char	mmw_fee_data_l;		/* Write data to EEPROM. */
+  unsigned char	mmw_fee_data_h;		/* high octet */
+  unsigned char	mmw_ext_ant;		/* Setting for external antenna */
+#define	MMW_EXT_ANT_EXTANT	0x01	/* Select external antenna */
+#define	MMW_EXT_ANT_POL		0x02	/* Polarity of the antenna */
+#define	MMW_EXT_ANT_INTERNAL	0x00	/* Internal antenna */
+#define	MMW_EXT_ANT_EXTERNAL	0x03	/* External antenna */
+#define	MMW_EXT_ANT_IQ_TEST	0x1C	/* IQ test pattern (set to 0) */
+};
+
+#define	MMW_SIZE	37
+
+#define	mmwoff(p,f) 	(unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
+
+/*
+ * Modem Management Controller (MMC) read structure.
+ */
+typedef struct mmr_t	mmr_t;
+struct mmr_t
+{
+  unsigned char	mmr_unused0[8];		/* unused */
+  unsigned char	mmr_des_status;		/* encryption status */
+  unsigned char	mmr_des_avail;		/* encryption available (0x55 read) */
+#define	MMR_DES_AVAIL_DES	0x55		/* DES available */
+#define	MMR_DES_AVAIL_AES	0x33		/* AES (AT&T) available */
+  unsigned char	mmr_des_io_invert;	/* des I/O invert register */
+  unsigned char	mmr_unused1[5];		/* unused */
+  unsigned char	mmr_dce_status;		/* DCE status */
+#define	MMR_DCE_STATUS_RX_BUSY		0x01	/* receiver busy */
+#define	MMR_DCE_STATUS_LOOPT_IND	0x02	/* loop test indicated */
+#define	MMR_DCE_STATUS_TX_BUSY		0x04	/* transmitter on */
+#define	MMR_DCE_STATUS_JBR_EXPIRED	0x08	/* jabber timer expired */
+#define MMR_DCE_STATUS			0x0F	/* mask to get the bits */
+  unsigned char	mmr_dsp_id;		/* DSP ID (AA = Daedalus rev A) */
+  unsigned char	mmr_unused2[2];		/* unused */
+  unsigned char	mmr_correct_nwid_l;	/* # of correct NWIDs rxd (low) */
+  unsigned char	mmr_correct_nwid_h;	/* # of correct NWIDs rxd (high) */
+  /* Warning:  read high-order octet first! */
+  unsigned char	mmr_wrong_nwid_l;	/* # of wrong NWIDs rxd (low) */
+  unsigned char	mmr_wrong_nwid_h;	/* # of wrong NWIDs rxd (high) */
+  unsigned char	mmr_thr_pre_set;	/* level threshold preset */
+#define	MMR_THR_PRE_SET		0x3F		/* level threshold preset */
+#define	MMR_THR_PRE_SET_CUR	0x80		/* Current signal above it */
+  unsigned char	mmr_signal_lvl;		/* signal level */
+#define	MMR_SIGNAL_LVL		0x3F		/* signal level */
+#define	MMR_SIGNAL_LVL_VALID	0x80		/* Updated since last read */
+  unsigned char	mmr_silence_lvl;	/* silence level (noise) */
+#define	MMR_SILENCE_LVL		0x3F		/* silence level */
+#define	MMR_SILENCE_LVL_VALID	0x80		/* Updated since last read */
+  unsigned char	mmr_sgnl_qual;		/* signal quality */
+#define	MMR_SGNL_QUAL		0x0F		/* signal quality */
+#define	MMR_SGNL_QUAL_ANT	0x80		/* current antenna used */
+  unsigned char	mmr_netw_id_l;		/* NWID low order byte (?) */
+  unsigned char	mmr_unused3[3];		/* unused */
+
+  /* 2.0 Hardware extension - frequency selection support */
+  unsigned char	mmr_fee_status;		/* Status of frequency EEPROM */
+#define	MMR_FEE_STATUS_ID	0xF0		/* Modem revision ID */
+#define	MMR_FEE_STATUS_DWLD	0x08		/* Download in progress */
+#define	MMR_FEE_STATUS_BUSY	0x04		/* EEPROM busy */
+  unsigned char	mmr_unused4[1];		/* unused */
+  unsigned char	mmr_fee_data_l;		/* Read data from EEPROM (low) */
+  unsigned char	mmr_fee_data_h;		/* Read data from EEPROM (high) */
+};
+
+#define	MMR_SIZE	36
+
+#define	mmroff(p,f) 	(unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
+
+/* Make the two above structures one */
+typedef union mm_t
+{
+  struct mmw_t	w;	/* Write to the mmc */
+  struct mmr_t	r;	/* Read from the mmc */
+} mm_t;
+
+#endif /* _WAVELAN_H */
+
+/*
+ * This software may only be used and distributed
+ * according to the terms of the GNU General Public License.
+ *
+ * For more details, see wavelan.c.
+ */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/wavelan.p.h linux/drivers/net/wireless/wavelan.p.h
--- v2.5.2/linux/drivers/net/wireless/wavelan.p.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/wavelan.p.h	Fri Oct 12 14:21:18 2001
@@ -0,0 +1,713 @@
+/*
+ *	WaveLAN ISA driver
+ *
+ *		Jean II - HPLB '96
+ *
+ * Reorganisation and extension of the driver.
+ *
+ * This file contains all definitions and declarations necessary for the
+ * WaveLAN ISA driver.  This file is a private header, so it should
+ * be included only in wavelan.c!
+ */
+
+#ifndef WAVELAN_P_H
+#define WAVELAN_P_H
+
+/************************** DOCUMENTATION ***************************/
+/*
+ * This driver provides a Linux interface to the WaveLAN ISA hardware.
+ * The WaveLAN is a product of Lucent (http://www.wavelan.com/).
+ * This division was formerly part of NCR and then AT&T.
+ * WaveLANs are also distributed by DEC (RoamAbout DS) and Digital Ocean.
+ *
+ * To learn how to use this driver, read the NET3 HOWTO.
+ * If you want to exploit the many other functionalities, read the comments
+ * in the code.
+ *
+ * This driver is the result of the effort of many people (see below).
+ */
+
+/* ------------------------ SPECIFIC NOTES ------------------------ */
+/*
+ * Web page
+ * --------
+ *	I try to maintain a web page with the Wireless LAN Howto at :
+ *	    http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
+ *
+ * SMP
+ * ---
+ *	We now are SMP compliant (I eventually fixed the remaining bugs).
+ *	The driver has been tested on a dual P6-150 and survived my usual
+ *	set of torture tests.
+ *	Anyway, I spent enough time chasing interrupt re-entrancy during
+ *	errors or reconfigure, and I designed the locked/unlocked sections
+ *	of the driver with great care, and with the recent addition of
+ *	the spinlock (thanks to the new API), we should be quite close to
+ *	the truth.
+ *	The SMP/IRQ locking is quite coarse and conservative (i.e. not fast),
+ *	but better safe than sorry (especially at 2 Mb/s ;-).
+ *
+ *	I have also looked into disabling only our interrupt on the card
+ *	(via HACR) instead of all interrupts in the processor (via cli),
+ *	so that other driver are not impacted, and it look like it's
+ *	possible, but it's very tricky to do right (full of races). As
+ *	the gain would be mostly for SMP systems, it can wait...
+ *
+ * Debugging and options
+ * ---------------------
+ *	You will find below a set of '#define" allowing a very fine control
+ *	on the driver behaviour and the debug messages printed.
+ *	The main options are :
+ *	o SET_PSA_CRC, to have your card correctly recognised by
+ *	  an access point and the Point-to-Point diagnostic tool.
+ *	o USE_PSA_CONFIG, to read configuration from the PSA (EEprom)
+ *	  (otherwise we always start afresh with some defaults)
+ *
+ * wavelan.o is too darned big
+ * ---------------------------
+ *	That's true!  There is a very simple way to reduce the driver
+ *	object by 33%!  Comment out the following line:
+ *		#include <linux/wireless.h>
+ *	Other compile options can also reduce the size of it...
+ *
+ * MAC address and hardware detection:
+ * -----------------------------------
+ *	The detection code for the WaveLAN checks that the first three
+ *	octets of the MAC address fit the company code.  This type of
+ *	detection works well for AT&T cards (because the AT&T code is
+ *	hardcoded in wavelan.h), but of course will fail for other
+ *	manufacturers.
+ *
+ *	If you are sure that your card is derived from the WaveLAN,
+ *	here is the way to configure it:
+ *	1) Get your MAC address
+ *		a) With your card utilities (wfreqsel, instconf, etc.)
+ *		b) With the driver:
+ *			o compile the kernel with DEBUG_CONFIG_INFO enabled
+ *			o Boot and look the card messages
+ *	2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h)
+ *	3) Compile and verify
+ *	4) Send me the MAC code.  I will include it in the next version.
+ *
+ */
+
+/* --------------------- WIRELESS EXTENSIONS --------------------- */
+/*
+ * This driver is the first to support "wireless extensions".
+ * This set of extensions provides a standard way to control the wireless
+ * characteristics of the hardware.  Applications such as mobile IP may
+ * take advantage of it.
+ *
+ * You will need to enable the CONFIG_NET_RADIO define in the kernel
+ * configuration to enable the wireless extensions (this is the one
+ * giving access to the radio network device choice).
+ *
+ * It might also be a good idea as well to fetch the wireless tools to
+ * configure the device and play a bit.
+ */
+
+/* ---------------------------- FILES ---------------------------- */
+/*
+ * wavelan.c:		actual code for the driver:  C functions
+ *
+ * wavelan.p.h:		private header:  local types and variables for driver
+ *
+ * wavelan.h:		description of the hardware interface and structs
+ *
+ * i82586.h:		description of the Ethernet controller
+ */
+
+/* --------------------------- HISTORY --------------------------- */
+/*
+ * This is based on information in the drivers' headers. It may not be
+ * accurate, and I guarantee only my best effort.
+ *
+ * The history of the WaveLAN drivers is as complicated as the history of
+ * the WaveLAN itself (NCR -> AT&T -> Lucent).
+ *
+ * It all started with Anders Klemets <klemets@paul.rutgers.edu>
+ * writing a WaveLAN ISA driver for the Mach microkernel.  Girish
+ * Welling <welling@paul.rutgers.edu> had also worked on it.
+ * Keith Moore modified this for the PCMCIA hardware.
+ * 
+ * Robert Morris <rtm@das.harvard.edu> ported these two drivers to BSDI
+ * and added specific PCMCIA support (there is currently no equivalent
+ * of the PCMCIA package under BSD).
+ *
+ * Jim Binkley <jrb@cs.pdx.edu> ported both BSDI drivers to FreeBSD.
+ *
+ * Bruce Janson <bruce@cs.usyd.edu.au> ported the BSDI ISA driver to Linux.
+ *
+ * Anthony D. Joseph <adj@lcs.mit.edu> started to modify Bruce's driver
+ * (with help of the BSDI PCMCIA driver) for PCMCIA.
+ * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished this work.
+ * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
+ * 2.00 cards correctly (2.4 GHz with frequency selection).
+ * David Hinds <dhinds@hyper.stanford.edu> integrated the whole in his
+ * PCMCIA package (and bug corrections).
+ *
+ * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
+ * patches to the PCMCIA driver.  Later, I added code in the ISA driver
+ * for Wireless Extensions and full support of frequency selection
+ * cards.  Then, I did the same to the PCMCIA driver, and did some
+ * reorganisation.  Finally, I came back to the ISA driver to
+ * upgrade it at the same level as the PCMCIA one and reorganise
+ * the code.
+ * Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me
+ * much needed information on the WaveLAN hardware.
+ */
+
+/* The original copyrights and literature mention others' names and
+ * credits.  I don't know what their part in this development was.
+ */
+
+/* By the way, for the copyright and legal stuff:
+ * almost everybody wrote code under the GNU or BSD license (or similar),
+ * and want their original copyright to remain somewhere in the
+ * code (for myself, I go with the GPL).
+ * Nobody wants to take responsibility for anything, except the fame.
+ */
+
+/* --------------------------- CREDITS --------------------------- */
+/*
+ * This software was developed as a component of the
+ * Linux operating system.
+ * It is based on other device drivers and information
+ * either written or supplied by:
+ *	Ajay Bakre <bakre@paul.rutgers.edu>,
+ *	Donald Becker <becker@cesdis.gsfc.nasa.gov>,
+ *	Loeke Brederveld <Loeke.Brederveld@Utrecht.NCR.com>,
+ *	Brent Elphick <belphick@uwaterloo.ca>,
+ *	Anders Klemets <klemets@it.kth.se>,
+ *	Vladimir V. Kolpakov <w@stier.koenig.ru>,
+ *	Marc Meertens <Marc.Meertens@Utrecht.NCR.com>,
+ *	Pauline Middelink <middelin@polyware.iaf.nl>,
+ *	Robert Morris <rtm@das.harvard.edu>,
+ *	Jean Tourrilhes <jt@hpl.hp.com>,
+ *	Girish Welling <welling@paul.rutgers.edu>,
+ *	Clark Woodworth <clark@hiway1.exit109.com>
+ *	Yongguang Zhang <ygz@isl.hrl.hac.com>
+ *
+ * Thanks go also to:
+ *	James Ashton <jaa101@syseng.anu.edu.au>,
+ *	Alan Cox <alan@redhat.com>,
+ *	Allan Creighton <allanc@cs.usyd.edu.au>,
+ *	Matthew Geier <matthew@cs.usyd.edu.au>,
+ *	Remo di Giovanni <remo@cs.usyd.edu.au>,
+ *	Eckhard Grah <grah@wrcs1.urz.uni-wuppertal.de>,
+ *	Vipul Gupta <vgupta@cs.binghamton.edu>,
+ *	Mark Hagan <mhagan@wtcpost.daytonoh.NCR.COM>,
+ *	Tim Nicholson <tim@cs.usyd.edu.au>,
+ *	Ian Parkin <ian@cs.usyd.edu.au>,
+ *	John Rosenberg <johnr@cs.usyd.edu.au>,
+ *	George Rossi <george@phm.gov.au>,
+ *	Arthur Scott <arthur@cs.usyd.edu.au>,
+ *	Stanislav Sinyagin <stas@isf.ru>
+ *	and Peter Storey for their assistance and advice.
+ *
+ * Additional Credits:
+ *
+ *	My development has been done initially under Debian 1.1 (Linux 2.0.x)
+ *	and now	under Debian 2.2, initially with an HP Vectra XP/60, and now
+ *	an HP Vectra XP/90.
+ *
+ */
+
+/* ------------------------- IMPROVEMENTS ------------------------- */
+/*
+ * I proudly present:
+ *
+ * Changes made in first pre-release:
+ * ----------------------------------
+ *	- reorganisation of the code, function name change
+ *	- creation of private header (wavelan.p.h)
+ *	- reorganised debug messages
+ *	- more comments, history, etc.
+ *	- mmc_init:  configure the PSA if not done
+ *	- mmc_init:  correct default value of level threshold for PCMCIA
+ *	- mmc_init:  2.00 detection better code for 2.00 initialization
+ *	- better info at startup
+ *	- IRQ setting (note:  this setting is permanent)
+ *	- watchdog:  change strategy (and solve module removal problems)
+ *	- add wireless extensions (ioctl and get_wireless_stats)
+ *	  get/set nwid/frequency on fly, info for /proc/net/wireless
+ *	- more wireless extensions:  SETSPY and GETSPY
+ *	- make wireless extensions optional
+ *	- private ioctl to set/get quality and level threshold, histogram
+ *	- remove /proc/net/wavelan
+ *	- suppress useless stuff from lp (net_local)
+ *	- kernel 2.1 support (copy_to/from_user instead of memcpy_to/fromfs)
+ *	- add message level (debug stuff in /var/adm/debug and errors not
+ *	  displayed at console and still in /var/adm/messages)
+ *	- multi device support
+ *	- start fixing the probe (init code)
+ *	- more inlines
+ *	- man page
+ *	- many other minor details and cleanups
+ *
+ * Changes made in second pre-release:
+ * -----------------------------------
+ *	- clean up init code (probe and module init)
+ *	- better multiple device support (module)
+ *	- name assignment (module)
+ *
+ * Changes made in third pre-release:
+ * ----------------------------------
+ *	- be more conservative on timers
+ *	- preliminary support for multicast (I still lack some details)
+ *
+ * Changes made in fourth pre-release:
+ * -----------------------------------
+ *	- multicast (revisited and finished)
+ *	- avoid reset in set_multicast_list (a really big hack)
+ *	  if somebody could apply this code for other i82586 based drivers
+ *	- share onboard memory 75% RU and 25% CU (instead of 50/50)
+ *
+ * Changes made for release in 2.1.15:
+ * -----------------------------------
+ *	- change the detection code for multi manufacturer code support
+ *
+ * Changes made for release in 2.1.17:
+ * -----------------------------------
+ *	- update to wireless extensions changes
+ *	- silly bug in card initial configuration (psa_conf_status)
+ *
+ * Changes made for release in 2.1.27 & 2.0.30:
+ * --------------------------------------------
+ *	- small bug in debug code (probably not the last one...)
+ *	- remove extern keyword for wavelan_probe()
+ *	- level threshold is now a standard wireless extension (version 4 !)
+ *	- modules parameters types (new module interface)
+ *
+ * Changes made for release in 2.1.36:
+ * -----------------------------------
+ *	- byte count stats (courtesy of David Hinds)
+ *	- remove dev_tint stuff (courtesy of David Hinds)
+ *	- encryption setting from Brent Elphick (thanks a lot!)
+ *	- 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin)
+ *
+ * Other changes (not by me) :
+ * -------------------------
+ *	- Spelling and gramar "rectification".
+ *
+ * Changes made for release in 2.0.37 & 2.2.2 :
+ * ------------------------------------------
+ *	- Correct status in /proc/net/wireless
+ *	- Set PSA CRC to make PtP diagnostic tool happy (Bob Gray)
+ *	- Module init code don't fail if we found at least one card in
+ *	  the address list (Karlis Peisenieks)
+ *	- Missing parenthesis (Christopher Peterson)
+ *	- Correct i82586 configuration parameters
+ *	- Encryption initialisation bug (Robert McCormack)
+ *	- New mac addresses detected in the probe
+ *	- Increase watchdog for busy environments
+ *
+ * Changes made for release in 2.0.38 & 2.2.7 :
+ * ------------------------------------------
+ *	- Correct the reception logic to better report errors and avoid
+ *	  sending bogus packet up the stack
+ *	- Delay RU config to avoid corrupting first received packet
+ *	- Change config completion code (to actually check something)
+ *	- Avoid reading out of bound in skbuf to transmit
+ *	- Rectify a lot of (useless) debugging code
+ *	- Change the way to `#ifdef SET_PSA_CRC'
+ *
+ * Changes made for release in 2.2.11 & 2.3.13 :
+ * -------------------------------------------
+ *	- Change e-mail and web page addresses
+ *	- Watchdog timer is now correctly expressed in HZ, not in jiffies
+ *	- Add channel number to the list of frequencies in range
+ *	- Add the (short) list of bit-rates in range
+ *	- Developp a new sensitivity... (sens.value & sens.fixed)
+ *
+ * Changes made for release in 2.2.14 & 2.3.23 :
+ * -------------------------------------------
+ *	- Fix check for root permission (break instead of exit)
+ *	- New nwid & encoding setting (Wireless Extension 9)
+ *
+ * Changes made for release in 2.3.49 :
+ * ----------------------------------
+ *	- Indentation reformating (Alan)
+ *	- Update to new network API (softnet - 2.3.43) :
+ *		o replace dev->tbusy (Alan)
+ *		o replace dev->tstart (Alan)
+ *		o remove dev->interrupt (Alan)
+ *		o add SMP locking via spinlock in splxx (me)
+ *		o add spinlock in interrupt handler (me)
+ *		o use kernel watchdog instead of ours (me)
+ *		o increase watchdog timeout (kernel is more sensitive) (me)
+ *		o verify that all the changes make sense and work (me)
+ *	- Fixup a potential gotcha when reconfiguring and thighten a bit
+ *		the interactions with Tx queue.
+ *
+ * Changes made for release in 2.4.0 :
+ * ---------------------------------
+ *	- Fix spinlock stupid bugs that I left in. The driver is now SMP
+ *		compliant and doesn't lockup at startup.
+ *
+ * Wishes & dreams:
+ * ----------------
+ *	- roaming (see Pcmcia driver)
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include	<linux/module.h>
+
+#include	<linux/kernel.h>
+#include	<linux/sched.h>
+#include	<linux/types.h>
+#include	<linux/fcntl.h>
+#include	<linux/interrupt.h>
+#include	<linux/stat.h>
+#include	<linux/ptrace.h>
+#include	<linux/ioport.h>
+#include	<linux/in.h>
+#include	<linux/string.h>
+#include	<linux/delay.h>
+#include	<asm/system.h>
+#include	<asm/bitops.h>
+#include	<asm/io.h>
+#include	<asm/dma.h>
+#include	<asm/uaccess.h>
+#include	<linux/errno.h>
+#include	<linux/netdevice.h>
+#include	<linux/etherdevice.h>
+#include	<linux/skbuff.h>
+#include	<linux/slab.h>
+#include	<linux/timer.h>
+#include	<linux/init.h>
+
+#include <linux/wireless.h>		/* Wireless extensions */
+
+/* WaveLAN declarations */
+#include	"i82586.h"
+#include	"wavelan.h"
+
+/************************** DRIVER OPTIONS **************************/
+/*
+ * `#define' or `#undef' the following constant to change the behaviour
+ * of the driver...
+ */
+#undef SET_PSA_CRC		/* Calculate and set the CRC on PSA (slower) */
+#define USE_PSA_CONFIG		/* Use info from the PSA. */
+#undef STRUCT_CHECK		/* Verify padding of structures. */
+#undef EEPROM_IS_PROTECTED	/* doesn't seem to be necessary */
+#define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical). */
+#undef SET_MAC_ADDRESS		/* Experimental */
+
+#ifdef WIRELESS_EXT	/* If wireless extensions exist in the kernel */
+/* Warning:  this stuff will slow down the driver. */
+#define WIRELESS_SPY		/* Enable spying addresses. */
+#undef HISTOGRAM		/* Enable histogram of signal level. */
+#endif
+
+/****************************** DEBUG ******************************/
+
+#undef DEBUG_MODULE_TRACE	/* module insertion/removal */
+#undef DEBUG_CALLBACK_TRACE	/* calls made by Linux */
+#undef DEBUG_INTERRUPT_TRACE	/* calls to handler */
+#undef DEBUG_INTERRUPT_INFO	/* type of interrupt and so on */
+#define DEBUG_INTERRUPT_ERROR	/* problems */
+#undef DEBUG_CONFIG_TRACE	/* Trace the config functions. */
+#undef DEBUG_CONFIG_INFO	/* what's going on */
+#define DEBUG_CONFIG_ERROR	/* errors on configuration */
+#undef DEBUG_TX_TRACE		/* transmission calls */
+#undef DEBUG_TX_INFO		/* header of the transmitted packet */
+#undef DEBUG_TX_FAIL		/* Normal failure conditions */
+#define DEBUG_TX_ERROR		/* Unexpected conditions */
+#undef DEBUG_RX_TRACE		/* transmission calls */
+#undef DEBUG_RX_INFO		/* header of the received packet */
+#undef DEBUG_RX_FAIL		/* Normal failure conditions */
+#define DEBUG_RX_ERROR		/* Unexpected conditions */
+
+#undef DEBUG_PACKET_DUMP	/* Dump packet on the screen if defined to 32. */
+#undef DEBUG_IOCTL_TRACE	/* misc. call by Linux */
+#undef DEBUG_IOCTL_INFO		/* various debugging info */
+#define DEBUG_IOCTL_ERROR	/* what's going wrong */
+#define DEBUG_BASIC_SHOW	/* Show basic startup info. */
+#undef DEBUG_VERSION_SHOW	/* Print version info. */
+#undef DEBUG_PSA_SHOW		/* Dump PSA to screen. */
+#undef DEBUG_MMC_SHOW		/* Dump mmc to screen. */
+#undef DEBUG_SHOW_UNUSED	/* Show unused fields too. */
+#undef DEBUG_I82586_SHOW	/* Show i82586 status. */
+#undef DEBUG_DEVICE_SHOW	/* Show device parameters. */
+
+/************************ CONSTANTS & MACROS ************************/
+
+#ifdef DEBUG_VERSION_SHOW
+static const char	*version	= "wavelan.c : v23 (SMP + wireless extensions) 05/10/00\n";
+#endif
+
+/* Watchdog temporisation */
+#define	WATCHDOG_JIFFIES	(512*HZ/100)
+
+/* Macro to get the number of elements in an array */
+#define	NELS(a)				(sizeof(a) / sizeof(a[0]))
+
+/* ------------------------ PRIVATE IOCTL ------------------------ */
+
+#define SIOCSIPQTHR	SIOCIWFIRSTPRIV		/* Set quality threshold */
+#define SIOCGIPQTHR	SIOCIWFIRSTPRIV + 1	/* Get quality threshold */
+#define SIOCSIPLTHR	SIOCIWFIRSTPRIV + 2	/* Set level threshold */
+#define SIOCGIPLTHR	SIOCIWFIRSTPRIV + 3	/* Get level threshold */
+
+#define SIOCSIPHISTO	SIOCIWFIRSTPRIV + 6	/* Set histogram ranges */
+#define SIOCGIPHISTO	SIOCIWFIRSTPRIV + 7	/* Get histogram values */
+
+/****************************** TYPES ******************************/
+
+/* Shortcuts */
+typedef struct net_device		device;
+typedef struct net_device_stats	en_stats;
+typedef struct iw_statistics	iw_stats;
+typedef struct iw_quality	iw_qual;
+typedef struct iw_freq		iw_freq;
+typedef struct net_local	net_local;
+typedef struct timer_list	timer_list;
+
+/* Basic types */
+typedef u_char		mac_addr[WAVELAN_ADDR_SIZE];	/* Hardware address */
+
+/*
+ * Static specific data for the interface.
+ *
+ * For each network interface, Linux keeps data in two structures:  "device"
+ * keeps the generic data (same format for everybody) and "net_local" keeps
+ * additional specific data.
+ * Note that some of this specific data is in fact generic (en_stats, for
+ * example).
+ */
+struct net_local
+{
+  net_local *	next;		/* linked list of the devices */
+  device *	dev;		/* reverse link */
+  spinlock_t	spinlock;	/* Serialize access to the hardware (SMP) */
+  en_stats	stats;		/* Ethernet interface statistics */
+  int		nresets;	/* number of hardware resets */
+  u_char	reconfig_82586;	/* We need to reconfigure the controller. */
+  u_char	promiscuous;	/* promiscuous mode */
+  int		mc_count;	/* number of multicast addresses */
+  u_short	hacr;		/* current host interface state */
+
+  int		tx_n_in_use;
+  u_short	rx_head;
+  u_short	rx_last;
+  u_short	tx_first_free;
+  u_short	tx_first_in_use;
+
+#ifdef WIRELESS_EXT
+  iw_stats	wstats;		/* Wireless-specific statistics */
+#endif
+
+#ifdef WIRELESS_SPY
+  int		spy_number;			/* number of addresses to spy */
+  mac_addr	spy_address[IW_MAX_SPY];	/* the addresses to spy */
+  iw_qual	spy_stat[IW_MAX_SPY];		/* statistics gathered */
+#endif	/* WIRELESS_SPY */
+
+#ifdef HISTOGRAM
+  int		his_number;		/* number of intervals */
+  u_char	his_range[16];		/* boundaries of interval ]n-1; n] */
+  u_long	his_sum[16];		/* sum in interval */
+#endif	/* HISTOGRAM */
+};
+
+/**************************** PROTOTYPES ****************************/
+
+/* ----------------------- MISC. SUBROUTINES ------------------------ */
+static inline void
+	wv_splhi(net_local *,		/* Disable interrupts, lock driver */
+		 unsigned long *);	/* flags */
+static inline void
+	wv_splx(net_local *,		/* Enable interrupts, unlock driver */
+		unsigned long *);	/* flags */
+static u_char
+	wv_irq_to_psa(int);
+static int
+	wv_psa_to_irq(u_char);
+/* ------------------- HOST ADAPTER SUBROUTINES ------------------- */
+static inline u_short		/* data */
+	hasr_read(u_long);	/* Read the host interface:  base address */
+static inline void
+	hacr_write(u_long,	/* Write to host interface:  base address */
+		   u_short),	/* data */
+	hacr_write_slow(u_long,
+		   u_short),
+	set_chan_attn(u_long,	/* ioaddr */
+		      u_short),	/* hacr   */
+	wv_hacr_reset(u_long),	/* ioaddr */
+	wv_16_off(u_long,	/* ioaddr */
+		  u_short),	/* hacr   */
+	wv_16_on(u_long,	/* ioaddr */
+		 u_short),	/* hacr   */
+	wv_ints_off(device *),
+	wv_ints_on(device *);
+/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
+static void
+	psa_read(u_long,	/* Read the Parameter Storage Area. */
+		 u_short,	/* hacr */
+		 int,		/* offset in PSA */
+		 u_char *,	/* buffer to fill */
+		 int),		/* size to read */
+	psa_write(u_long, 	/* Write to the PSA. */
+		  u_short,	/* hacr */
+		  int,		/* offset in PSA */
+		  u_char *,	/* buffer in memory */
+		  int);		/* length of buffer */
+static inline void
+	mmc_out(u_long,		/* Write 1 byte to the Modem Manag Control. */
+		u_short,
+		u_char),
+	mmc_write(u_long,	/* Write n bytes to the MMC. */
+		  u_char,
+		  u_char *,
+		  int);
+static inline u_char		/* Read 1 byte from the MMC. */
+	mmc_in(u_long,
+	       u_short);
+static inline void
+	mmc_read(u_long,	/* Read n bytes from the MMC. */
+		 u_char,
+		 u_char *,
+		 int),
+	fee_wait(u_long,	/* Wait for frequency EEPROM:  base address */
+		 int,		/* base delay to wait for */
+		 int);		/* time to wait */
+static void
+	fee_read(u_long,	/* Read the frequency EEPROM:  base address */
+		 u_short,	/* destination offset */
+		 u_short *,	/* data buffer */
+		 int);		/* number of registers */
+/* ---------------------- I82586 SUBROUTINES ----------------------- */
+static /*inline*/ void
+	obram_read(u_long,	/* ioaddr */
+		   u_short,	/* o */
+		   u_char *,	/* b */
+		   int);	/* n */
+static inline void
+	obram_write(u_long,	/* ioaddr */
+		    u_short,	/* o */
+		    u_char *,	/* b */
+		    int);	/* n */
+static void
+	wv_ack(device *);
+static inline int
+	wv_synchronous_cmd(device *,
+			   const char *),
+	wv_config_complete(device *,
+			   u_long,
+			   net_local *);
+static int
+	wv_complete(device *,
+		    u_long,
+		    net_local *);
+static inline void
+	wv_82586_reconfig(device *);
+/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */
+#ifdef DEBUG_I82586_SHOW
+static void
+	wv_scb_show(unsigned short);
+#endif
+static inline void
+	wv_init_info(device *);	/* display startup info */
+/* ------------------- IOCTL, STATS & RECONFIG ------------------- */
+static en_stats	*
+	wavelan_get_stats(device *);	/* Give stats /proc/net/dev */
+static void
+	wavelan_set_multicast_list(device *);
+/* ----------------------- PACKET RECEPTION ----------------------- */
+static inline void
+	wv_packet_read(device *,	/* Read a packet from a frame. */
+		       u_short,
+		       int),
+	wv_receive(device *);	/* Read all packets waiting. */
+/* --------------------- PACKET TRANSMISSION --------------------- */
+static inline int
+	wv_packet_write(device *,	/* Write a packet to the Tx buffer. */
+			void *,
+			short);
+static int
+	wavelan_packet_xmit(struct sk_buff *,	/* Send a packet. */
+			    device *);
+/* -------------------- HARDWARE CONFIGURATION -------------------- */
+static inline int
+	wv_mmc_init(device *),		/* Initialize the modem. */
+	wv_ru_start(device *),		/* Start the i82586 receiver unit. */
+	wv_cu_start(device *),		/* Start the i82586 command unit. */
+	wv_82586_start(device *);	/* Start the i82586. */
+static void
+	wv_82586_config(device *);	/* Configure the i82586. */
+static inline void
+	wv_82586_stop(device *);
+static int
+	wv_hw_reset(device *),		/* Reset the WaveLAN hardware. */
+	wv_check_ioaddr(u_long,		/* ioaddr */
+			u_char *);	/* mac address (read) */
+/* ---------------------- INTERRUPT HANDLING ---------------------- */
+static void
+	wavelan_interrupt(int,		/* interrupt handler */
+			  void *,
+			  struct pt_regs *);
+static void
+	wavelan_watchdog(device *);	/* transmission watchdog */
+/* ------------------- CONFIGURATION CALLBACKS ------------------- */
+static int
+	wavelan_open(device *),		/* Open the device. */
+	wavelan_close(device *),	/* Close the device. */
+	wavelan_config(device *);	/* Configure one device. */
+extern int
+	wavelan_probe(device *);	/* See Space.c. */
+
+/**************************** VARIABLES ****************************/
+
+/*
+ * This is the root of the linked list of WaveLAN drivers
+ * It is use to verify that we don't reuse the same base address
+ * for two different drivers and to clean up when removing the module.
+ */
+static net_local *	wavelan_list	= (net_local *) NULL;
+
+/*
+ * This table is used to translate the PSA value to IRQ number
+ * and vice versa.
+ */
+static u_char	irqvals[]	=
+{
+	   0,    0,    0, 0x01,
+	0x02, 0x04,    0, 0x08,
+	   0,    0, 0x10, 0x20,
+	0x40,    0,    0, 0x80,
+};
+
+/*
+ * Table of the available I/O addresses (base addresses) for WaveLAN
+ */
+static unsigned short	iobase[]	=
+{
+#if	0
+  /* Leave out 0x3C0 for now -- seems to clash with some video
+   * controllers.
+   * Leave out the others too -- we will always use 0x390 and leave
+   * 0x300 for the Ethernet device.
+   * Jean II:  0x3E0 is fine as well.
+   */
+  0x300, 0x390, 0x3E0, 0x3C0
+#endif	/* 0 */
+  0x390, 0x3E0
+};
+
+#ifdef	MODULE
+/* Parameters set by insmod */
+static int	io[4];
+static int	irq[4];
+static char	name[4][IFNAMSIZ];
+MODULE_PARM(io, "1-4i");
+MODULE_PARM(irq, "1-4i");
+MODULE_PARM(name, "1-4c" __MODULE_STRING(IFNAMSIZ));
+MODULE_PARM_DESC(io, "WaveLAN I/O base address(es),required");
+MODULE_PARM_DESC(irq, "WaveLAN IRQ number(s)");
+MODULE_PARM_DESC(name, "WaveLAN interface neme(s)");
+#endif	/* MODULE */
+
+#endif	/* WAVELAN_P_H */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/wavelan_cs.c linux/drivers/net/wireless/wavelan_cs.c
--- v2.5.2/linux/drivers/net/wireless/wavelan_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/wavelan_cs.c	Thu Jan 24 22:03:56 2002
@@ -0,0 +1,4837 @@
+/*
+ *	Wavelan Pcmcia driver
+ *
+ *		Jean II - HPLB '96
+ *
+ * Reorganisation and extension of the driver.
+ * Original copyright follow. See wavelan_cs.p.h for details.
+ *
+ * This code is derived from Anthony D. Joseph's code and all the changes here
+ * are also under the original copyright below.
+ *
+ * This code supports version 2.00 of WaveLAN/PCMCIA cards (2.4GHz), and
+ * can work on Linux 2.0.36 with support of David Hinds' PCMCIA Card Services
+ *
+ * Joe Finney (joe@comp.lancs.ac.uk) at Lancaster University in UK added
+ * critical code in the routine to initialize the Modem Management Controller.
+ *
+ * Thanks to Alan Cox and Bruce Janson for their advice.
+ *
+ *	-- Yunzhou Li (scip4166@nus.sg)
+ *
+#ifdef WAVELAN_ROAMING	
+ * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu)
+ * based on patch by Joe Finney from Lancaster University.
+#endif
+ *
+ * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An
+ * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor.
+ *
+ *   A non-shared memory PCMCIA ethernet driver for linux
+ *
+ * ISA version modified to support PCMCIA by Anthony Joseph (adj@lcs.mit.edu)
+ *
+ *
+ * Joseph O'Sullivan & John Langford (josullvn@cs.cmu.edu & jcl@cs.cmu.edu)
+ *
+ * Apr 2 '98  made changes to bring the i82593 control/int handling in line
+ *             with offical specs...
+ *
+ ****************************************************************************
+ *   Copyright 1995
+ *   Anthony D. Joseph
+ *   Massachusetts Institute of Technology
+ *
+ *   Permission to use, copy, modify, and distribute this program
+ *   for any purpose and without fee is hereby granted, provided
+ *   that this copyright and permission notice appear on all copies
+ *   and supporting documentation, the name of M.I.T. not be used
+ *   in advertising or publicity pertaining to distribution of the
+ *   program without specific prior permission, and notice be given
+ *   in supporting documentation that copying and distribution is
+ *   by permission of M.I.T.  M.I.T. makes no representations about
+ *   the suitability of this software for any purpose.  It is pro-
+ *   vided "as is" without express or implied warranty.         
+ ****************************************************************************
+ *
+ */
+
+#include "wavelan_cs.p.h"		/* Private header */
+
+/************************* MISC SUBROUTINES **************************/
+/*
+ * Subroutines which won't fit in one of the following category
+ * (wavelan modem or i82593)
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for disabling interrupts.
+ * (note : inline, so optimised away)
+ */
+static inline void
+wv_splhi(net_local *		lp,
+	 unsigned long *	pflags)
+{
+  spin_lock_irqsave(&lp->spinlock, *pflags);
+  /* Note : above does the cli(); itself */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for re-enabling interrupts.
+ */
+static inline void
+wv_splx(net_local *		lp,
+	unsigned long *		pflags)
+{
+  spin_unlock_irqrestore(&lp->spinlock, *pflags);
+
+  /* Note : enabling interrupts on the hardware is done in wv_ru_start()
+   * via : outb(OP1_INT_ENABLE, LCCR(base));
+   */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for reporting error to cardservices
+ */
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+#ifdef STRUCT_CHECK
+/*------------------------------------------------------------------*/
+/*
+ * Sanity routine to verify the sizes of the various WaveLAN interface
+ * structures.
+ */
+static char *
+wv_structuct_check(void)
+{
+#define	SC(t,s,n)	if (sizeof(t) != s) return(n);
+
+  SC(psa_t, PSA_SIZE, "psa_t");
+  SC(mmw_t, MMW_SIZE, "mmw_t");
+  SC(mmr_t, MMR_SIZE, "mmr_t");
+
+#undef	SC
+
+  return((char *) NULL);
+} /* wv_structuct_check */
+#endif	/* STRUCT_CHECK */
+
+/******************* MODEM MANAGEMENT SUBROUTINES *******************/
+/*
+ * Useful subroutines to manage the modem of the wavelan
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read from card's Host Adaptor Status Register.
+ */
+static inline u_char
+hasr_read(u_long	base)
+{
+  return(inb(HASR(base)));
+} /* hasr_read */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write to card's Host Adapter Command Register.
+ */
+static inline void
+hacr_write(u_long	base,
+	   u_char	hacr)
+{
+  outb(hacr, HACR(base));
+} /* hacr_write */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write to card's Host Adapter Command Register. Include a delay for
+ * those times when it is needed.
+ */
+static inline void
+hacr_write_slow(u_long	base,
+		u_char	hacr)
+{
+  hacr_write(base, hacr);
+  /* delay might only be needed sometimes */
+  mdelay(1);
+} /* hacr_write_slow */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read the Parameter Storage Area from the WaveLAN card's memory
+ */
+static void
+psa_read(device *	dev,
+	 int		o,	/* offset in PSA */
+	 u_char *	b,	/* buffer to fill */
+	 int		n)	/* size to read */
+{
+  u_char *	ptr = ((u_char *)dev->mem_start) + PSA_ADDR + (o << 1);
+
+  while(n-- > 0)
+    {
+      *b++ = readb(ptr);
+      /* Due to a lack of address decode pins, the WaveLAN PCMCIA card
+       * only supports reading even memory addresses. That means the
+       * increment here MUST be two.
+       * Because of that, we can't use memcpy_fromio()...
+       */
+      ptr += 2;
+    }
+} /* psa_read */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write the Paramter Storage Area to the WaveLAN card's memory
+ */
+static void
+psa_write(device *	dev,
+	  int		o,	/* Offset in psa */
+	  u_char *	b,	/* Buffer in memory */
+	  int		n)	/* Length of buffer */
+{
+  u_char *	ptr = ((u_char *) dev->mem_start) + PSA_ADDR + (o << 1);
+  int		count = 0;
+  ioaddr_t	base = dev->base_addr;
+  /* As there seem to have no flag PSA_BUSY as in the ISA model, we are
+   * oblige to verify this address to know when the PSA is ready... */
+  volatile u_char *	verify = ((u_char *) dev->mem_start) + PSA_ADDR +
+    (psaoff(0, psa_comp_number) << 1);
+
+  /* Authorize writting to PSA */
+  hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN);
+
+  while(n-- > 0)
+    {
+      /* write to PSA */
+      writeb(*b++, ptr);
+      ptr += 2;
+
+      /* I don't have the spec, so I don't know what the correct
+       * sequence to write is. This hack seem to work for me... */
+      count = 0;
+      while((readb(verify) != PSA_COMP_PCMCIA_915) && (count++ < 100))
+	mdelay(1);
+    }
+
+  /* Put the host interface back in standard state */
+  hacr_write(base, HACR_DEFAULT);
+} /* psa_write */
+
+#ifdef SET_PSA_CRC
+/*------------------------------------------------------------------*/
+/*
+ * Calculate the PSA CRC
+ * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code
+ * NOTE: By specifying a length including the CRC position the
+ * returned value should be zero. (i.e. a correct checksum in the PSA)
+ *
+ * The Windows drivers don't use the CRC, but the AP and the PtP tool
+ * depend on it.
+ */
+static u_short
+psa_crc(unsigned char *	psa,	/* The PSA */
+	int		size)	/* Number of short for CRC */
+{
+  int		byte_cnt;	/* Loop on the PSA */
+  u_short	crc_bytes = 0;	/* Data in the PSA */
+  int		bit_cnt;	/* Loop on the bits of the short */
+
+  for(byte_cnt = 0; byte_cnt < size; byte_cnt++ )
+    {
+      crc_bytes ^= psa[byte_cnt];	/* Its an xor */
+
+      for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ )
+	{
+	  if(crc_bytes & 0x0001)
+	    crc_bytes = (crc_bytes >> 1) ^ 0xA001;
+	  else
+	    crc_bytes >>= 1 ;
+        }
+    }
+
+  return crc_bytes;
+} /* psa_crc */
+#endif	/* SET_PSA_CRC */
+
+/*------------------------------------------------------------------*/
+/*
+ * update the checksum field in the Wavelan's PSA
+ */
+static void
+update_psa_checksum(device *	dev)
+{
+#ifdef SET_PSA_CRC
+  psa_t		psa;
+  u_short	crc;
+
+  /* read the parameter storage area */
+  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+
+  /* update the checksum */
+  crc = psa_crc((unsigned char *) &psa,
+		sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1])
+		- sizeof(psa.psa_crc_status));
+
+  psa.psa_crc[0] = crc & 0xFF;
+  psa.psa_crc[1] = (crc & 0xFF00) >> 8;
+
+  /* Write it ! */
+  psa_write(dev, (char *)&psa.psa_crc - (char *)&psa,
+	    (unsigned char *)&psa.psa_crc, 2);
+
+#ifdef DEBUG_IOCTL_INFO
+  printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n",
+          dev->name, psa.psa_crc[0], psa.psa_crc[1]);
+
+  /* Check again (luxury !) */
+  crc = psa_crc((unsigned char *) &psa,
+		 sizeof(psa) - sizeof(psa.psa_crc_status));
+
+  if(crc != 0)
+    printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name);
+#endif /* DEBUG_IOCTL_INFO */
+#endif	/* SET_PSA_CRC */
+} /* update_psa_checksum */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write 1 byte to the MMC.
+ */
+static inline void
+mmc_out(u_long		base,
+	u_short		o,
+	u_char		d)
+{
+  /* Wait for MMC to go idle */
+  while(inb(HASR(base)) & HASR_MMI_BUSY)
+    ;
+
+  outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base));
+  outb(d, MMD(base));
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to write bytes to the Modem Management Controller.
+ * We start by the end because it is the way it should be !
+ */
+static inline void
+mmc_write(u_long	base,
+	  u_char	o,
+	  u_char *	b,
+	  int		n)
+{
+  o += n;
+  b += n;
+
+  while(n-- > 0 )
+    mmc_out(base, --o, *(--b));
+} /* mmc_write */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read 1 byte from the MMC.
+ * Optimised version for 1 byte, avoid using memory...
+ */
+static inline u_char
+mmc_in(u_long	base,
+       u_short	o)
+{
+  while(inb(HASR(base)) & HASR_MMI_BUSY)
+    ;
+  outb(o << 1, MMR(base));		/* Set the read address */
+
+  outb(0, MMD(base));			/* Required dummy write */
+
+  while(inb(HASR(base)) & HASR_MMI_BUSY)
+    ;
+  return (u_char) (inb(MMD(base)));	/* Now do the actual read */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to read bytes from the Modem Management Controller.
+ * The implementation is complicated by a lack of address lines,
+ * which prevents decoding of the low-order bit.
+ * (code has just been moved in the above function)
+ * We start by the end because it is the way it should be !
+ */
+static inline void
+mmc_read(u_long		base,
+	 u_char		o,
+	 u_char *	b,
+	 int		n)
+{
+  o += n;
+  b += n;
+
+  while(n-- > 0)
+    *(--b) = mmc_in(base, --o);
+} /* mmc_read */
+
+/*------------------------------------------------------------------*/
+/*
+ * Get the type of encryption available...
+ */
+static inline int
+mmc_encr(u_long		base)	/* i/o port of the card */
+{
+  int	temp;
+
+  temp = mmc_in(base, mmroff(0, mmr_des_avail));
+  if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES))
+    return 0;
+  else
+    return temp;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wait for the frequency EEprom to complete a command...
+ * I hope this one will be optimally inlined...
+ */
+static inline void
+fee_wait(u_long		base,	/* i/o port of the card */
+	 int		delay,	/* Base delay to wait for */
+	 int		number)	/* Number of time to wait */
+{
+  int		count = 0;	/* Wait only a limited time */
+
+  while((count++ < number) &&
+	(mmc_in(base, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY))
+    udelay(delay);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Read bytes from the Frequency EEprom (frequency select cards).
+ */
+static void
+fee_read(u_long		base,	/* i/o port of the card */
+	 u_short	o,	/* destination offset */
+	 u_short *	b,	/* data buffer */
+	 int		n)	/* number of registers */
+{
+  b += n;		/* Position at the end of the area */
+
+  /* Write the address */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1);
+
+  /* Loop on all buffer */
+  while(n-- > 0)
+    {
+      /* Write the read command */
+      mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ);
+
+      /* Wait until EEprom is ready (should be quick !) */
+      fee_wait(base, 10, 100);
+
+      /* Read the value */
+      *--b = ((mmc_in(base, mmroff(0, mmr_fee_data_h)) << 8) |
+	      mmc_in(base, mmroff(0, mmr_fee_data_l)));
+    }
+}
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write bytes from the Frequency EEprom (frequency select cards).
+ * This is a bit complicated, because the frequency eeprom has to
+ * be unprotected and the write enabled.
+ * Jean II
+ */
+static void
+fee_write(u_long	base,	/* i/o port of the card */
+	  u_short	o,	/* destination offset */
+	  u_short *	b,	/* data buffer */
+	  int		n)	/* number of registers */
+{
+  b += n;		/* Position at the end of the area */
+
+#ifdef EEPROM_IS_PROTECTED	/* disabled */
+#ifdef DOESNT_SEEM_TO_WORK	/* disabled */
+  /* Ask to read the protected register */
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD);
+
+  fee_wait(base, 10, 100);
+
+  /* Read the protected register */
+  printk("Protected 2 : %02X-%02X\n",
+	 mmc_in(base, mmroff(0, mmr_fee_data_h)),
+	 mmc_in(base, mmroff(0, mmr_fee_data_l)));
+#endif	/* DOESNT_SEEM_TO_WORK */
+
+  /* Enable protected register */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
+
+  fee_wait(base, 10, 100);
+
+  /* Unprotect area */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
+#ifdef DOESNT_SEEM_TO_WORK	/* disabled */
+  /* Or use : */
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
+#endif	/* DOESNT_SEEM_TO_WORK */
+
+  fee_wait(base, 10, 100);
+#endif	/* EEPROM_IS_PROTECTED */
+
+  /* Write enable */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
+
+  fee_wait(base, 10, 100);
+
+  /* Write the EEprom address */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1);
+
+  /* Loop on all buffer */
+  while(n-- > 0)
+    {
+      /* Write the value */
+      mmc_out(base, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
+      mmc_out(base, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
+
+      /* Write the write command */
+      mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE);
+
+      /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */
+      mdelay(10);
+      fee_wait(base, 10, 100);
+    }
+
+  /* Write disable */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
+
+  fee_wait(base, 10, 100);
+
+#ifdef EEPROM_IS_PROTECTED	/* disabled */
+  /* Reprotect EEprom */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), 0x00);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
+
+  fee_wait(base, 10, 100);
+#endif	/* EEPROM_IS_PROTECTED */
+}
+#endif	/* WIRELESS_EXT */
+
+/******************* WaveLAN Roaming routines... ********************/
+
+#ifdef WAVELAN_ROAMING	/* Conditional compile, see wavelan_cs.h */
+
+unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00};
+  
+void wv_roam_init(struct net_device *dev)
+{
+  net_local  *lp= (net_local *)dev->priv;
+
+  /* Do not remove this unless you have a good reason */
+  printk(KERN_NOTICE "%s: Warning, you have enabled roaming on"
+	 " device %s !\n", dev->name, dev->name);
+  printk(KERN_NOTICE "Roaming is currently an experimental unsupported feature"
+	 " of the Wavelan driver.\n");
+  printk(KERN_NOTICE "It may work, but may also make the driver behave in"
+	 " erratic ways or crash.\n");
+
+  lp->wavepoint_table.head=NULL;           /* Initialise WavePoint table */
+  lp->wavepoint_table.num_wavepoints=0;
+  lp->wavepoint_table.locked=0;
+  lp->curr_point=NULL;                        /* No default WavePoint */
+  lp->cell_search=0;
+  
+  lp->cell_timer.data=(long)lp;               /* Start cell expiry timer */
+  lp->cell_timer.function=wl_cell_expiry;
+  lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
+  add_timer(&lp->cell_timer);
+  
+  wv_nwid_filter(NWID_PROMISC,lp) ;    /* Enter NWID promiscuous mode */
+  /* to build up a good WavePoint */
+                                           /* table... */
+  printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name);
+}
+ 
+void wv_roam_cleanup(struct net_device *dev)
+{
+  wavepoint_history *ptr,*old_ptr;
+  net_local *lp= (net_local *)dev->priv;
+  
+  printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name);
+  
+  /* Fixme : maybe we should check that the timer exist before deleting it */
+  del_timer(&lp->cell_timer);          /* Remove cell expiry timer       */
+  ptr=lp->wavepoint_table.head;        /* Clear device's WavePoint table */
+  while(ptr!=NULL)
+    {
+      old_ptr=ptr;
+      ptr=ptr->next;	
+      wl_del_wavepoint(old_ptr,lp);	
+    }
+}
+
+/* Enable/Disable NWID promiscuous mode on a given device */
+void wv_nwid_filter(unsigned char mode, net_local *lp)
+{
+  mm_t                  m;
+  unsigned long         flags;
+  
+#ifdef WAVELAN_ROAMING_DEBUG
+  printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name);
+#endif
+  
+  /* Disable interrupts & save flags */
+  wv_splhi(lp, &flags);
+  
+  m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
+  mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
+  
+  if(mode==NWID_PROMISC)
+    lp->cell_search=1;
+  else
+    lp->cell_search=0;
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
+}
+
+/* Find a record in the WavePoint table matching a given NWID */
+wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp)
+{
+  wavepoint_history	*ptr=lp->wavepoint_table.head;
+  
+  while(ptr!=NULL){
+    if(ptr->nwid==nwid)
+      return ptr;	
+    ptr=ptr->next;
+  }
+  return NULL;
+}
+
+/* Create a new wavepoint table entry */
+wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp)
+{
+  wavepoint_history *new_wavepoint;
+
+#ifdef WAVELAN_ROAMING_DEBUG	
+  printk(KERN_DEBUG "WaveLAN: New Wavepoint, NWID:%.4X\n",nwid);
+#endif
+  
+  if(lp->wavepoint_table.num_wavepoints==MAX_WAVEPOINTS)
+    return NULL;
+  
+  new_wavepoint=(wavepoint_history *) kmalloc(sizeof(wavepoint_history),GFP_ATOMIC);
+  if(new_wavepoint==NULL)
+    return NULL;
+  
+  new_wavepoint->nwid=nwid;                       /* New WavePoints NWID */
+  new_wavepoint->average_fast=0;                    /* Running Averages..*/
+  new_wavepoint->average_slow=0;
+  new_wavepoint->qualptr=0;                       /* Start of ringbuffer */
+  new_wavepoint->last_seq=seq-1;                /* Last sequence no.seen */
+  memset(new_wavepoint->sigqual,0,WAVEPOINT_HISTORY);/* Empty ringbuffer */
+  
+  new_wavepoint->next=lp->wavepoint_table.head;/* Add to wavepoint table */
+  new_wavepoint->prev=NULL;
+  
+  if(lp->wavepoint_table.head!=NULL)
+    lp->wavepoint_table.head->prev=new_wavepoint;
+  
+  lp->wavepoint_table.head=new_wavepoint;
+  
+  lp->wavepoint_table.num_wavepoints++;     /* no. of visible wavepoints */
+  
+  return new_wavepoint;
+}
+
+/* Remove a wavepoint entry from WavePoint table */
+void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp)
+{
+  if(wavepoint==NULL)
+    return;
+  
+  if(lp->curr_point==wavepoint)
+    lp->curr_point=NULL;
+  
+  if(wavepoint->prev!=NULL)
+    wavepoint->prev->next=wavepoint->next;
+  
+  if(wavepoint->next!=NULL)
+    wavepoint->next->prev=wavepoint->prev;
+  
+  if(lp->wavepoint_table.head==wavepoint)
+    lp->wavepoint_table.head=wavepoint->next;
+  
+  lp->wavepoint_table.num_wavepoints--;
+  kfree(wavepoint);
+}
+
+/* Timer callback function - checks WavePoint table for stale entries */ 
+void wl_cell_expiry(unsigned long data)
+{
+  net_local *lp=(net_local *)data;
+  wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point;
+  
+#if WAVELAN_ROAMING_DEBUG > 1
+  printk(KERN_DEBUG "WaveLAN: Wavepoint timeout, dev %s\n",lp->dev->name);
+#endif
+  
+  if(lp->wavepoint_table.locked)
+    {
+#if WAVELAN_ROAMING_DEBUG > 1
+      printk(KERN_DEBUG "WaveLAN: Wavepoint table locked...\n");
+#endif
+      
+      lp->cell_timer.expires=jiffies+1; /* If table in use, come back later */
+      add_timer(&lp->cell_timer);
+      return;
+    }
+  
+  while(wavepoint!=NULL)
+    {
+      if(wavepoint->last_seen < jiffies-CELL_TIMEOUT)
+	{
+#ifdef WAVELAN_ROAMING_DEBUG
+	  printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid);
+#endif
+	  
+	  old_point=wavepoint;
+	  wavepoint=wavepoint->next;
+	  wl_del_wavepoint(old_point,lp);
+	}
+      else
+	wavepoint=wavepoint->next;
+    }
+  lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
+  add_timer(&lp->cell_timer);
+}
+
+/* Update SNR history of a wavepoint */
+void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq)	
+{
+  int i=0,num_missed=0,ptr=0;
+  int average_fast=0,average_slow=0;
+  
+  num_missed=(seq-wavepoint->last_seq)%WAVEPOINT_HISTORY;/* Have we missed
+							    any beacons? */
+  if(num_missed)
+    for(i=0;i<num_missed;i++)
+      {
+	wavepoint->sigqual[wavepoint->qualptr++]=0; /* If so, enter them as 0's */
+	wavepoint->qualptr %=WAVEPOINT_HISTORY;    /* in the ringbuffer. */
+      }
+  wavepoint->last_seen=jiffies;                 /* Add beacon to history */
+  wavepoint->last_seq=seq;	
+  wavepoint->sigqual[wavepoint->qualptr++]=sigqual;          
+  wavepoint->qualptr %=WAVEPOINT_HISTORY;
+  ptr=(wavepoint->qualptr-WAVEPOINT_FAST_HISTORY+WAVEPOINT_HISTORY)%WAVEPOINT_HISTORY;
+  
+  for(i=0;i<WAVEPOINT_FAST_HISTORY;i++)       /* Update running averages */
+    {
+      average_fast+=wavepoint->sigqual[ptr++];
+      ptr %=WAVEPOINT_HISTORY;
+    }
+  
+  average_slow=average_fast;
+  for(i=WAVEPOINT_FAST_HISTORY;i<WAVEPOINT_HISTORY;i++)
+    {
+      average_slow+=wavepoint->sigqual[ptr++];
+      ptr %=WAVEPOINT_HISTORY;
+    }
+  
+  wavepoint->average_fast=average_fast/WAVEPOINT_FAST_HISTORY;
+  wavepoint->average_slow=average_slow/WAVEPOINT_HISTORY;	
+}
+
+/* Perform a handover to a new WavePoint */
+void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
+{
+  ioaddr_t              base = lp->dev->base_addr;  
+  mm_t                  m;
+  unsigned long         flags;
+
+  if(wavepoint==lp->curr_point)          /* Sanity check... */
+    {
+      wv_nwid_filter(!NWID_PROMISC,lp);
+      return;
+    }
+  
+#ifdef WAVELAN_ROAMING_DEBUG
+  printk(KERN_DEBUG "WaveLAN: Doing handover to %.4X, dev %s\n",wavepoint->nwid,lp->dev->name);
+#endif
+ 	
+  /* Disable interrupts & save flags */
+  wv_splhi(lp, &flags);
+
+  m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
+  m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
+  
+  mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
+  
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
+
+  wv_nwid_filter(!NWID_PROMISC,lp);
+  lp->curr_point=wavepoint;
+}
+
+/* Called when a WavePoint beacon is received */
+static inline void wl_roam_gather(device *  dev,
+				  u_char *  hdr,   /* Beacon header */
+				  u_char *  stats) /* SNR, Signal quality 
+						      of packet */
+{
+  wavepoint_beacon *beacon= (wavepoint_beacon *)hdr; /* Rcvd. Beacon */
+  unsigned short nwid=ntohs(beacon->nwid);  
+  unsigned short sigqual=stats[2] & MMR_SGNL_QUAL;   /* SNR of beacon */
+  wavepoint_history *wavepoint=NULL;                /* WavePoint table entry */
+  net_local *lp=(net_local *)dev->priv;              /* Device info */
+
+#ifdef I_NEED_THIS_FEATURE
+  /* Some people don't need this, some other may need it */
+  nwid=nwid^ntohs(beacon->domain_id);
+#endif
+
+#if WAVELAN_ROAMING_DEBUG > 1
+  printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name);
+  printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual);
+#endif
+  
+  lp->wavepoint_table.locked=1;                            /* <Mutex> */
+  
+  wavepoint=wl_roam_check(nwid,lp);            /* Find WavePoint table entry */
+  if(wavepoint==NULL)                    /* If no entry, Create a new one... */
+    {
+      wavepoint=wl_new_wavepoint(nwid,beacon->seq,lp);
+      if(wavepoint==NULL)
+	goto out;
+    }
+  if(lp->curr_point==NULL)             /* If this is the only WavePoint, */
+    wv_roam_handover(wavepoint, lp);	         /* Jump on it! */
+  
+  wl_update_history(wavepoint, sigqual, beacon->seq); /* Update SNR history
+							 stats. */
+  
+  if(lp->curr_point->average_slow < SEARCH_THRESH_LOW) /* If our current */
+    if(!lp->cell_search)                  /* WavePoint is getting faint, */
+      wv_nwid_filter(NWID_PROMISC,lp);    /* start looking for a new one */
+  
+  if(wavepoint->average_slow > 
+     lp->curr_point->average_slow + WAVELAN_ROAMING_DELTA)
+    wv_roam_handover(wavepoint, lp);   /* Handover to a better WavePoint */
+  
+  if(lp->curr_point->average_slow > SEARCH_THRESH_HIGH) /* If our SNR is */
+    if(lp->cell_search)  /* getting better, drop out of cell search mode */
+      wv_nwid_filter(!NWID_PROMISC,lp);
+  
+out:
+  lp->wavepoint_table.locked=0;                        /* </MUTEX>   :-) */
+}
+
+/* Test this MAC frame a WavePoint beacon */
+static inline int WAVELAN_BEACON(unsigned char *data)
+{
+  wavepoint_beacon *beacon= (wavepoint_beacon *)data;
+  static wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00};
+  
+  if(memcmp(beacon,&beacon_template,9)==0)
+    return 1;
+  else
+    return 0;
+}
+#endif	/* WAVELAN_ROAMING */
+
+/************************ I82593 SUBROUTINES *************************/
+/*
+ * Useful subroutines to manage the Ethernet controller
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to synchronously send a command to the i82593 chip. 
+ * Should be called with interrupts disabled.
+ * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(),
+ *  wv_82593_config() & wv_diag())
+ */
+static int
+wv_82593_cmd(device *	dev,
+	     char *	str,
+	     int	cmd,
+	     int	result)
+{
+  ioaddr_t	base = dev->base_addr;
+  int		status;
+  int		wait_completed;
+  long		spin;
+
+  /* Spin until the chip finishes executing its current command (if any) */
+  spin = 1000;
+  do
+    {
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
+      outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
+      status = inb(LCSR(base));
+    }
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
+
+  /* If the interrupt hasn't be posted */
+  if(spin <= 0)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n",
+	     str, status);
+#endif
+      return(FALSE);
+    }
+
+  /* Issue the command to the controller */
+  outb(cmd, LCCR(base));
+
+  /* If we don't have to check the result of the command
+   * Note : this mean that the irq handler will deal with that */
+  if(result == SR0_NO_RESULT)
+    return(TRUE);
+
+  /* We are waiting for command completion */
+  wait_completed = TRUE;
+
+  /* Busy wait while the LAN controller executes the command. */
+  spin = 1000;
+  do
+    {
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
+      outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
+      status = inb(LCSR(base));
+
+      /* Check if there was an interrupt posted */
+      if((status & SR0_INTERRUPT))
+	{
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
+
+	  /* Check if interrupt is a command completion */
+	  if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) &&
+	     ((status & SR0_BOTH_RX_TX) != 0x0) &&
+	     !(status & SR0_RECEPTION))
+	    {
+	      /* Signal command completion */
+	      wait_completed = FALSE;
+	    }
+	  else
+	    {
+	      /* Note : Rx interrupts will be handled later, because we can
+	       * handle multiple Rx packets at once */
+#ifdef DEBUG_INTERRUPT_INFO
+	      printk(KERN_INFO "wv_82593_cmd: not our interrupt\n");
+#endif
+	    }
+	}
+    }
+  while(wait_completed && (spin-- > 0));
+
+  /* If the interrupt hasn't be posted */
+  if(wait_completed)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n",
+	     str, status);
+#endif
+      return(FALSE);
+    }
+
+  /* Check the return code returned by the card (see above) against
+   * the expected return code provided by the caller */
+  if((status & SR0_EVENT_MASK) != result)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n",
+	     str, status);
+#endif
+      return(FALSE);
+    }
+
+  return(TRUE);
+} /* wv_82593_cmd */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine does a 593 op-code number 7, and obtains the diagnose
+ * status for the WaveLAN.
+ */
+static inline int
+wv_diag(device *	dev)
+{
+  int		ret = FALSE;
+
+  if(wv_82593_cmd(dev, "wv_diag(): diagnose",
+		  OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED))
+    ret = TRUE;
+
+#ifdef DEBUG_CONFIG_ERROR
+  printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n");
+#endif
+  return(ret);
+} /* wv_diag */
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to read len bytes from the i82593's ring buffer, starting at
+ * chip address addr. The results read from the chip are stored in buf.
+ * The return value is the address to use for next the call.
+ */
+static int
+read_ringbuf(device *	dev,
+	     int	addr,
+	     char *	buf,
+	     int	len)
+{
+  ioaddr_t	base = dev->base_addr;
+  int		ring_ptr = addr;
+  int		chunk_len;
+  char *	buf_ptr = buf;
+
+  /* Get all the buffer */
+  while(len > 0)
+    {
+      /* Position the Program I/O Register at the ring buffer pointer */
+      outb(ring_ptr & 0xff, PIORL(base));
+      outb(((ring_ptr >> 8) & PIORH_MASK), PIORH(base));
+
+      /* First, determine how much we can read without wrapping around the
+	 ring buffer */
+      if((addr + len) < (RX_BASE + RX_SIZE))
+	chunk_len = len;
+      else
+	chunk_len = RX_BASE + RX_SIZE - addr;
+      insb(PIOP(base), buf_ptr, chunk_len);
+      buf_ptr += chunk_len;
+      len -= chunk_len;
+      ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE;
+    }
+  return(ring_ptr);
+} /* read_ringbuf */
+
+/*------------------------------------------------------------------*/
+/*
+ * Reconfigure the i82593, or at least ask for it...
+ * Because wv_82593_config use the transmission buffer, we must do it
+ * when we are sure that there is no transmission, so we do it now
+ * or in wavelan_packet_xmit() (I can't find any better place,
+ * wavelan_interrupt is not an option...), so you may experience
+ * some delay sometime...
+ */
+static inline void
+wv_82593_reconfig(device *	dev)
+{
+  net_local *		lp = (net_local *)dev->priv;
+  dev_link_t *		link = ((net_local *) dev->priv)->link;
+  unsigned long		flags;
+
+  /* Arm the flag, will be cleard in wv_82593_config() */
+  lp->reconfig_82593 = TRUE;
+
+  /* Check if we can do it now ! */
+  if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev)))
+    {
+      wv_splhi(lp, &flags);	/* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);	/* Re-enable interrupts */
+    }
+  else
+    {
+#ifdef DEBUG_IOCTL_INFO
+      printk(KERN_DEBUG
+	     "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n",
+	     dev->name, dev->state, link->open);
+#endif
+    }
+}
+
+/********************* DEBUG & INFO SUBROUTINES *********************/
+/*
+ * This routines are used in the code to show debug informations.
+ * Most of the time, it dump the content of hardware structures...
+ */
+
+#ifdef DEBUG_PSA_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted contents of the Parameter Storage Area.
+ */
+static void
+wv_psa_show(psa_t *	p)
+{
+  printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
+  printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
+	 p->psa_io_base_addr_1,
+	 p->psa_io_base_addr_2,
+	 p->psa_io_base_addr_3,
+	 p->psa_io_base_addr_4);
+  printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n",
+	 p->psa_rem_boot_addr_1,
+	 p->psa_rem_boot_addr_2,
+	 p->psa_rem_boot_addr_3);
+  printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
+  printk("psa_int_req_no: %d\n", p->psa_int_req_no);
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	 p->psa_unused0[0],
+	 p->psa_unused0[1],
+	 p->psa_unused0[2],
+	 p->psa_unused0[3],
+	 p->psa_unused0[4],
+	 p->psa_unused0[5],
+	 p->psa_unused0[6]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	 p->psa_univ_mac_addr[0],
+	 p->psa_univ_mac_addr[1],
+	 p->psa_univ_mac_addr[2],
+	 p->psa_univ_mac_addr[3],
+	 p->psa_univ_mac_addr[4],
+	 p->psa_univ_mac_addr[5]);
+  printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	 p->psa_local_mac_addr[0],
+	 p->psa_local_mac_addr[1],
+	 p->psa_local_mac_addr[2],
+	 p->psa_local_mac_addr[3],
+	 p->psa_local_mac_addr[4],
+	 p->psa_local_mac_addr[5]);
+  printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel);
+  printk("psa_comp_number: %d, ", p->psa_comp_number);
+  printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
+  printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ",
+	 p->psa_feature_select);
+  printk("psa_subband/decay_update_prm: %d\n", p->psa_subband);
+  printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr);
+  printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay);
+  printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]);
+  printk("psa_nwid_select: %d\n", p->psa_nwid_select);
+  printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select);
+  printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+	 p->psa_encryption_key[0],
+	 p->psa_encryption_key[1],
+	 p->psa_encryption_key[2],
+	 p->psa_encryption_key[3],
+	 p->psa_encryption_key[4],
+	 p->psa_encryption_key[5],
+	 p->psa_encryption_key[6],
+	 p->psa_encryption_key[7]);
+  printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width);
+  printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ",
+	 p->psa_call_code[0]);
+  printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	 p->psa_call_code[0],
+	 p->psa_call_code[1],
+	 p->psa_call_code[2],
+	 p->psa_call_code[3],
+	 p->psa_call_code[4],
+	 p->psa_call_code[5],
+	 p->psa_call_code[6],
+	 p->psa_call_code[7]);
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
+	 p->psa_reserved[0],
+	 p->psa_reserved[1],
+	 p->psa_reserved[2],
+	 p->psa_reserved[3]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
+  printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
+  printk("psa_crc_status: 0x%02x\n", p->psa_crc_status);
+} /* wv_psa_show */
+#endif	/* DEBUG_PSA_SHOW */
+
+#ifdef DEBUG_MMC_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the Modem Management Controller.
+ * This function need to be completed...
+ */
+static void
+wv_mmc_show(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  net_local *	lp = (net_local *)dev->priv;
+  mmr_t		m;
+
+  /* Basic check */
+  if(hasr_read(base) & HASR_NO_CLK)
+    {
+      printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n",
+	     dev->name);
+      return;
+    }
+
+  wv_splhi(lp, &flags);
+
+  /* Read the mmc */
+  mmc_out(base, mmwoff(0, mmw_freeze), 1);
+  mmc_read(base, 0, (u_char *)&m, sizeof(m));
+  mmc_out(base, mmwoff(0, mmw_freeze), 0);
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+  /* Don't forget to update statistics */
+  lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+#endif	/* WIRELESS_EXT */
+
+  wv_splx(lp, &flags);
+
+  printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	 m.mmr_unused0[0],
+	 m.mmr_unused0[1],
+	 m.mmr_unused0[2],
+	 m.mmr_unused0[3],
+	 m.mmr_unused0[4],
+	 m.mmr_unused0[5],
+	 m.mmr_unused0[6],
+	 m.mmr_unused0[7]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n",
+	 m.mmr_des_avail, m.mmr_des_status);
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
+	 m.mmr_unused1[0],
+	 m.mmr_unused1[1],
+	 m.mmr_unused1[2],
+	 m.mmr_unused1[3],
+	 m.mmr_unused1[4]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n",
+	 m.mmr_dce_status,
+	 (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"",
+	 (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ?
+	 "loop test indicated," : "",
+	 (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "",
+	 (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ?
+	 "jabber timer expired," : "");
+  printk(KERN_DEBUG "Dsp ID: %02X\n",
+	 m.mmr_dsp_id);
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n",
+	 m.mmr_unused2[0],
+	 m.mmr_unused2[1]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n",
+	 (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l,
+	 (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l);
+  printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n",
+	 m.mmr_thr_pre_set & MMR_THR_PRE_SET,
+	 (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below");
+  printk(KERN_DEBUG "signal_lvl: %d [%s], ",
+	 m.mmr_signal_lvl & MMR_SIGNAL_LVL,
+	 (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg");
+  printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL,
+	 (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update");
+  printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL,
+	 (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0");
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l);
+#endif	/* DEBUG_SHOW_UNUSED */
+} /* wv_mmc_show */
+#endif	/* DEBUG_MMC_SHOW */
+
+#ifdef DEBUG_I82593_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the i82593's receive unit.
+ */
+static void
+wv_ru_show(device *	dev)
+{
+  net_local *lp = (net_local *) dev->priv;
+
+  printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n");
+  printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop);
+  /*
+   * Not implemented yet...
+   */
+  printk("\n");
+} /* wv_ru_show */
+#endif	/* DEBUG_I82593_SHOW */
+
+#ifdef DEBUG_DEVICE_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the WaveLAN PCMCIA device driver.
+ */
+static void
+wv_dev_show(device *	dev)
+{
+  printk(KERN_DEBUG "dev:");
+  printk(" state=%lX,", dev->state);
+  printk(" trans_start=%ld,", dev->trans_start);
+  printk(" flags=0x%x,", dev->flags);
+  printk("\n");
+} /* wv_dev_show */
+
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the WaveLAN PCMCIA device driver's
+ * private information.
+ */
+static void
+wv_local_show(device *	dev)
+{
+  net_local *lp;
+
+  lp = (net_local *)dev->priv;
+
+  printk(KERN_DEBUG "local:");
+  /*
+   * Not implemented yet...
+   */
+  printk("\n");
+} /* wv_local_show */
+#endif	/* DEBUG_DEVICE_SHOW */
+
+#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO)
+/*------------------------------------------------------------------*/
+/*
+ * Dump packet header (and content if necessary) on the screen
+ */
+static inline void
+wv_packet_info(u_char *		p,		/* Packet to dump */
+	       int		length,		/* Length of the packet */
+	       char *		msg1,		/* Name of the device */
+	       char *		msg2)		/* Name of the function */
+{
+  int		i;
+  int		maxi;
+
+  printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
+	 msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
+  printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
+	 msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]);
+
+#ifdef DEBUG_PACKET_DUMP
+
+  printk(KERN_DEBUG "data=\"");
+
+  if((maxi = length) > DEBUG_PACKET_DUMP)
+    maxi = DEBUG_PACKET_DUMP;
+  for(i = 14; i < maxi; i++)
+    if(p[i] >= ' ' && p[i] <= '~')
+      printk(" %c", p[i]);
+    else
+      printk("%02X", p[i]);
+  if(maxi < length)
+    printk("..");
+  printk("\"\n");
+  printk(KERN_DEBUG "\n");
+#endif	/* DEBUG_PACKET_DUMP */
+}
+#endif	/* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */
+
+/*------------------------------------------------------------------*/
+/*
+ * This is the information which is displayed by the driver at startup
+ * There  is a lot of flag to configure it at your will...
+ */
+static inline void
+wv_init_info(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  psa_t		psa;
+  int		i;
+
+  /* Read the parameter storage area */
+  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+
+#ifdef DEBUG_PSA_SHOW
+  wv_psa_show(&psa);
+#endif
+#ifdef DEBUG_MMC_SHOW
+  wv_mmc_show(dev);
+#endif
+#ifdef DEBUG_I82593_SHOW
+  wv_ru_show(dev);
+#endif
+
+#ifdef DEBUG_BASIC_SHOW
+  /* Now, let's go for the basic stuff */
+  printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr",
+	 dev->name, base, dev->irq);
+  for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
+    printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
+
+  /* Print current network id */
+  if(psa.psa_nwid_select)
+    printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]);
+  else
+    printk(", nwid off");
+
+  /* If 2.00 card */
+  if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+    {
+      unsigned short	freq;
+
+      /* Ask the EEprom to read the frequency from the first area */
+      fee_read(base, 0x00 /* 1st area - frequency... */,
+	       &freq, 1);
+
+      /* Print frequency */
+      printk(", 2.00, %ld", (freq >> 6) + 2400L);
+
+      /* Hack !!! */
+      if(freq & 0x20)
+	printk(".5");
+    }
+  else
+    {
+      printk(", PCMCIA, ");
+      switch (psa.psa_subband)
+	{
+	case PSA_SUBBAND_915:
+	  printk("915");
+	  break;
+	case PSA_SUBBAND_2425:
+	  printk("2425");
+	  break;
+	case PSA_SUBBAND_2460:
+	  printk("2460");
+	  break;
+	case PSA_SUBBAND_2484:
+	  printk("2484");
+	  break;
+	case PSA_SUBBAND_2430_5:
+	  printk("2430.5");
+	  break;
+	default:
+	  printk("unknown");
+	}
+    }
+
+  printk(" MHz\n");
+#endif	/* DEBUG_BASIC_SHOW */
+
+#ifdef DEBUG_VERSION_SHOW
+  /* Print version information */
+  printk(KERN_NOTICE "%s", version);
+#endif
+} /* wv_init_info */
+
+/********************* IOCTL, STATS & RECONFIG *********************/
+/*
+ * We found here routines that are called by Linux on differents
+ * occasions after the configuration and not for transmitting data
+ * These may be called when the user use ifconfig, /proc/net/dev
+ * or wireless extensions
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Get the current ethernet statistics. This may be called with the
+ * card open or closed.
+ * Used when the user read /proc/net/dev
+ */
+static en_stats	*
+wavelan_get_stats(device *	dev)
+{
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
+#endif
+
+  return(&((net_local *) dev->priv)->stats);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1	Promiscuous mode, receive all packets
+ * num_addrs == 0	Normal mode, clear multicast list
+ * num_addrs > 0	Multicast mode, receive normal and MC packets,
+ *			and do best-effort filtering.
+ */
+
+static void
+wavelan_set_multicast_list(device *	dev)
+{
+  net_local *	lp = (net_local *) dev->priv;
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name);
+#endif
+
+#ifdef DEBUG_IOCTL_INFO
+  printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n",
+	 dev->name, dev->flags, dev->mc_count);
+#endif
+
+  if(dev->flags & IFF_PROMISC)
+    {
+      /*
+       * Enable promiscuous mode: receive all packets.
+       */
+      if(!lp->promiscuous)
+	{
+	  lp->promiscuous = 1;
+	  lp->allmulticast = 0;
+	  lp->mc_count = 0;
+
+	  wv_82593_reconfig(dev);
+
+	  /* Tell the kernel that we are doing a really bad job... */
+	  dev->flags |= IFF_PROMISC;
+	}
+    }
+  else
+    /* If all multicast addresses
+     * or too much multicast addresses for the hardware filter */
+    if((dev->flags & IFF_ALLMULTI) ||
+       (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES))
+      {
+	/*
+	 * Disable promiscuous mode, but active the all multicast mode
+	 */
+	if(!lp->allmulticast)
+	  {
+	    lp->promiscuous = 0;
+	    lp->allmulticast = 1;
+	    lp->mc_count = 0;
+
+	    wv_82593_reconfig(dev);
+
+	    /* Tell the kernel that we are doing a really bad job... */
+	    dev->flags |= IFF_ALLMULTI;
+	  }
+      }
+    else
+      /* If there is some multicast addresses to send */
+      if(dev->mc_list != (struct dev_mc_list *) NULL)
+	{
+	  /*
+	   * Disable promiscuous mode, but receive all packets
+	   * in multicast list
+	   */
+#ifdef MULTICAST_AVOID
+	  if(lp->promiscuous || lp->allmulticast ||
+	     (dev->mc_count != lp->mc_count))
+#endif
+	    {
+	      lp->promiscuous = 0;
+	      lp->allmulticast = 0;
+	      lp->mc_count = dev->mc_count;
+
+	      wv_82593_reconfig(dev);
+	    }
+	}
+      else
+	{
+	  /*
+	   * Switch to normal mode: disable promiscuous mode and 
+	   * clear the multicast list.
+	   */
+	  if(lp->promiscuous || lp->mc_count == 0)
+	    {
+	      lp->promiscuous = 0;
+	      lp->allmulticast = 0;
+	      lp->mc_count = 0;
+
+	      wv_82593_reconfig(dev);
+	    }
+	}
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This function doesn't exist...
+ * (Note : it was a nice way to test the reconfigure stuff...)
+ */
+#ifdef SET_MAC_ADDRESS
+static int
+wavelan_set_mac_address(device *	dev,
+			void *		addr)
+{
+  struct sockaddr *	mac = addr;
+
+  /* Copy the address */
+  memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
+
+  /* Reconfig the beast */
+  wv_82593_reconfig(dev);
+
+  return 0;
+}
+#endif	/* SET_MAC_ADDRESS */
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+
+/*------------------------------------------------------------------*/
+/*
+ * Frequency setting (for hardware able of it)
+ * It's a bit complicated and you don't really want to look into it...
+ * (called in wavelan_ioctl)
+ */
+static inline int
+wv_set_frequency(u_long		base,	/* i/o port of the card */
+		 iw_freq *	frequency)
+{
+  const int	BAND_NUM = 10;	/* Number of bands */
+  long		freq = 0L;	/* offset to 2.4 GHz in .5 MHz */
+#ifdef DEBUG_IOCTL_INFO
+  int		i;
+#endif
+
+  /* Setting by frequency */
+  /* Theoritically, you may set any frequency between
+   * the two limits with a 0.5 MHz precision. In practice,
+   * I don't want you to have trouble with local
+   * regulations... */
+  if((frequency->e == 1) &&
+     (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
+    {
+      freq = ((frequency->m / 10000) - 24000L) / 5;
+    }
+
+  /* Setting by channel (same as wfreqsel) */
+  /* Warning : each channel is 22MHz wide, so some of the channels
+   * will interfere... */
+  if((frequency->e == 0) &&
+     (frequency->m >= 0) && (frequency->m < BAND_NUM))
+    {
+      /* Get frequency offset. */
+      freq = channel_bands[frequency->m] >> 1;
+    }
+
+  /* Verify if the frequency is allowed */
+  if(freq != 0L)
+    {
+      u_short	table[10];	/* Authorized frequency table */
+
+      /* Read the frequency table */
+      fee_read(base, 0x71 /* frequency table */,
+	       table, 10);
+
+#ifdef DEBUG_IOCTL_INFO
+      printk(KERN_DEBUG "Frequency table :");
+      for(i = 0; i < 10; i++)
+	{
+	  printk(" %04X",
+		 table[i]);
+	}
+      printk("\n");
+#endif
+
+      /* Look in the table if the frequency is allowed */
+      if(!(table[9 - ((freq - 24) / 16)] &
+	   (1 << ((freq - 24) % 16))))
+	return -EINVAL;		/* not allowed */
+    }
+  else
+    return -EINVAL;
+
+  /* If we get a usable frequency */
+  if(freq != 0L)
+    {
+      unsigned short	area[16];
+      unsigned short	dac[2];
+      unsigned short	area_verify[16];
+      unsigned short	dac_verify[2];
+      /* Corresponding gain (in the power adjust value table)
+       * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8
+       * & WCIN062D.DOC, page 6.2.9 */
+      unsigned short	power_limit[] = { 40, 80, 120, 160, 0 };
+      int		power_band = 0;		/* Selected band */
+      unsigned short	power_adjust;		/* Correct value */
+
+      /* Search for the gain */
+      power_band = 0;
+      while((freq > power_limit[power_band]) &&
+	    (power_limit[++power_band] != 0))
+	;
+
+      /* Read the first area */
+      fee_read(base, 0x00,
+	       area, 16);
+
+      /* Read the DAC */
+      fee_read(base, 0x60,
+	       dac, 2);
+
+      /* Read the new power adjust value */
+      fee_read(base, 0x6B - (power_band >> 1),
+	       &power_adjust, 1);
+      if(power_band & 0x1)
+	power_adjust >>= 8;
+      else
+	power_adjust &= 0xFF;
+
+#ifdef DEBUG_IOCTL_INFO
+      printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+      for(i = 0; i < 16; i++)
+	{
+	  printk(" %04X",
+		 area[i]);
+	}
+      printk("\n");
+
+      printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+	     dac[0], dac[1]);
+#endif
+
+      /* Frequency offset (for info only...) */
+      area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
+
+      /* Receiver Principle main divider coefficient */
+      area[3] = (freq >> 1) + 2400L - 352L;
+      area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
+
+      /* Transmitter Main divider coefficient */
+      area[13] = (freq >> 1) + 2400L;
+      area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
+
+      /* Others part of the area are flags, bit streams or unused... */
+
+      /* Set the value in the DAC */
+      dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
+      dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
+
+      /* Write the first area */
+      fee_write(base, 0x00,
+		area, 16);
+
+      /* Write the DAC */
+      fee_write(base, 0x60,
+		dac, 2);
+
+      /* We now should verify here that the EEprom writting was ok */
+
+      /* ReRead the first area */
+      fee_read(base, 0x00,
+	       area_verify, 16);
+
+      /* ReRead the DAC */
+      fee_read(base, 0x60,
+	       dac_verify, 2);
+
+      /* Compare */
+      if(memcmp(area, area_verify, 16 * 2) ||
+	 memcmp(dac, dac_verify, 2 * 2))
+	{
+#ifdef DEBUG_IOCTL_ERROR
+	  printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n");
+#endif
+	  return -EOPNOTSUPP;
+	}
+
+      /* We must download the frequency parameters to the
+       * synthetisers (from the EEprom - area 1)
+       * Note : as the EEprom is auto decremented, we set the end
+       * if the area... */
+      mmc_out(base, mmwoff(0, mmw_fee_addr), 0x0F);
+      mmc_out(base, mmwoff(0, mmw_fee_ctrl),
+	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
+
+      /* Wait until the download is finished */
+      fee_wait(base, 100, 100);
+
+      /* We must now download the power adjust value (gain) to
+       * the synthetisers (from the EEprom - area 7 - DAC) */
+      mmc_out(base, mmwoff(0, mmw_fee_addr), 0x61);
+      mmc_out(base, mmwoff(0, mmw_fee_ctrl),
+	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
+
+      /* Wait until the download is finished */
+      fee_wait(base, 100, 100);
+
+#ifdef DEBUG_IOCTL_INFO
+      /* Verification of what we have done... */
+
+      printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+      for(i = 0; i < 16; i++)
+	{
+	  printk(" %04X",
+		 area_verify[i]);
+	}
+      printk("\n");
+
+      printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+	     dac_verify[0], dac_verify[1]);
+#endif
+
+      return 0;
+    }
+  else
+    return -EINVAL;		/* Bah, never get there... */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Give the list of available frequencies
+ */
+static inline int
+wv_frequency_list(u_long	base,	/* i/o port of the card */
+		  iw_freq *	list,	/* List of frequency to fill */
+		  int		max)	/* Maximum number of frequencies */
+{
+  u_short	table[10];	/* Authorized frequency table */
+  long		freq = 0L;	/* offset to 2.4 GHz in .5 MHz + 12 MHz */
+  int		i;		/* index in the table */
+#if WIRELESS_EXT > 7
+  const int	BAND_NUM = 10;	/* Number of bands */
+  int		c = 0;		/* Channel number */
+#endif /* WIRELESS_EXT */
+
+  /* Read the frequency table */
+  fee_read(base, 0x71 /* frequency table */,
+	   table, 10);
+
+  /* Look all frequencies */
+  i = 0;
+  for(freq = 0; freq < 150; freq++)
+    /* Look in the table if the frequency is allowed */
+    if(table[9 - (freq / 16)] & (1 << (freq % 16)))
+      {
+#if WIRELESS_EXT > 7
+	/* Compute approximate channel number */
+	while((((channel_bands[c] >> 1) - 24) < freq) &&
+	      (c < BAND_NUM))
+	  c++;
+	list[i].i = c;	/* Set the list index */
+#endif /* WIRELESS_EXT */
+
+	/* put in the list */
+	list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
+	list[i++].e = 1;
+
+	/* Check number */
+	if(i >= max)
+	  return(i);
+      }
+
+  return(i);
+}
+
+#ifdef WIRELESS_SPY
+/*------------------------------------------------------------------*/
+/*
+ * Gather wireless spy statistics : for each packet, compare the source
+ * address with out list, and if match, get the stats...
+ * Sorry, but this function really need wireless extensions...
+ */
+static inline void
+wl_spy_gather(device *	dev,
+	      u_char *	mac,		/* MAC address */
+	      u_char *	stats)		/* Statistics to gather */
+{
+  net_local *	lp = (net_local *) dev->priv;
+  int		i;
+
+  /* Look all addresses */
+  for(i = 0; i < lp->spy_number; i++)
+    /* If match */
+    if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE))
+      {
+	/* Update statistics */
+	lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL;
+	lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL;
+	lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL;
+	lp->spy_stat[i].updated = 0x7;
+      }
+}
+#endif	/* WIRELESS_SPY */
+
+#ifdef HISTOGRAM
+/*------------------------------------------------------------------*/
+/*
+ * This function calculate an histogram on the signal level.
+ * As the noise is quite constant, it's like doing it on the SNR.
+ * We have defined a set of interval (lp->his_range), and each time
+ * the level goes in that interval, we increment the count (lp->his_sum).
+ * With this histogram you may detect if one wavelan is really weak,
+ * or you may also calculate the mean and standard deviation of the level...
+ */
+static inline void
+wl_his_gather(device *	dev,
+	      u_char *	stats)		/* Statistics to gather */
+{
+  net_local *	lp = (net_local *) dev->priv;
+  u_char	level = stats[0] & MMR_SIGNAL_LVL;
+  int		i;
+
+  /* Find the correct interval */
+  i = 0;
+  while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++]))
+    ;
+
+  /* Increment interval counter */
+  (lp->his_sum[i])++;
+}
+#endif	/* HISTOGRAM */
+
+/*------------------------------------------------------------------*/
+/*
+ * Perform ioctl : config & info stuff
+ * This is here that are treated the wireless extensions (iwconfig)
+ */
+static int
+wavelan_ioctl(struct net_device *	dev,	/* Device on wich the ioctl apply */
+	      struct ifreq *	rq,	/* Data passed */
+	      int		cmd)	/* Ioctl number */
+{
+  ioaddr_t		base = dev->base_addr;
+  net_local *		lp = (net_local *)dev->priv;	/* lp is not unused */
+  struct iwreq *	wrq = (struct iwreq *) rq;
+  psa_t			psa;
+  mm_t			m;
+  unsigned long		flags;
+  int			ret = 0;
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
+#endif
+
+  /* Disable interrupts & save flags */
+  wv_splhi(lp, &flags);
+
+  /* Look what is the request */
+  switch(cmd)
+    {
+      /* --------------- WIRELESS EXTENSIONS --------------- */
+
+    case SIOCGIWNAME:
+      strcpy(wrq->u.name, "Wavelan");
+      break;
+
+    case SIOCSIWNWID:
+      /* Set NWID in wavelan */
+#if WIRELESS_EXT > 8
+      if(!wrq->u.nwid.disabled)
+	{
+	  /* Set NWID in psa */
+	  psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8;
+	  psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
+#else	/* WIRELESS_EXT > 8 */
+      if(wrq->u.nwid.on)
+	{
+	  /* Set NWID in psa */
+	  psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
+	  psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
+#endif	/* WIRELESS_EXT > 8 */
+	  psa.psa_nwid_select = 0x01;
+	  psa_write(dev, (char *)psa.psa_nwid - (char *)&psa,
+		    (unsigned char *)psa.psa_nwid, 3);
+
+	  /* Set NWID in mmc */
+	  m.w.mmw_netw_id_l = psa.psa_nwid[1];
+	  m.w.mmw_netw_id_h = psa.psa_nwid[0];
+	  mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m,
+		    (unsigned char *)&m.w.mmw_netw_id_l, 2);
+	  mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00);
+	}
+      else
+	{
+	  /* Disable nwid in the psa */
+	  psa.psa_nwid_select = 0x00;
+	  psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa,
+		    (unsigned char *)&psa.psa_nwid_select, 1);
+
+	  /* Disable nwid in the mmc (no filtering) */
+	  mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
+	}
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+      break;
+
+    case SIOCGIWNWID:
+      /* Read the NWID */
+      psa_read(dev, (char *)psa.psa_nwid - (char *)&psa,
+	       (unsigned char *)psa.psa_nwid, 3);
+#if WIRELESS_EXT > 8
+      wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+      wrq->u.nwid.disabled = !(psa.psa_nwid_select);
+      wrq->u.nwid.fixed = 1;	/* Superfluous */
+#else	/* WIRELESS_EXT > 8 */
+      wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+      wrq->u.nwid.on = psa.psa_nwid_select;
+#endif	/* WIRELESS_EXT > 8 */
+      break;
+
+    case SIOCSIWFREQ:
+      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+      if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+	ret = wv_set_frequency(base, &(wrq->u.freq));
+      else
+	ret = -EOPNOTSUPP;
+      break;
+
+    case SIOCGIWFREQ:
+      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
+       * (does it work for everybody ? - especially old cards...) */
+      if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+	{
+	  unsigned short	freq;
+
+	  /* Ask the EEprom to read the frequency from the first area */
+	  fee_read(base, 0x00 /* 1st area - frequency... */,
+		   &freq, 1);
+	  wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
+	  wrq->u.freq.e = 1;
+	}
+      else
+	{
+	  psa_read(dev, (char *)&psa.psa_subband - (char *)&psa,
+		   (unsigned char *)&psa.psa_subband, 1);
+
+	  if(psa.psa_subband <= 4)
+	    {
+	      wrq->u.freq.m = fixed_bands[psa.psa_subband];
+	      wrq->u.freq.e = (psa.psa_subband != 0);
+	    }
+	  else
+	    ret = -EOPNOTSUPP;
+	}
+      break;
+
+    case SIOCSIWSENS:
+      /* Set the level threshold */
+#if WIRELESS_EXT > 7
+      /* We should complain loudly if wrq->u.sens.fixed = 0, because we
+       * can't set auto mode... */
+      psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
+#else	/* WIRELESS_EXT > 7 */
+      psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
+#endif	/* WIRELESS_EXT > 7 */
+      psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
+	       (unsigned char *)&psa.psa_thr_pre_set, 1);
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+      mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set);
+      break;
+
+    case SIOCGIWSENS:
+      /* Read the level threshold */
+      psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
+	       (unsigned char *)&psa.psa_thr_pre_set, 1);
+#if WIRELESS_EXT > 7
+      wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
+      wrq->u.sens.fixed = 1;
+#else	/* WIRELESS_EXT > 7 */
+      wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
+#endif	/* WIRELESS_EXT > 7 */
+      break;
+
+#if WIRELESS_EXT > 8
+    case SIOCSIWENCODE:
+      /* Set encryption key */
+      if(!mmc_encr(base))
+	{
+	  ret = -EOPNOTSUPP;
+	  break;
+	}
+
+      /* Basic checking... */
+      if(wrq->u.encoding.pointer != (caddr_t) 0)
+	{
+	  /* Check the size of the key */
+	  if(wrq->u.encoding.length != 8)
+	    {
+	      ret = -EINVAL;
+	      break;
+	    }
+
+	  /* Copy the key in the driver */
+	  if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer,
+			    wrq->u.encoding.length))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  psa.psa_encryption_select = 1;
+	  psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
+		    (unsigned char *) &psa.psa_encryption_select, 8+1);
+
+	  mmc_out(base, mmwoff(0, mmw_encr_enable),
+		  MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
+	  mmc_write(base, mmwoff(0, mmw_encr_key),
+		    (unsigned char *) &psa.psa_encryption_key, 8);
+	}
+
+      if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
+	{	/* disable encryption */
+	  psa.psa_encryption_select = 0;
+	  psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
+		    (unsigned char *) &psa.psa_encryption_select, 1);
+
+	  mmc_out(base, mmwoff(0, mmw_encr_enable), 0);
+	}
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+      break;
+
+    case SIOCGIWENCODE:
+      /* Read the encryption key */
+      if(!mmc_encr(base))
+	{
+	  ret = -EOPNOTSUPP;
+	  break;
+	}
+
+      /* only super-user can see encryption key */
+      if(!capable(CAP_NET_ADMIN))
+	{
+	  ret = -EPERM;
+	  break;
+	}
+
+      /* Basic checking... */
+      if(wrq->u.encoding.pointer != (caddr_t) 0)
+	{
+	  psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
+		   (unsigned char *) &psa.psa_encryption_select, 1+8);
+
+	  /* encryption is enabled ? */
+	  if(psa.psa_encryption_select)
+	    wrq->u.encoding.flags = IW_ENCODE_ENABLED;
+	  else
+	    wrq->u.encoding.flags = IW_ENCODE_DISABLED;
+	  wrq->u.encoding.flags |= mmc_encr(base);
+
+	  /* Copy the key to the user buffer */
+	  wrq->u.encoding.length = 8;
+	  if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8))
+	    ret = -EFAULT;
+	}
+      break;
+#endif	/* WIRELESS_EXT > 8 */
+
+#ifdef WAVELAN_ROAMING_EXT
+#if WIRELESS_EXT > 5
+    case SIOCSIWESSID:
+      /* Check if disable */
+      if(wrq->u.data.flags == 0)
+	lp->filter_domains = 0;
+      else
+	/* Basic checking... */
+	if(wrq->u.data.pointer != (caddr_t) 0)
+	  {
+	    char	essid[IW_ESSID_MAX_SIZE + 1];
+	    char *	endp;
+
+	    /* Check the size of the string */
+	    if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1)
+	      {
+		ret = -E2BIG;
+		break;
+	      }
+
+	    /* Copy the string in the driver */
+	    if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length))
+	      {
+		ret = -EFAULT;
+		break;
+	      }
+	    essid[IW_ESSID_MAX_SIZE] = '\0';
+
+#ifdef DEBUG_IOCTL_INFO
+	    printk(KERN_DEBUG "SetEssid : ``%s''\n", essid);
+#endif	/* DEBUG_IOCTL_INFO */
+
+	    /* Convert to a number (note : Wavelan specific) */
+	    lp->domain_id = simple_strtoul(essid, &endp, 16);
+	    /* Has it worked  ? */
+	    if(endp > essid)
+	      lp->filter_domains = 1;
+	    else
+	      {
+		lp->filter_domains = 0;
+		ret = -EINVAL;
+	      }
+	  }
+      break;
+
+    case SIOCGIWESSID:
+      /* Basic checking... */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  char		essid[IW_ESSID_MAX_SIZE + 1];
+
+	  /* Is the domain ID active ? */
+	  wrq->u.data.flags = lp->filter_domains;
+
+	  /* Copy Domain ID into a string (Wavelan specific) */
+	  /* Sound crazy, be we can't have a snprintf in the kernel !!! */
+	  sprintf(essid, "%lX", lp->domain_id);
+	  essid[IW_ESSID_MAX_SIZE] = '\0';
+
+	  /* Set the length */
+	  wrq->u.data.length = strlen(essid) + 1;
+
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length))
+	    ret = -EFAULT;
+	}
+      break;
+
+    case SIOCSIWAP:
+#ifdef DEBUG_IOCTL_INFO
+      printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n",
+	     wrq->u.ap_addr.sa_data[0],
+	     wrq->u.ap_addr.sa_data[1],
+	     wrq->u.ap_addr.sa_data[2],
+	     wrq->u.ap_addr.sa_data[3],
+	     wrq->u.ap_addr.sa_data[4],
+	     wrq->u.ap_addr.sa_data[5]);
+#endif	/* DEBUG_IOCTL_INFO */
+
+      ret = -EOPNOTSUPP;	/* Not supported yet */
+      break;
+
+    case SIOCGIWAP:
+      /* Should get the real McCoy instead of own Ethernet address */
+      memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE);
+      wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
+
+      ret = -EOPNOTSUPP;	/* Not supported yet */
+      break;
+#endif	/* WIRELESS_EXT > 5 */
+#endif	/* WAVELAN_ROAMING_EXT */
+
+#if WIRELESS_EXT > 8
+#ifdef WAVELAN_ROAMING
+    case SIOCSIWMODE:
+      switch(wrq->u.mode)
+	{
+	case IW_MODE_ADHOC:
+	  if(do_roaming)
+	    {
+	      wv_roam_cleanup(dev);
+	      do_roaming = 0;
+	    }
+	  break;
+	case IW_MODE_INFRA:
+	  if(!do_roaming)
+	    {
+	      wv_roam_init(dev);
+	      do_roaming = 1;
+	    }
+	  break;
+	default:
+	  ret = -EINVAL;
+	}
+      break;
+
+    case SIOCGIWMODE:
+      if(do_roaming)
+	wrq->u.mode = IW_MODE_INFRA;
+      else
+	wrq->u.mode = IW_MODE_ADHOC;
+      break;
+#endif	/* WAVELAN_ROAMING */
+#endif /* WIRELESS_EXT > 8 */
+
+    case SIOCGIWRANGE:
+      /* Basic checking... */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  struct iw_range	range;
+
+	   /* Set the length (very important for backward compatibility) */
+	   wrq->u.data.length = sizeof(struct iw_range);
+
+	   /* Set all the info we don't care or don't know about to zero */
+	   memset(&range, 0, sizeof(range));
+
+#if WIRELESS_EXT > 10
+	   /* Set the Wireless Extension versions */
+	   range.we_version_compiled = WIRELESS_EXT;
+	   range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#endif /* WIRELESS_EXT > 10 */
+
+	  /* Set information in the range struct */
+	  range.throughput = 1.4 * 1000 * 1000;	/* don't argue on this ! */
+	  range.min_nwid = 0x0000;
+	  range.max_nwid = 0xFFFF;
+
+	  /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+	  if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+	       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+	    {
+	      range.num_channels = 10;
+	      range.num_frequency = wv_frequency_list(base, range.freq,
+						      IW_MAX_FREQUENCIES);
+	    }
+	  else
+	    range.num_channels = range.num_frequency = 0;
+
+	  range.sensitivity = 0x3F;
+	  range.max_qual.qual = MMR_SGNL_QUAL;
+	  range.max_qual.level = MMR_SIGNAL_LVL;
+	  range.max_qual.noise = MMR_SILENCE_LVL;
+#if WIRELESS_EXT > 11
+	  range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
+	  /* Need to get better values for those two */
+	  range.avg_qual.level = 30;
+	  range.avg_qual.noise = 8;
+#endif /* WIRELESS_EXT > 11 */
+
+#if WIRELESS_EXT > 7
+	  range.num_bitrates = 1;
+	  range.bitrate[0] = 2000000;	/* 2 Mb/s */
+#endif /* WIRELESS_EXT > 7 */
+
+#if WIRELESS_EXT > 8
+	  /* Encryption supported ? */
+	  if(mmc_encr(base))
+	    {
+	      range.encoding_size[0] = 8;	/* DES = 64 bits key */
+	      range.num_encoding_sizes = 1;
+	      range.max_encoding_tokens = 1;	/* Only one key possible */
+	    }
+	  else
+	    {
+	      range.num_encoding_sizes = 0;
+	      range.max_encoding_tokens = 0;
+	    }
+#endif /* WIRELESS_EXT > 8 */
+
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, &range,
+			  sizeof(struct iw_range)))
+	    ret = -EFAULT;
+	}
+      break;
+
+    case SIOCGIWPRIV:
+      /* Basic checking... */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  struct iw_priv_args	priv[] =
+	  {	/* cmd,		set_args,	get_args,	name */
+	    { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
+	    { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
+	    { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16,	0, "sethisto" },
+	    { SIOCGIPHISTO, 0,	    IW_PRIV_TYPE_INT | 16, "gethisto" },
+	    { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1 , 0, "setroam" },
+	    { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" },
+	  };
+
+	  /* Set the number of ioctl available */
+	  wrq->u.data.length = 6;
+
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
+		       sizeof(priv)))
+	    ret = -EFAULT;
+	}
+      break;
+
+#ifdef WIRELESS_SPY
+    case SIOCSIWSPY:
+      /* Set the spy list */
+
+      /* Check the number of addresses */
+      if(wrq->u.data.length > IW_MAX_SPY)
+	{
+	  ret = -E2BIG;
+	  break;
+	}
+      lp->spy_number = wrq->u.data.length;
+
+      /* If there is some addresses to copy */
+      if(lp->spy_number > 0)
+	{
+	  struct sockaddr	address[IW_MAX_SPY];
+	  int			i;
+
+	  /* Copy addresses to the driver */
+	  if(copy_from_user(address, wrq->u.data.pointer,
+			    sizeof(struct sockaddr) * lp->spy_number))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  /* Copy addresses to the lp structure */
+	  for(i = 0; i < lp->spy_number; i++)
+	    {
+	      memcpy(lp->spy_address[i], address[i].sa_data,
+		     WAVELAN_ADDR_SIZE);
+	    }
+
+	  /* Reset structure... */
+	  memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
+
+#ifdef DEBUG_IOCTL_INFO
+	  printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
+	  for(i = 0; i < wrq->u.data.length; i++)
+	    printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n",
+		   lp->spy_address[i][0],
+		   lp->spy_address[i][1],
+		   lp->spy_address[i][2],
+		   lp->spy_address[i][3],
+		   lp->spy_address[i][4],
+		   lp->spy_address[i][5]);
+#endif	/* DEBUG_IOCTL_INFO */
+	}
+
+      break;
+
+    case SIOCGIWSPY:
+      /* Get the spy list and spy stats */
+
+      /* Set the number of addresses */
+      wrq->u.data.length = lp->spy_number;
+
+      /* If the user want to have the addresses back... */
+      if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
+	{
+	  struct sockaddr	address[IW_MAX_SPY];
+	  int			i;
+
+	  /* Copy addresses from the lp structure */
+	  for(i = 0; i < lp->spy_number; i++)
+	    {
+	      memcpy(address[i].sa_data, lp->spy_address[i],
+		     WAVELAN_ADDR_SIZE);
+	      address[i].sa_family = ARPHRD_ETHER;
+	    }
+
+	  /* Copy addresses to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, address,
+		       sizeof(struct sockaddr) * lp->spy_number))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  /* Copy stats to the user buffer (just after) */
+	  if(copy_to_user(wrq->u.data.pointer +
+		       (sizeof(struct sockaddr) * lp->spy_number),
+		       lp->spy_stat, sizeof(iw_qual) * lp->spy_number))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  /* Reset updated flags */
+	  for(i = 0; i < lp->spy_number; i++)
+	    lp->spy_stat[i].updated = 0x0;
+	}	/* if(pointer != NULL) */
+
+      break;
+#endif	/* WIRELESS_SPY */
+
+      /* ------------------ PRIVATE IOCTL ------------------ */
+
+    case SIOCSIPQTHR:
+      if(!capable(CAP_NET_ADMIN))
+	{
+	  ret = -EPERM;
+	  break;
+	}
+      psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
+      psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
+	       (unsigned char *)&psa.psa_quality_thr, 1);
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+      mmc_out(base, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr);
+      break;
+
+    case SIOCGIPQTHR:
+      psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
+	       (unsigned char *)&psa.psa_quality_thr, 1);
+      *(wrq->u.name) = psa.psa_quality_thr & 0x0F;
+      break;
+
+#ifdef WAVELAN_ROAMING
+    case SIOCSIPROAM:
+      /* Note : should check if user == root */
+      if(do_roaming && (*wrq->u.name)==0)
+	wv_roam_cleanup(dev);
+      else if(do_roaming==0 && (*wrq->u.name)!=0)
+	wv_roam_init(dev);
+
+      do_roaming = (*wrq->u.name);
+	  
+      break;
+
+    case SIOCGIPROAM:
+      *(wrq->u.name) = do_roaming;
+      break;
+#endif	/* WAVELAN_ROAMING */
+
+#ifdef HISTOGRAM
+    case SIOCSIPHISTO:
+      /* Verif if the user is root */
+      if(!capable(CAP_NET_ADMIN))
+	{
+	  ret = -EPERM;
+	}
+
+      /* Check the number of intervals */
+      if(wrq->u.data.length > 16)
+	{
+	  ret = -E2BIG;
+	  break;
+	}
+      lp->his_number = wrq->u.data.length;
+
+      /* If there is some addresses to copy */
+      if(lp->his_number > 0)
+	{
+	  /* Copy interval ranges to the driver */
+	  if(copy_from_user(lp->his_range, wrq->u.data.pointer,
+			 sizeof(char) * lp->his_number))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  /* Reset structure... */
+	  memset(lp->his_sum, 0x00, sizeof(long) * 16);
+	}
+      break;
+
+    case SIOCGIPHISTO:
+      /* Set the number of intervals */
+      wrq->u.data.length = lp->his_number;
+
+      /* Give back the distribution statistics */
+      if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
+	{
+	  /* Copy data to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, lp->his_sum,
+		       sizeof(long) * lp->his_number))
+	    ret = -EFAULT;
+
+	}	/* if(pointer != NULL) */
+      break;
+#endif	/* HISTOGRAM */
+
+      /* ------------------- OTHER IOCTL ------------------- */
+
+    default:
+      ret = -EOPNOTSUPP;
+    }
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
+#endif
+  return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get wireless statistics
+ * Called by /proc/net/wireless...
+ */
+static iw_stats *
+wavelan_get_wireless_stats(device *	dev)
+{
+  ioaddr_t		base = dev->base_addr;
+  net_local *		lp = (net_local *) dev->priv;
+  mmr_t			m;
+  iw_stats *		wstats;
+  unsigned long		flags;
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
+#endif
+
+  /* Disable interrupts & save flags */
+  wv_splhi(lp, &flags);
+
+  wstats = &lp->wstats;
+
+  /* Get data from the mmc */
+  mmc_out(base, mmwoff(0, mmw_freeze), 1);
+
+  mmc_read(base, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
+  mmc_read(base, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2);
+  mmc_read(base, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4);
+
+  mmc_out(base, mmwoff(0, mmw_freeze), 0);
+
+  /* Copy data to wireless stuff */
+  wstats->status = m.mmr_dce_status & MMR_DCE_STATUS;
+  wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
+  wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
+  wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL;
+  wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) |
+			  ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) |
+			  ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5));
+  wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+  wstats->discard.code = 0L;
+  wstats->discard.misc = 0L;
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
+#endif
+  return &lp->wstats;
+}
+#endif	/* WIRELESS_EXT */
+
+/************************* PACKET RECEPTION *************************/
+/*
+ * This part deal with receiving the packets.
+ * The interrupt handler get an interrupt when a packet has been
+ * successfully received and called this part...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Calculate the starting address of the frame pointed to by the receive
+ * frame pointer and verify that the frame seem correct
+ * (called by wv_packet_rcv())
+ */
+static inline int
+wv_start_of_frame(device *	dev,
+		  int		rfp,	/* end of frame */
+		  int		wrap)	/* start of buffer */
+{
+  ioaddr_t	base = dev->base_addr;
+  int		rp;
+  int		len;
+
+  rp = (rfp - 5 + RX_SIZE) % RX_SIZE;
+  outb(rp & 0xff, PIORL(base));
+  outb(((rp >> 8) & PIORH_MASK), PIORH(base));
+  len = inb(PIOP(base));
+  len |= inb(PIOP(base)) << 8;
+
+  /* Sanity checks on size */
+  /* Frame too big */
+  if(len > MAXDATAZ + 100)
+    {
+#ifdef DEBUG_RX_ERROR
+      printk(KERN_INFO "%s: wv_start_of_frame: Received frame too large, rfp %d len 0x%x\n",
+	     dev->name, rfp, len);
+#endif
+      return(-1);
+    }
+  
+  /* Frame too short */
+  if(len < 7)
+    {
+#ifdef DEBUG_RX_ERROR
+      printk(KERN_INFO "%s: wv_start_of_frame: Received null frame, rfp %d len 0x%x\n",
+	     dev->name, rfp, len);
+#endif
+      return(-1);
+    }
+  
+  /* Wrap around buffer */
+  if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE))	/* magic formula ! */
+    {
+#ifdef DEBUG_RX_ERROR
+      printk(KERN_INFO "%s: wv_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n",
+	     dev->name, wrap, rfp, len);
+#endif
+      return(-1);
+    }
+
+  return((rp - len + RX_SIZE) % RX_SIZE);
+} /* wv_start_of_frame */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine does the actual copy of data (including the ethernet
+ * header structure) from the WaveLAN card to an sk_buff chain that
+ * will be passed up to the network interface layer. NOTE: We
+ * currently don't handle trailer protocols (neither does the rest of
+ * the network interface), so if that is needed, it will (at least in
+ * part) be added here.  The contents of the receive ring buffer are
+ * copied to a message chain that is then passed to the kernel.
+ *
+ * Note: if any errors occur, the packet is "dropped on the floor"
+ * (called by wv_packet_rcv())
+ */
+static inline void
+wv_packet_read(device *		dev,
+	       int		fd_p,
+	       int		sksize)
+{
+  net_local *		lp = (net_local *) dev->priv;
+  struct sk_buff *	skb;
+
+#ifdef DEBUG_RX_TRACE
+  printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n",
+	 dev->name, fd_p, sksize);
+#endif
+
+  /* Allocate some buffer for the new packet */
+  if((skb = dev_alloc_skb(sksize+2)) == (struct sk_buff *) NULL)
+    {
+#ifdef DEBUG_RX_ERROR
+      printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC)\n",
+	     dev->name, sksize);
+#endif
+      lp->stats.rx_dropped++;
+      /*
+       * Not only do we want to return here, but we also need to drop the
+       * packet on the floor to clear the interrupt.
+       */
+      return;
+    }
+
+  skb->dev = dev;
+
+  skb_reserve(skb, 2);
+  fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize);
+  skb->protocol = eth_type_trans(skb, dev);
+
+#ifdef DEBUG_RX_INFO
+  wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
+#endif	/* DEBUG_RX_INFO */
+     
+  /* Statistics gathering & stuff associated.
+   * It seem a bit messy with all the define, but it's really simple... */
+  if(
+#ifdef WIRELESS_SPY
+     (lp->spy_number > 0) ||
+#endif	/* WIRELESS_SPY */
+#ifdef HISTOGRAM
+     (lp->his_number > 0) ||
+#endif	/* HISTOGRAM */
+#ifdef WAVELAN_ROAMING
+     (do_roaming) ||
+#endif	/* WAVELAN_ROAMING */
+     0)
+    {
+      u_char	stats[3];	/* Signal level, Noise level, Signal quality */
+
+      /* read signal level, silence level and signal quality bytes */
+      fd_p = read_ringbuf(dev, (fd_p + 4) % RX_SIZE + RX_BASE,
+			  stats, 3);
+#ifdef DEBUG_RX_INFO
+      printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n",
+	     dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F);
+#endif
+
+#ifdef WAVELAN_ROAMING
+      if(do_roaming)
+	if(WAVELAN_BEACON(skb->data))
+	  wl_roam_gather(dev, skb->data, stats);
+#endif	/* WAVELAN_ROAMING */
+	  
+#ifdef WIRELESS_SPY
+      wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
+#endif	/* WIRELESS_SPY */
+#ifdef HISTOGRAM
+      wl_his_gather(dev, stats);
+#endif	/* HISTOGRAM */
+    }
+
+  /*
+   * Hand the packet to the Network Module
+   */
+  netif_rx(skb);
+
+  /* Keep stats up to date */
+  dev->last_rx = jiffies;
+  lp->stats.rx_packets++;
+  lp->stats.rx_bytes += sksize;
+
+#ifdef DEBUG_RX_TRACE
+  printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name);
+#endif
+  return;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine is called by the interrupt handler to initiate a
+ * packet transfer from the card to the network interface layer above
+ * this driver.  This routine checks if a buffer has been successfully
+ * received by the WaveLAN card.  If so, the routine wv_packet_read is
+ * called to do the actual transfer of the card's data including the
+ * ethernet header into a packet consisting of an sk_buff chain.
+ * (called by wavelan_interrupt())
+ * Note : the spinlock is already grabbed for us and irq are disabled.
+ */
+static inline void
+wv_packet_rcv(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  net_local *	lp = (net_local *) dev->priv;
+  int		newrfp;
+  int		rp;
+  int		len;
+  int		f_start;
+  int		status;
+  int		i593_rfp;
+  int		stat_ptr;
+  u_char	c[4];
+
+#ifdef DEBUG_RX_TRACE
+  printk(KERN_DEBUG "%s: ->wv_packet_rcv()\n", dev->name);
+#endif
+
+  /* Get the new receive frame pointer from the i82593 chip */
+  outb(CR0_STATUS_2 | OP0_NOP, LCCR(base));
+  i593_rfp = inb(LCSR(base));
+  i593_rfp |= inb(LCSR(base)) << 8;
+  i593_rfp %= RX_SIZE;
+
+  /* Get the new receive frame pointer from the WaveLAN card.
+   * It is 3 bytes more than the increment of the i82593 receive
+   * frame pointer, for each packet. This is because it includes the
+   * 3 roaming bytes added by the mmc.
+   */
+  newrfp = inb(RPLL(base));
+  newrfp |= inb(RPLH(base)) << 8;
+  newrfp %= RX_SIZE;
+
+#ifdef DEBUG_RX_INFO
+  printk(KERN_DEBUG "%s: wv_packet_rcv(): i593_rfp %d stop %d newrfp %d lp->rfp %d\n",
+	 dev->name, i593_rfp, lp->stop, newrfp, lp->rfp);
+#endif
+
+#ifdef DEBUG_RX_ERROR
+  /* If no new frame pointer... */
+  if(lp->overrunning || newrfp == lp->rfp)
+    printk(KERN_INFO "%s: wv_packet_rcv(): no new frame: i593_rfp %d stop %d newrfp %d lp->rfp %d\n",
+	   dev->name, i593_rfp, lp->stop, newrfp, lp->rfp);
+#endif
+
+  /* Read all frames (packets) received */
+  while(newrfp != lp->rfp)
+    {
+      /* A frame is composed of the packet, followed by a status word,
+       * the length of the frame (word) and the mmc info (SNR & qual).
+       * It's because the length is at the end that we can only scan
+       * frames backward. */
+
+      /* Find the first frame by skipping backwards over the frames */
+      rp = newrfp;	/* End of last frame */
+      while(((f_start = wv_start_of_frame(dev, rp, newrfp)) != lp->rfp) &&
+	    (f_start != -1))
+	  rp = f_start;
+
+      /* If we had a problem */
+      if(f_start == -1)
+	{
+#ifdef DEBUG_RX_ERROR
+	  printk(KERN_INFO "wavelan_cs: cannot find start of frame ");
+	  printk(" i593_rfp %d stop %d newrfp %d lp->rfp %d\n",
+		 i593_rfp, lp->stop, newrfp, lp->rfp);
+#endif
+	  lp->rfp = rp;		/* Get to the last usable frame */
+	  continue;
+	}
+
+      /* f_start point to the beggining of the first frame received
+       * and rp to the beggining of the next one */
+
+      /* Read status & length of the frame */
+      stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE;
+      stat_ptr = read_ringbuf(dev, stat_ptr, c, 4);
+      status = c[0] | (c[1] << 8);
+      len = c[2] | (c[3] << 8);
+
+      /* Check status */
+      if((status & RX_RCV_OK) != RX_RCV_OK)
+	{
+	  lp->stats.rx_errors++;
+	  if(status & RX_NO_SFD)
+	    lp->stats.rx_frame_errors++;
+	  if(status & RX_CRC_ERR)
+	    lp->stats.rx_crc_errors++;
+	  if(status & RX_OVRRUN)
+	    lp->stats.rx_over_errors++;
+
+#ifdef DEBUG_RX_FAIL
+	  printk(KERN_DEBUG "%s: wv_packet_rcv(): packet not received ok, status = 0x%x\n",
+		 dev->name, status);
+#endif
+	}
+      else
+	/* Read the packet and transmit to Linux */
+	wv_packet_read(dev, f_start, len - 2);
+
+      /* One frame has been processed, skip it */
+      lp->rfp = rp;
+    }
+
+  /*
+   * Update the frame stop register, but set it to less than
+   * the full 8K to allow space for 3 bytes of signal strength
+   * per packet.
+   */
+  lp->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+  outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base));
+  outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
+  outb(OP1_SWIT_TO_PORT_0, LCCR(base));
+
+#ifdef DEBUG_RX_TRACE
+  printk(KERN_DEBUG "%s: <-wv_packet_rcv()\n", dev->name);
+#endif
+}
+
+/*********************** PACKET TRANSMISSION ***********************/
+/*
+ * This part deal with sending packet through the wavelan
+ * We copy the packet to the send buffer and then issue the send
+ * command to the i82593. The result of this operation will be
+ * checked in wavelan_interrupt()
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine fills in the appropriate registers and memory
+ * locations on the WaveLAN card and starts the card off on
+ * the transmit.
+ * (called in wavelan_packet_xmit())
+ */
+static inline void
+wv_packet_write(device *	dev,
+		void *		buf,
+		short		length)
+{
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			clen = length;
+  register u_short	xmtdata_base = TX_BASE;
+
+#ifdef DEBUG_TX_TRACE
+  printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
+#endif
+
+  wv_splhi(lp, &flags);
+
+  /* Check if we need some padding */
+  if(clen < ETH_ZLEN)
+    clen = ETH_ZLEN;
+
+  /* Write the length of data buffer followed by the buffer */
+  outb(xmtdata_base & 0xff, PIORL(base));
+  outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
+  outb(clen & 0xff, PIOP(base));	/* lsb */
+  outb(clen >> 8, PIOP(base));  	/* msb */
+
+  /* Send the data */
+  outsb(PIOP(base), buf, clen);
+
+  /* Indicate end of transmit chain */
+  outb(OP0_NOP, PIOP(base));
+  /* josullvn@cs.cmu.edu: need to send a second NOP for alignment... */
+  outb(OP0_NOP, PIOP(base));
+
+  /* Reset the transmit DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+  hacr_write(base, HACR_DEFAULT);
+  /* Send the transmit command */
+  wv_82593_cmd(dev, "wv_packet_write(): transmit",
+	       OP0_TRANSMIT, SR0_NO_RESULT);
+
+  /* Keep stats up to date */
+  lp->stats.tx_bytes += length;
+
+  wv_splx(lp, &flags);
+
+#ifdef DEBUG_TX_INFO
+  wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
+#endif	/* DEBUG_TX_INFO */
+
+#ifdef DEBUG_TX_TRACE
+  printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine is called when we want to send a packet (NET3 callback)
+ * In this routine, we check if the harware is ready to accept
+ * the packet. We also prevent reentrance. Then, we call the function
+ * to send the packet...
+ */
+static int
+wavelan_packet_xmit(struct sk_buff *	skb,
+		    device *		dev)
+{
+  net_local *		lp = (net_local *)dev->priv;
+  unsigned long		flags;
+
+#ifdef DEBUG_TX_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+	 (unsigned) skb);
+#endif
+
+  /*
+   * Block a timer-based transmit from overlapping a previous transmit.
+   * In other words, prevent reentering this routine.
+   */
+  netif_stop_queue(dev);
+
+  /* If somebody has asked to reconfigure the controller,
+   * we can do it now */
+  if(lp->reconfig_82593)
+    {
+      wv_splhi(lp, &flags);	/* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);	/* Re-enable interrupts */
+      /* Note : the configure procedure was totally synchronous,
+       * so the Tx buffer is now free */
+    }
+
+#ifdef DEBUG_TX_ERROR
+	if (skb->next)
+		printk(KERN_INFO "skb has next\n");
+#endif
+
+  wv_packet_write(dev, skb->data, skb->len);
+
+  dev_kfree_skb(skb);
+
+#ifdef DEBUG_TX_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+#endif
+  return(0);
+}
+
+/********************** HARDWARE CONFIGURATION **********************/
+/*
+ * This part do the real job of starting and configuring the hardware.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to initialize the Modem Management Controller.
+ * (called by wv_hw_config())
+ */
+static inline int
+wv_mmc_init(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  psa_t		psa;
+  mmw_t		m;
+  int		configured;
+  int		i;		/* Loop counter */
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
+#endif
+
+  /* Read the parameter storage area */
+  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+
+  /*
+   * Check the first three octets of the MAC addr for the manufacturer's code.
+   * Note: If you get the error message below, you've got a
+   * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on
+   * how to configure your card...
+   */
+  for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
+    if((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) &&
+       (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) &&
+       (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2]))
+      break;
+
+  /* If we have not found it... */
+  if(i == (sizeof(MAC_ADDRESSES) / sizeof(char) / 3))
+    {
+#ifdef DEBUG_CONFIG_ERRORS
+      printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n",
+	     dev->name, psa.psa_univ_mac_addr[0],
+	     psa.psa_univ_mac_addr[1], psa.psa_univ_mac_addr[2]);
+#endif
+      return FALSE;
+    }
+
+  /* Get the MAC address */
+  memcpy(&dev->dev_addr[0], &psa.psa_univ_mac_addr[0], WAVELAN_ADDR_SIZE);
+
+#ifdef USE_PSA_CONFIG
+  configured = psa.psa_conf_status & 1;
+#else
+  configured = 0;
+#endif
+
+  /* Is the PSA is not configured */
+  if(!configured)
+    {
+      /* User will be able to configure NWID after (with iwconfig) */
+      psa.psa_nwid[0] = 0;
+      psa.psa_nwid[1] = 0;
+
+      /* As NWID is not set : no NWID checking */
+      psa.psa_nwid_select = 0;
+
+      /* Disable encryption */
+      psa.psa_encryption_select = 0;
+
+      /* Set to standard values
+       * 0x04 for AT,
+       * 0x01 for MCA,
+       * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
+       */
+      if (psa.psa_comp_number & 1)
+	psa.psa_thr_pre_set = 0x01;
+      else
+	psa.psa_thr_pre_set = 0x04;
+      psa.psa_quality_thr = 0x03;
+
+      /* It is configured */
+      psa.psa_conf_status |= 1;
+
+#ifdef USE_PSA_CONFIG
+      /* Write the psa */
+      psa_write(dev, (char *)psa.psa_nwid - (char *)&psa,
+		(unsigned char *)psa.psa_nwid, 4);
+      psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
+		(unsigned char *)&psa.psa_thr_pre_set, 1);
+      psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
+		(unsigned char *)&psa.psa_quality_thr, 1);
+      psa_write(dev, (char *)&psa.psa_conf_status - (char *)&psa,
+		(unsigned char *)&psa.psa_conf_status, 1);
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+#endif	/* USE_PSA_CONFIG */
+    }
+
+  /* Zero the mmc structure */
+  memset(&m, 0x00, sizeof(m));
+
+  /* Copy PSA info to the mmc */
+  m.mmw_netw_id_l = psa.psa_nwid[1];
+  m.mmw_netw_id_h = psa.psa_nwid[0];
+  
+  if(psa.psa_nwid_select & 1)
+    m.mmw_loopt_sel = 0x00;
+  else
+    m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID;
+
+  memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, 
+	 sizeof(m.mmw_encr_key));
+
+  if(psa.psa_encryption_select)
+    m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE;
+  else
+    m.mmw_encr_enable = 0;
+
+  m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
+  m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
+
+  /*
+   * Set default modem control parameters.
+   * See NCR document 407-0024326 Rev. A.
+   */
+  m.mmw_jabber_enable = 0x01;
+  m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
+  m.mmw_ifs = 0x20;
+  m.mmw_mod_delay = 0x04;
+  m.mmw_jam_time = 0x38;
+
+  m.mmw_des_io_invert = 0;
+  m.mmw_freeze = 0;
+  m.mmw_decay_prm = 0;
+  m.mmw_decay_updat_prm = 0;
+
+  /* Write all info to mmc */
+  mmc_write(base, 0, (u_char *)&m, sizeof(m));
+
+  /* The following code start the modem of the 2.00 frequency
+   * selectable cards at power on. It's not strictly needed for the
+   * following boots...
+   * The original patch was by Joe Finney for the PCMCIA driver, but
+   * I've cleaned it a bit and add documentation.
+   * Thanks to Loeke Brederveld from Lucent for the info.
+   */
+
+  /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
+   * (does it work for everybody ? - especially old cards...) */
+  /* Note : WFREQSEL verify that it is able to read from EEprom
+   * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
+   * is 0xA (Xilinx version) or 0xB (Ariadne version).
+   * My test is more crude but do work... */
+  if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+    {
+      /* We must download the frequency parameters to the
+       * synthetisers (from the EEprom - area 1)
+       * Note : as the EEprom is auto decremented, we set the end
+       * if the area... */
+      m.mmw_fee_addr = 0x0F;
+      m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
+      mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m,
+		(unsigned char *)&m.mmw_fee_ctrl, 2);
+
+      /* Wait until the download is finished */
+      fee_wait(base, 100, 100);
+
+#ifdef DEBUG_CONFIG_INFO
+      /* The frequency was in the last word downloaded... */
+      mmc_read(base, (char *)&m.mmw_fee_data_l - (char *)&m,
+	       (unsigned char *)&m.mmw_fee_data_l, 2);
+
+      /* Print some info for the user */
+      printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n",
+	     dev->name,
+	     ((m.mmw_fee_data_h << 4) |
+	      (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L);
+#endif
+
+      /* We must now download the power adjust value (gain) to
+       * the synthetisers (from the EEprom - area 7 - DAC) */
+      m.mmw_fee_addr = 0x61;
+      m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
+      mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m,
+		(unsigned char *)&m.mmw_fee_ctrl, 2);
+
+      /* Wait until the download is finished */
+    }	/* if 2.00 card */
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name);
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to gracefully turn off reception, and wait for any commands
+ * to complete.
+ * (called in wv_ru_start() and wavelan_close() and wavelan_event())
+ */
+static int
+wv_ru_stop(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  net_local *	lp = (net_local *) dev->priv;
+  unsigned long	flags;
+  int		status;
+  int		spin;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
+#endif
+
+  wv_splhi(lp, &flags);
+
+  /* First, send the LAN controller a stop receive command */
+  wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
+	       OP0_STOP_RCV, SR0_NO_RESULT);
+
+  /* Then, spin until the receive unit goes idle */
+  spin = 300;
+  do
+    {
+      udelay(10);
+      outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
+      status = inb(LCSR(base));
+    }
+  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0));
+
+  /* Now, spin until the chip finishes executing its current command */
+  do
+    {
+      udelay(10);
+      outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
+      status = inb(LCSR(base));
+    }
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
+
+  wv_splx(lp, &flags);
+
+  /* If there was a problem */
+  if(spin <= 0)
+    {
+#ifdef DEBUG_CONFIG_ERROR
+      printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n",
+	     dev->name);
+#endif
+      return FALSE;
+    }
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_ru_stop()\n", dev->name);
+#endif
+  return TRUE;
+} /* wv_ru_stop */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine starts the receive unit running.  First, it checks if
+ * the card is actually ready. Then the card is instructed to receive
+ * packets again.
+ * (called in wv_hw_reset() & wavelan_open())
+ */
+static int
+wv_ru_start(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  net_local *	lp = (net_local *) dev->priv;
+  unsigned long	flags;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
+#endif
+
+  /*
+   * We need to start from a quiescent state. To do so, we could check
+   * if the card is already running, but instead we just try to shut
+   * it down. First, we disable reception (in case it was already enabled).
+   */
+  if(!wv_ru_stop(dev))
+    return FALSE;
+
+  wv_splhi(lp, &flags);
+
+  /* Now we know that no command is being executed. */
+
+  /* Set the receive frame pointer and stop pointer */
+  lp->rfp = 0;
+  outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base));
+
+  /* Reset ring management.  This sets the receive frame pointer to 1 */
+  outb(OP1_RESET_RING_MNGMT, LCCR(base));
+
+#if 0
+  /* XXX the i82593 manual page 6-4 seems to indicate that the stop register
+     should be set as below */
+  /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/
+#elif 0
+  /* but I set it 0 instead */
+  lp->stop = 0;
+#else
+  /* but I set it to 3 bytes per packet less than 8K */
+  lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+#endif
+  outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
+  outb(OP1_INT_ENABLE, LCCR(base));
+  outb(OP1_SWIT_TO_PORT_0, LCCR(base));
+
+  /* Reset receive DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+  hacr_write_slow(base, HACR_DEFAULT);
+
+  /* Receive DMA on channel 1 */
+  wv_82593_cmd(dev, "wv_ru_start(): rcv-enable",
+	       CR0_CHNL | OP0_RCV_ENABLE, SR0_NO_RESULT);
+
+#ifdef DEBUG_I82593_SHOW
+  {
+    int	status;
+    int	opri;
+    int	spin = 10000;
+
+    /* spin until the chip starts receiving */
+    do
+      {
+	outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
+	status = inb(LCSR(base));
+	if(spin-- <= 0)
+	  break;
+      }
+    while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) &&
+	  ((status & SR3_RCV_STATE_MASK) != SR3_RCV_READY));
+    printk(KERN_DEBUG "rcv status is 0x%x [i:%d]\n",
+	   (status & SR3_RCV_STATE_MASK), i);
+  }
+#endif
+
+  wv_splx(lp, &flags);
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine does a standard config of the WaveLAN controller (i82593).
+ * In the ISA driver, this is integrated in wavelan_hardware_reset()
+ * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit())
+ */
+static int
+wv_82593_config(device *	dev)
+{
+  ioaddr_t			base = dev->base_addr;
+  net_local *			lp = (net_local *) dev->priv;
+  struct i82593_conf_block	cfblk;
+  int				ret = TRUE;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name);
+#endif
+
+  /* Create & fill i82593 config block
+   *
+   * Now conform to Wavelan document WCIN085B
+   */
+  memset(&cfblk, 0x00, sizeof(struct i82593_conf_block));
+  cfblk.d6mod = FALSE;  	/* Run in i82593 advanced mode */
+  cfblk.fifo_limit = 5;         /* = 56 B rx and 40 B tx fifo thresholds */
+  cfblk.forgnesi = FALSE;       /* 0=82C501, 1=AMD7992B compatibility */
+  cfblk.fifo_32 = 1;
+  cfblk.throttle_enb = FALSE;
+  cfblk.contin = TRUE;          /* enable continuous mode */
+  cfblk.cntrxint = FALSE;       /* enable continuous mode receive interrupts */
+  cfblk.addr_len = WAVELAN_ADDR_SIZE;
+  cfblk.acloc = TRUE;           /* Disable source addr insertion by i82593 */
+  cfblk.preamb_len = 0;         /* 2 bytes preamble (SFD) */
+  cfblk.loopback = FALSE;
+  cfblk.lin_prio = 0;   	/* conform to 802.3 backoff algoritm */
+  cfblk.exp_prio = 5;	        /* conform to 802.3 backoff algoritm */
+  cfblk.bof_met = 1;	        /* conform to 802.3 backoff algoritm */
+  cfblk.ifrm_spc = 0x20;	/* 32 bit times interframe spacing */
+  cfblk.slottim_low = 0x20;	/* 32 bit times slot time */
+  cfblk.slottim_hi = 0x0;
+  cfblk.max_retr = 15;
+  cfblk.prmisc = ((lp->promiscuous) ? TRUE: FALSE);	/* Promiscuous mode */
+  cfblk.bc_dis = FALSE;         /* Enable broadcast reception */
+  cfblk.crs_1 = TRUE;		/* Transmit without carrier sense */
+  cfblk.nocrc_ins = FALSE;	/* i82593 generates CRC */	
+  cfblk.crc_1632 = FALSE;	/* 32-bit Autodin-II CRC */
+  cfblk.crs_cdt = FALSE;	/* CD not to be interpreted as CS */
+  cfblk.cs_filter = 0;  	/* CS is recognized immediately */
+  cfblk.crs_src = FALSE;	/* External carrier sense */
+  cfblk.cd_filter = 0;  	/* CD is recognized immediately */
+  cfblk.min_fr_len = ETH_ZLEN >> 2;     /* Minimum frame length 64 bytes */
+  cfblk.lng_typ = FALSE;	/* Length field > 1500 = type field */
+  cfblk.lng_fld = TRUE; 	/* Disable 802.3 length field check */
+  cfblk.rxcrc_xf = TRUE;	/* Don't transfer CRC to memory */
+  cfblk.artx = TRUE;		/* Disable automatic retransmission */
+  cfblk.sarec = TRUE;		/* Disable source addr trig of CD */
+  cfblk.tx_jabber = TRUE;	/* Disable jabber jam sequence */
+  cfblk.hash_1 = FALSE; 	/* Use bits 0-5 in mc address hash */
+  cfblk.lbpkpol = TRUE; 	/* Loopback pin active high */
+  cfblk.fdx = FALSE;		/* Disable full duplex operation */
+  cfblk.dummy_6 = 0x3f; 	/* all ones */
+  cfblk.mult_ia = FALSE;	/* No multiple individual addresses */
+  cfblk.dis_bof = FALSE;	/* Disable the backoff algorithm ?! */
+  cfblk.dummy_1 = TRUE; 	/* set to 1 */
+  cfblk.tx_ifs_retrig = 3;	/* Hmm... Disabled */
+#ifdef MULTICAST_ALL
+  cfblk.mc_all = (lp->allmulticast ? TRUE: FALSE);	/* Allow all multicasts */
+#else
+  cfblk.mc_all = FALSE;		/* No multicast all mode */
+#endif
+  cfblk.rcv_mon = 0;		/* Monitor mode disabled */
+  cfblk.frag_acpt = TRUE;	/* Do not accept fragments */
+  cfblk.tstrttrs = FALSE;	/* No start transmission threshold */
+  cfblk.fretx = TRUE;		/* FIFO automatic retransmission */
+  cfblk.syncrqs = FALSE; 	/* Synchronous DRQ deassertion... */
+  cfblk.sttlen = TRUE;  	/* 6 byte status registers */
+  cfblk.rx_eop = TRUE;  	/* Signal EOP on packet reception */
+  cfblk.tx_eop = TRUE;  	/* Signal EOP on packet transmission */
+  cfblk.rbuf_size = RX_SIZE>>11;	/* Set receive buffer size */
+  cfblk.rcvstop = TRUE; 	/* Enable Receive Stop Register */
+
+#ifdef DEBUG_I82593_SHOW
+  {
+    u_char *c = (u_char *) &cfblk;
+    int i;
+    printk(KERN_DEBUG "wavelan_cs: config block:");
+    for(i = 0; i < sizeof(struct i82593_conf_block); i++,c++)
+      {
+	if((i % 16) == 0) printk("\n" KERN_DEBUG);
+	printk("%02x ", *c);
+      }
+    printk("\n");
+  }
+#endif
+
+  /* Copy the config block to the i82593 */
+  outb(TX_BASE & 0xff, PIORL(base));
+  outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
+  outb(sizeof(struct i82593_conf_block) & 0xff, PIOP(base));    /* lsb */
+  outb(sizeof(struct i82593_conf_block) >> 8, PIOP(base));	/* msb */
+  outsb(PIOP(base), (char *) &cfblk, sizeof(struct i82593_conf_block));
+
+  /* reset transmit DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+  hacr_write(base, HACR_DEFAULT);
+  if(!wv_82593_cmd(dev, "wv_82593_config(): configure",
+		   OP0_CONFIGURE, SR0_CONFIGURE_DONE))
+    ret = FALSE;
+
+  /* Initialize adapter's ethernet MAC address */
+  outb(TX_BASE & 0xff, PIORL(base));
+  outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
+  outb(WAVELAN_ADDR_SIZE, PIOP(base));	/* byte count lsb */
+  outb(0, PIOP(base));			/* byte count msb */
+  outsb(PIOP(base), &dev->dev_addr[0], WAVELAN_ADDR_SIZE);
+
+  /* reset transmit DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+  hacr_write(base, HACR_DEFAULT);
+  if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup",
+		   OP0_IA_SETUP, SR0_IA_SETUP_DONE))
+    ret = FALSE;
+
+#ifdef WAVELAN_ROAMING
+    /* If roaming is enabled, join the "Beacon Request" multicast group... */
+    /* But only if it's not in there already! */
+  if(do_roaming)
+    dev_mc_add(dev,WAVELAN_BEACON_ADDRESS, WAVELAN_ADDR_SIZE, 1);
+#endif	/* WAVELAN_ROAMING */
+
+  /* If any multicast address to set */
+  if(lp->mc_count)
+    {
+      struct dev_mc_list *	dmi;
+      int			addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count;
+
+#ifdef DEBUG_CONFIG_INFO
+      printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n",
+	     dev->name, lp->mc_count);
+      for(dmi=dev->mc_list; dmi; dmi=dmi->next)
+	printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
+	       dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] );
+#endif
+
+      /* Initialize adapter's ethernet multicast addresses */
+      outb(TX_BASE & 0xff, PIORL(base));
+      outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
+      outb(addrs_len & 0xff, PIOP(base));	/* byte count lsb */
+      outb((addrs_len >> 8), PIOP(base));	/* byte count msb */
+      for(dmi=dev->mc_list; dmi; dmi=dmi->next)
+	outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen);
+
+      /* reset transmit DMA pointer */
+      hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+      hacr_write(base, HACR_DEFAULT);
+      if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup",
+		       OP0_MC_SETUP, SR0_MC_SETUP_DONE))
+	ret = FALSE;
+      lp->mc_count = dev->mc_count;	/* remember to avoid repeated reset */
+    }
+
+  /* Job done, clear the flag */
+  lp->reconfig_82593 = FALSE;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name);
+#endif
+  return(ret);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Read the Access Configuration Register, perform a software reset,
+ * and then re-enable the card's software.
+ *
+ * If I understand correctly : reset the pcmcia interface of the
+ * wavelan.
+ * (called by wv_config())
+ */
+static inline int
+wv_pcmcia_reset(device *	dev)
+{
+  int		i;
+  conf_reg_t	reg = { 0, CS_READ, CISREG_COR, 0 };
+  dev_link_t *	link = ((net_local *) dev->priv)->link;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name);
+#endif
+
+  i = CardServices(AccessConfigurationRegister, link->handle, &reg);
+  if(i != CS_SUCCESS)
+    {
+      cs_error(link->handle, AccessConfigurationRegister, i);
+      return FALSE;
+    }
+      
+#ifdef DEBUG_CONFIG_INFO
+  printk(KERN_DEBUG "%s: wavelan_pcmcia_reset(): Config reg is 0x%x\n",
+	 dev->name, (u_int) reg.Value);
+#endif
+
+  reg.Action = CS_WRITE;
+  reg.Value = reg.Value | COR_SW_RESET;
+  i = CardServices(AccessConfigurationRegister, link->handle, &reg);
+  if(i != CS_SUCCESS)
+    {
+      cs_error(link->handle, AccessConfigurationRegister, i);
+      return FALSE;
+    }
+      
+  reg.Action = CS_WRITE;
+  reg.Value = COR_LEVEL_IRQ | COR_CONFIG;
+  i = CardServices(AccessConfigurationRegister, link->handle, &reg);
+  if(i != CS_SUCCESS)
+    {
+      cs_error(link->handle, AccessConfigurationRegister, i);
+      return FALSE;
+    }
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_pcmcia_reset()\n", dev->name);
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * wavelan_hw_config() is called after a CARD_INSERTION event is
+ * received, to configure the wavelan hardware.
+ * Note that the reception will be enabled in wavelan->open(), so the
+ * device is configured but idle...
+ * Performs the following actions:
+ * 	1. A pcmcia software reset (using wv_pcmcia_reset())
+ *	2. A power reset (reset DMA)
+ *	3. Reset the LAN controller
+ *	4. Initialize the radio modem (using wv_mmc_init)
+ *	5. Configure LAN controller (using wv_82593_config)
+ *	6. Perform a diagnostic on the LAN controller
+ * (called by wavelan_event() & wv_hw_reset())
+ */
+static int
+wv_hw_config(device *	dev)
+{
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			ret = FALSE;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name);
+#endif
+
+#ifdef STRUCT_CHECK
+  if(wv_structuct_check() != (char *) NULL)
+    {
+      printk(KERN_WARNING "%s: wv_hw_config: structure/compiler botch: \"%s\"\n",
+	     dev->name, wv_structuct_check());
+      return FALSE;
+    }
+#endif	/* STRUCT_CHECK == 1 */
+
+  /* Reset the pcmcia interface */
+  if(wv_pcmcia_reset(dev) == FALSE)
+    return FALSE;
+
+  /* Disable interrupts */
+  wv_splhi(lp, &flags);
+
+  /* Disguised goto ;-) */
+  do
+    {
+      /* Power UP the module + reset the modem + reset host adapter
+       * (in fact, reset DMA channels) */
+      hacr_write_slow(base, HACR_RESET);
+      hacr_write(base, HACR_DEFAULT);
+
+      /* Check if the module has been powered up... */
+      if(hasr_read(base) & HASR_NO_CLK)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
+		 dev->name);
+#endif
+	  break;
+	}
+
+      /* initialize the modem */
+      if(wv_mmc_init(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n",
+		 dev->name);
+#endif
+	  break;
+	}
+
+      /* reset the LAN controller (i82593) */
+      outb(OP0_RESET, LCCR(base));
+      mdelay(1);	/* A bit crude ! */
+
+      /* Initialize the LAN controller */
+      if(wv_82593_config(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n",
+		 dev->name);
+#endif
+	  break;
+	}
+
+      /* Diagnostic */
+      if(wv_diag(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n",
+		 dev->name);
+#endif
+	  break;
+	}
+
+      /* 
+       * insert code for loopback test here
+       */
+
+      /* The device is now configured */
+      lp->configured = 1;
+      ret = TRUE;
+    }
+  while(0);
+
+  /* Re-enable interrupts */
+  wv_splx(lp, &flags);
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
+#endif
+  return(ret);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Totally reset the wavelan and restart it.
+ * Performs the following actions:
+ * 	1. Call wv_hw_config()
+ *	2. Start the LAN controller's receive unit
+ * (called by wavelan_event(), wavelan_watchdog() and wavelan_open())
+ */
+static inline void
+wv_hw_reset(device *	dev)
+{
+  net_local *	lp = (net_local *) dev->priv;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
+#endif
+
+  lp->nresets++;
+  lp->configured = 0;
+  
+  /* Call wv_hw_config() for most of the reset & init stuff */
+  if(wv_hw_config(dev) == FALSE)
+    return;
+
+  /* start receive unit */
+  wv_ru_start(dev);
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * wv_pcmcia_config() is called after a CARD_INSERTION event is
+ * received, to configure the PCMCIA socket, and to make the ethernet
+ * device available to the system.
+ * (called by wavelan_event())
+ */
+static inline int
+wv_pcmcia_config(dev_link_t *	link)
+{
+  client_handle_t	handle;
+  tuple_t		tuple;
+  cisparse_t		parse;
+  struct net_device *	dev;
+  int			i;
+  u_char		buf[64];
+  win_req_t		req;
+  memreq_t		mem;
+
+  handle = link->handle;
+  dev = (device *) link->priv;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link);
+#endif
+
+  /*
+   * This reads the card's CONFIG tuple to find its configuration
+   * registers.
+   */
+  do
+    {
+      tuple.Attributes = 0;
+      tuple.DesiredTuple = CISTPL_CONFIG;
+      i = CardServices(GetFirstTuple, handle, &tuple);
+      if(i != CS_SUCCESS)
+	break;
+      tuple.TupleData = (cisdata_t *)buf;
+      tuple.TupleDataMax = 64;
+      tuple.TupleOffset = 0;
+      i = CardServices(GetTupleData, handle, &tuple);
+      if(i != CS_SUCCESS)
+	break;
+      i = CardServices(ParseTuple, handle, &tuple, &parse);
+      if(i != CS_SUCCESS)
+	break;
+      link->conf.ConfigBase = parse.config.base;
+      link->conf.Present = parse.config.rmask[0];
+    }
+  while(0);
+  if(i != CS_SUCCESS)
+    {
+      cs_error(link->handle, ParseTuple, i);
+      link->state &= ~DEV_CONFIG_PENDING;
+      return FALSE;
+    }
+    
+  /* Configure card */
+  link->state |= DEV_CONFIG;
+  do
+    {
+      i = CardServices(RequestIO, link->handle, &link->io);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, RequestIO, i);
+	  break;
+	}
+
+      /*
+       * Now allocate an interrupt line.  Note that this does not
+       * actually assign a handler to the interrupt.
+       */
+      i = CardServices(RequestIRQ, link->handle, &link->irq);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, RequestIRQ, i);
+	  break;
+	}
+
+      /*
+       * This actually configures the PCMCIA socket -- setting up
+       * the I/O windows and the interrupt mapping.
+       */
+      link->conf.ConfigIndex = 1;
+      i = CardServices(RequestConfiguration, link->handle, &link->conf);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, RequestConfiguration, i);
+	  break;
+	}
+
+      /*
+       * Allocate a small memory window.  Note that the dev_link_t
+       * structure provides space for one window handle -- if your
+       * device needs several windows, you'll need to keep track of
+       * the handles in your private data structure, link->priv.
+       */
+      req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+      req.Base = req.Size = 0;
+      req.AccessSpeed = mem_speed;
+      link->win = (window_handle_t)link->handle;
+      i = CardServices(RequestWindow, &link->win, &req);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, RequestWindow, i);
+	  break;
+	}
+
+      dev->rmem_start = dev->mem_start =
+	  (u_long)ioremap(req.Base, req.Size);
+      dev->rmem_end = dev->mem_end = dev->mem_start + req.Size;
+
+      mem.CardOffset = 0; mem.Page = 0;
+      i = CardServices(MapMemPage, link->win, &mem);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, MapMemPage, i);
+	  break;
+	}
+
+      /* Feed device with this info... */
+      dev->irq = link->irq.AssignedIRQ;
+      dev->base_addr = link->io.BasePort1;
+      netif_start_queue(dev);
+
+#ifdef DEBUG_CONFIG_INFO
+      printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
+	     (u_int) dev->mem_start, dev->irq, (u_int) dev->base_addr);
+#endif
+
+      i = register_netdev(dev);
+      if(i != 0)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_INFO "wv_pcmcia_config(): register_netdev() failed\n");
+#endif
+	  break;
+	}
+    }
+  while(0);		/* Humm... Disguised goto !!! */
+
+  link->state &= ~DEV_CONFIG_PENDING;
+  /* If any step failed, release any partially configured state */
+  if(i != 0)
+    {
+      wv_pcmcia_release((u_long) link);
+      return FALSE;
+    }
+
+  strcpy(((net_local *) dev->priv)->node.dev_name, dev->name);
+  link->dev = &((net_local *) dev->priv)->node;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "<-wv_pcmcia_config()\n");
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * After a card is removed, wv_pcmcia_release() will unregister the net
+ * device, and release the PCMCIA configuration.  If the device is
+ * still open, this will be postponed until it is closed.
+ */
+static void
+wv_pcmcia_release(u_long	arg)	/* Address of the interface struct */
+{
+  dev_link_t *	link = (dev_link_t *) arg;
+  device *	dev = (device *) link->priv;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link);
+#endif
+
+  /* If the device is currently in use, we won't release until it is
+   * actually closed. */
+  if(link->open)
+    {
+#ifdef DEBUG_CONFIG_INFO
+      printk(KERN_DEBUG "%s: wv_pcmcia_release: release postponed, device still open\n",
+	     dev->name);
+#endif
+      link->state |= DEV_STALE_CONFIG;
+      return;
+    }
+
+  /* Don't bother checking to see if these succeed or not */
+  iounmap((u_char *)dev->mem_start);
+  CardServices(ReleaseWindow, link->win);
+  CardServices(ReleaseConfiguration, link->handle);
+  CardServices(ReleaseIO, link->handle, &link->io);
+  CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+  link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG);
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
+#endif
+} /* wv_pcmcia_release */
+
+/*------------------------------------------------------------------*/
+/*
+ * Sometimes, wavelan_detach can't be performed following a call from
+ * cardmgr (device still open, pcmcia_release not done) and the device
+ * is put in a STALE_LINK state and remains in memory.
+ *
+ * This function run through our current list of device and attempt
+ * another time to remove them. We hope that since last time the
+ * device has properly been closed.
+ *
+ * (called by wavelan_attach() & cleanup_module())
+ */
+static void
+wv_flush_stale_links(void)
+{
+  dev_link_t *	link;		/* Current node in linked list */
+  dev_link_t *	next;		/* Next node in linked list */
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "-> wv_flush_stale_links(0x%p)\n", dev_list);
+#endif
+
+  /* Go through the list */
+  for (link = dev_list; link; link = next)
+    {
+      next = link->next;
+
+      /* Check if in need of being removed */
+      if((link->state & DEV_STALE_LINK) ||
+	 (! (link->state & DEV_PRESENT)))
+	wavelan_detach(link);
+
+    }
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "<- wv_flush_stale_links()\n");
+#endif
+}
+
+/************************ INTERRUPT HANDLING ************************/
+
+/*
+ * This function is the interrupt handler for the WaveLAN card. This
+ * routine will be called whenever: 
+ *	1. A packet is received.
+ *	2. A packet has successfully been transferred and the unit is
+ *	   ready to transmit another packet.
+ *	3. A command has completed execution.
+ */
+static void
+wavelan_interrupt(int		irq,
+		  void *	dev_id,
+		  struct pt_regs * regs)
+{
+  device *	dev;
+  net_local *	lp;
+  ioaddr_t	base;
+  int		status0;
+  u_int		tx_status;
+
+  if((dev = (device *)dev_id) == (device *) NULL)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n",
+	     irq);
+#endif
+      return;
+    }
+
+#ifdef DEBUG_INTERRUPT_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
+#endif
+
+  lp = (net_local *) dev->priv;
+  base = dev->base_addr;
+
+#ifdef DEBUG_INTERRUPT_INFO
+  /* Check state of our spinlock (it should be cleared) */
+  if(spin_is_locked(&lp->spinlock))
+    printk(KERN_DEBUG
+	   "%s: wavelan_interrupt(): spinlock is already locked !!!\n",
+	   dev->name);
+#endif
+
+  /* Prevent reentrancy. We need to do that because we may have
+   * multiple interrupt handler running concurently.
+   * It is safe because wv_splhi() disable interrupts before aquiring
+   * the spinlock. */
+  spin_lock(&lp->spinlock);
+
+  /* Treat all pending interrupts */
+  while(1)
+    {
+      /* ---------------- INTERRUPT CHECKING ---------------- */
+      /*
+       * Look for the interrupt and verify the validity
+       */
+      outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
+      status0 = inb(LCSR(base));
+
+#ifdef DEBUG_INTERRUPT_INFO
+      printk(KERN_DEBUG "status0 0x%x [%s => 0x%x]", status0, 
+	     (status0&SR0_INTERRUPT)?"int":"no int",status0&~SR0_INTERRUPT);
+      if(status0&SR0_INTERRUPT)
+	{
+	  printk(" [%s => %d]\n", (status0 & SR0_CHNL) ? "chnl" :
+		 ((status0 & SR0_EXECUTION) ? "cmd" :
+		  ((status0 & SR0_RECEPTION) ? "recv" : "unknown")),
+		 (status0 & SR0_EVENT_MASK));
+	}
+      else
+	printk("\n");
+#endif
+
+      /* Return if no actual interrupt from i82593 (normal exit) */
+      if(!(status0 & SR0_INTERRUPT))
+	break;
+
+      /* If interrupt is both Rx and Tx or none...
+       * This code in fact is there to catch the spurious interrupt
+       * when you remove the wavelan pcmcia card from the socket */
+      if(((status0 & SR0_BOTH_RX_TX) == SR0_BOTH_RX_TX) ||
+	 ((status0 & SR0_BOTH_RX_TX) == 0x0))
+	{
+#ifdef DEBUG_INTERRUPT_INFO
+	  printk(KERN_INFO "%s: wv_interrupt(): bogus interrupt (or from dead card) : %X\n",
+		 dev->name, status0);
+#endif
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
+	  break;
+	}
+
+      /* ----------------- RECEIVING PACKET ----------------- */
+      /*
+       * When the wavelan signal the reception of a new packet,
+       * we call wv_packet_rcv() to copy if from the buffer and
+       * send it to NET3
+       */
+      if(status0 & SR0_RECEPTION)
+	{
+#ifdef DEBUG_INTERRUPT_INFO
+	  printk(KERN_DEBUG "%s: wv_interrupt(): receive\n", dev->name);
+#endif
+
+	  if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT)
+	    {
+#ifdef DEBUG_INTERRUPT_ERROR
+	      printk(KERN_INFO "%s: wv_interrupt(): receive buffer overflow\n",
+		     dev->name);
+#endif
+	      lp->stats.rx_over_errors++;
+	      lp->overrunning = 1;
+      	    }
+
+	  /* Get the packet */
+	  wv_packet_rcv(dev);
+	  lp->overrunning = 0;
+
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
+	  continue;
+    	}
+
+      /* ---------------- COMMAND COMPLETION ---------------- */
+      /*
+       * Interrupts issued when the i82593 has completed a command.
+       * Most likely : transmission done
+       */
+
+      /* If a transmission has been done */
+      if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
+	 (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
+	 (status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE)
+	{
+#ifdef DEBUG_TX_ERROR
+	  if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE)
+	    printk(KERN_INFO "%s: wv_interrupt(): packet transmitted without CRC.\n",
+		   dev->name);
+#endif
+
+	  /* Get transmission status */
+	  tx_status = inb(LCSR(base));
+	  tx_status |= (inb(LCSR(base)) << 8);
+#ifdef DEBUG_INTERRUPT_INFO
+	  printk(KERN_DEBUG "%s: wv_interrupt(): transmission done\n",
+		 dev->name);
+	  {
+	    u_int	rcv_bytes;
+	    u_char	status3;
+	    rcv_bytes = inb(LCSR(base));
+	    rcv_bytes |= (inb(LCSR(base)) << 8);
+	    status3 = inb(LCSR(base));
+	    printk(KERN_DEBUG "tx_status 0x%02x rcv_bytes 0x%02x status3 0x%x\n",
+		   tx_status, rcv_bytes, (u_int) status3);
+	  }
+#endif
+	  /* Check for possible errors */
+	  if((tx_status & TX_OK) != TX_OK)
+	    {
+	      lp->stats.tx_errors++;
+
+	      if(tx_status & TX_FRTL)
+		{
+#ifdef DEBUG_TX_ERROR
+		  printk(KERN_INFO "%s: wv_interrupt(): frame too long\n",
+			 dev->name);
+#endif
+		}
+	      if(tx_status & TX_UND_RUN)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): DMA underrun\n",
+			 dev->name);
+#endif
+		  lp->stats.tx_aborted_errors++;
+		}
+	      if(tx_status & TX_LOST_CTS)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): no CTS\n", dev->name);
+#endif
+		  lp->stats.tx_carrier_errors++;
+		}
+	      if(tx_status & TX_LOST_CRS)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): no carrier\n",
+			 dev->name);
+#endif
+		  lp->stats.tx_carrier_errors++;
+		}
+	      if(tx_status & TX_HRT_BEAT)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): heart beat\n", dev->name);
+#endif
+		  lp->stats.tx_heartbeat_errors++;
+		}
+	      if(tx_status & TX_DEFER)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): channel jammed\n",
+			 dev->name);
+#endif
+		}
+	      /* Ignore late collisions since they're more likely to happen
+	       * here (the WaveLAN design prevents the LAN controller from
+	       * receiving while it is transmitting). We take action only when
+	       * the maximum retransmit attempts is exceeded.
+	       */
+	      if(tx_status & TX_COLL)
+		{
+		  if(tx_status & TX_MAX_COL)
+		    {
+#ifdef DEBUG_TX_FAIL
+		      printk(KERN_DEBUG "%s: wv_interrupt(): channel congestion\n",
+			     dev->name);
+#endif
+		      if(!(tx_status & TX_NCOL_MASK))
+			{
+			  lp->stats.collisions += 0x10;
+			}
+		    }
+		}
+	    }	/* if(!(tx_status & TX_OK)) */
+
+	  lp->stats.collisions += (tx_status & TX_NCOL_MASK);
+	  lp->stats.tx_packets++;
+
+	  netif_wake_queue(dev);
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
+    	} 
+      else	/* if interrupt = transmit done or retransmit done */
+	{
+#ifdef DEBUG_INTERRUPT_ERROR
+	  printk(KERN_INFO "wavelan_cs: unknown interrupt, status0 = %02x\n",
+		 status0);
+#endif
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
+    	}
+    }	/* while(1) */
+
+  spin_unlock(&lp->spinlock);
+
+#ifdef DEBUG_INTERRUPT_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
+#endif
+} /* wv_interrupt */
+
+/*------------------------------------------------------------------*/
+/*
+ * Watchdog: when we start a transmission, a timer is set for us in the
+ * kernel.  If the transmission completes, this timer is disabled. If
+ * the timer expires, we are called and we try to unlock the hardware.
+ *
+ * Note : This watchdog is move clever than the one in the ISA driver,
+ * because it try to abort the current command before reseting
+ * everything...
+ * On the other hand, it's a bit simpler, because we don't have to
+ * deal with the multiple Tx buffers...
+ */
+static void
+wavelan_watchdog(device *	dev)
+{
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			aborted = FALSE;
+
+#ifdef DEBUG_INTERRUPT_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
+#endif
+
+#ifdef DEBUG_INTERRUPT_ERROR
+  printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n",
+	 dev->name);
+#endif
+
+  wv_splhi(lp, &flags);
+
+  /* Ask to abort the current command */
+  outb(OP0_ABORT, LCCR(base));
+
+  /* Wait for the end of the command (a bit hackish) */
+  if(wv_82593_cmd(dev, "wavelan_watchdog(): abort",
+		  OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED))
+    aborted = TRUE;
+
+  /* Release spinlock here so that wv_hw_reset() can grab it */
+  wv_splx(lp, &flags);
+
+  /* Check if we were successful in aborting it */
+  if(!aborted)
+    {
+      /* It seem that it wasn't enough */
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "%s: wavelan_watchdog: abort failed, trying reset\n",
+	     dev->name);
+#endif
+      wv_hw_reset(dev);
+    }
+
+#ifdef DEBUG_PSA_SHOW
+  {
+    psa_t		psa;
+    psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+    wv_psa_show(&psa);
+  }
+#endif
+#ifdef DEBUG_MMC_SHOW
+  wv_mmc_show(dev);
+#endif
+#ifdef DEBUG_I82593_SHOW
+  wv_ru_show(dev);
+#endif
+
+  /* We are no more waiting for something... */
+  netif_wake_queue(dev);
+
+#ifdef DEBUG_INTERRUPT_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
+#endif
+}
+
+/********************* CONFIGURATION CALLBACKS *********************/
+/*
+ * Here are the functions called by the pcmcia package (cardmgr) and
+ * linux networking (NET3) for initialization, configuration and
+ * deinstallations of the Wavelan Pcmcia Hardware.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Configure and start up the WaveLAN PCMCIA adaptor.
+ * Called by NET3 when it "open" the device.
+ */
+static int
+wavelan_open(device *	dev)
+{
+  dev_link_t *	link = ((net_local *) dev->priv)->link;
+  net_local *	lp = (net_local *)dev->priv;
+  ioaddr_t	base = dev->base_addr;
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
+	 (unsigned int) dev);
+#endif
+
+  /* Check if the modem is powered up (wavelan_close() power it down */
+  if(hasr_read(base) & HASR_NO_CLK)
+    {
+      /* Power up (power up time is 250us) */
+      hacr_write(base, HACR_DEFAULT);
+
+      /* Check if the module has been powered up... */
+      if(hasr_read(base) & HASR_NO_CLK)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "%s: wavelan_open(): modem not connected\n",
+		 dev->name);
+#endif
+	  return FALSE;
+	}
+    }
+
+  /* Start reception and declare the driver ready */
+  if(!lp->configured)
+    return FALSE;
+  if(!wv_ru_start(dev))
+    wv_hw_reset(dev);		/* If problem : reset */
+  netif_start_queue(dev);
+
+  /* Mark the device as used */
+  link->open++;
+  MOD_INC_USE_COUNT;
+
+#ifdef WAVELAN_ROAMING
+  if(do_roaming)
+    wv_roam_init(dev);
+#endif	/* WAVELAN_ROAMING */
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
+#endif
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Shutdown the WaveLAN PCMCIA adaptor.
+ * Called by NET3 when it "close" the device.
+ */
+static int
+wavelan_close(device *	dev)
+{
+  dev_link_t *	link = ((net_local *) dev->priv)->link;
+  ioaddr_t	base = dev->base_addr;
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
+	 (unsigned int) dev);
+#endif
+
+  /* If the device isn't open, then nothing to do */
+  if(!link->open)
+    {
+#ifdef DEBUG_CONFIG_INFO
+      printk(KERN_DEBUG "%s: wavelan_close(): device not open\n", dev->name);
+#endif
+      return 0;
+    }
+
+#ifdef WAVELAN_ROAMING
+  /* Cleanup of roaming stuff... */
+  if(do_roaming)
+    wv_roam_cleanup(dev);
+#endif	/* WAVELAN_ROAMING */
+
+  link->open--;
+  MOD_DEC_USE_COUNT;
+
+  /* If the card is still present */
+  if(netif_running(dev))
+    {
+      netif_stop_queue(dev);
+
+      /* Stop receiving new messages and wait end of transmission */
+      wv_ru_stop(dev);
+
+      /* Power down the module */
+      hacr_write(base, HACR_DEFAULT & (~HACR_PWR_STAT));
+    }
+  else
+    /* The card is no more there (flag is activated in wv_pcmcia_release) */
+    if(link->state & DEV_STALE_CONFIG)
+      wv_pcmcia_release((u_long)link);
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name);
+#endif
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * wavelan_attach() creates an "instance" of the driver, allocating
+ * local data structures for one device (one interface).  The device
+ * is registered with Card Services.
+ *
+ * The dev_link structure is initialized, but we don't actually
+ * configure the card at this point -- we wait until we receive a
+ * card insertion event.
+ */
+static dev_link_t *
+wavelan_attach(void)
+{
+  client_reg_t	client_reg;	/* Register with cardmgr */
+  dev_link_t *	link;		/* Info for cardmgr */
+  device *	dev;		/* Interface generic data */
+  net_local *	lp;		/* Interface specific data */
+  int		i, ret;
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "-> wavelan_attach()\n");
+#endif
+
+  /* Perform some cleanup */
+  wv_flush_stale_links();
+
+  /* Initialize the dev_link_t structure */
+  link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+  if (!link) return NULL;
+  memset(link, 0, sizeof(struct dev_link_t));
+
+  /* Unused for the Wavelan */
+  link->release.function = &wv_pcmcia_release;
+  link->release.data = (u_long) link;
+
+  /* The io structure describes IO port mapping */
+  link->io.NumPorts1 = 8;
+  link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+  link->io.IOAddrLines = 3;
+
+  /* Interrupt setup */
+  link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+  link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+  if (irq_list[0] == -1)
+    link->irq.IRQInfo2 = irq_mask;
+  else
+    for (i = 0; i < 4; i++)
+      link->irq.IRQInfo2 |= 1 << irq_list[i];
+  link->irq.Handler = wavelan_interrupt;
+
+  /* General socket configuration */
+  link->conf.Attributes = CONF_ENABLE_IRQ;
+  link->conf.Vcc = 50;
+  link->conf.IntType = INT_MEMORY_AND_IO;
+
+  /* Chain drivers */
+  link->next = dev_list;
+  dev_list = link;
+
+  /* Allocate the generic data structure */
+  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+  if (!dev) {
+      kfree(link);
+      return NULL;
+  }
+  memset(dev, 0x00, sizeof(struct net_device));
+  link->priv = link->irq.Instance = dev;
+
+  /* Allocate the wavelan-specific data structure. */
+  dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
+  if (!lp) {
+      kfree(link);
+      kfree(dev);
+      return NULL;
+  }
+  memset(lp, 0x00, sizeof(net_local));
+
+  /* Init specific data */
+  lp->configured = 0;
+  lp->reconfig_82593 = FALSE;
+  lp->nresets = 0;
+  /* Multicast stuff */
+  lp->promiscuous = 0;
+  lp->allmulticast = 0;
+  lp->mc_count = 0;
+
+  /* Init spinlock */
+  spin_lock_init(&lp->spinlock);
+
+  /* back links */
+  lp->link = link;
+  lp->dev = dev;
+
+  /* Standard setup for generic data */
+  ether_setup(dev);
+
+  /* wavelan NET3 callbacks */
+  dev->open = &wavelan_open;
+  dev->stop = &wavelan_close;
+  dev->hard_start_xmit = &wavelan_packet_xmit;
+  dev->get_stats = &wavelan_get_stats;
+  dev->set_multicast_list = &wavelan_set_multicast_list;
+#ifdef SET_MAC_ADDRESS
+  dev->set_mac_address = &wavelan_set_mac_address;
+#endif	/* SET_MAC_ADDRESS */
+
+  /* Set the watchdog timer */
+  dev->tx_timeout	= &wavelan_watchdog;
+  dev->watchdog_timeo	= WATCHDOG_JIFFIES;
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+  dev->do_ioctl = wavelan_ioctl;	/* wireless extensions */
+  dev->get_wireless_stats = wavelan_get_wireless_stats;
+#endif
+
+  /* Other specific data */
+  dev->mtu = WAVELAN_MTU;
+
+  /* Register with Card Services */
+  client_reg.dev_info = &dev_info;
+  client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+  client_reg.EventMask = 
+    CS_EVENT_REGISTRATION_COMPLETE |
+    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+  client_reg.event_handler = &wavelan_event;
+  client_reg.Version = 0x0210;
+  client_reg.event_callback_args.client_data = link;
+
+#ifdef DEBUG_CONFIG_INFO
+  printk(KERN_DEBUG "wavelan_attach(): almost done, calling CardServices\n");
+#endif
+
+  ret = CardServices(RegisterClient, &link->handle, &client_reg);
+  if(ret != 0)
+    {
+      cs_error(link->handle, RegisterClient, ret);
+      wavelan_detach(link);
+      return NULL;
+    }
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "<- wavelan_attach()\n");
+#endif
+
+  return link;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This deletes a driver "instance".  The device is de-registered with
+ * Card Services.  If it has been released, all local data structures
+ * are freed.  Otherwise, the structures will be freed when the device
+ * is released.
+ */
+static void
+wavelan_detach(dev_link_t *	link)
+{
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link);
+#endif
+
+  /*
+   * If the device is currently configured and active, we won't
+   * actually delete it yet.  Instead, it is marked so that when the
+   * release() function is called, that will trigger a proper
+   * detach().
+   */
+  if(link->state & DEV_CONFIG)
+    {
+      /* Some others haven't done their job : give them another chance */
+      wv_pcmcia_release((u_long) link);
+      if(link->state & DEV_STALE_CONFIG)
+	{
+#ifdef DEBUG_CONFIG_INFO
+	  printk(KERN_DEBUG "wavelan_detach: detach postponed,"
+		 " '%s' still locked\n", link->dev->dev_name);
+#endif
+	  link->state |= DEV_STALE_LINK;
+	  return;
+	}
+    }
+
+  /* Break the link with Card Services */
+  if(link->handle)
+    CardServices(DeregisterClient, link->handle);
+    
+  /* Remove the interface data from the linked list */
+  if(dev_list == link)
+    dev_list = link->next;
+  else
+    {
+      dev_link_t *	prev = dev_list;
+
+      while((prev != (dev_link_t *) NULL) && (prev->next != link))
+	prev = prev->next;
+
+      if(prev == (dev_link_t *) NULL)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "wavelan_detach : Attempting to remove a nonexistent device.\n");
+#endif
+	  return;
+	}
+
+      prev->next = link->next;
+    }
+
+  /* Free pieces */
+  if(link->priv)
+    {
+      device *	dev = (device *) link->priv;
+
+      /* Remove ourselves from the kernel list of ethernet devices */
+      /* Warning : can't be called from interrupt, timer or wavelan_close() */
+      if(link->dev != NULL)
+	unregister_netdev(dev);
+      link->dev = NULL;
+
+      if(dev->priv)
+	{
+	  /* Sound strange, but safe... */
+	  ((net_local *) dev->priv)->link = (dev_link_t *) NULL;
+	  ((net_local *) dev->priv)->dev = (device *) NULL;
+	  kfree(dev->priv);
+	}
+      kfree(link->priv);
+    }
+  kfree(link);
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "<- wavelan_detach()\n");
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * The card status event handler. Mostly, this schedules other stuff
+ * to run after an event is received. A CARD_REMOVAL event also sets
+ * some flags to discourage the net drivers from trying to talk to the
+ * card any more.
+ */
+static int
+wavelan_event(event_t		event,		/* The event received */
+	      int		priority,
+	      event_callback_args_t *	args)
+{
+  dev_link_t *	link = (dev_link_t *) args->client_data;
+  device *	dev = (device *) link->priv;
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "->wavelan_event(): %s\n",
+	 ((event == CS_EVENT_REGISTRATION_COMPLETE)?"registration complete" :
+	  ((event == CS_EVENT_CARD_REMOVAL) ? "card removal" :
+	   ((event == CS_EVENT_CARD_INSERTION) ? "card insertion" :
+	    ((event == CS_EVENT_PM_SUSPEND) ? "pm suspend" :
+	     ((event == CS_EVENT_RESET_PHYSICAL) ? "physical reset" :
+	      ((event == CS_EVENT_PM_RESUME) ? "pm resume" :
+	       ((event == CS_EVENT_CARD_RESET) ? "card reset" :
+		"unknown"))))))));
+#endif
+
+    switch(event)
+      {
+      case CS_EVENT_REGISTRATION_COMPLETE:
+#ifdef DEBUG_CONFIG_INFO
+	printk(KERN_DEBUG "wavelan_cs: registration complete\n");
+#endif
+	break;
+
+      case CS_EVENT_CARD_REMOVAL:
+	/* Oups ! The card is no more there */
+	link->state &= ~DEV_PRESENT;
+	if(link->state & DEV_CONFIG)
+	  {
+	    /* Accept no more transmissions */
+	    netif_device_detach(dev);
+
+	    /* Release the card */
+	    wv_pcmcia_release((u_long) link);
+	  }
+	break;
+
+      case CS_EVENT_CARD_INSERTION:
+	/* Reset and configure the card */
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	if(wv_pcmcia_config(link) &&
+	   wv_hw_config(dev))
+	  wv_init_info(dev);
+	else
+	  dev->irq = 0;
+	break;
+
+      case CS_EVENT_PM_SUSPEND:
+	/* NB: wavelan_close will be called, but too late, so we are
+	 * obliged to close nicely the wavelan here. David, could you
+	 * close the device before suspending them ? And, by the way,
+	 * could you, on resume, add a "route add -net ..." after the
+	 * ifconfig up ? Thanks... */
+
+	/* Stop receiving new messages and wait end of transmission */
+	wv_ru_stop(dev);
+
+	/* Power down the module */
+	hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT));
+
+	/* The card is now suspended */
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+      case CS_EVENT_RESET_PHYSICAL:
+    	if(link->state & DEV_CONFIG)
+	  {
+      	    if(link->open)
+	      netif_device_detach(dev);
+      	    CardServices(ReleaseConfiguration, link->handle);
+	  }
+	break;
+
+      case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+      case CS_EVENT_CARD_RESET:
+	if(link->state & DEV_CONFIG)
+	  {
+      	    CardServices(RequestConfiguration, link->handle, &link->conf);
+      	    if(link->open)	/* If RESET -> True, If RESUME -> False ? */
+	      {
+		wv_hw_reset(dev);
+		netif_device_attach(dev);
+	      }
+	  }
+	break;
+    }
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "<-wavelan_event()\n");
+#endif
+  return 0;
+}
+
+/****************************** MODULE ******************************/
+/*
+ * Module entry points : insertion & removal
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Module insertion : initialisation of the module.
+ * Register the card with cardmgr...
+ */
+static int __init
+init_wavelan_cs(void)
+{
+  servinfo_t	serv;
+
+#ifdef DEBUG_MODULE_TRACE
+  printk(KERN_DEBUG "-> init_wavelan_cs()\n");
+#ifdef DEBUG_VERSION_SHOW
+  printk(KERN_DEBUG "%s", version);
+#endif
+#endif
+
+  CardServices(GetCardServicesInfo, &serv);
+  if(serv.Revision != CS_RELEASE_CODE)
+    {
+#ifdef DEBUG_CONFIG_ERRORS
+      printk(KERN_WARNING "init_wavelan_cs: Card Services release does not match!\n");
+#endif
+      return -1;
+    }
+
+  register_pccard_driver(&dev_info, &wavelan_attach, &wavelan_detach);
+
+#ifdef DEBUG_MODULE_TRACE
+  printk(KERN_DEBUG "<- init_wavelan_cs()\n");
+#endif
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Module removal
+ */
+static void __exit
+exit_wavelan_cs(void)
+{
+#ifdef DEBUG_MODULE_TRACE
+  printk(KERN_DEBUG "-> cleanup_module()\n");
+#endif
+#ifdef DEBUG_BASIC_SHOW
+  printk(KERN_NOTICE "wavelan_cs: unloading\n");
+#endif
+
+  /* Do some cleanup of the device list */
+  wv_flush_stale_links();
+
+  /* If there remain some devices... */
+#ifdef DEBUG_CONFIG_ERRORS
+  if(dev_list != NULL)
+    {
+      /* Honestly, if this happen we are in a deep s**t */
+      printk(KERN_INFO "wavelan_cs: devices remaining when removing module\n");
+      printk(KERN_INFO "Please flush your disks and reboot NOW !\n");
+    }
+#endif
+
+  unregister_pccard_driver(&dev_info);
+
+#ifdef DEBUG_MODULE_TRACE
+  printk(KERN_DEBUG "<- cleanup_module()\n");
+#endif
+}
+
+module_init(init_wavelan_cs);
+module_exit(exit_wavelan_cs);
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/wavelan_cs.h linux/drivers/net/wireless/wavelan_cs.h
--- v2.5.2/linux/drivers/net/wireless/wavelan_cs.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/wavelan_cs.h	Mon Jan 21 16:04:47 2002
@@ -0,0 +1,386 @@
+/*
+ *	Wavelan Pcmcia driver
+ *
+ *		Jean II - HPLB '96
+ *
+ * Reorganization and extension of the driver.
+ * Original copyright follow. See wavelan_cs.h for details.
+ *
+ * This file contain the declarations of the Wavelan hardware. Note that
+ * the Pcmcia Wavelan include a i82593 controller (see definitions in
+ * file i82593.h).
+ *
+ * The main difference between the pcmcia hardware and the ISA one is
+ * the Ethernet Controller (i82593 instead of i82586). The i82593 allow
+ * only one send buffer. The PSA (Parameter Storage Area : EEprom for
+ * permanent storage of various info) is memory mapped, but not the
+ * MMI (Modem Management Interface).
+ */
+
+/*
+ * Definitions for the AT&T GIS (formerly NCR) WaveLAN PCMCIA card: 
+ *   An Ethernet-like radio transceiver controlled by an Intel 82593
+ *   coprocessor.
+ *
+ *
+ ****************************************************************************
+ *   Copyright 1995
+ *   Anthony D. Joseph
+ *   Massachusetts Institute of Technology
+ *
+ *   Permission to use, copy, modify, and distribute this program
+ *   for any purpose and without fee is hereby granted, provided
+ *   that this copyright and permission notice appear on all copies
+ *   and supporting documentation, the name of M.I.T. not be used
+ *   in advertising or publicity pertaining to distribution of the
+ *   program without specific prior permission, and notice be given
+ *   in supporting documentation that copying and distribution is
+ *   by permission of M.I.T.  M.I.T. makes no representations about
+ *   the suitability of this software for any purpose.  It is pro-
+ *   vided "as is" without express or implied warranty.         
+ ****************************************************************************
+ *
+ *
+ * Credits:
+ *     Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht for
+ *       providing extremely useful information about WaveLAN PCMCIA hardware
+ *
+ *     This driver is based upon several other drivers, in particular:
+ *       David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter
+ *       Bruce Janson's Linux driver for the AT-bus WaveLAN adapter
+ *	 Anders Klemets' PCMCIA WaveLAN adapter driver
+ *       Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter
+ */
+
+#ifndef _WAVELAN_CS_H
+#define	_WAVELAN_CS_H
+
+/************************** MAGIC NUMBERS ***************************/
+
+/* The detection of the wavelan card is made by reading the MAC address
+ * from the card and checking it. If you have a non AT&T product (OEM,
+ * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this
+ * part to accomodate your hardware...
+ */
+const unsigned char	MAC_ADDRESSES[][3] =
+{
+  { 0x08, 0x00, 0x0E },		/* AT&T Wavelan (standard) & DEC RoamAbout */
+  { 0x08, 0x00, 0x6A },		/* AT&T Wavelan (alternate) */
+  { 0x00, 0x00, 0xE1 },		/* Hitachi Wavelan */
+  { 0x00, 0x60, 0x1D }		/* Lucent Wavelan (another one) */
+  /* Add your card here and send me the patch ! */
+};
+
+/*
+ * Constants used to convert channels to frequencies
+ */
+
+/* Frequency available in the 2.0 modem, in units of 250 kHz
+ * (as read in the offset register of the dac area).
+ * Used to map channel numbers used by `wfreqsel' to frequencies
+ */
+const short	channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8,
+				    0xD0, 0xF0, 0xF8, 0x150 };
+
+/* Frequencies of the 1.0 modem (fixed frequencies).
+ * Use to map the PSA `subband' to a frequency
+ * Note : all frequencies apart from the first one need to be multiplied by 10
+ */
+const int	fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
+
+
+/*************************** PC INTERFACE ****************************/
+
+/* WaveLAN host interface definitions */
+
+#define	LCCR(base)	(base)		/* LAN Controller Command Register */
+#define	LCSR(base)	(base)		/* LAN Controller Status Register */
+#define	HACR(base)	(base+0x1)	/* Host Adapter Command Register */
+#define	HASR(base)	(base+0x1)	/* Host Adapter Status Register */
+#define PIORL(base)	(base+0x2)	/* Program I/O Register Low */
+#define RPLL(base)	(base+0x2)	/* Receive Pointer Latched Low */
+#define PIORH(base)	(base+0x3)	/* Program I/O Register High */
+#define RPLH(base)	(base+0x3)	/* Receive Pointer Latched High */
+#define PIOP(base)	(base+0x4)	/* Program I/O Port */
+#define MMR(base)	(base+0x6)	/* MMI Address Register */
+#define MMD(base)	(base+0x7)	/* MMI Data Register */
+
+/* Host Adaptor Command Register bit definitions */
+
+#define HACR_LOF	  (1 << 3)	/* Lock Out Flag, toggle every 250ms */
+#define HACR_PWR_STAT	  (1 << 4)	/* Power State, 1=active, 0=sleep */
+#define HACR_TX_DMA_RESET (1 << 5)	/* Reset transmit DMA ptr on high */
+#define HACR_RX_DMA_RESET (1 << 6)	/* Reset receive DMA ptr on high */
+#define HACR_ROM_WEN	  (1 << 7)	/* EEPROM write enabled when true */
+
+#define HACR_RESET              (HACR_TX_DMA_RESET | HACR_RX_DMA_RESET)
+#define	HACR_DEFAULT		(HACR_PWR_STAT)
+
+/* Host Adapter Status Register bit definitions */
+
+#define HASR_MMI_BUSY	(1 << 2)	/* MMI is busy when true */
+#define HASR_LOF	(1 << 3)	/* Lock out flag status */
+#define HASR_NO_CLK	(1 << 4)	/* active when modem not connected */
+
+/* Miscellaneous bit definitions */
+
+#define PIORH_SEL_TX	(1 << 5)	/* PIOR points to 0=rx/1=tx buffer */
+#define MMR_MMI_WR	(1 << 0)	/* Next MMI cycle is 0=read, 1=write */
+#define PIORH_MASK	0x1f		/* only low 5 bits are significant */
+#define RPLH_MASK	0x1f		/* only low 5 bits are significant */
+#define MMI_ADDR_MASK	0x7e		/* Bits 1-6 of MMR are significant */
+
+/* Attribute Memory map */
+
+#define CIS_ADDR	0x0000		/* Card Information Status Register */
+#define PSA_ADDR	0x0e00		/* Parameter Storage Area address */
+#define EEPROM_ADDR	0x1000		/* EEPROM address (unused ?) */
+#define COR_ADDR	0x4000		/* Configuration Option Register */
+
+/* Configuration Option Register bit definitions */
+
+#define COR_CONFIG	(1 << 0)	/* Config Index, 0 when unconfigured */
+#define COR_SW_RESET	(1 << 7)	/* Software Reset on true */
+#define COR_LEVEL_IRQ	(1 << 6)	/* Level IRQ */
+
+/* Local Memory map */
+
+#define RX_BASE		0x0000		/* Receive memory, 8 kB */
+#define TX_BASE		0x2000		/* Transmit memory, 2 kB */
+#define UNUSED_BASE	0x2800		/* Unused, 22 kB */
+#define RX_SIZE		(TX_BASE-RX_BASE)	/* Size of receive area */
+#define RX_SIZE_SHIFT	6		/* Bits to shift in stop register */
+
+#define TRUE  1
+#define FALSE 0
+
+#define MOD_ENAL 1
+#define MOD_PROM 2
+
+/* Size of a MAC address */
+#define WAVELAN_ADDR_SIZE	6
+
+/* Maximum size of Wavelan packet */
+#define WAVELAN_MTU	1500
+
+#define	MAXDATAZ		(6 + 6 + 2 + WAVELAN_MTU)
+
+/********************** PARAMETER STORAGE AREA **********************/
+
+/*
+ * Parameter Storage Area (PSA).
+ */
+typedef struct psa_t	psa_t;
+struct psa_t
+{
+  /* For the PCMCIA Adapter, locations 0x00-0x0F are unused and fixed at 00 */
+  unsigned char	psa_io_base_addr_1;	/* [0x00] Base address 1 ??? */
+  unsigned char	psa_io_base_addr_2;	/* [0x01] Base address 2 */
+  unsigned char	psa_io_base_addr_3;	/* [0x02] Base address 3 */
+  unsigned char	psa_io_base_addr_4;	/* [0x03] Base address 4 */
+  unsigned char	psa_rem_boot_addr_1;	/* [0x04] Remote Boot Address 1 */
+  unsigned char	psa_rem_boot_addr_2;	/* [0x05] Remote Boot Address 2 */
+  unsigned char	psa_rem_boot_addr_3;	/* [0x06] Remote Boot Address 3 */
+  unsigned char	psa_holi_params;	/* [0x07] HOst Lan Interface (HOLI) Parameters */
+  unsigned char	psa_int_req_no;		/* [0x08] Interrupt Request Line */
+  unsigned char	psa_unused0[7];		/* [0x09-0x0F] unused */
+
+  unsigned char	psa_univ_mac_addr[WAVELAN_ADDR_SIZE];	/* [0x10-0x15] Universal (factory) MAC Address */
+  unsigned char	psa_local_mac_addr[WAVELAN_ADDR_SIZE];	/* [0x16-1B] Local MAC Address */
+  unsigned char	psa_univ_local_sel;	/* [0x1C] Universal Local Selection */
+#define		PSA_UNIVERSAL	0		/* Universal (factory) */
+#define		PSA_LOCAL	1		/* Local */
+  unsigned char	psa_comp_number;	/* [0x1D] Compatability Number: */
+#define		PSA_COMP_PC_AT_915	0 	/* PC-AT 915 MHz	*/
+#define		PSA_COMP_PC_MC_915	1 	/* PC-MC 915 MHz	*/
+#define		PSA_COMP_PC_AT_2400	2 	/* PC-AT 2.4 GHz	*/
+#define		PSA_COMP_PC_MC_2400	3 	/* PC-MC 2.4 GHz	*/
+#define		PSA_COMP_PCMCIA_915	4 	/* PCMCIA 915 MHz or 2.0 */
+  unsigned char	psa_thr_pre_set;	/* [0x1E] Modem Threshold Preset */
+  unsigned char	psa_feature_select;	/* [0x1F] Call code required (1=on) */
+#define		PSA_FEATURE_CALL_CODE	0x01 	/* Call code required (Japan) */
+  unsigned char	psa_subband;		/* [0x20] Subband	*/
+#define		PSA_SUBBAND_915		0	/* 915 MHz or 2.0 */
+#define		PSA_SUBBAND_2425	1	/* 2425 MHz	*/
+#define		PSA_SUBBAND_2460	2	/* 2460 MHz	*/
+#define		PSA_SUBBAND_2484	3	/* 2484 MHz	*/
+#define		PSA_SUBBAND_2430_5	4	/* 2430.5 MHz	*/
+  unsigned char	psa_quality_thr;	/* [0x21] Modem Quality Threshold */
+  unsigned char	psa_mod_delay;		/* [0x22] Modem Delay ??? (reserved) */
+  unsigned char	psa_nwid[2];		/* [0x23-0x24] Network ID */
+  unsigned char	psa_nwid_select;	/* [0x25] Network ID Select On Off */
+  unsigned char	psa_encryption_select;	/* [0x26] Encryption On Off */
+  unsigned char	psa_encryption_key[8];	/* [0x27-0x2E] Encryption Key */
+  unsigned char	psa_databus_width;	/* [0x2F] AT bus width select 8/16 */
+  unsigned char	psa_call_code[8];	/* [0x30-0x37] (Japan) Call Code */
+  unsigned char	psa_nwid_prefix[2];	/* [0x38-0x39] Roaming domain */
+  unsigned char	psa_reserved[2];	/* [0x3A-0x3B] Reserved - fixed 00 */
+  unsigned char	psa_conf_status;	/* [0x3C] Conf Status, bit 0=1:config*/
+  unsigned char	psa_crc[2];		/* [0x3D] CRC-16 over PSA */
+  unsigned char	psa_crc_status;		/* [0x3F] CRC Valid Flag */
+};
+
+/* Size for structure checking (if padding is correct) */
+#define	PSA_SIZE	64
+
+/* Calculate offset of a field in the above structure
+ * Warning : only even addresses are used */
+#define	psaoff(p,f) 	((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL))
+
+/******************** MODEM MANAGEMENT INTERFACE ********************/
+
+/*
+ * Modem Management Controller (MMC) write structure.
+ */
+typedef struct mmw_t	mmw_t;
+struct mmw_t
+{
+  unsigned char	mmw_encr_key[8];	/* encryption key */
+  unsigned char	mmw_encr_enable;	/* enable/disable encryption */
+#define	MMW_ENCR_ENABLE_MODE	0x02	/* Mode of security option */
+#define	MMW_ENCR_ENABLE_EN	0x01	/* Enable security option */
+  unsigned char	mmw_unused0[1];		/* unused */
+  unsigned char	mmw_des_io_invert;	/* Encryption option */
+#define	MMW_DES_IO_INVERT_RES	0x0F	/* Reserved */
+#define	MMW_DES_IO_INVERT_CTRL	0xF0	/* Control ??? (set to 0) */
+  unsigned char	mmw_unused1[5];		/* unused */
+  unsigned char	mmw_loopt_sel;		/* looptest selection */
+#define	MMW_LOOPT_SEL_DIS_NWID	0x40	/* disable NWID filtering */
+#define	MMW_LOOPT_SEL_INT	0x20	/* activate Attention Request */
+#define	MMW_LOOPT_SEL_LS	0x10	/* looptest w/o collision avoidance */
+#define MMW_LOOPT_SEL_LT3A	0x08	/* looptest 3a */
+#define	MMW_LOOPT_SEL_LT3B	0x04	/* looptest 3b */
+#define	MMW_LOOPT_SEL_LT3C	0x02	/* looptest 3c */
+#define	MMW_LOOPT_SEL_LT3D	0x01	/* looptest 3d */
+  unsigned char	mmw_jabber_enable;	/* jabber timer enable */
+  /* Abort transmissions > 200 ms */
+  unsigned char	mmw_freeze;		/* freeze / unfreeeze signal level */
+  /* 0 : signal level & qual updated for every new message, 1 : frozen */
+  unsigned char	mmw_anten_sel;		/* antenna selection */
+#define MMW_ANTEN_SEL_SEL	0x01	/* direct antenna selection */
+#define	MMW_ANTEN_SEL_ALG_EN	0x02	/* antenna selection algo. enable */
+  unsigned char	mmw_ifs;		/* inter frame spacing */
+  /* min time between transmission in bit periods (.5 us) - bit 0 ignored */
+  unsigned char	mmw_mod_delay;	 	/* modem delay (synchro) */
+  unsigned char	mmw_jam_time;		/* jamming time (after collision) */
+  unsigned char	mmw_unused2[1];		/* unused */
+  unsigned char	mmw_thr_pre_set;	/* level threshold preset */
+  /* Discard all packet with signal < this value (4) */
+  unsigned char	mmw_decay_prm;		/* decay parameters */
+  unsigned char	mmw_decay_updat_prm;	/* decay update parameterz */
+  unsigned char	mmw_quality_thr;	/* quality (z-quotient) threshold */
+  /* Discard all packet with quality < this value (3) */
+  unsigned char	mmw_netw_id_l;		/* NWID low order byte */
+  unsigned char	mmw_netw_id_h;		/* NWID high order byte */
+  /* Network ID or Domain : create virtual net on the air */
+
+  /* 2.0 Hardware extension - frequency selection support */
+  unsigned char	mmw_mode_select;	/* for analog tests (set to 0) */
+  unsigned char	mmw_unused3[1];		/* unused */
+  unsigned char	mmw_fee_ctrl;		/* frequency eeprom control */
+#define	MMW_FEE_CTRL_PRE	0x10	/* Enable protected instructions */
+#define	MMW_FEE_CTRL_DWLD	0x08	/* Download eeprom to mmc */
+#define	MMW_FEE_CTRL_CMD	0x07	/* EEprom commands : */
+#define	MMW_FEE_CTRL_READ	0x06	/* Read */
+#define	MMW_FEE_CTRL_WREN	0x04	/* Write enable */
+#define	MMW_FEE_CTRL_WRITE	0x05	/* Write data to address */
+#define	MMW_FEE_CTRL_WRALL	0x04	/* Write data to all addresses */
+#define	MMW_FEE_CTRL_WDS	0x04	/* Write disable */
+#define	MMW_FEE_CTRL_PRREAD	0x16	/* Read addr from protect register */
+#define	MMW_FEE_CTRL_PREN	0x14	/* Protect register enable */
+#define	MMW_FEE_CTRL_PRCLEAR	0x17	/* Unprotect all registers */
+#define	MMW_FEE_CTRL_PRWRITE	0x15	/* Write addr in protect register */
+#define	MMW_FEE_CTRL_PRDS	0x14	/* Protect register disable */
+  /* Never issue this command (PRDS) : it's irreversible !!! */
+
+  unsigned char	mmw_fee_addr;		/* EEprom address */
+#define	MMW_FEE_ADDR_CHANNEL	0xF0	/* Select the channel */
+#define	MMW_FEE_ADDR_OFFSET	0x0F	/* Offset in channel data */
+#define	MMW_FEE_ADDR_EN		0xC0	/* FEE_CTRL enable operations */
+#define	MMW_FEE_ADDR_DS		0x00	/* FEE_CTRL disable operations */
+#define	MMW_FEE_ADDR_ALL	0x40	/* FEE_CTRL all operations */
+#define	MMW_FEE_ADDR_CLEAR	0xFF	/* FEE_CTRL clear operations */
+
+  unsigned char	mmw_fee_data_l;		/* Write data to EEprom */
+  unsigned char	mmw_fee_data_h;		/* high octet */
+  unsigned char	mmw_ext_ant;		/* Setting for external antenna */
+#define	MMW_EXT_ANT_EXTANT	0x01	/* Select external antenna */
+#define	MMW_EXT_ANT_POL		0x02	/* Polarity of the antenna */
+#define	MMW_EXT_ANT_INTERNAL	0x00	/* Internal antenna */
+#define	MMW_EXT_ANT_EXTERNAL	0x03	/* External antenna */
+#define	MMW_EXT_ANT_IQ_TEST	0x1C	/* IQ test pattern (set to 0) */
+};
+
+/* Size for structure checking (if padding is correct) */
+#define	MMW_SIZE	37
+
+/* Calculate offset of a field in the above structure */
+#define	mmwoff(p,f) 	(unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
+
+
+/*
+ * Modem Management Controller (MMC) read structure.
+ */
+typedef struct mmr_t	mmr_t;
+struct mmr_t
+{
+  unsigned char	mmr_unused0[8];		/* unused */
+  unsigned char	mmr_des_status;		/* encryption status */
+  unsigned char	mmr_des_avail;		/* encryption available (0x55 read) */
+#define	MMR_DES_AVAIL_DES	0x55		/* DES available */
+#define	MMR_DES_AVAIL_AES	0x33		/* AES (AT&T) available */
+  unsigned char	mmr_des_io_invert;	/* des I/O invert register */
+  unsigned char	mmr_unused1[5];		/* unused */
+  unsigned char	mmr_dce_status;		/* DCE status */
+#define	MMR_DCE_STATUS_RX_BUSY		0x01	/* receiver busy */
+#define	MMR_DCE_STATUS_LOOPT_IND	0x02	/* loop test indicated */
+#define	MMR_DCE_STATUS_TX_BUSY		0x04	/* transmitter on */
+#define	MMR_DCE_STATUS_JBR_EXPIRED	0x08	/* jabber timer expired */
+#define MMR_DCE_STATUS			0x0F	/* mask to get the bits */
+  unsigned char	mmr_dsp_id;		/* DSP id (AA = Daedalus rev A) */
+  unsigned char	mmr_unused2[2];		/* unused */
+  unsigned char	mmr_correct_nwid_l;	/* # of correct NWID's rxd (low) */
+  unsigned char	mmr_correct_nwid_h;	/* # of correct NWID's rxd (high) */
+  /* Warning : Read high order octet first !!! */
+  unsigned char	mmr_wrong_nwid_l;	/* # of wrong NWID's rxd (low) */
+  unsigned char	mmr_wrong_nwid_h;	/* # of wrong NWID's rxd (high) */
+  unsigned char	mmr_thr_pre_set;	/* level threshold preset */
+#define	MMR_THR_PRE_SET		0x3F		/* level threshold preset */
+#define	MMR_THR_PRE_SET_CUR	0x80		/* Current signal above it */
+  unsigned char	mmr_signal_lvl;		/* signal level */
+#define	MMR_SIGNAL_LVL		0x3F		/* signal level */
+#define	MMR_SIGNAL_LVL_VALID	0x80		/* Updated since last read */
+  unsigned char	mmr_silence_lvl;	/* silence level (noise) */
+#define	MMR_SILENCE_LVL		0x3F		/* silence level */
+#define	MMR_SILENCE_LVL_VALID	0x80		/* Updated since last read */
+  unsigned char	mmr_sgnl_qual;		/* signal quality */
+#define	MMR_SGNL_QUAL		0x0F		/* signal quality */
+#define	MMR_SGNL_QUAL_ANT	0x80		/* current antenna used */
+  unsigned char	mmr_netw_id_l;		/* NWID low order byte ??? */
+  unsigned char	mmr_unused3[3];		/* unused */
+
+  /* 2.0 Hardware extension - frequency selection support */
+  unsigned char	mmr_fee_status;		/* Status of frequency eeprom */
+#define	MMR_FEE_STATUS_ID	0xF0		/* Modem revision id */
+#define	MMR_FEE_STATUS_DWLD	0x08		/* Download in progress */
+#define	MMR_FEE_STATUS_BUSY	0x04		/* EEprom busy */
+  unsigned char	mmr_unused4[1];		/* unused */
+  unsigned char	mmr_fee_data_l;		/* Read data from eeprom (low) */
+  unsigned char	mmr_fee_data_h;		/* Read data from eeprom (high) */
+};
+
+/* Size for structure checking (if padding is correct) */
+#define	MMR_SIZE	36
+
+/* Calculate offset of a field in the above structure */
+#define	mmroff(p,f) 	(unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
+
+
+/* Make the two above structures one */
+typedef union mm_t
+{
+  struct mmw_t	w;	/* Write to the mmc */
+  struct mmr_t	r;	/* Read from the mmc */
+} mm_t;
+
+#endif /* _WAVELAN_CS_H */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/wireless/wavelan_cs.p.h linux/drivers/net/wireless/wavelan_cs.p.h
--- v2.5.2/linux/drivers/net/wireless/wavelan_cs.p.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/wavelan_cs.p.h	Mon Jan 21 16:04:47 2002
@@ -0,0 +1,825 @@
+/*
+ *	Wavelan Pcmcia driver
+ *
+ *		Jean II - HPLB '96
+ *
+ * Reorganisation and extension of the driver.
+ *
+ * This file contain all definition and declarations necessary for the
+ * wavelan pcmcia driver. This file is a private header, so it should
+ * be included only on wavelan_cs.c !!!
+ */
+
+#ifndef WAVELAN_CS_P_H
+#define WAVELAN_CS_P_H
+
+/************************** DOCUMENTATION **************************/
+/*
+ * This driver provide a Linux interface to the Wavelan Pcmcia hardware
+ * The Wavelan is a product of Lucent (http://www.wavelan.com/).
+ * This division was formerly part of NCR and then AT&T.
+ * Wavelan are also distributed by DEC (RoamAbout DS)...
+ *
+ * To know how to use this driver, read the PCMCIA HOWTO.
+ * If you want to exploit the many other fonctionalities, look comments
+ * in the code...
+ *
+ * This driver is the result of the effort of many peoples (see below).
+ */
+
+/* ------------------------ SPECIFIC NOTES ------------------------ */
+/*
+ * Web page
+ * --------
+ *	I try to maintain a web page with the Wireless LAN Howto at :
+ *	    http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
+ *
+ * SMP
+ * ---
+ *	We now are SMP compliant (I eventually fixed the remaining bugs).
+ *	The driver has been tested on a dual P6-150 and survived my usual
+ *	set of torture tests.
+ *	Anyway, I spent enough time chasing interrupt re-entrancy during
+ *	errors or reconfigure, and I designed the locked/unlocked sections
+ *	of the driver with great care, and with the recent addition of
+ *	the spinlock (thanks to the new API), we should be quite close to
+ *	the truth.
+ *	The SMP/IRQ locking is quite coarse and conservative (i.e. not fast),
+ *	but better safe than sorry (especially at 2 Mb/s ;-).
+ *
+ *	I have also looked into disabling only our interrupt on the card
+ *	(via HACR) instead of all interrupts in the processor (via cli),
+ *	so that other driver are not impacted, and it look like it's
+ *	possible, but it's very tricky to do right (full of races). As
+ *	the gain would be mostly for SMP systems, it can wait...
+ *
+ * Debugging and options
+ * ---------------------
+ *	You will find below a set of '#define" allowing a very fine control
+ *	on the driver behaviour and the debug messages printed.
+ *	The main options are :
+ *	o WAVELAN_ROAMING, for the experimental roaming support.
+ *	o SET_PSA_CRC, to have your card correctly recognised by
+ *	  an access point and the Point-to-Point diagnostic tool.
+ *	o USE_PSA_CONFIG, to read configuration from the PSA (EEprom)
+ *	  (otherwise we always start afresh with some defaults)
+ *
+ * wavelan_cs.o is darn too big
+ * -------------------------
+ *	That's true ! There is a very simple way to reduce the driver
+ *	object by 33% (yes !). Comment out the following line :
+ *		#include <linux/wireless.h>
+ *	Other compile options can also reduce the size of it...
+ *
+ * MAC address and hardware detection :
+ * ----------------------------------
+ *	The detection code of the wavelan chech that the first 3
+ *	octets of the MAC address fit the company code. This type of
+ *	detection work well for AT&T cards (because the AT&T code is
+ *	hardcoded in wavelan_cs.h), but of course will fail for other
+ *	manufacturer.
+ *
+ *	If you are sure that your card is derived from the wavelan,
+ *	here is the way to configure it :
+ *	1) Get your MAC address
+ *		a) With your card utilities (wfreqsel, instconf, ...)
+ *		b) With the driver :
+ *			o compile the kernel with DEBUG_CONFIG_INFO enabled
+ *			o Boot and look the card messages
+ *	2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan_cs.h)
+ *	3) Compile & verify
+ *	4) Send me the MAC code - I will include it in the next version...
+ *
+ */
+
+/* --------------------- WIRELESS EXTENSIONS --------------------- */
+/*
+ * This driver is the first one to support "wireless extensions".
+ * This set of extensions provide you some way to control the wireless
+ * caracteristics of the hardware in a standard way and support for
+ * applications for taking advantage of it (like Mobile IP).
+ *
+ * You will need to enable the CONFIG_NET_RADIO define in the kernel
+ * configuration to enable the wireless extensions (this is the one
+ * giving access to the radio network device choice).
+ *
+ * It might also be a good idea as well to fetch the wireless tools to
+ * configure the device and play a bit.
+ */
+
+/* ---------------------------- FILES ---------------------------- */
+/*
+ * wavelan_cs.c :	The actual code for the driver - C functions
+ *
+ * wavelan_cs.p.h :	Private header : local types / vars for the driver
+ *
+ * wavelan_cs.h :	Description of the hardware interface & structs
+ *
+ * i82593.h :		Description if the Ethernet controller
+ */
+
+/* --------------------------- HISTORY --------------------------- */
+/*
+ * The history of the Wavelan drivers is as complicated as history of
+ * the Wavelan itself (NCR -> AT&T -> Lucent).
+ *
+ * All started with Anders Klemets <klemets@paul.rutgers.edu>,
+ * writting a Wavelan ISA driver for the MACH microkernel. Girish
+ * Welling <welling@paul.rutgers.edu> had also worked on it.
+ * Keith Moore modify this for the Pcmcia hardware.
+ * 
+ * Robert Morris <rtm@das.harvard.edu> port these two drivers to BSDI
+ * and add specific Pcmcia support (there is currently no equivalent
+ * of the PCMCIA package under BSD...).
+ *
+ * Jim Binkley <jrb@cs.pdx.edu> port both BSDI drivers to FreeBSD.
+ *
+ * Bruce Janson <bruce@cs.usyd.edu.au> port the BSDI ISA driver to Linux.
+ *
+ * Anthony D. Joseph <adj@lcs.mit.edu> started modify Bruce driver
+ * (with help of the BSDI PCMCIA driver) for PCMCIA.
+ * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
+ * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
+ * correctly 2.00 cards (2.4 GHz with frequency selection).
+ * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his
+ * Pcmcia package (+ bug corrections).
+ *
+ * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
+ * patchs to the Pcmcia driver. After, I added code in the ISA driver
+ * for Wireless Extensions and full support of frequency selection
+ * cards. Now, I'm doing the same to the Pcmcia driver + some
+ * reorganisation.
+ * Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me
+ * much needed informations on the Wavelan hardware.
+ */
+
+/* By the way : for the copyright & legal stuff :
+ * Almost everybody wrote code under GNU or BSD license (or alike),
+ * and want that their original copyright remain somewhere in the
+ * code (for myself, I go with the GPL).
+ * Nobody want to take responsibility for anything, except the fame...
+ */
+
+/* --------------------------- CREDITS --------------------------- */
+/*
+ * Credits:
+ *    Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht and
+ *	Loeke Brederveld of Lucent for providing extremely useful
+ *	information about WaveLAN PCMCIA hardware
+ *
+ *    This driver is based upon several other drivers, in particular:
+ *	David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter
+ *	Bruce Janson's Linux driver for the AT-bus WaveLAN adapter
+ *	Anders Klemets' PCMCIA WaveLAN adapter driver
+ *	Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter
+ *
+ * Additional Credits:
+ *
+ *    This software was originally developed under Linux 1.2.3
+ *	(Slackware 2.0 distribution).
+ *    And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+)
+ *	with an HP OmniBook 4000 and then a 5500.
+ *
+ *    It is based on other device drivers and information either written
+ *    or supplied by:
+ *	James Ashton (jaa101@syseng.anu.edu.au),
+ *	Ajay Bakre (bakre@paul.rutgers.edu),
+ *	Donald Becker (becker@super.org),
+ *	Jim Binkley <jrb@cs.pdx.edu>,
+ *	Loeke Brederveld <lbrederv@wavelan.com>,
+ *	Allan Creighton (allanc@cs.su.oz.au),
+ *	Brent Elphick <belphick@uwaterloo.ca>,
+ *	Joe Finney <joe@comp.lancs.ac.uk>,
+ *	Matthew Geier (matthew@cs.su.oz.au),
+ *	Remo di Giovanni (remo@cs.su.oz.au),
+ *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
+ *	David Hinds <dahinds@users.sourceforge.net>,
+ *	Jan Hoogendoorn (c/o marteijn@lucent.com),
+ *      Bruce Janson <bruce@cs.usyd.edu.au>,
+ *	Anthony D. Joseph <adj@lcs.mit.edu>,
+ *	Anders Klemets (klemets@paul.rutgers.edu),
+ *	Yunzhou Li <yunzhou@strat.iol.unh.edu>,
+ *	Marc Meertens (mmeertens@lucent.com),
+ *	Keith Moore,
+ *	Robert Morris (rtm@das.harvard.edu),
+ *	Ian Parkin (ian@cs.su.oz.au),
+ *	John Rosenberg (johnr@cs.su.oz.au),
+ *	George Rossi (george@phm.gov.au),
+ *	Arthur Scott (arthur@cs.su.oz.au),
+ *	Stanislav Sinyagin <stas@isf.ru>
+ *	Peter Storey,
+ *	Jean Tourrilhes <jt@hpl.hp.com>,
+ *	Girish Welling (welling@paul.rutgers.edu)
+ *	Clark Woodworth <clark@hiway1.exit109.com>
+ *	Yongguang Zhang <ygz@isl.hrl.hac.com>...
+ */
+
+/* ------------------------- IMPROVEMENTS ------------------------- */
+/*
+ * I proudly present :
+ *
+ * Changes made in 2.8.22 :
+ * ----------------------
+ *	- improved wv_set_multicast_list
+ *	- catch spurious interrupt
+ *	- correct release of the device
+ *
+ * Changes mades in release :
+ * ------------------------
+ *	- Reorganisation of the code, function name change
+ *	- Creation of private header (wavelan_cs.h)
+ *	- Reorganised debug messages
+ *	- More comments, history, ...
+ *	- Configure earlier (in "insert" instead of "open")
+ *        and do things only once
+ *	- mmc_init : configure the PSA if not done
+ *	- mmc_init : 2.00 detection better code for 2.00 init
+ *	- better info at startup
+ *	- Correct a HUGE bug (volatile & uncalibrated busy loop)
+ *	  in wv_82593_cmd => config speedup
+ *	- Stop receiving & power down on close (and power up on open)
+ *	  use "ifconfig down" & "ifconfig up ; route add -net ..."
+ *	- Send packets : add watchdog instead of pooling
+ *	- Receive : check frame wrap around & try to recover some frames
+ *	- wavelan_set_multicast_list : avoid reset
+ *	- add wireless extensions (ioctl & get_wireless_stats)
+ *	  get/set nwid/frequency on fly, info for /proc/net/wireless
+ *	- Suppress useless stuff from lp (net_local), but add link
+ *	- More inlines
+ *	- Lot of others minor details & cleanups
+ *
+ * Changes made in second release :
+ * ------------------------------
+ *	- Optimise wv_85893_reconfig stuff, fix potential problems
+ *	- Change error values for ioctl
+ *	- Non blocking wv_ru_stop() + call wv_reset() in case of problems
+ *	- Remove development printk from wavelan_watchdog()
+ *	- Remove of the watchdog to wavelan_close instead of wavelan_release
+ *	  fix potential problems...
+ *	- Start debugging suspend stuff (but it's still a bit weird)
+ *	- Debug & optimize dump header/packet in Rx & Tx (debug)
+ *	- Use "readb" and "writeb" to be kernel 2.1 compliant
+ *	- Better handling of bogus interrupts
+ *	- Wireless extension : SETSPY and GETSPY
+ *	- Remove old stuff (stats - for those needing it, just ask me...)
+ *	- Make wireless extensions optional
+ *
+ * Changes made in third release :
+ * -----------------------------
+ *	- cleanups & typos
+ *	- modif wireless ext (spy -> only one pointer)
+ *	- new private ioctl to set/get quality & level threshold
+ *	- Init : correct default value of level threshold for pcmcia
+ *	- kill watchdog in hw_reset
+ *	- more 2.1 support (copy_to/from_user instead of memcpy_to/fromfs)
+ *	- Add message level (debug stuff in /var/adm/debug & errors not
+ *	  displayed at console and still in /var/adm/messages)
+ *
+ * Changes made in fourth release :
+ * ------------------------------
+ *	- multicast support (yes !) thanks to Yongguang Zhang.
+ *
+ * Changes made in fifth release (2.9.0) :
+ * -------------------------------------
+ *	- Revisited multicast code (it was mostly wrong).
+ *	- protect code in wv_82593_reconfig with dev->tbusy (oups !)
+ *
+ * Changes made in sixth release (2.9.1a) :
+ * --------------------------------------
+ *	- Change the detection code for multi manufacturer code support
+ *	- Correct bug (hang kernel) in init when we were "rejecting" a card 
+ *
+ * Changes made in seventh release (2.9.1b) :
+ * ----------------------------------------
+ *	- Update to wireless extensions changes
+ *	- Silly bug in card initial configuration (psa_conf_status)
+ *
+ * Changes made in eigth release :
+ * -----------------------------
+ *	- Small bug in debug code (probably not the last one...)
+ *	- 1.2.13 support (thanks to Clark Woodworth)
+ *
+ * Changes made for release in 2.9.2b :
+ * ----------------------------------
+ *	- Level threshold is now a standard wireless extension (version 4 !)
+ *	- modules parameters types for kernel > 2.1.17
+ *	- updated man page
+ *	- Others cleanup from David Hinds
+ *
+ * Changes made for release in 2.9.5 :
+ * ---------------------------------
+ *	- byte count stats (courtesy of David Hinds)
+ *	- Remove dev_tint stuff (courtesy of David Hinds)
+ *	- Others cleanup from David Hinds
+ *	- Encryption setting from Brent Elphick (thanks a lot !)
+ *	- 'base' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin)
+ *
+ * Changes made for release in 2.9.6 :
+ * ---------------------------------
+ *	- fix bug : no longuer disable watchdog in case of bogus interrupt
+ *	- increase timeout in config code for picky hardware
+ *	- mask unused bits in status (Wireless Extensions)
+ *
+ * Changes integrated by Justin Seger <jseger@MIT.EDU> & David Hinds :
+ * -----------------------------------------------------------------
+ *	- Roaming "hack" from Joe Finney <joe@comp.lancs.ac.uk>
+ *	- PSA CRC code from Bob Gray <rgray@bald.cs.dartmouth.edu>
+ *	- Better initialisation of the i82593 controller
+ *	  from Joseph K. O'Sullivan <josullvn+@cs.cmu.edu>
+ *
+ * Changes made for release in 3.0.10 :
+ * ----------------------------------
+ *	- Fix eject "hang" of the driver under 2.2.X :
+ *		o create wv_flush_stale_links()
+ *		o Rename wavelan_release to wv_pcmcia_release & move up
+ *		o move unregister_netdev to wavelan_detach()
+ *		o wavelan_release() no longer call wavelan_detach()
+ *		o Suppress "release" timer
+ *		o Other cleanups & fixes
+ *	- New MAC address in the probe
+ *	- Reorg PSA_CRC code (endian neutral & cleaner)
+ *	- Correct initialisation of the i82593 from Lucent manual
+ *	- Put back the watchdog, with larger timeout
+ *	- TRANSMIT_NO_CRC is a "normal" error, so recover from it
+ *	  from Derrick J Brashear <shadow@dementia.org>
+ *	- Better handling of TX and RX normal failure conditions
+ *	- #ifdef out all the roaming code
+ *	- Add ESSID & "AP current address" ioctl stubs
+ *	- General cleanup of the code
+ *
+ * Changes made for release in 3.0.13 :
+ * ----------------------------------
+ *	- Re-enable compilation of roaming code by default, but with
+ *	  do_roaming = 0
+ *	- Nuke `nwid=nwid^ntohs(beacon->domain_id)' in wl_roam_gather
+ *	  at the demand of John Carol Langford <jcl@gs176.sp.cs.cmu.edu>
+ *	- Introduced WAVELAN_ROAMING_EXT for incomplete ESSID stuff.
+ *
+ * Changes made for release in 3.0.15 :
+ * ----------------------------------
+ *	- Change e-mail and web page addresses
+ *	- Watchdog timer is now correctly expressed in HZ, not in jiffies
+ *	- Add channel number to the list of frequencies in range
+ *	- Add the (short) list of bit-rates in range
+ *	- Developp a new sensitivity... (sens.value & sens.fixed)
+ *
+ * Changes made for release in 3.1.2 :
+ * ---------------------------------
+ *	- Fix check for root permission (break instead of exit)
+ *	- New nwid & encoding setting (Wireless Extension 9)
+ *
+ * Changes made for release in 3.1.12 :
+ * ----------------------------------
+ *	- reworked wv_82593_cmd to avoid using the IRQ handler and doing
+ *	  ugly things with interrupts.
+ *	- Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog
+ *	- Update to new network API (softnet - 2.3.43) :
+ *		o replace dev->tbusy (David + me)
+ *		o replace dev->tstart (David + me)
+ *		o remove dev->interrupt (David)
+ *		o add SMP locking via spinlock in splxx (me)
+ *		o add spinlock in interrupt handler (me)
+ *		o use kernel watchdog instead of ours (me)
+ *		o verify that all the changes make sense and work (me)
+ *	- Re-sync kernel/pcmcia versions (not much actually)
+ *	- A few other cleanups (David & me)...
+ *
+ * Changes made for release in 3.1.22 :
+ * ----------------------------------
+ *	- Check that SMP works, remove annoying log message
+ *
+ * Changes made for release in 3.1.24 :
+ * ----------------------------------
+ *	- Fix unfrequent card lockup when watchdog was reseting the hardware :
+ *		o control first busy loop in wv_82593_cmd()
+ *		o Extend spinlock protection in wv_hw_config()
+ *
+ * Wishes & dreams:
+ * ----------------
+ *	- Cleanup and integrate the roaming code
+ *	  (std debug, set DomainID, decay avg and co...)
+ */
+
+/***************************** INCLUDES *****************************/
+
+/* Linux headers that we need */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+
+#ifdef CONFIG_NET_RADIO
+#include <linux/wireless.h>		/* Wireless extensions */
+#endif
+
+/* Pcmcia headers that we need */
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/version.h>
+
+/* Wavelan declarations */
+#include "i82593.h"	/* Definitions for the Intel chip */
+
+#include "wavelan_cs.h"	/* Others bits of the hardware */
+
+/************************** DRIVER OPTIONS **************************/
+/*
+ * `#define' or `#undef' the following constant to change the behaviour
+ * of the driver...
+ */
+#define WAVELAN_ROAMING		/* Include experimental roaming code */
+#undef WAVELAN_ROAMING_EXT	/* Enable roaming wireless extensions */
+#undef SET_PSA_CRC		/* Set the CRC in PSA (slower) */
+#define USE_PSA_CONFIG		/* Use info from the PSA */
+#undef STRUCT_CHECK		/* Verify padding of structures */
+#undef EEPROM_IS_PROTECTED	/* Doesn't seem to be necessary */
+#define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical) */
+#undef SET_MAC_ADDRESS		/* Experimental */
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+/* Warning : these stuff will slow down the driver... */
+#define WIRELESS_SPY		/* Enable spying addresses */
+#undef HISTOGRAM		/* Enable histogram of sig level... */
+#endif
+
+/****************************** DEBUG ******************************/
+
+#undef DEBUG_MODULE_TRACE	/* Module insertion/removal */
+#undef DEBUG_CALLBACK_TRACE	/* Calls made by Linux */
+#undef DEBUG_INTERRUPT_TRACE	/* Calls to handler */
+#undef DEBUG_INTERRUPT_INFO	/* type of interrupt & so on */
+#define DEBUG_INTERRUPT_ERROR	/* problems */
+#undef DEBUG_CONFIG_TRACE	/* Trace the config functions */
+#undef DEBUG_CONFIG_INFO	/* What's going on... */
+#define DEBUG_CONFIG_ERRORS	/* Errors on configuration */
+#undef DEBUG_TX_TRACE		/* Transmission calls */
+#undef DEBUG_TX_INFO		/* Header of the transmitted packet */
+#undef DEBUG_TX_FAIL		/* Normal failure conditions */
+#define DEBUG_TX_ERROR		/* Unexpected conditions */
+#undef DEBUG_RX_TRACE		/* Transmission calls */
+#undef DEBUG_RX_INFO		/* Header of the transmitted packet */
+#undef DEBUG_RX_FAIL		/* Normal failure conditions */
+#define DEBUG_RX_ERROR		/* Unexpected conditions */
+#undef DEBUG_PACKET_DUMP	32	/* Dump packet on the screen */
+#undef DEBUG_IOCTL_TRACE	/* Misc call by Linux */
+#undef DEBUG_IOCTL_INFO		/* Various debug info */
+#define DEBUG_IOCTL_ERROR	/* What's going wrong */
+#define DEBUG_BASIC_SHOW	/* Show basic startup info */
+#undef DEBUG_VERSION_SHOW	/* Print version info */
+#undef DEBUG_PSA_SHOW		/* Dump psa to screen */
+#undef DEBUG_MMC_SHOW		/* Dump mmc to screen */
+#undef DEBUG_SHOW_UNUSED	/* Show also unused fields */
+#undef DEBUG_I82593_SHOW	/* Show i82593 status */
+#undef DEBUG_DEVICE_SHOW	/* Show device parameters */
+
+/************************ CONSTANTS & MACROS ************************/
+
+#ifdef DEBUG_VERSION_SHOW
+static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n";
+#endif
+
+/* Watchdog temporisation */
+#define	WATCHDOG_JIFFIES	(256*HZ/100)
+
+/* Fix a bug in some old wireless extension definitions */
+#ifndef IW_ESSID_MAX_SIZE
+#define IW_ESSID_MAX_SIZE	32
+#endif
+
+/* ------------------------ PRIVATE IOCTL ------------------------ */
+
+/* Wireless Extension Backward compatibility - Jean II
+ * If the new wireless device private ioctl range is not defined,
+ * default to standard device private ioctl range */
+#ifndef SIOCIWFIRSTPRIV
+#define SIOCIWFIRSTPRIV	SIOCDEVPRIVATE
+#endif /* SIOCIWFIRSTPRIV */
+
+#define SIOCSIPQTHR	SIOCIWFIRSTPRIV		/* Set quality threshold */
+#define SIOCGIPQTHR	SIOCIWFIRSTPRIV + 1	/* Get quality threshold */
+#define SIOCSIPROAM     SIOCIWFIRSTPRIV + 2	/* Set roaming state */
+#define SIOCGIPROAM     SIOCIWFIRSTPRIV + 3	/* Get roaming state */
+
+#define SIOCSIPHISTO	SIOCIWFIRSTPRIV + 6	/* Set histogram ranges */
+#define SIOCGIPHISTO	SIOCIWFIRSTPRIV + 7	/* Get histogram values */
+
+/*************************** WaveLAN Roaming  **************************/
+#ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
+
+#define WAVELAN_ROAMING_DEBUG	 0	/* 1 = Trace of handover decisions */
+					/* 2 = Info on each beacon rcvd... */
+#define MAX_WAVEPOINTS		7	/* Max visible at one time */
+#define WAVEPOINT_HISTORY	5	/* SNR sample history slow search */
+#define WAVEPOINT_FAST_HISTORY	2	/* SNR sample history fast search */
+#define SEARCH_THRESH_LOW	10	/* SNR to enter cell search */
+#define SEARCH_THRESH_HIGH	13	/* SNR to leave cell search */
+#define WAVELAN_ROAMING_DELTA	1	/* Hysteresis value (+/- SNR) */
+#define CELL_TIMEOUT		2*HZ	/* in jiffies */
+
+#define FAST_CELL_SEARCH	1	/* Boolean values... */
+#define NWID_PROMISC		1	/* for code clarity. */
+
+typedef struct wavepoint_beacon
+{
+  unsigned char		dsap,		/* Unused */
+			ssap,		/* Unused */
+			ctrl,		/* Unused */
+			O,U,I,		/* Unused */
+			spec_id1,	/* Unused */
+			spec_id2,	/* Unused */
+			pdu_type,	/* Unused */
+			seq;		/* WavePoint beacon sequence number */
+  unsigned short	domain_id,	/* WavePoint Domain ID */
+			nwid;		/* WavePoint NWID */
+} wavepoint_beacon;
+
+typedef struct wavepoint_history
+{
+  unsigned short	nwid;		/* WavePoint's NWID */
+  int			average_slow;	/* SNR running average */
+  int			average_fast;	/* SNR running average */
+  unsigned char	  sigqual[WAVEPOINT_HISTORY]; /* Ringbuffer of recent SNR's */
+  unsigned char		qualptr;	/* Index into ringbuffer */
+  unsigned char		last_seq;	/* Last seq. no seen for WavePoint */
+  struct wavepoint_history *next;	/* Next WavePoint in table */
+  struct wavepoint_history *prev;	/* Previous WavePoint in table */
+  unsigned long		last_seen;	/* Time of last beacon recvd, jiffies */
+} wavepoint_history;
+
+struct wavepoint_table
+{
+  wavepoint_history	*head;		/* Start of ringbuffer */
+  int			num_wavepoints;	/* No. of WavePoints visible */
+  unsigned char		locked;		/* Table lock */
+};
+
+#endif	/* WAVELAN_ROAMING */
+
+/****************************** TYPES ******************************/
+
+/* Shortcuts */
+typedef struct net_device	device;
+typedef struct net_device_stats	en_stats;
+typedef struct iw_statistics	iw_stats;
+typedef struct iw_quality	iw_qual;
+typedef struct iw_freq		iw_freq;
+typedef struct net_local	net_local;
+typedef struct timer_list	timer_list;
+
+/* Basic types */
+typedef u_char		mac_addr[WAVELAN_ADDR_SIZE];	/* Hardware address */
+
+/*
+ * Static specific data for the interface.
+ *
+ * For each network interface, Linux keep data in two structure. "device"
+ * keep the generic data (same format for everybody) and "net_local" keep
+ * the additional specific data.
+ * Note that some of this specific data is in fact generic (en_stats, for
+ * example).
+ */
+struct net_local
+{
+  dev_node_t 	node;		/* ???? What is this stuff ???? */
+  device *	dev;		/* Reverse link... */
+  spinlock_t	spinlock;	/* Serialize access to the hardware (SMP) */
+  dev_link_t *	link;		/* pcmcia structure */
+  en_stats	stats;		/* Ethernet interface statistics */
+  int		nresets;	/* Number of hw resets */
+  u_char	configured;	/* If it is configured */
+  u_char	reconfig_82593;	/* Need to reconfigure the controller */
+  u_char	promiscuous;	/* Promiscuous mode */
+  u_char	allmulticast;	/* All Multicast mode */
+  int		mc_count;	/* Number of multicast addresses */
+
+  int   	stop;		/* Current i82593 Stop Hit Register */
+  int   	rfp;		/* Last DMA machine receive pointer */
+  int		overrunning;	/* Receiver overrun flag */
+
+#ifdef WIRELESS_EXT
+  iw_stats	wstats;		/* Wireless specific stats */
+#endif
+
+#ifdef WIRELESS_SPY
+  int		spy_number;		/* Number of addresses to spy */
+  mac_addr	spy_address[IW_MAX_SPY];	/* The addresses to spy */
+  iw_qual	spy_stat[IW_MAX_SPY];		/* Statistics gathered */
+#endif	/* WIRELESS_SPY */
+#ifdef HISTOGRAM
+  int		his_number;		/* Number of intervals */
+  u_char	his_range[16];		/* Boundaries of interval ]n-1; n] */
+  u_long	his_sum[16];		/* Sum in interval */
+#endif	/* HISTOGRAM */
+#ifdef WAVELAN_ROAMING
+  u_long	domain_id;	/* Domain ID we lock on for roaming */
+  int		filter_domains;	/* Check Domain ID of beacon found */
+ struct wavepoint_table	wavepoint_table;	/* Table of visible WavePoints*/
+  wavepoint_history *	curr_point;		/* Current wavepoint */
+  int			cell_search;		/* Searching for new cell? */
+  struct timer_list	cell_timer;		/* Garbage collection */
+#endif	/* WAVELAN_ROAMING */
+};
+
+/**************************** PROTOTYPES ****************************/
+
+#ifdef WAVELAN_ROAMING
+/* ---------------------- ROAMING SUBROUTINES -----------------------*/
+
+wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp);
+wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp);
+void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp);
+void wl_cell_expiry(unsigned long data);
+wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp);
+void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq);
+void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp);
+void wv_nwid_filter(unsigned char mode, net_local *lp);
+void wv_roam_init(struct net_device *dev);
+void wv_roam_cleanup(struct net_device *dev);
+#endif	/* WAVELAN_ROAMING */
+
+/* ----------------------- MISC SUBROUTINES ------------------------ */
+static inline void
+	wv_splhi(net_local *,		/* Disable interrupts */
+		 unsigned long *);	/* flags */
+static inline void
+	wv_splx(net_local *,		/* ReEnable interrupts */
+		unsigned long *);	/* flags */
+static void
+	cs_error(client_handle_t,	/* Report error to cardmgr */
+		 int,
+		 int);
+/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
+static inline u_char		/* data */
+	hasr_read(u_long);	/* Read the host interface : base address */
+static inline void
+	hacr_write(u_long,	/* Write to host interface : base address */
+		   u_char),	/* data */
+	hacr_write_slow(u_long,
+		   u_char);
+static void
+	psa_read(device *,	/* Read the Parameter Storage Area */
+		 int,		/* offset in PSA */
+		 u_char *,	/* buffer to fill */
+		 int),		/* size to read */
+	psa_write(device *,	/* Write to the PSA */
+		  int,		/* Offset in psa */
+		  u_char *,	/* Buffer in memory */
+		  int);		/* Length of buffer */
+static inline void
+	mmc_out(u_long,		/* Write 1 byte to the Modem Manag Control */
+		u_short,
+		u_char),
+	mmc_write(u_long,	/* Write n bytes to the MMC */
+		  u_char,
+		  u_char *,
+		  int);
+static inline u_char		/* Read 1 byte from the MMC */
+	mmc_in(u_long,
+	       u_short);
+static inline void
+	mmc_read(u_long,	/* Read n bytes from the MMC */
+		 u_char,
+		 u_char *,
+		 int),
+	fee_wait(u_long,	/* Wait for frequency EEprom : base address */
+		 int,		/* Base delay to wait for */
+		 int);		/* Number of time to wait */
+static void
+	fee_read(u_long,	/* Read the frequency EEprom : base address */
+		 u_short,	/* destination offset */
+		 u_short *,	/* data buffer */
+		 int);		/* number of registers */
+/* ---------------------- I82593 SUBROUTINES ----------------------- */
+static int
+	wv_82593_cmd(device *,	/* synchronously send a command to i82593 */ 
+		     char *,
+		     int,
+		     int);
+static inline int
+	wv_diag(device *);	/* Diagnostique the i82593 */
+static int
+	read_ringbuf(device *,	/* Read a receive buffer */
+		     int,
+		     char *,
+		     int);
+static inline void
+	wv_82593_reconfig(device *);	/* Reconfigure the controller */
+/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */
+static inline void
+	wv_init_info(device *);	/* display startup info */
+/* ------------------- IOCTL, STATS & RECONFIG ------------------- */
+static en_stats	*
+	wavelan_get_stats(device *);	/* Give stats /proc/net/dev */
+/* ----------------------- PACKET RECEPTION ----------------------- */
+static inline int
+	wv_start_of_frame(device *,	/* Seek beggining of current frame */
+			  int,	/* end of frame */
+			  int);	/* start of buffer */
+static inline void
+	wv_packet_read(device *,	/* Read a packet from a frame */
+		       int,
+		       int),
+	wv_packet_rcv(device *);	/* Read all packets waiting */
+/* --------------------- PACKET TRANSMISSION --------------------- */
+static inline void
+	wv_packet_write(device *,	/* Write a packet to the Tx buffer */
+			void *,
+			short);
+static int
+	wavelan_packet_xmit(struct sk_buff *,	/* Send a packet */
+			    device *);
+/* -------------------- HARDWARE CONFIGURATION -------------------- */
+static inline int
+	wv_mmc_init(device *);	/* Initialize the modem */
+static int
+	wv_ru_stop(device *),	/* Stop the i82593 receiver unit */
+	wv_ru_start(device *);	/* Start the i82593 receiver unit */
+static int
+	wv_82593_config(device *);	/* Configure the i82593 */
+static inline int
+	wv_pcmcia_reset(device *);	/* Reset the pcmcia interface */
+static int
+	wv_hw_config(device *);	/* Reset & configure the whole hardware */
+static inline void
+	wv_hw_reset(device *);	/* Same, + start receiver unit */
+static inline int
+	wv_pcmcia_config(dev_link_t *);	/* Configure the pcmcia interface */
+static void
+	wv_pcmcia_release(u_long),	/* Remove a device */
+	wv_flush_stale_links(void);	/* "detach" all possible devices */
+/* ---------------------- INTERRUPT HANDLING ---------------------- */
+static void
+	wavelan_interrupt(int,	/* Interrupt handler */
+			  void *,
+			  struct pt_regs *);
+static void
+	wavelan_watchdog(device *);	/* Transmission watchdog */
+/* ------------------- CONFIGURATION CALLBACKS ------------------- */
+static int
+	wavelan_open(device *),		/* Open the device */
+	wavelan_close(device *);	/* Close the device */
+static dev_link_t *
+	wavelan_attach(void);		/* Create a new device */
+static void
+	wavelan_detach(dev_link_t *);	/* Destroy a removed device */
+static int
+	wavelan_event(event_t,		/* Manage pcmcia events */
+		      int,
+		      event_callback_args_t *);
+
+/**************************** VARIABLES ****************************/
+
+static dev_info_t dev_info = "wavelan_cs";
+static dev_link_t *dev_list = NULL;	/* Linked list of devices */
+
+/*
+ * Parameters that can be set with 'insmod'
+ * The exact syntax is 'insmod wavelan_cs.o <var>=<value>'
+ */
+
+/* Bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4 and 3 */
+static int	irq_mask = 0xdeb8;
+static int 	irq_list[4] = { -1 };
+
+/* Shared memory speed, in ns */
+static int	mem_speed = 0;
+
+/* New module interface */
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(mem_speed, "i");
+
+#ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
+/* Enable roaming mode ? No ! Please keep this to 0 */
+static int	do_roaming = 0;
+MODULE_PARM(do_roaming, "i");
+#endif	/* WAVELAN_ROAMING */
+
+MODULE_LICENSE("GPL");
+
+#endif	/* WAVELAN_CS_P_H */
+
diff -u --recursive --new-file v2.5.2/linux/drivers/net/zlib.c linux/drivers/net/zlib.c
--- v2.5.2/linux/drivers/net/zlib.c	Wed Apr 18 14:40:04 2001
+++ linux/drivers/net/zlib.c	Wed Dec 31 16:00:00 1969
@@ -1,5371 +0,0 @@
-/*
- * This file is derived from various .h and .c files from the zlib-1.0.4
- * distribution by Jean-loup Gailly and Mark Adler, with some additions
- * by Paul Mackerras to aid in implementing Deflate compression and
- * decompression for PPP packets.  See zlib.h for conditions of
- * distribution and use.
- *
- * Changes that have been made include:
- * - added Z_PACKET_FLUSH (see zlib.h for details)
- * - added inflateIncomp and deflateOutputPending
- * - allow strm->next_out to be NULL, meaning discard the output
- *
- * $Id: zlib.c,v 1.3 1997/12/23 10:47:42 paulus Exp $
- */
-
-/* 
- *  ==FILEVERSION 971210==
- *
- * This marker is used by the Linux installation script to determine
- * whether an up-to-date version of this file is already installed.
- */
-
-#define NO_DUMMY_DECL
-#define NO_ZCFUNCS
-#define MY_ZCALLOC
-
-#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
-#define inflate	inflate_ppp	/* FreeBSD already has an inflate :-( */
-#endif
-
-
-/* +++ zutil.h */
-/* zutil.h -- internal interface and configuration of the compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */
-
-#ifndef _Z_UTIL_H
-#define _Z_UTIL_H
-
-#include "zlib.h"
-
-#if defined(KERNEL) || defined(_KERNEL)
-/* Assume this is a *BSD or SVR4 kernel */
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/systm.h>
-#  define HAVE_MEMCPY
-#  define memcpy(d, s, n)	bcopy((s), (d), (n))
-#  define memset(d, v, n)	bzero((d), (n))
-#  define memcmp		bcmp
-
-#else
-#if defined(__KERNEL__)
-/* Assume this is a Linux kernel */
-#include <linux/string.h>
-#define HAVE_MEMCPY
-
-#else /* not kernel */
-
-#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
-#   include <stddef.h>
-#   include <errno.h>
-#else
-    extern int errno;
-#endif
-#ifdef STDC
-#  include <string.h>
-#  include <stdlib.h>
-#endif
-#endif /* __KERNEL__ */
-#endif /* _KERNEL || KERNEL */
-
-#ifndef local
-#  define local static
-#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
-
-typedef unsigned char  uch;
-typedef uch FAR uchf;
-typedef unsigned short ush;
-typedef ush FAR ushf;
-typedef unsigned long  ulg;
-
-extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
-/* (size given to avoid silly warnings with Visual C++) */
-
-#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
-
-#define ERR_RETURN(strm,err) \
-  return (strm->msg = (char*)ERR_MSG(err), (err))
-/* To be used only when the state is known to be valid */
-
-        /* common constants */
-
-#ifndef DEF_WBITS
-#  define DEF_WBITS MAX_WBITS
-#endif
-/* default windowBits for decompression. MAX_WBITS is for compression only */
-
-#if MAX_MEM_LEVEL >= 8
-#  define DEF_MEM_LEVEL 8
-#else
-#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
-#endif
-/* default memLevel */
-
-#define STORED_BLOCK 0
-#define STATIC_TREES 1
-#define DYN_TREES    2
-/* The three kinds of block type */
-
-#define MIN_MATCH  3
-#define MAX_MATCH  258
-/* The minimum and maximum match lengths */
-
-#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
-
-        /* target dependencies */
-
-#ifdef MSDOS
-#  define OS_CODE  0x00
-#  ifdef __TURBOC__
-#    include <alloc.h>
-#  else /* MSC or DJGPP */
-#    include <malloc.h>
-#  endif
-#endif
-
-#ifdef OS2
-#  define OS_CODE  0x06
-#endif
-
-#ifdef WIN32 /* Window 95 & Windows NT */
-#  define OS_CODE  0x0b
-#endif
-
-#if defined(VAXC) || defined(VMS)
-#  define OS_CODE  0x02
-#  define FOPEN(name, mode) \
-     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
-#endif
-
-#ifdef AMIGA
-#  define OS_CODE  0x01
-#endif
-
-#if defined(ATARI) || defined(atarist)
-#  define OS_CODE  0x05
-#endif
-
-#ifdef MACOS
-#  define OS_CODE  0x07
-#endif
-
-#ifdef __50SERIES /* Prime/PRIMOS */
-#  define OS_CODE  0x0F
-#endif
-
-#ifdef TOPS20
-#  define OS_CODE  0x0a
-#endif
-
-#if defined(_BEOS_) || defined(RISCOS)
-#  define fdopen(fd,mode) NULL /* No fdopen() */
-#endif
-
-        /* Common defaults */
-
-#ifndef OS_CODE
-#  define OS_CODE  0x03  /* assume Unix */
-#endif
-
-#ifndef FOPEN
-#  define FOPEN(name, mode) fopen((name), (mode))
-#endif
-
-         /* functions */
-
-#ifdef HAVE_STRERROR
-   extern char *strerror OF((int));
-#  define zstrerror(errnum) strerror(errnum)
-#else
-#  define zstrerror(errnum) ""
-#endif
-
-#if defined(pyr)
-#  define NO_MEMCPY
-#endif
-#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
- /* Use our own functions for small and medium model with MSC <= 5.0.
-  * You may have to use the same strategy for Borland C (untested).
-  */
-#  define NO_MEMCPY
-#endif
-#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
-#  define HAVE_MEMCPY
-#endif
-#ifdef HAVE_MEMCPY
-#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
-#    define zmemcpy _fmemcpy
-#    define zmemcmp _fmemcmp
-#    define zmemzero(dest, len) _fmemset(dest, 0, len)
-#  else
-#    define zmemcpy memcpy
-#    define zmemcmp memcmp
-#    define zmemzero(dest, len) memset(dest, 0, len)
-#  endif
-#else
-   extern void zmemcpy  OF((Bytef* dest, Bytef* source, uInt len));
-   extern int  zmemcmp  OF((Bytef* s1,   Bytef* s2, uInt len));
-   extern void zmemzero OF((Bytef* dest, uInt len));
-#endif
-
-/* Diagnostic functions */
-#ifdef DEBUG_ZLIB
-#  include <stdio.h>
-#  ifndef verbose
-#    define verbose 0
-#  endif
-   extern void z_error    OF((char *m));
-#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
-#  define Trace(x) fprintf x
-#  define Tracev(x) {if (verbose) fprintf x ;}
-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-#  define Assert(cond,msg)
-#  define Trace(x)
-#  define Tracev(x)
-#  define Tracevv(x)
-#  define Tracec(c,x)
-#  define Tracecv(c,x)
-#endif
-
-
-typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len));
-
-voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
-void   zcfree  OF((voidpf opaque, voidpf ptr));
-
-#define ZALLOC(strm, items, size) \
-           (*((strm)->zalloc))((strm)->opaque, (items), (size))
-#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
-#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
-
-#endif /* _Z_UTIL_H */
-/* --- zutil.h */
-
-/* +++ deflate.h */
-/* deflate.h -- internal compression state
- * Copyright (C) 1995-1996 Jean-loup Gailly
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */
-
-#ifndef _DEFLATE_H
-#define _DEFLATE_H
-
-/* #include "zutil.h" */
-
-/* ===========================================================================
- * Internal compression state.
- */
-
-#define LENGTH_CODES 29
-/* number of length codes, not counting the special END_BLOCK code */
-
-#define LITERALS  256
-/* number of literal bytes 0..255 */
-
-#define L_CODES (LITERALS+1+LENGTH_CODES)
-/* number of Literal or Length codes, including the END_BLOCK code */
-
-#define D_CODES   30
-/* number of distance codes */
-
-#define BL_CODES  19
-/* number of codes used to transfer the bit lengths */
-
-#define HEAP_SIZE (2*L_CODES+1)
-/* maximum heap size */
-
-#define MAX_BITS 15
-/* All codes must not exceed MAX_BITS bits */
-
-#define INIT_STATE    42
-#define BUSY_STATE   113
-#define FINISH_STATE 666
-/* Stream status */
-
-
-/* Data structure describing a single value and its code string. */
-typedef struct ct_data_s {
-    union {
-        ush  freq;       /* frequency count */
-        ush  code;       /* bit string */
-    } fc;
-    union {
-        ush  dad;        /* father node in Huffman tree */
-        ush  len;        /* length of bit string */
-    } dl;
-} FAR ct_data;
-
-#define Freq fc.freq
-#define Code fc.code
-#define Dad  dl.dad
-#define Len  dl.len
-
-typedef struct static_tree_desc_s  static_tree_desc;
-
-typedef struct tree_desc_s {
-    ct_data *dyn_tree;           /* the dynamic tree */
-    int     max_code;            /* largest code with non zero frequency */
-    static_tree_desc *stat_desc; /* the corresponding static tree */
-} FAR tree_desc;
-
-typedef ush Pos;
-typedef Pos FAR Posf;
-typedef unsigned IPos;
-
-/* A Pos is an index in the character window. We use short instead of int to
- * save space in the various tables. IPos is used only for parameter passing.
- */
-
-typedef struct deflate_state {
-    z_streamp strm;      /* pointer back to this zlib stream */
-    int   status;        /* as the name implies */
-    Bytef *pending_buf;  /* output still pending */
-    ulg   pending_buf_size; /* size of pending_buf */
-    Bytef *pending_out;  /* next pending byte to output to the stream */
-    int   pending;       /* nb of bytes in the pending buffer */
-    int   noheader;      /* suppress zlib header and adler32 */
-    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
-    Byte  method;        /* STORED (for zip only) or DEFLATED */
-    int   last_flush;    /* value of flush param for previous deflate call */
-
-                /* used by deflate.c: */
-
-    uInt  w_size;        /* LZ77 window size (32K by default) */
-    uInt  w_bits;        /* log2(w_size)  (8..16) */
-    uInt  w_mask;        /* w_size - 1 */
-
-    Bytef *window;
-    /* Sliding window. Input bytes are read into the second half of the window,
-     * and move to the first half later to keep a dictionary of at least wSize
-     * bytes. With this organization, matches are limited to a distance of
-     * wSize-MAX_MATCH bytes, but this ensures that IO is always
-     * performed with a length multiple of the block size. Also, it limits
-     * the window size to 64K, which is quite useful on MSDOS.
-     * To do: use the user input buffer as sliding window.
-     */
-
-    ulg window_size;
-    /* Actual size of window: 2*wSize, except when the user input buffer
-     * is directly used as sliding window.
-     */
-
-    Posf *prev;
-    /* Link to older string with same hash index. To limit the size of this
-     * array to 64K, this link is maintained only for the last 32K strings.
-     * An index in this array is thus a window index modulo 32K.
-     */
-
-    Posf *head; /* Heads of the hash chains or NIL. */
-
-    uInt  ins_h;          /* hash index of string to be inserted */
-    uInt  hash_size;      /* number of elements in hash table */
-    uInt  hash_bits;      /* log2(hash_size) */
-    uInt  hash_mask;      /* hash_size-1 */
-
-    uInt  hash_shift;
-    /* Number of bits by which ins_h must be shifted at each input
-     * step. It must be such that after MIN_MATCH steps, the oldest
-     * byte no longer takes part in the hash key, that is:
-     *   hash_shift * MIN_MATCH >= hash_bits
-     */
-
-    long block_start;
-    /* Window position at the beginning of the current output block. Gets
-     * negative when the window is moved backwards.
-     */
-
-    uInt match_length;           /* length of best match */
-    IPos prev_match;             /* previous match */
-    int match_available;         /* set if previous match exists */
-    uInt strstart;               /* start of string to insert */
-    uInt match_start;            /* start of matching string */
-    uInt lookahead;              /* number of valid bytes ahead in window */
-
-    uInt prev_length;
-    /* Length of the best match at previous step. Matches not greater than this
-     * are discarded. This is used in the lazy match evaluation.
-     */
-
-    uInt max_chain_length;
-    /* To speed up deflation, hash chains are never searched beyond this
-     * length.  A higher limit improves compression ratio but degrades the
-     * speed.
-     */
-
-    uInt max_lazy_match;
-    /* Attempt to find a better match only when the current match is strictly
-     * smaller than this value. This mechanism is used only for compression
-     * levels >= 4.
-     */
-#   define max_insert_length  max_lazy_match
-    /* Insert new strings in the hash table only if the match length is not
-     * greater than this length. This saves time but degrades compression.
-     * max_insert_length is used only for compression levels <= 3.
-     */
-
-    int level;    /* compression level (1..9) */
-    int strategy; /* favor or force Huffman coding*/
-
-    uInt good_match;
-    /* Use a faster search when the previous match is longer than this */
-
-    int nice_match; /* Stop searching when current match exceeds this */
-
-                /* used by trees.c: */
-    /* Didn't use ct_data typedef below to suppress compiler warning */
-    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
-    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
-    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
-
-    struct tree_desc_s l_desc;               /* desc. for literal tree */
-    struct tree_desc_s d_desc;               /* desc. for distance tree */
-    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
-
-    ush bl_count[MAX_BITS+1];
-    /* number of codes at each bit length for an optimal tree */
-
-    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
-    int heap_len;               /* number of elements in the heap */
-    int heap_max;               /* element of largest frequency */
-    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
-     * The same heap array is used to build all trees.
-     */
-
-    uch depth[2*L_CODES+1];
-    /* Depth of each subtree used as tie breaker for trees of equal frequency
-     */
-
-    uchf *l_buf;          /* buffer for literals or lengths */
-
-    uInt  lit_bufsize;
-    /* Size of match buffer for literals/lengths.  There are 4 reasons for
-     * limiting lit_bufsize to 64K:
-     *   - frequencies can be kept in 16 bit counters
-     *   - if compression is not successful for the first block, all input
-     *     data is still in the window so we can still emit a stored block even
-     *     when input comes from standard input.  (This can also be done for
-     *     all blocks if lit_bufsize is not greater than 32K.)
-     *   - if compression is not successful for a file smaller than 64K, we can
-     *     even emit a stored file instead of a stored block (saving 5 bytes).
-     *     This is applicable only for zip (not gzip or zlib).
-     *   - creating new Huffman trees less frequently may not provide fast
-     *     adaptation to changes in the input data statistics. (Take for
-     *     example a binary file with poorly compressible code followed by
-     *     a highly compressible string table.) Smaller buffer sizes give
-     *     fast adaptation but have of course the overhead of transmitting
-     *     trees more frequently.
-     *   - I can't count above 4
-     */
-
-    uInt last_lit;      /* running index in l_buf */
-
-    ushf *d_buf;
-    /* Buffer for distances. To simplify the code, d_buf and l_buf have
-     * the same number of elements. To use different lengths, an extra flag
-     * array would be necessary.
-     */
-
-    ulg opt_len;        /* bit length of current block with optimal trees */
-    ulg static_len;     /* bit length of current block with static trees */
-    ulg compressed_len; /* total bit length of compressed file */
-    uInt matches;       /* number of string matches in current block */
-    int last_eob_len;   /* bit length of EOB code for last block */
-
-#ifdef DEBUG_ZLIB
-    ulg bits_sent;      /* bit length of the compressed data */
-#endif
-
-    ush bi_buf;
-    /* Output buffer. bits are inserted starting at the bottom (least
-     * significant bits).
-     */
-    int bi_valid;
-    /* Number of valid bits in bi_buf.  All bits above the last valid bit
-     * are always zero.
-     */
-
-} FAR deflate_state;
-
-/* Output a byte on the stream.
- * IN assertion: there is enough room in pending_buf.
- */
-#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
-
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
-/* In order to simplify the code, particularly on 16 bit machines, match
- * distances are limited to MAX_DIST instead of WSIZE.
- */
-
-        /* in trees.c */
-void _tr_init         OF((deflate_state *s));
-int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
-ulg  _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
-			  int eof));
-void _tr_align        OF((deflate_state *s));
-void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
-                          int eof));
-void _tr_stored_type_only OF((deflate_state *));
-
-#endif
-/* --- deflate.h */
-
-/* +++ deflate.c */
-/* deflate.c -- compress data using the deflation algorithm
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/*
- *  ALGORITHM
- *
- *      The "deflation" process depends on being able to identify portions
- *      of the input text which are identical to earlier input (within a
- *      sliding window trailing behind the input currently being processed).
- *
- *      The most straightforward technique turns out to be the fastest for
- *      most input files: try all possible matches and select the longest.
- *      The key feature of this algorithm is that insertions into the string
- *      dictionary are very simple and thus fast, and deletions are avoided
- *      completely. Insertions are performed at each input character, whereas
- *      string matches are performed only when the previous match ends. So it
- *      is preferable to spend more time in matches to allow very fast string
- *      insertions and avoid deletions. The matching algorithm for small
- *      strings is inspired from that of Rabin & Karp. A brute force approach
- *      is used to find longer strings when a small match has been found.
- *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
- *      (by Leonid Broukhis).
- *         A previous version of this file used a more sophisticated algorithm
- *      (by Fiala and Greene) which is guaranteed to run in linear amortized
- *      time, but has a larger average cost, uses more memory and is patented.
- *      However the F&G algorithm may be faster for some highly redundant
- *      files if the parameter max_chain_length (described below) is too large.
- *
- *  ACKNOWLEDGEMENTS
- *
- *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
- *      I found it in 'freeze' written by Leonid Broukhis.
- *      Thanks to many people for bug reports and testing.
- *
- *  REFERENCES
- *
- *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
- *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
- *
- *      A description of the Rabin and Karp algorithm is given in the book
- *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
- *
- *      Fiala,E.R., and Greene,D.H.
- *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
- *
- */
-
-/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */
-
-/* #include "deflate.h" */
-
-char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
-/* ===========================================================================
- *  Function prototypes.
- */
-typedef enum {
-    need_more,      /* block not completed, need more input or more output */
-    block_done,     /* block flush performed */
-    finish_started, /* finish started, need only more output at next deflate */
-    finish_done     /* finish done, accept no more input or output */
-} block_state;
-
-typedef block_state (*compress_func) OF((deflate_state *s, int flush));
-/* Compression function. Returns the block state after the call. */
-
-local void fill_window    OF((deflate_state *s));
-local block_state deflate_stored OF((deflate_state *s, int flush));
-local block_state deflate_fast   OF((deflate_state *s, int flush));
-local block_state deflate_slow   OF((deflate_state *s, int flush));
-local void lm_init        OF((deflate_state *s));
-local void putShortMSB    OF((deflate_state *s, uInt b));
-local void flush_pending  OF((z_streamp strm));
-local int read_buf        OF((z_streamp strm, charf *buf, unsigned size));
-#ifdef ASMV
-      void match_init OF((void)); /* asm code initialization */
-      uInt longest_match  OF((deflate_state *s, IPos cur_match));
-#else
-local uInt longest_match  OF((deflate_state *s, IPos cur_match));
-#endif
-
-#ifdef DEBUG_ZLIB
-local  void check_match OF((deflate_state *s, IPos start, IPos match,
-                            int length));
-#endif
-
-/* ===========================================================================
- * Local data
- */
-
-#define NIL 0
-/* Tail of hash chains */
-
-#ifndef TOO_FAR
-#  define TOO_FAR 4096
-#endif
-/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-/* Values for max_lazy_match, good_match and max_chain_length, depending on
- * the desired pack level (0..9). The values given below have been tuned to
- * exclude worst case performance for pathological files. Better values may be
- * found for specific files.
- */
-typedef struct config_s {
-   ush good_length; /* reduce lazy search above this match length */
-   ush max_lazy;    /* do not perform lazy search above this match length */
-   ush nice_length; /* quit search above this match length */
-   ush max_chain;
-   compress_func func;
-} config;
-
-local config configuration_table[10] = {
-/*      good lazy nice chain */
-/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
-/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
-/* 2 */ {4,    5, 16,    8, deflate_fast},
-/* 3 */ {4,    6, 32,   32, deflate_fast},
-
-/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
-/* 5 */ {8,   16, 32,   32, deflate_slow},
-/* 6 */ {8,   16, 128, 128, deflate_slow},
-/* 7 */ {8,   32, 128, 256, deflate_slow},
-/* 8 */ {32, 128, 258, 1024, deflate_slow},
-/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
-
-/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
- * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
- * meaning.
- */
-
-#define EQUAL 0
-/* result of memcmp for equal strings */
-
-#ifndef NO_DUMMY_DECL
-struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
-#endif
-
-/* ===========================================================================
- * Update a hash value with the given input byte
- * IN  assertion: all calls to UPDATE_HASH are made with consecutive
- *    input characters, so that a running hash key can be computed from the
- *    previous key instead of complete recalculation each time.
- */
-#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
-
-
-/* ===========================================================================
- * Insert string str in the dictionary and set match_head to the previous head
- * of the hash chain (the most recent string with same hash key). Return
- * the previous length of the hash chain.
- * IN  assertion: all calls to INSERT_STRING are made with consecutive
- *    input characters and the first MIN_MATCH bytes of str are valid
- *    (except for the last MIN_MATCH-1 bytes of the input file).
- */
-#define INSERT_STRING(s, str, match_head) \
-   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
-    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
-    s->head[s->ins_h] = (Pos)(str))
-
-/* ===========================================================================
- * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
- * prev[] will be initialized on the fly.
- */
-#define CLEAR_HASH(s) \
-    s->head[s->hash_size-1] = NIL; \
-    zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
-
-/* ========================================================================= */
-int deflateInit_(strm, level, version, stream_size)
-    z_streamp strm;
-    int level;
-    const char *version;
-    int stream_size;
-{
-    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
-			 Z_DEFAULT_STRATEGY, version, stream_size);
-    /* To do: ignore strm->next_in if we use it as window */
-}
-
-/* ========================================================================= */
-int deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
-		  version, stream_size)
-    z_streamp strm;
-    int  level;
-    int  method;
-    int  windowBits;
-    int  memLevel;
-    int  strategy;
-    const char *version;
-    int stream_size;
-{
-    deflate_state *s;
-    int noheader = 0;
-    static char* my_version = ZLIB_VERSION;
-
-    ushf *overlay;
-    /* We overlay pending_buf and d_buf+l_buf. This works since the average
-     * output size for (length,distance) codes is <= 24 bits.
-     */
-
-    if (version == Z_NULL || version[0] != my_version[0] ||
-        stream_size != sizeof(z_stream)) {
-	return Z_VERSION_ERROR;
-    }
-    if (strm == Z_NULL) return Z_STREAM_ERROR;
-
-    strm->msg = Z_NULL;
-#ifndef NO_ZCFUNCS
-    if (strm->zalloc == Z_NULL) {
-	strm->zalloc = zcalloc;
-	strm->opaque = (voidpf)0;
-    }
-    if (strm->zfree == Z_NULL) strm->zfree = zcfree;
-#endif
-
-    if (level == Z_DEFAULT_COMPRESSION) level = 6;
-
-    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
-        noheader = 1;
-        windowBits = -windowBits;
-    }
-    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
-        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
-	strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-        return Z_STREAM_ERROR;
-    }
-    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
-    if (s == Z_NULL) return Z_MEM_ERROR;
-    strm->state = (struct internal_state FAR *)s;
-    s->strm = strm;
-
-    s->noheader = noheader;
-    s->w_bits = windowBits;
-    s->w_size = 1 << s->w_bits;
-    s->w_mask = s->w_size - 1;
-
-    s->hash_bits = memLevel + 7;
-    s->hash_size = 1 << s->hash_bits;
-    s->hash_mask = s->hash_size - 1;
-    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
-
-    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
-    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
-    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
-
-    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
-
-    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
-    s->pending_buf = (uchf *) overlay;
-    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
-
-    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
-        s->pending_buf == Z_NULL) {
-        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
-        deflateEnd (strm);
-        return Z_MEM_ERROR;
-    }
-    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
-    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
-
-    s->level = level;
-    s->strategy = strategy;
-    s->method = (Byte)method;
-
-    return deflateReset(strm);
-}
-
-/* ========================================================================= */
-int deflateSetDictionary (strm, dictionary, dictLength)
-    z_streamp strm;
-    const Bytef *dictionary;
-    uInt  dictLength;
-{
-    deflate_state *s;
-    uInt length = dictLength;
-    uInt n;
-    IPos hash_head = 0;
-
-    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
-	return Z_STREAM_ERROR;
-
-    s = (deflate_state *) strm->state;
-    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
-
-    strm->adler = adler32(strm->adler, dictionary, dictLength);
-
-    if (length < MIN_MATCH) return Z_OK;
-    if (length > MAX_DIST(s)) {
-	length = MAX_DIST(s);
-#ifndef USE_DICT_HEAD
-	dictionary += dictLength - length; /* use the tail of the dictionary */
-#endif
-    }
-    zmemcpy((charf *)s->window, dictionary, length);
-    s->strstart = length;
-    s->block_start = (long)length;
-
-    /* Insert all strings in the hash table (except for the last two bytes).
-     * s->lookahead stays null, so s->ins_h will be recomputed at the next
-     * call of fill_window.
-     */
-    s->ins_h = s->window[0];
-    UPDATE_HASH(s, s->ins_h, s->window[1]);
-    for (n = 0; n <= length - MIN_MATCH; n++) {
-	INSERT_STRING(s, n, hash_head);
-    }
-    if (hash_head) hash_head = 0;  /* to make compiler happy */
-    return Z_OK;
-}
-
-/* ========================================================================= */
-int deflateReset (strm)
-    z_streamp strm;
-{
-    deflate_state *s;
-    
-    if (strm == Z_NULL || strm->state == Z_NULL ||
-        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
-
-    strm->total_in = strm->total_out = 0;
-    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
-    strm->data_type = Z_UNKNOWN;
-
-    s = (deflate_state *)strm->state;
-    s->pending = 0;
-    s->pending_out = s->pending_buf;
-
-    if (s->noheader < 0) {
-        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
-    }
-    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
-    strm->adler = 1;
-    s->last_flush = Z_NO_FLUSH;
-
-    _tr_init(s);
-    lm_init(s);
-
-    return Z_OK;
-}
-
-/* ========================================================================= */
-int deflateParams(strm, level, strategy)
-    z_streamp strm;
-    int level;
-    int strategy;
-{
-    deflate_state *s;
-    compress_func func;
-    int err = Z_OK;
-
-    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-    s = (deflate_state *) strm->state;
-
-    if (level == Z_DEFAULT_COMPRESSION) {
-	level = 6;
-    }
-    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-	return Z_STREAM_ERROR;
-    }
-    func = configuration_table[s->level].func;
-
-    if (func != configuration_table[level].func && strm->total_in != 0) {
-	/* Flush the last buffer: */
-	err = deflate(strm, Z_PARTIAL_FLUSH);
-    }
-    if (s->level != level) {
-	s->level = level;
-	s->max_lazy_match   = configuration_table[level].max_lazy;
-	s->good_match       = configuration_table[level].good_length;
-	s->nice_match       = configuration_table[level].nice_length;
-	s->max_chain_length = configuration_table[level].max_chain;
-    }
-    s->strategy = strategy;
-    return err;
-}
-
-/* =========================================================================
- * Put a short in the pending buffer. The 16-bit value is put in MSB order.
- * IN assertion: the stream state is correct and there is enough room in
- * pending_buf.
- */
-local void putShortMSB (s, b)
-    deflate_state *s;
-    uInt b;
-{
-    put_byte(s, (Byte)(b >> 8));
-    put_byte(s, (Byte)(b & 0xff));
-}   
-
-/* =========================================================================
- * Flush as much pending output as possible. All deflate() output goes
- * through this function so some applications may wish to modify it
- * to avoid allocating a large strm->next_out buffer and copying into it.
- * (See also read_buf()).
- */
-local void flush_pending(strm)
-    z_streamp strm;
-{
-    deflate_state *s = (deflate_state *) strm->state;
-    unsigned len = s->pending;
-
-    if (len > strm->avail_out) len = strm->avail_out;
-    if (len == 0) return;
-
-    if (strm->next_out != Z_NULL) {
-	zmemcpy(strm->next_out, s->pending_out, len);
-	strm->next_out += len;
-    }
-    s->pending_out += len;
-    strm->total_out += len;
-    strm->avail_out  -= len;
-    s->pending -= len;
-    if (s->pending == 0) {
-        s->pending_out = s->pending_buf;
-    }
-}
-
-/* ========================================================================= */
-int deflate (strm, flush)
-    z_streamp strm;
-    int flush;
-{
-    int old_flush; /* value of flush param for previous deflate call */
-    deflate_state *s;
-
-    if (strm == Z_NULL || strm->state == Z_NULL ||
-	flush > Z_FINISH || flush < 0) {
-        return Z_STREAM_ERROR;
-    }
-    s = (deflate_state *) strm->state;
-
-    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
-	(s->status == FINISH_STATE && flush != Z_FINISH)) {
-        ERR_RETURN(strm, Z_STREAM_ERROR);
-    }
-    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
-
-    s->strm = strm; /* just in case */
-    old_flush = s->last_flush;
-    s->last_flush = flush;
-
-    /* Write the zlib header */
-    if (s->status == INIT_STATE) {
-
-        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
-        uInt level_flags = (s->level-1) >> 1;
-
-        if (level_flags > 3) level_flags = 3;
-        header |= (level_flags << 6);
-	if (s->strstart != 0) header |= PRESET_DICT;
-        header += 31 - (header % 31);
-
-        s->status = BUSY_STATE;
-        putShortMSB(s, header);
-
-	/* Save the adler32 of the preset dictionary: */
-	if (s->strstart != 0) {
-	    putShortMSB(s, (uInt)(strm->adler >> 16));
-	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
-	}
-	strm->adler = 1L;
-    }
-
-    /* Flush as much pending output as possible */
-    if (s->pending != 0) {
-        flush_pending(strm);
-        if (strm->avail_out == 0) {
-	    /* Since avail_out is 0, deflate will be called again with
-	     * more output space, but possibly with both pending and
-	     * avail_in equal to zero. There won't be anything to do,
-	     * but this is not an error situation so make sure we
-	     * return OK instead of BUF_ERROR at next call of deflate:
-             */
-	    s->last_flush = -1;
-	    return Z_OK;
-	}
-
-    /* Make sure there is something to do and avoid duplicate consecutive
-     * flushes. For repeated and useless calls with Z_FINISH, we keep
-     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
-     */
-    } else if (strm->avail_in == 0 && flush <= old_flush &&
-	       flush != Z_FINISH) {
-        ERR_RETURN(strm, Z_BUF_ERROR);
-    }
-
-    /* User must not provide more input after the first FINISH: */
-    if (s->status == FINISH_STATE && strm->avail_in != 0) {
-        ERR_RETURN(strm, Z_BUF_ERROR);
-    }
-
-    /* Start a new block or continue the current one.
-     */
-    if (strm->avail_in != 0 || s->lookahead != 0 ||
-        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
-        block_state bstate;
-
-	bstate = (*(configuration_table[s->level].func))(s, flush);
-
-        if (bstate == finish_started || bstate == finish_done) {
-            s->status = FINISH_STATE;
-        }
-        if (bstate == need_more || bstate == finish_started) {
-	    if (strm->avail_out == 0) {
-	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
-	    }
-	    return Z_OK;
-	    /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
-	     * of deflate should use the same flush parameter to make sure
-	     * that the flush is complete. So we don't have to output an
-	     * empty block here, this will be done at next call. This also
-	     * ensures that for a very small output buffer, we emit at most
-	     * one empty block.
-	     */
-	}
-        if (bstate == block_done) {
-            if (flush == Z_PARTIAL_FLUSH) {
-                _tr_align(s);
-	    } else if (flush == Z_PACKET_FLUSH) {
-		/* Output just the 3-bit `stored' block type value,
-		   but not a zero length. */
-		_tr_stored_type_only(s);
-            } else { /* FULL_FLUSH or SYNC_FLUSH */
-                _tr_stored_block(s, (char*)0, 0L, 0);
-                /* For a full flush, this empty block will be recognized
-                 * as a special marker by inflate_sync().
-                 */
-                if (flush == Z_FULL_FLUSH) {
-                    CLEAR_HASH(s);             /* forget history */
-                }
-            }
-            flush_pending(strm);
-	    if (strm->avail_out == 0) {
-	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
-	      return Z_OK;
-	    }
-        }
-    }
-    Assert(strm->avail_out > 0, "bug2");
-
-    if (flush != Z_FINISH) return Z_OK;
-    if (s->noheader) return Z_STREAM_END;
-
-    /* Write the zlib trailer (adler32) */
-    putShortMSB(s, (uInt)(strm->adler >> 16));
-    putShortMSB(s, (uInt)(strm->adler & 0xffff));
-    flush_pending(strm);
-    /* If avail_out is zero, the application will call deflate again
-     * to flush the rest.
-     */
-    s->noheader = -1; /* write the trailer only once! */
-    return s->pending != 0 ? Z_OK : Z_STREAM_END;
-}
-
-/* ========================================================================= */
-int deflateEnd (strm)
-    z_streamp strm;
-{
-    int status;
-    deflate_state *s;
-
-    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-    s = (deflate_state *) strm->state;
-
-    status = s->status;
-    if (status != INIT_STATE && status != BUSY_STATE &&
-	status != FINISH_STATE) {
-      return Z_STREAM_ERROR;
-    }
-
-    /* Deallocate in reverse order of allocations: */
-    TRY_FREE(strm, s->pending_buf);
-    TRY_FREE(strm, s->head);
-    TRY_FREE(strm, s->prev);
-    TRY_FREE(strm, s->window);
-
-    ZFREE(strm, s);
-    strm->state = Z_NULL;
-
-    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
-}
-
-/* =========================================================================
- * Copy the source state to the destination state.
- */
-int deflateCopy (dest, source)
-    z_streamp dest;
-    z_streamp source;
-{
-    deflate_state *ds;
-    deflate_state *ss;
-    ushf *overlay;
-
-    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL)
-        return Z_STREAM_ERROR;
-    ss = (deflate_state *) source->state;
-
-    *dest = *source;
-
-    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
-    if (ds == Z_NULL) return Z_MEM_ERROR;
-    dest->state = (struct internal_state FAR *) ds;
-    *ds = *ss;
-    ds->strm = dest;
-
-    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
-    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
-    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
-    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
-    ds->pending_buf = (uchf *) overlay;
-
-    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
-        ds->pending_buf == Z_NULL) {
-        deflateEnd (dest);
-        return Z_MEM_ERROR;
-    }
-    /* ??? following zmemcpy doesn't work for 16-bit MSDOS */
-    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
-    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
-    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
-    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
-
-    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
-    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
-    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
-
-    ds->l_desc.dyn_tree = ds->dyn_ltree;
-    ds->d_desc.dyn_tree = ds->dyn_dtree;
-    ds->bl_desc.dyn_tree = ds->bl_tree;
-
-    return Z_OK;
-}
-
-/* ===========================================================================
- * Return the number of bytes of output which are immediately available
- * for output from the decompressor.
- */
-int deflateOutputPending (strm)
-    z_streamp strm;
-{
-    if (strm == Z_NULL || strm->state == Z_NULL) return 0;
-    
-    return ((deflate_state *)(strm->state))->pending;
-}
-
-/* ===========================================================================
- * Read a new buffer from the current input stream, update the adler32
- * and total number of bytes read.  All deflate() input goes through
- * this function so some applications may wish to modify it to avoid
- * allocating a large strm->next_in buffer and copying from it.
- * (See also flush_pending()).
- */
-local int read_buf(strm, buf, size)
-    z_streamp strm;
-    charf *buf;
-    unsigned size;
-{
-    unsigned len = strm->avail_in;
-
-    if (len > size) len = size;
-    if (len == 0) return 0;
-
-    strm->avail_in  -= len;
-
-    if (!((deflate_state *)(strm->state))->noheader) {
-        strm->adler = adler32(strm->adler, strm->next_in, len);
-    }
-    zmemcpy(buf, strm->next_in, len);
-    strm->next_in  += len;
-    strm->total_in += len;
-
-    return (int)len;
-}
-
-/* ===========================================================================
- * Initialize the "longest match" routines for a new zlib stream
- */
-local void lm_init (s)
-    deflate_state *s;
-{
-    s->window_size = (ulg)2L*s->w_size;
-
-    CLEAR_HASH(s);
-
-    /* Set the default configuration parameters:
-     */
-    s->max_lazy_match   = configuration_table[s->level].max_lazy;
-    s->good_match       = configuration_table[s->level].good_length;
-    s->nice_match       = configuration_table[s->level].nice_length;
-    s->max_chain_length = configuration_table[s->level].max_chain;
-
-    s->strstart = 0;
-    s->block_start = 0L;
-    s->lookahead = 0;
-    s->match_length = s->prev_length = MIN_MATCH-1;
-    s->match_available = 0;
-    s->ins_h = 0;
-#ifdef ASMV
-    match_init(); /* initialize the asm code */
-#endif
-}
-
-/* ===========================================================================
- * Set match_start to the longest match starting at the given string and
- * return its length. Matches shorter or equal to prev_length are discarded,
- * in which case the result is equal to prev_length and match_start is
- * garbage.
- * IN assertions: cur_match is the head of the hash chain for the current
- *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
- * OUT assertion: the match length is not greater than s->lookahead.
- */
-#ifndef ASMV
-/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
- * match.S. The code will be functionally equivalent.
- */
-local uInt longest_match(s, cur_match)
-    deflate_state *s;
-    IPos cur_match;                             /* current match */
-{
-    unsigned chain_length = s->max_chain_length;/* max hash chain length */
-    register Bytef *scan = s->window + s->strstart; /* current string */
-    register Bytef *match;                       /* matched string */
-    register int len;                           /* length of current match */
-    int best_len = s->prev_length;              /* best match length so far */
-    int nice_match = s->nice_match;             /* stop if match long enough */
-    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
-        s->strstart - (IPos)MAX_DIST(s) : NIL;
-    /* Stop when cur_match becomes <= limit. To simplify the code,
-     * we prevent matches with the string of window index 0.
-     */
-    Posf *prev = s->prev;
-    uInt wmask = s->w_mask;
-
-#ifdef UNALIGNED_OK
-    /* Compare two bytes at a time. Note: this is not always beneficial.
-     * Try with and without -DUNALIGNED_OK to check.
-     */
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
-    register ush scan_start = *(ushf*)scan;
-    register ush scan_end   = *(ushf*)(scan+best_len-1);
-#else
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
-    register Byte scan_end1  = scan[best_len-1];
-    register Byte scan_end   = scan[best_len];
-#endif
-
-    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
-     * It is easy to get rid of this optimization if necessary.
-     */
-    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
-
-    /* Do not waste too much time if we already have a good match: */
-    if (s->prev_length >= s->good_match) {
-        chain_length >>= 2;
-    }
-    /* Do not look for matches beyond the end of the input. This is necessary
-     * to make deflate deterministic.
-     */
-    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
-
-    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
-
-    do {
-        Assert(cur_match < s->strstart, "no future");
-        match = s->window + cur_match;
-
-        /* Skip to next match if the match length cannot increase
-         * or if the match length is less than 2:
-         */
-#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
-        /* This code assumes sizeof(unsigned short) == 2. Do not use
-         * UNALIGNED_OK if your compiler uses a different size.
-         */
-        if (*(ushf*)(match+best_len-1) != scan_end ||
-            *(ushf*)match != scan_start) continue;
-
-        /* It is not necessary to compare scan[2] and match[2] since they are
-         * always equal when the other bytes match, given that the hash keys
-         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
-         * strstart+3, +5, ... up to strstart+257. We check for insufficient
-         * lookahead only every 4th comparison; the 128th check will be made
-         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
-         * necessary to put more guard bytes at the end of the window, or
-         * to check more often for insufficient lookahead.
-         */
-        Assert(scan[2] == match[2], "scan[2]?");
-        scan++, match++;
-        do {
-        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 scan < strend);
-        /* The funny "do {}" generates better code on most compilers */
-
-        /* Here, scan <= window+strstart+257 */
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-        if (*scan == *match) scan++;
-
-        len = (MAX_MATCH - 1) - (int)(strend-scan);
-        scan = strend - (MAX_MATCH-1);
-
-#else /* UNALIGNED_OK */
-
-        if (match[best_len]   != scan_end  ||
-            match[best_len-1] != scan_end1 ||
-            *match            != *scan     ||
-            *++match          != scan[1])      continue;
-
-        /* The check at best_len-1 can be removed because it will be made
-         * again later. (This heuristic is not always a win.)
-         * It is not necessary to compare scan[2] and match[2] since they
-         * are always equal when the other bytes match, given that
-         * the hash keys are equal and that HASH_BITS >= 8.
-         */
-        scan += 2, match++;
-        Assert(*scan == *match, "match[2]?");
-
-        /* We check for insufficient lookahead only every 8th comparison;
-         * the 256th check will be made at strstart+258.
-         */
-        do {
-        } while (*++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 scan < strend);
-
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-
-        len = MAX_MATCH - (int)(strend - scan);
-        scan = strend - MAX_MATCH;
-
-#endif /* UNALIGNED_OK */
-
-        if (len > best_len) {
-            s->match_start = cur_match;
-            best_len = len;
-            if (len >= nice_match) break;
-#ifdef UNALIGNED_OK
-            scan_end = *(ushf*)(scan+best_len-1);
-#else
-            scan_end1  = scan[best_len-1];
-            scan_end   = scan[best_len];
-#endif
-        }
-    } while ((cur_match = prev[cur_match & wmask]) > limit
-             && --chain_length != 0);
-
-    if ((uInt)best_len <= s->lookahead) return best_len;
-    return s->lookahead;
-}
-#endif /* ASMV */
-
-#ifdef DEBUG_ZLIB
-/* ===========================================================================
- * Check that the match at match_start is indeed a match.
- */
-local void check_match(s, start, match, length)
-    deflate_state *s;
-    IPos start, match;
-    int length;
-{
-    /* check that the match is indeed a match */
-    if (zmemcmp((charf *)s->window + match,
-                (charf *)s->window + start, length) != EQUAL) {
-        fprintf(stderr, " start %u, match %u, length %d\n",
-		start, match, length);
-        do {
-	    fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
-	} while (--length != 0);
-        z_error("invalid match");
-    }
-    if (z_verbose > 1) {
-        fprintf(stderr,"\\[%d,%d]", start-match, length);
-        do { putc(s->window[start++], stderr); } while (--length != 0);
-    }
-}
-#else
-#  define check_match(s, start, match, length)
-#endif
-
-/* ===========================================================================
- * Fill the window when the lookahead becomes insufficient.
- * Updates strstart and lookahead.
- *
- * IN assertion: lookahead < MIN_LOOKAHEAD
- * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
- *    At least one byte has been read, or avail_in == 0; reads are
- *    performed for at least two bytes (required for the zip translate_eol
- *    option -- not supported here).
- */
-local void fill_window(s)
-    deflate_state *s;
-{
-    register unsigned n, m;
-    register Posf *p;
-    unsigned more;    /* Amount of free space at the end of the window. */
-    uInt wsize = s->w_size;
-
-    do {
-        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
-
-        /* Deal with !@#$% 64K limit: */
-        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
-            more = wsize;
-
-        } else if (more == (unsigned)(-1)) {
-            /* Very unlikely, but possible on 16 bit machine if strstart == 0
-             * and lookahead == 1 (input done one byte at time)
-             */
-            more--;
-
-        /* If the window is almost full and there is insufficient lookahead,
-         * move the upper half to the lower one to make room in the upper half.
-         */
-        } else if (s->strstart >= wsize+MAX_DIST(s)) {
-
-            zmemcpy((charf *)s->window, (charf *)s->window+wsize,
-                   (unsigned)wsize);
-            s->match_start -= wsize;
-            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
-            s->block_start -= (long) wsize;
-
-            /* Slide the hash table (could be avoided with 32 bit values
-               at the expense of memory usage). We slide even when level == 0
-               to keep the hash table consistent if we switch back to level > 0
-               later. (Using level 0 permanently is not an optimal usage of
-               zlib, so we don't care about this pathological case.)
-             */
-            n = s->hash_size;
-            p = &s->head[n];
-            do {
-                m = *--p;
-                *p = (Pos)(m >= wsize ? m-wsize : NIL);
-            } while (--n);
-
-            n = wsize;
-            p = &s->prev[n];
-            do {
-                m = *--p;
-                *p = (Pos)(m >= wsize ? m-wsize : NIL);
-                /* If n is not on any hash chain, prev[n] is garbage but
-                 * its value will never be used.
-                 */
-            } while (--n);
-            more += wsize;
-        }
-        if (s->strm->avail_in == 0) return;
-
-        /* If there was no sliding:
-         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
-         *    more == window_size - lookahead - strstart
-         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
-         * => more >= window_size - 2*WSIZE + 2
-         * In the BIG_MEM or MMAP case (not yet supported),
-         *   window_size == input_size + MIN_LOOKAHEAD  &&
-         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
-         * Otherwise, window_size == 2*WSIZE so more >= 2.
-         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
-         */
-        Assert(more >= 2, "more < 2");
-
-        n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
-                     more);
-        s->lookahead += n;
-
-        /* Initialize the hash value now that we have some input: */
-        if (s->lookahead >= MIN_MATCH) {
-            s->ins_h = s->window[s->strstart];
-            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-#if MIN_MATCH != 3
-            Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
-        }
-        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
-         * but this is not important since only literal bytes will be emitted.
-         */
-
-    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
-}
-
-/* ===========================================================================
- * Flush the current block, with given end-of-file flag.
- * IN assertion: strstart is set to the end of the current match.
- */
-#define FLUSH_BLOCK_ONLY(s, eof) { \
-   _tr_flush_block(s, (s->block_start >= 0L ? \
-                   (charf *)&s->window[(unsigned)s->block_start] : \
-                   (charf *)Z_NULL), \
-		(ulg)((long)s->strstart - s->block_start), \
-		(eof)); \
-   s->block_start = s->strstart; \
-   flush_pending(s->strm); \
-   Tracev((stderr,"[FLUSH]")); \
-}
-
-/* Same but force premature exit if necessary. */
-#define FLUSH_BLOCK(s, eof) { \
-   FLUSH_BLOCK_ONLY(s, eof); \
-   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
-}
-
-/* ===========================================================================
- * Copy without compression as much as possible from the input stream, return
- * the current block state.
- * This function does not insert new strings in the dictionary since
- * uncompressible data is probably not useful. This function is used
- * only for the level=0 compression option.
- * NOTE: this function should be optimized to avoid extra copying from
- * window to pending_buf.
- */
-local block_state deflate_stored(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
-     * to pending_buf_size, and each stored block has a 5 byte header:
-     */
-    ulg max_block_size = 0xffff;
-    ulg max_start;
-
-    if (max_block_size > s->pending_buf_size - 5) {
-        max_block_size = s->pending_buf_size - 5;
-    }
-
-    /* Copy as much as possible from input to output: */
-    for (;;) {
-        /* Fill the window as much as possible: */
-        if (s->lookahead <= 1) {
-
-            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
-		   s->block_start >= (long)s->w_size, "slide too late");
-
-            fill_window(s);
-            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
-
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-	Assert(s->block_start >= 0L, "block gone");
-
-	s->strstart += s->lookahead;
-	s->lookahead = 0;
-
-	/* Emit a stored block if pending_buf will be full: */
- 	max_start = s->block_start + max_block_size;
-        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
-	    /* strstart == 0 is possible when wraparound on 16-bit machine */
-	    s->lookahead = (uInt)(s->strstart - max_start);
-	    s->strstart = (uInt)max_start;
-            FLUSH_BLOCK(s, 0);
-	}
-	/* Flush if we may have to slide, otherwise block_start may become
-         * negative and the data will be gone:
-         */
-        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
-            FLUSH_BLOCK(s, 0);
-	}
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-
-/* ===========================================================================
- * Compress as much as possible from the input stream, return the current
- * block state.
- * This function does not perform lazy evaluation of matches and inserts
- * new strings in the dictionary only for unmatched strings or for short
- * matches. It is used only for the fast compression options.
- */
-local block_state deflate_fast(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    IPos hash_head = NIL; /* head of the hash chain */
-    int bflush;           /* set if current block must be flushed */
-
-    for (;;) {
-        /* Make sure that we always have enough lookahead, except
-         * at the end of the input file. We need MAX_MATCH bytes
-         * for the next match, plus MIN_MATCH bytes to insert the
-         * string following the next match.
-         */
-        if (s->lookahead < MIN_LOOKAHEAD) {
-            fill_window(s);
-            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-	        return need_more;
-	    }
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-
-        /* Insert the string window[strstart .. strstart+2] in the
-         * dictionary, and set hash_head to the head of the hash chain:
-         */
-        if (s->lookahead >= MIN_MATCH) {
-            INSERT_STRING(s, s->strstart, hash_head);
-        }
-
-        /* Find the longest match, discarding those <= prev_length.
-         * At this point we have always match_length < MIN_MATCH
-         */
-        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
-            /* To simplify the code, we prevent matches with the string
-             * of window index 0 (in particular we have to avoid a match
-             * of the string with itself at the start of the input file).
-             */
-            if (s->strategy != Z_HUFFMAN_ONLY) {
-                s->match_length = longest_match (s, hash_head);
-            }
-            /* longest_match() sets match_start */
-        }
-        if (s->match_length >= MIN_MATCH) {
-            check_match(s, s->strstart, s->match_start, s->match_length);
-
-            bflush = _tr_tally(s, s->strstart - s->match_start,
-                               s->match_length - MIN_MATCH);
-
-            s->lookahead -= s->match_length;
-
-            /* Insert new strings in the hash table only if the match length
-             * is not too large. This saves time but degrades compression.
-             */
-            if (s->match_length <= s->max_insert_length &&
-                s->lookahead >= MIN_MATCH) {
-                s->match_length--; /* string at strstart already in hash table */
-                do {
-                    s->strstart++;
-                    INSERT_STRING(s, s->strstart, hash_head);
-                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
-                     * always MIN_MATCH bytes ahead.
-                     */
-                } while (--s->match_length != 0);
-                s->strstart++; 
-            } else {
-                s->strstart += s->match_length;
-                s->match_length = 0;
-                s->ins_h = s->window[s->strstart];
-                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-#if MIN_MATCH != 3
-                Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
-                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
-                 * matter since it will be recomputed at next deflate call.
-                 */
-            }
-        } else {
-            /* No match, output a literal byte */
-            Tracevv((stderr,"%c", s->window[s->strstart]));
-            bflush = _tr_tally (s, 0, s->window[s->strstart]);
-            s->lookahead--;
-            s->strstart++; 
-        }
-        if (bflush) FLUSH_BLOCK(s, 0);
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-
-/* ===========================================================================
- * Same as above, but achieves better compression. We use a lazy
- * evaluation for matches: a match is finally adopted only if there is
- * no better match at the next window position.
- */
-local block_state deflate_slow(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    IPos hash_head = NIL;    /* head of hash chain */
-    int bflush;              /* set if current block must be flushed */
-
-    /* Process the input block. */
-    for (;;) {
-        /* Make sure that we always have enough lookahead, except
-         * at the end of the input file. We need MAX_MATCH bytes
-         * for the next match, plus MIN_MATCH bytes to insert the
-         * string following the next match.
-         */
-        if (s->lookahead < MIN_LOOKAHEAD) {
-            fill_window(s);
-            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-	        return need_more;
-	    }
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-
-        /* Insert the string window[strstart .. strstart+2] in the
-         * dictionary, and set hash_head to the head of the hash chain:
-         */
-        if (s->lookahead >= MIN_MATCH) {
-            INSERT_STRING(s, s->strstart, hash_head);
-        }
-
-        /* Find the longest match, discarding those <= prev_length.
-         */
-        s->prev_length = s->match_length, s->prev_match = s->match_start;
-        s->match_length = MIN_MATCH-1;
-
-        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
-            s->strstart - hash_head <= MAX_DIST(s)) {
-            /* To simplify the code, we prevent matches with the string
-             * of window index 0 (in particular we have to avoid a match
-             * of the string with itself at the start of the input file).
-             */
-            if (s->strategy != Z_HUFFMAN_ONLY) {
-                s->match_length = longest_match (s, hash_head);
-            }
-            /* longest_match() sets match_start */
-
-            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
-                 (s->match_length == MIN_MATCH &&
-                  s->strstart - s->match_start > TOO_FAR))) {
-
-                /* If prev_match is also MIN_MATCH, match_start is garbage
-                 * but we will ignore the current match anyway.
-                 */
-                s->match_length = MIN_MATCH-1;
-            }
-        }
-        /* If there was a match at the previous step and the current
-         * match is not better, output the previous match:
-         */
-        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
-            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
-            /* Do not insert strings in hash table beyond this. */
-
-            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
-
-            bflush = _tr_tally(s, s->strstart -1 - s->prev_match,
-                               s->prev_length - MIN_MATCH);
-
-            /* Insert in hash table all strings up to the end of the match.
-             * strstart-1 and strstart are already inserted. If there is not
-             * enough lookahead, the last two strings are not inserted in
-             * the hash table.
-             */
-            s->lookahead -= s->prev_length-1;
-            s->prev_length -= 2;
-            do {
-                if (++s->strstart <= max_insert) {
-                    INSERT_STRING(s, s->strstart, hash_head);
-                }
-            } while (--s->prev_length != 0);
-            s->match_available = 0;
-            s->match_length = MIN_MATCH-1;
-            s->strstart++;
-
-            if (bflush) FLUSH_BLOCK(s, 0);
-
-        } else if (s->match_available) {
-            /* If there was no match at the previous position, output a
-             * single literal. If there was a match but the current match
-             * is longer, truncate the previous match to a single literal.
-             */
-            Tracevv((stderr,"%c", s->window[s->strstart-1]));
-            if (_tr_tally (s, 0, s->window[s->strstart-1])) {
-                FLUSH_BLOCK_ONLY(s, 0);
-            }
-            s->strstart++;
-            s->lookahead--;
-            if (s->strm->avail_out == 0) return need_more;
-        } else {
-            /* There is no previous match to compare with, wait for
-             * the next step to decide.
-             */
-            s->match_available = 1;
-            s->strstart++;
-            s->lookahead--;
-        }
-    }
-    Assert (flush != Z_NO_FLUSH, "no flush?");
-    if (s->match_available) {
-        Tracevv((stderr,"%c", s->window[s->strstart-1]));
-        _tr_tally (s, 0, s->window[s->strstart-1]);
-        s->match_available = 0;
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-/* --- deflate.c */
-
-/* +++ trees.c */
-/* trees.c -- output deflated data using Huffman coding
- * Copyright (C) 1995-1996 Jean-loup Gailly
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/*
- *  ALGORITHM
- *
- *      The "deflation" process uses several Huffman trees. The more
- *      common source values are represented by shorter bit sequences.
- *
- *      Each code tree is stored in a compressed form which is itself
- * a Huffman encoding of the lengths of all the code strings (in
- * ascending order by source values).  The actual code strings are
- * reconstructed from the lengths in the inflate process, as described
- * in the deflate specification.
- *
- *  REFERENCES
- *
- *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
- *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
- *
- *      Storer, James A.
- *          Data Compression:  Methods and Theory, pp. 49-50.
- *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
- *
- *      Sedgewick, R.
- *          Algorithms, p290.
- *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
- */
-
-/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
-
-/* #include "deflate.h" */
-
-#ifdef DEBUG_ZLIB
-#  include <ctype.h>
-#endif
-
-/* ===========================================================================
- * Constants
- */
-
-#define MAX_BL_BITS 7
-/* Bit length codes must not exceed MAX_BL_BITS bits */
-
-#define END_BLOCK 256
-/* end of block literal code */
-
-#define REP_3_6      16
-/* repeat previous bit length 3-6 times (2 bits of repeat count) */
-
-#define REPZ_3_10    17
-/* repeat a zero length 3-10 times  (3 bits of repeat count) */
-
-#define REPZ_11_138  18
-/* repeat a zero length 11-138 times  (7 bits of repeat count) */
-
-local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
-   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
-
-local int extra_dbits[D_CODES] /* extra bits for each distance code */
-   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
-
-local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
-   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
-
-local uch bl_order[BL_CODES]
-   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
-/* The lengths of the bit length codes are sent in order of decreasing
- * probability, to avoid transmitting the lengths for unused bit length codes.
- */
-
-#define Buf_size (8 * 2*sizeof(char))
-/* Number of bits used within bi_buf. (bi_buf might be implemented on
- * more than 16 bits on some systems.)
- */
-
-/* ===========================================================================
- * Local data. These are initialized only once.
- */
-
-local ct_data static_ltree[L_CODES+2];
-/* The static literal tree. Since the bit lengths are imposed, there is no
- * need for the L_CODES extra codes used during heap construction. However
- * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
- * below).
- */
-
-local ct_data static_dtree[D_CODES];
-/* The static distance tree. (Actually a trivial tree since all codes use
- * 5 bits.)
- */
-
-local uch dist_code[512];
-/* distance codes. The first 256 values correspond to the distances
- * 3 .. 258, the last 256 values correspond to the top 8 bits of
- * the 15 bit distances.
- */
-
-local uch length_code[MAX_MATCH-MIN_MATCH+1];
-/* length code for each normalized match length (0 == MIN_MATCH) */
-
-local int base_length[LENGTH_CODES];
-/* First normalized length for each code (0 = MIN_MATCH) */
-
-local int base_dist[D_CODES];
-/* First normalized distance for each code (0 = distance of 1) */
-
-struct static_tree_desc_s {
-    ct_data *static_tree;        /* static tree or NULL */
-    intf    *extra_bits;         /* extra bits for each code or NULL */
-    int     extra_base;          /* base index for extra_bits */
-    int     elems;               /* max number of elements in the tree */
-    int     max_length;          /* max bit length for the codes */
-};
-
-local static_tree_desc  static_l_desc =
-{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
-
-local static_tree_desc  static_d_desc =
-{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
-
-local static_tree_desc  static_bl_desc =
-{(ct_data *)0, extra_blbits, 0,      BL_CODES, MAX_BL_BITS};
-
-/* ===========================================================================
- * Local (static) routines in this file.
- */
-
-local void tr_static_init OF((void));
-local void init_block     OF((deflate_state *s));
-local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
-local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
-local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
-local void build_tree     OF((deflate_state *s, tree_desc *desc));
-local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
-local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
-local int  build_bl_tree  OF((deflate_state *s));
-local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
-                              int blcodes));
-local void compress_block OF((deflate_state *s, ct_data *ltree,
-                              ct_data *dtree));
-local void set_data_type  OF((deflate_state *s));
-local unsigned bi_reverse OF((unsigned value, int length));
-local void bi_windup      OF((deflate_state *s));
-local void bi_flush       OF((deflate_state *s));
-local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
-                              int header));
-
-#ifndef DEBUG_ZLIB
-#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
-   /* Send a code of the given tree. c and tree must not have side effects */
-
-#else /* DEBUG_ZLIB */
-#  define send_code(s, c, tree) \
-     { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
-       send_bits(s, tree[c].Code, tree[c].Len); }
-#endif
-
-#define d_code(dist) \
-   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
-/* Mapping from a distance to a distance code. dist is the distance - 1 and
- * must not have side effects. dist_code[256] and dist_code[257] are never
- * used.
- */
-
-/* ===========================================================================
- * Output a short LSB first on the stream.
- * IN assertion: there is enough room in pendingBuf.
- */
-#define put_short(s, w) { \
-    put_byte(s, (uch)((w) & 0xff)); \
-    put_byte(s, (uch)((ush)(w) >> 8)); \
-}
-
-/* ===========================================================================
- * Send a value on a given number of bits.
- * IN assertion: length <= 16 and value fits in length bits.
- */
-#ifdef DEBUG_ZLIB
-local void send_bits      OF((deflate_state *s, int value, int length));
-
-local void send_bits(s, value, length)
-    deflate_state *s;
-    int value;  /* value to send */
-    int length; /* number of bits */
-{
-    Tracevv((stderr," l %2d v %4x ", length, value));
-    Assert(length > 0 && length <= 15, "invalid length");
-    s->bits_sent += (ulg)length;
-
-    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
-     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
-     * unused bits in value.
-     */
-    if (s->bi_valid > (int)Buf_size - length) {
-        s->bi_buf |= (value << s->bi_valid);
-        put_short(s, s->bi_buf);
-        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
-        s->bi_valid += length - Buf_size;
-    } else {
-        s->bi_buf |= value << s->bi_valid;
-        s->bi_valid += length;
-    }
-}
-#else /* !DEBUG_ZLIB */
-
-#define send_bits(s, value, length) \
-{ int len = length;\
-  if (s->bi_valid > (int)Buf_size - len) {\
-    int val = value;\
-    s->bi_buf |= (val << s->bi_valid);\
-    put_short(s, s->bi_buf);\
-    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
-    s->bi_valid += len - Buf_size;\
-  } else {\
-    s->bi_buf |= (value) << s->bi_valid;\
-    s->bi_valid += len;\
-  }\
-}
-#endif /* DEBUG_ZLIB */
-
-
-#define MAX(a,b) (a >= b ? a : b)
-/* the arguments must not have side effects */
-
-/* ===========================================================================
- * Initialize the various 'constant' tables. In a multi-threaded environment,
- * this function may be called by two threads concurrently, but this is
- * harmless since both invocations do exactly the same thing.
- */
-local void tr_static_init()
-{
-    static int static_init_done;
-    int n;        /* iterates over tree elements */
-    int bits;     /* bit counter */
-    int length;   /* length value */
-    int code;     /* code value */
-    int dist;     /* distance index */
-    ush bl_count[MAX_BITS+1];
-    /* number of codes at each bit length for an optimal tree */
-
-    if (static_init_done) return;
-
-    /* Initialize the mapping length (0..255) -> length code (0..28) */
-    length = 0;
-    for (code = 0; code < LENGTH_CODES-1; code++) {
-        base_length[code] = length;
-        for (n = 0; n < (1<<extra_lbits[code]); n++) {
-            length_code[length++] = (uch)code;
-        }
-    }
-    Assert (length == 256, "tr_static_init: length != 256");
-    /* Note that the length 255 (match length 258) can be represented
-     * in two different ways: code 284 + 5 bits or code 285, so we
-     * overwrite length_code[255] to use the best encoding:
-     */
-    length_code[length-1] = (uch)code;
-
-    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
-    dist = 0;
-    for (code = 0 ; code < 16; code++) {
-        base_dist[code] = dist;
-        for (n = 0; n < (1<<extra_dbits[code]); n++) {
-            dist_code[dist++] = (uch)code;
-        }
-    }
-    Assert (dist == 256, "tr_static_init: dist != 256");
-    dist >>= 7; /* from now on, all distances are divided by 128 */
-    for ( ; code < D_CODES; code++) {
-        base_dist[code] = dist << 7;
-        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
-            dist_code[256 + dist++] = (uch)code;
-        }
-    }
-    Assert (dist == 256, "tr_static_init: 256+dist != 512");
-
-    /* Construct the codes of the static literal tree */
-    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
-    n = 0;
-    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
-    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
-    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
-    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
-    /* Codes 286 and 287 do not exist, but we must include them in the
-     * tree construction to get a canonical Huffman tree (longest code
-     * all ones)
-     */
-    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
-
-    /* The static distance tree is trivial: */
-    for (n = 0; n < D_CODES; n++) {
-        static_dtree[n].Len = 5;
-        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
-    }
-    static_init_done = 1;
-}
-
-/* ===========================================================================
- * Initialize the tree data structures for a new zlib stream.
- */
-void _tr_init(s)
-    deflate_state *s;
-{
-    tr_static_init();
-
-    s->compressed_len = 0L;
-
-    s->l_desc.dyn_tree = s->dyn_ltree;
-    s->l_desc.stat_desc = &static_l_desc;
-
-    s->d_desc.dyn_tree = s->dyn_dtree;
-    s->d_desc.stat_desc = &static_d_desc;
-
-    s->bl_desc.dyn_tree = s->bl_tree;
-    s->bl_desc.stat_desc = &static_bl_desc;
-
-    s->bi_buf = 0;
-    s->bi_valid = 0;
-    s->last_eob_len = 8; /* enough lookahead for inflate */
-#ifdef DEBUG_ZLIB
-    s->bits_sent = 0L;
-#endif
-
-    /* Initialize the first block of the first file: */
-    init_block(s);
-}
-
-/* ===========================================================================
- * Initialize a new block.
- */
-local void init_block(s)
-    deflate_state *s;
-{
-    int n; /* iterates over tree elements */
-
-    /* Initialize the trees. */
-    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
-    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
-    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
-
-    s->dyn_ltree[END_BLOCK].Freq = 1;
-    s->opt_len = s->static_len = 0L;
-    s->last_lit = s->matches = 0;
-}
-
-#define SMALLEST 1
-/* Index within the heap array of least frequent node in the Huffman tree */
-
-
-/* ===========================================================================
- * Remove the smallest element from the heap and recreate the heap with
- * one less element. Updates heap and heap_len.
- */
-#define pqremove(s, tree, top) \
-{\
-    top = s->heap[SMALLEST]; \
-    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
-    pqdownheap(s, tree, SMALLEST); \
-}
-
-/* ===========================================================================
- * Compares to subtrees, using the tree depth as tie breaker when
- * the subtrees have equal frequency. This minimizes the worst case length.
- */
-#define smaller(tree, n, m, depth) \
-   (tree[n].Freq < tree[m].Freq || \
-   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
-
-/* ===========================================================================
- * Restore the heap property by moving down the tree starting at node k,
- * exchanging a node with the smallest of its two sons if necessary, stopping
- * when the heap property is re-established (each father smaller than its
- * two sons).
- */
-local void pqdownheap(s, tree, k)
-    deflate_state *s;
-    ct_data *tree;  /* the tree to restore */
-    int k;               /* node to move down */
-{
-    int v = s->heap[k];
-    int j = k << 1;  /* left son of k */
-    while (j <= s->heap_len) {
-        /* Set j to the smallest of the two sons: */
-        if (j < s->heap_len &&
-            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
-            j++;
-        }
-        /* Exit if v is smaller than both sons */
-        if (smaller(tree, v, s->heap[j], s->depth)) break;
-
-        /* Exchange v with the smallest son */
-        s->heap[k] = s->heap[j];  k = j;
-
-        /* And continue down the tree, setting j to the left son of k */
-        j <<= 1;
-    }
-    s->heap[k] = v;
-}
-
-/* ===========================================================================
- * Compute the optimal bit lengths for a tree and update the total bit length
- * for the current block.
- * IN assertion: the fields freq and dad are set, heap[heap_max] and
- *    above are the tree nodes sorted by increasing frequency.
- * OUT assertions: the field len is set to the optimal bit length, the
- *     array bl_count contains the frequencies for each bit length.
- *     The length opt_len is updated; static_len is also updated if stree is
- *     not null.
- */
-local void gen_bitlen(s, desc)
-    deflate_state *s;
-    tree_desc *desc;    /* the tree descriptor */
-{
-    ct_data *tree  = desc->dyn_tree;
-    int max_code   = desc->max_code;
-    ct_data *stree = desc->stat_desc->static_tree;
-    intf *extra    = desc->stat_desc->extra_bits;
-    int base       = desc->stat_desc->extra_base;
-    int max_length = desc->stat_desc->max_length;
-    int h;              /* heap index */
-    int n, m;           /* iterate over the tree elements */
-    int bits;           /* bit length */
-    int xbits;          /* extra bits */
-    ush f;              /* frequency */
-    int overflow = 0;   /* number of elements with bit length too large */
-
-    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
-
-    /* In a first pass, compute the optimal bit lengths (which may
-     * overflow in the case of the bit length tree).
-     */
-    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
-
-    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
-        n = s->heap[h];
-        bits = tree[tree[n].Dad].Len + 1;
-        if (bits > max_length) bits = max_length, overflow++;
-        tree[n].Len = (ush)bits;
-        /* We overwrite tree[n].Dad which is no longer needed */
-
-        if (n > max_code) continue; /* not a leaf node */
-
-        s->bl_count[bits]++;
-        xbits = 0;
-        if (n >= base) xbits = extra[n-base];
-        f = tree[n].Freq;
-        s->opt_len += (ulg)f * (bits + xbits);
-        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
-    }
-    if (overflow == 0) return;
-
-    Trace((stderr,"\nbit length overflow\n"));
-    /* This happens for example on obj2 and pic of the Calgary corpus */
-
-    /* Find the first bit length which could increase: */
-    do {
-        bits = max_length-1;
-        while (s->bl_count[bits] == 0) bits--;
-        s->bl_count[bits]--;      /* move one leaf down the tree */
-        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
-        s->bl_count[max_length]--;
-        /* The brother of the overflow item also moves one step up,
-         * but this does not affect bl_count[max_length]
-         */
-        overflow -= 2;
-    } while (overflow > 0);
-
-    /* Now recompute all bit lengths, scanning in increasing frequency.
-     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
-     * lengths instead of fixing only the wrong ones. This idea is taken
-     * from 'ar' written by Haruhiko Okumura.)
-     */
-    for (bits = max_length; bits != 0; bits--) {
-        n = s->bl_count[bits];
-        while (n != 0) {
-            m = s->heap[--h];
-            if (m > max_code) continue;
-            if (tree[m].Len != (unsigned) bits) {
-                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
-                s->opt_len += ((long)bits - (long)tree[m].Len)
-                              *(long)tree[m].Freq;
-                tree[m].Len = (ush)bits;
-            }
-            n--;
-        }
-    }
-}
-
-/* ===========================================================================
- * Generate the codes for a given tree and bit counts (which need not be
- * optimal).
- * IN assertion: the array bl_count contains the bit length statistics for
- * the given tree and the field len is set for all tree elements.
- * OUT assertion: the field code is set for all tree elements of non
- *     zero code length.
- */
-local void gen_codes (tree, max_code, bl_count)
-    ct_data *tree;             /* the tree to decorate */
-    int max_code;              /* largest code with non zero frequency */
-    ushf *bl_count;            /* number of codes at each bit length */
-{
-    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
-    ush code = 0;              /* running code value */
-    int bits;                  /* bit index */
-    int n;                     /* code index */
-
-    /* The distribution counts are first used to generate the code values
-     * without bit reversal.
-     */
-    for (bits = 1; bits <= MAX_BITS; bits++) {
-        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
-    }
-    /* Check that the bit counts in bl_count are consistent. The last code
-     * must be all ones.
-     */
-    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
-            "inconsistent bit counts");
-    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
-
-    for (n = 0;  n <= max_code; n++) {
-        int len = tree[n].Len;
-        if (len == 0) continue;
-        /* Now reverse the bits */
-        tree[n].Code = bi_reverse(next_code[len]++, len);
-
-        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
-             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
-    }
-}
-
-/* ===========================================================================
- * Construct one Huffman tree and assigns the code bit strings and lengths.
- * Update the total bit length for the current block.
- * IN assertion: the field freq is set for all tree elements.
- * OUT assertions: the fields len and code are set to the optimal bit length
- *     and corresponding code. The length opt_len is updated; static_len is
- *     also updated if stree is not null. The field max_code is set.
- */
-local void build_tree(s, desc)
-    deflate_state *s;
-    tree_desc *desc; /* the tree descriptor */
-{
-    ct_data *tree   = desc->dyn_tree;
-    ct_data *stree  = desc->stat_desc->static_tree;
-    int elems       = desc->stat_desc->elems;
-    int n, m;          /* iterate over heap elements */
-    int max_code = -1; /* largest code with non zero frequency */
-    int node;          /* new node being created */
-
-    /* Construct the initial heap, with least frequent element in
-     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
-     * heap[0] is not used.
-     */
-    s->heap_len = 0, s->heap_max = HEAP_SIZE;
-
-    for (n = 0; n < elems; n++) {
-        if (tree[n].Freq != 0) {
-            s->heap[++(s->heap_len)] = max_code = n;
-            s->depth[n] = 0;
-        } else {
-            tree[n].Len = 0;
-        }
-    }
-
-    /* The pkzip format requires that at least one distance code exists,
-     * and that at least one bit should be sent even if there is only one
-     * possible code. So to avoid special checks later on we force at least
-     * two codes of non zero frequency.
-     */
-    while (s->heap_len < 2) {
-        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
-        tree[node].Freq = 1;
-        s->depth[node] = 0;
-        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
-        /* node is 0 or 1 so it does not have extra bits */
-    }
-    desc->max_code = max_code;
-
-    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
-     * establish sub-heaps of increasing lengths:
-     */
-    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
-
-    /* Construct the Huffman tree by repeatedly combining the least two
-     * frequent nodes.
-     */
-    node = elems;              /* next internal node of the tree */
-    do {
-        pqremove(s, tree, n);  /* n = node of least frequency */
-        m = s->heap[SMALLEST]; /* m = node of next least frequency */
-
-        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
-        s->heap[--(s->heap_max)] = m;
-
-        /* Create a new node father of n and m */
-        tree[node].Freq = tree[n].Freq + tree[m].Freq;
-        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
-        tree[n].Dad = tree[m].Dad = (ush)node;
-#ifdef DUMP_BL_TREE
-        if (tree == s->bl_tree) {
-            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
-                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
-        }
-#endif
-        /* and insert the new node in the heap */
-        s->heap[SMALLEST] = node++;
-        pqdownheap(s, tree, SMALLEST);
-
-    } while (s->heap_len >= 2);
-
-    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
-
-    /* At this point, the fields freq and dad are set. We can now
-     * generate the bit lengths.
-     */
-    gen_bitlen(s, (tree_desc *)desc);
-
-    /* The field len is now set, we can generate the bit codes */
-    gen_codes ((ct_data *)tree, max_code, s->bl_count);
-}
-
-/* ===========================================================================
- * Scan a literal or distance tree to determine the frequencies of the codes
- * in the bit length tree.
- */
-local void scan_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree;   /* the tree to be scanned */
-    int max_code;    /* and its largest code of non zero frequency */
-{
-    int n;                     /* iterates over all tree elements */
-    int prevlen = -1;          /* last emitted length */
-    int curlen;                /* length of current code */
-    int nextlen = tree[0].Len; /* length of next code */
-    int count = 0;             /* repeat count of the current code */
-    int max_count = 7;         /* max repeat count */
-    int min_count = 4;         /* min repeat count */
-
-    if (nextlen == 0) max_count = 138, min_count = 3;
-    tree[max_code+1].Len = (ush)0xffff; /* guard */
-
-    for (n = 0; n <= max_code; n++) {
-        curlen = nextlen; nextlen = tree[n+1].Len;
-        if (++count < max_count && curlen == nextlen) {
-            continue;
-        } else if (count < min_count) {
-            s->bl_tree[curlen].Freq += count;
-        } else if (curlen != 0) {
-            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
-            s->bl_tree[REP_3_6].Freq++;
-        } else if (count <= 10) {
-            s->bl_tree[REPZ_3_10].Freq++;
-        } else {
-            s->bl_tree[REPZ_11_138].Freq++;
-        }
-        count = 0; prevlen = curlen;
-        if (nextlen == 0) {
-            max_count = 138, min_count = 3;
-        } else if (curlen == nextlen) {
-            max_count = 6, min_count = 3;
-        } else {
-            max_count = 7, min_count = 4;
-        }
-    }
-}
-
-/* ===========================================================================
- * Send a literal or distance tree in compressed form, using the codes in
- * bl_tree.
- */
-local void send_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree; /* the tree to be scanned */
-    int max_code;       /* and its largest code of non zero frequency */
-{
-    int n;                     /* iterates over all tree elements */
-    int prevlen = -1;          /* last emitted length */
-    int curlen;                /* length of current code */
-    int nextlen = tree[0].Len; /* length of next code */
-    int count = 0;             /* repeat count of the current code */
-    int max_count = 7;         /* max repeat count */
-    int min_count = 4;         /* min repeat count */
-
-    /* tree[max_code+1].Len = -1; */  /* guard already set */
-    if (nextlen == 0) max_count = 138, min_count = 3;
-
-    for (n = 0; n <= max_code; n++) {
-        curlen = nextlen; nextlen = tree[n+1].Len;
-        if (++count < max_count && curlen == nextlen) {
-            continue;
-        } else if (count < min_count) {
-            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
-
-        } else if (curlen != 0) {
-            if (curlen != prevlen) {
-                send_code(s, curlen, s->bl_tree); count--;
-            }
-            Assert(count >= 3 && count <= 6, " 3_6?");
-            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
-
-        } else if (count <= 10) {
-            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
-
-        } else {
-            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
-        }
-        count = 0; prevlen = curlen;
-        if (nextlen == 0) {
-            max_count = 138, min_count = 3;
-        } else if (curlen == nextlen) {
-            max_count = 6, min_count = 3;
-        } else {
-            max_count = 7, min_count = 4;
-        }
-    }
-}
-
-/* ===========================================================================
- * Construct the Huffman tree for the bit lengths and return the index in
- * bl_order of the last bit length code to send.
- */
-local int build_bl_tree(s)
-    deflate_state *s;
-{
-    int max_blindex;  /* index of last bit length code of non zero freq */
-
-    /* Determine the bit length frequencies for literal and distance trees */
-    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
-    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
-
-    /* Build the bit length tree: */
-    build_tree(s, (tree_desc *)(&(s->bl_desc)));
-    /* opt_len now includes the length of the tree representations, except
-     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
-     */
-
-    /* Determine the number of bit length codes to send. The pkzip format
-     * requires that at least 4 bit length codes be sent. (appnote.txt says
-     * 3 but the actual value used is 4.)
-     */
-    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
-        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
-    }
-    /* Update opt_len to include the bit length tree and counts */
-    s->opt_len += 3*(max_blindex+1) + 5+5+4;
-    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
-            s->opt_len, s->static_len));
-
-    return max_blindex;
-}
-
-/* ===========================================================================
- * Send the header for a block using dynamic Huffman trees: the counts, the
- * lengths of the bit length codes, the literal tree and the distance tree.
- * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
- */
-local void send_all_trees(s, lcodes, dcodes, blcodes)
-    deflate_state *s;
-    int lcodes, dcodes, blcodes; /* number of codes for each tree */
-{
-    int rank;                    /* index in bl_order */
-
-    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
-    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
-            "too many codes");
-    Tracev((stderr, "\nbl counts: "));
-    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
-    send_bits(s, dcodes-1,   5);
-    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
-    for (rank = 0; rank < blcodes; rank++) {
-        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
-        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
-    }
-    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
-
-    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
-    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
-
-    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
-    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
-}
-
-/* ===========================================================================
- * Send a stored block
- */
-void _tr_stored_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
-{
-    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
-    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
-    s->compressed_len += (stored_len + 4) << 3;
-
-    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
-}
-
-/* Send just the `stored block' type code without any length bytes or data.
- */
-void _tr_stored_type_only(s)
-    deflate_state *s;
-{
-    send_bits(s, (STORED_BLOCK << 1), 3);
-    bi_windup(s);
-    s->compressed_len = (s->compressed_len + 3) & ~7L;
-}
-
-
-/* ===========================================================================
- * Send one empty static block to give enough lookahead for inflate.
- * This takes 10 bits, of which 7 may remain in the bit buffer.
- * The current inflate code requires 9 bits of lookahead. If the
- * last two codes for the previous block (real code plus EOB) were coded
- * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
- * the last real code. In this case we send two empty static blocks instead
- * of one. (There are no problems if the previous block is stored or fixed.)
- * To simplify the code, we assume the worst case of last real code encoded
- * on one bit only.
- */
-void _tr_align(s)
-    deflate_state *s;
-{
-    send_bits(s, STATIC_TREES<<1, 3);
-    send_code(s, END_BLOCK, static_ltree);
-    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
-    bi_flush(s);
-    /* Of the 10 bits for the empty block, we have already sent
-     * (10 - bi_valid) bits. The lookahead for the last real code (before
-     * the EOB of the previous block) was thus at least one plus the length
-     * of the EOB plus what we have just sent of the empty static block.
-     */
-    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
-        send_bits(s, STATIC_TREES<<1, 3);
-        send_code(s, END_BLOCK, static_ltree);
-        s->compressed_len += 10L;
-        bi_flush(s);
-    }
-    s->last_eob_len = 7;
-}
-
-/* ===========================================================================
- * Determine the best encoding for the current block: dynamic trees, static
- * trees or store, and output the encoded block to the zip file. This function
- * returns the total compressed length for the file so far.
- */
-ulg _tr_flush_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block, or NULL if too old */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
-{
-    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
-    int max_blindex = 0;  /* index of last bit length code of non zero freq */
-
-    /* Build the Huffman trees unless a stored block is forced */
-    if (s->level > 0) {
-
-	 /* Check if the file is ascii or binary */
-	if (s->data_type == Z_UNKNOWN) set_data_type(s);
-
-	/* Construct the literal and distance trees */
-	build_tree(s, (tree_desc *)(&(s->l_desc)));
-	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
-		s->static_len));
-
-	build_tree(s, (tree_desc *)(&(s->d_desc)));
-	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
-		s->static_len));
-	/* At this point, opt_len and static_len are the total bit lengths of
-	 * the compressed block data, excluding the tree representations.
-	 */
-
-	/* Build the bit length tree for the above two trees, and get the index
-	 * in bl_order of the last bit length code to send.
-	 */
-	max_blindex = build_bl_tree(s);
-
-	/* Determine the best encoding. Compute first the block length in bytes*/
-	opt_lenb = (s->opt_len+3+7)>>3;
-	static_lenb = (s->static_len+3+7)>>3;
-
-	Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
-		opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
-		s->last_lit));
-
-	if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
-
-    } else {
-        Assert(buf != (char*)0, "lost buf");
-	opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
-    }
-
-    /* If compression failed and this is the first and last block,
-     * and if the .zip file can be seeked (to rewrite the local header),
-     * the whole file is transformed into a stored file:
-     */
-#ifdef STORED_FILE_OK
-#  ifdef FORCE_STORED_FILE
-    if (eof && s->compressed_len == 0L) { /* force stored file */
-#  else
-    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
-#  endif
-        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
-        if (buf == (charf*)0) error ("block vanished");
-
-        copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
-        s->compressed_len = stored_len << 3;
-        s->method = STORED;
-    } else
-#endif /* STORED_FILE_OK */
-
-#ifdef FORCE_STORED
-    if (buf != (char*)0) { /* force stored block */
-#else
-    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
-                       /* 4: two words for the lengths */
-#endif
-        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
-         * Otherwise we can't have processed more than WSIZE input bytes since
-         * the last block flush, because compression would have been
-         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
-         * transform a block into a stored block.
-         */
-        _tr_stored_block(s, buf, stored_len, eof);
-
-#ifdef FORCE_STATIC
-    } else if (static_lenb >= 0) { /* force static trees */
-#else
-    } else if (static_lenb == opt_lenb) {
-#endif
-        send_bits(s, (STATIC_TREES<<1)+eof, 3);
-        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
-        s->compressed_len += 3 + s->static_len;
-    } else {
-        send_bits(s, (DYN_TREES<<1)+eof, 3);
-        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
-                       max_blindex+1);
-        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
-        s->compressed_len += 3 + s->opt_len;
-    }
-    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
-    init_block(s);
-
-    if (eof) {
-        bi_windup(s);
-        s->compressed_len += 7;  /* align on byte boundary */
-    }
-    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
-           s->compressed_len-7*eof));
-
-    return s->compressed_len >> 3;
-}
-
-/* ===========================================================================
- * Save the match info and tally the frequency counts. Return true if
- * the current block must be flushed.
- */
-int _tr_tally (s, dist, lc)
-    deflate_state *s;
-    unsigned dist;  /* distance of matched string */
-    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
-{
-    s->d_buf[s->last_lit] = (ush)dist;
-    s->l_buf[s->last_lit++] = (uch)lc;
-    if (dist == 0) {
-        /* lc is the unmatched char */
-        s->dyn_ltree[lc].Freq++;
-    } else {
-        s->matches++;
-        /* Here, lc is the match length - MIN_MATCH */
-        dist--;             /* dist = match distance - 1 */
-        Assert((ush)dist < (ush)MAX_DIST(s) &&
-               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
-               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
-
-        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
-        s->dyn_dtree[d_code(dist)].Freq++;
-    }
-
-    /* Try to guess if it is profitable to stop the current block here */
-    if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
-        /* Compute an upper bound for the compressed length */
-        ulg out_length = (ulg)s->last_lit*8L;
-        ulg in_length = (ulg)((long)s->strstart - s->block_start);
-        int dcode;
-        for (dcode = 0; dcode < D_CODES; dcode++) {
-            out_length += (ulg)s->dyn_dtree[dcode].Freq *
-                (5L+extra_dbits[dcode]);
-        }
-        out_length >>= 3;
-        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
-               s->last_lit, in_length, out_length,
-               100L - out_length*100L/in_length));
-        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
-    }
-    return (s->last_lit == s->lit_bufsize-1);
-    /* We avoid equality with lit_bufsize because of wraparound at 64K
-     * on 16 bit machines and because stored blocks are restricted to
-     * 64K-1 bytes.
-     */
-}
-
-/* ===========================================================================
- * Send the block data compressed using the given Huffman trees
- */
-local void compress_block(s, ltree, dtree)
-    deflate_state *s;
-    ct_data *ltree; /* literal tree */
-    ct_data *dtree; /* distance tree */
-{
-    unsigned dist;      /* distance of matched string */
-    int lc;             /* match length or unmatched char (if dist == 0) */
-    unsigned lx = 0;    /* running index in l_buf */
-    unsigned code;      /* the code to send */
-    int extra;          /* number of extra bits to send */
-
-    if (s->last_lit != 0) do {
-        dist = s->d_buf[lx];
-        lc = s->l_buf[lx++];
-        if (dist == 0) {
-            send_code(s, lc, ltree); /* send a literal byte */
-            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
-        } else {
-            /* Here, lc is the match length - MIN_MATCH */
-            code = length_code[lc];
-            send_code(s, code+LITERALS+1, ltree); /* send the length code */
-            extra = extra_lbits[code];
-            if (extra != 0) {
-                lc -= base_length[code];
-                send_bits(s, lc, extra);       /* send the extra length bits */
-            }
-            dist--; /* dist is now the match distance - 1 */
-            code = d_code(dist);
-            Assert (code < D_CODES, "bad d_code");
-
-            send_code(s, code, dtree);       /* send the distance code */
-            extra = extra_dbits[code];
-            if (extra != 0) {
-                dist -= base_dist[code];
-                send_bits(s, dist, extra);   /* send the extra distance bits */
-            }
-        } /* literal or match pair ? */
-
-        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
-        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
-
-    } while (lx < s->last_lit);
-
-    send_code(s, END_BLOCK, ltree);
-    s->last_eob_len = ltree[END_BLOCK].Len;
-}
-
-/* ===========================================================================
- * Set the data type to ASCII or BINARY, using a crude approximation:
- * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
- * IN assertion: the fields freq of dyn_ltree are set and the total of all
- * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
- */
-local void set_data_type(s)
-    deflate_state *s;
-{
-    int n = 0;
-    unsigned ascii_freq = 0;
-    unsigned bin_freq = 0;
-    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
-    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
-    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
-    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
-}
-
-/* ===========================================================================
- * Reverse the first len bits of a code, using straightforward code (a faster
- * method would use a table)
- * IN assertion: 1 <= len <= 15
- */
-local unsigned bi_reverse(code, len)
-    unsigned code; /* the value to invert */
-    int len;       /* its bit length */
-{
-    register unsigned res = 0;
-    do {
-        res |= code & 1;
-        code >>= 1, res <<= 1;
-    } while (--len > 0);
-    return res >> 1;
-}
-
-/* ===========================================================================
- * Flush the bit buffer, keeping at most 7 bits in it.
- */
-local void bi_flush(s)
-    deflate_state *s;
-{
-    if (s->bi_valid == 16) {
-        put_short(s, s->bi_buf);
-        s->bi_buf = 0;
-        s->bi_valid = 0;
-    } else if (s->bi_valid >= 8) {
-        put_byte(s, (Byte)s->bi_buf);
-        s->bi_buf >>= 8;
-        s->bi_valid -= 8;
-    }
-}
-
-/* ===========================================================================
- * Flush the bit buffer and align the output on a byte boundary
- */
-local void bi_windup(s)
-    deflate_state *s;
-{
-    if (s->bi_valid > 8) {
-        put_short(s, s->bi_buf);
-    } else if (s->bi_valid > 0) {
-        put_byte(s, (Byte)s->bi_buf);
-    }
-    s->bi_buf = 0;
-    s->bi_valid = 0;
-#ifdef DEBUG_ZLIB
-    s->bits_sent = (s->bits_sent+7) & ~7;
-#endif
-}
-
-/* ===========================================================================
- * Copy a stored block, storing first the length and its
- * one's complement if requested.
- */
-local void copy_block(s, buf, len, header)
-    deflate_state *s;
-    charf    *buf;    /* the input data */
-    unsigned len;     /* its length */
-    int      header;  /* true if block header must be written */
-{
-    bi_windup(s);        /* align on byte boundary */
-    s->last_eob_len = 8; /* enough lookahead for inflate */
-
-    if (header) {
-        put_short(s, (ush)len);   
-        put_short(s, (ush)~len);
-#ifdef DEBUG_ZLIB
-        s->bits_sent += 2*16;
-#endif
-    }
-#ifdef DEBUG_ZLIB
-    s->bits_sent += (ulg)len<<3;
-#endif
-    /* bundle up the put_byte(s, *buf++) calls */
-    zmemcpy(&s->pending_buf[s->pending], buf, len);
-    s->pending += len;
-}
-/* --- trees.c */
-
-/* +++ inflate.c */
-/* inflate.c -- zlib interface to inflate modules
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-
-/* +++ infblock.h */
-/* infblock.h -- header to use infblock.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-struct inflate_blocks_state;
-typedef struct inflate_blocks_state FAR inflate_blocks_statef;
-
-extern inflate_blocks_statef * inflate_blocks_new OF((
-    z_streamp z,
-    check_func c,               /* check function */
-    uInt w));                   /* window size */
-
-extern int inflate_blocks OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));                      /* initial return code */
-
-extern void inflate_blocks_reset OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern int inflate_blocks_free OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern void inflate_set_dictionary OF((
-    inflate_blocks_statef *s,
-    const Bytef *d,  /* dictionary */
-    uInt  n));       /* dictionary length */
-
-extern int inflate_addhistory OF((
-    inflate_blocks_statef *,
-    z_streamp));
-
-extern int inflate_packet_flush OF((
-    inflate_blocks_statef *));
-/* --- infblock.h */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* inflate private state */
-struct internal_state {
-
-  /* mode */
-  enum {
-      METHOD,   /* waiting for method byte */
-      FLAG,     /* waiting for flag byte */
-      DICT4,    /* four dictionary check bytes to go */
-      DICT3,    /* three dictionary check bytes to go */
-      DICT2,    /* two dictionary check bytes to go */
-      DICT1,    /* one dictionary check byte to go */
-      DICT0,    /* waiting for inflateSetDictionary */
-      BLOCKS,   /* decompressing blocks */
-      CHECK4,   /* four check bytes to go */
-      CHECK3,   /* three check bytes to go */
-      CHECK2,   /* two check bytes to go */
-      CHECK1,   /* one check byte to go */
-      DONE,     /* finished check, done */
-      BAD}      /* got an error--stay here */
-    mode;               /* current inflate mode */
-
-  /* mode dependent information */
-  union {
-    uInt method;        /* if FLAGS, method byte */
-    struct {
-      uLong was;                /* computed check value */
-      uLong need;               /* stream check value */
-    } check;            /* if CHECK, check values to compare */
-    uInt marker;        /* if BAD, inflateSync's marker bytes count */
-  } sub;        /* submode */
-
-  /* mode independent information */
-  int  nowrap;          /* flag for no wrapper */
-  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
-  inflate_blocks_statef 
-    *blocks;            /* current inflate_blocks state */
-
-};
-
-
-int inflateReset(z)
-z_streamp z;
-{
-  uLong c;
-
-  if (z == Z_NULL || z->state == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->total_in = z->total_out = 0;
-  z->msg = Z_NULL;
-  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
-  inflate_blocks_reset(z->state->blocks, z, &c);
-  Trace((stderr, "inflate: reset\n"));
-  return Z_OK;
-}
-
-
-int inflateEnd(z)
-z_streamp z;
-{
-  uLong c;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->blocks != Z_NULL)
-    inflate_blocks_free(z->state->blocks, z, &c);
-  ZFREE(z, z->state);
-  z->state = Z_NULL;
-  Trace((stderr, "inflate: end\n"));
-  return Z_OK;
-}
-
-
-int inflateInit2_(z, w, version, stream_size)
-z_streamp z;
-int w;
-const char *version;
-int stream_size;
-{
-  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
-      stream_size != sizeof(z_stream))
-      return Z_VERSION_ERROR;
-
-  /* initialize state */
-  if (z == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->msg = Z_NULL;
-#ifndef NO_ZCFUNCS
-  if (z->zalloc == Z_NULL)
-  {
-    z->zalloc = zcalloc;
-    z->opaque = (voidpf)0;
-  }
-  if (z->zfree == Z_NULL) z->zfree = zcfree;
-#endif
-  if ((z->state = (struct internal_state FAR *)
-       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
-    return Z_MEM_ERROR;
-  z->state->blocks = Z_NULL;
-
-  /* handle undocumented nowrap option (no zlib header or check) */
-  z->state->nowrap = 0;
-  if (w < 0)
-  {
-    w = - w;
-    z->state->nowrap = 1;
-  }
-
-  /* set window size */
-  if (w < 8 || w > 15)
-  {
-    inflateEnd(z);
-    return Z_STREAM_ERROR;
-  }
-  z->state->wbits = (uInt)w;
-
-  /* create inflate_blocks state */
-  if ((z->state->blocks =
-      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
-      == Z_NULL)
-  {
-    inflateEnd(z);
-    return Z_MEM_ERROR;
-  }
-  Trace((stderr, "inflate: allocated\n"));
-
-  /* reset state */
-  inflateReset(z);
-  return Z_OK;
-}
-
-
-int inflateInit_(z, version, stream_size)
-z_streamp z;
-const char *version;
-int stream_size;
-{
-  return inflateInit2_(z, DEF_WBITS, version, stream_size);
-}
-
-
-#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
-#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
-
-int inflate(z, f)
-z_streamp z;
-int f;
-{
-  int r;
-  uInt b;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0)
-    return Z_STREAM_ERROR;
-  r = Z_BUF_ERROR;
-  while (1) switch (z->state->mode)
-  {
-    case METHOD:
-      NEEDBYTE
-      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"unknown compression method";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"invalid window size";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      z->state->mode = FLAG;
-    case FLAG:
-      NEEDBYTE
-      b = NEXTBYTE;
-      if (((z->state->sub.method << 8) + b) % 31)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"incorrect header check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      Trace((stderr, "inflate: zlib header ok\n"));
-      if (!(b & PRESET_DICT))
-      {
-        z->state->mode = BLOCKS;
-	break;
-      }
-      z->state->mode = DICT4;
-    case DICT4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = DICT3;
-    case DICT3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = DICT2;
-    case DICT2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = DICT1;
-    case DICT1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-      z->adler = z->state->sub.check.need;
-      z->state->mode = DICT0;
-      return Z_NEED_DICT;
-    case DICT0:
-      z->state->mode = BAD;
-      z->msg = (char*)"need dictionary";
-      z->state->sub.marker = 0;       /* can try inflateSync */
-      return Z_STREAM_ERROR;
-    case BLOCKS:
-      r = inflate_blocks(z->state->blocks, z, r);
-      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
-	  r = inflate_packet_flush(z->state->blocks);
-      if (r == Z_DATA_ERROR)
-      {
-        z->state->mode = BAD;
-        z->state->sub.marker = 0;       /* can try inflateSync */
-        break;
-      }
-      if (r != Z_STREAM_END)
-        return r;
-      r = Z_OK;
-      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
-      if (z->state->nowrap)
-      {
-        z->state->mode = DONE;
-        break;
-      }
-      z->state->mode = CHECK4;
-    case CHECK4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = CHECK3;
-    case CHECK3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = CHECK2;
-    case CHECK2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = CHECK1;
-    case CHECK1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-
-      if (z->state->sub.check.was != z->state->sub.check.need)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"incorrect data check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      Trace((stderr, "inflate: zlib check ok\n"));
-      z->state->mode = DONE;
-    case DONE:
-      return Z_STREAM_END;
-    case BAD:
-      return Z_DATA_ERROR;
-    default:
-      return Z_STREAM_ERROR;
-  }
-
- empty:
-  if (f != Z_PACKET_FLUSH)
-    return r;
-  z->state->mode = BAD;
-  z->msg = (char *)"need more for packet flush";
-  z->state->sub.marker = 0;       /* can try inflateSync */
-  return Z_DATA_ERROR;
-}
-
-
-int inflateSetDictionary(z, dictionary, dictLength)
-z_streamp z;
-const Bytef *dictionary;
-uInt  dictLength;
-{
-  uInt length = dictLength;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
-    return Z_STREAM_ERROR;
-
-  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
-  z->adler = 1L;
-
-  if (length >= ((uInt)1<<z->state->wbits))
-  {
-    length = (1<<z->state->wbits)-1;
-    dictionary += dictLength - length;
-  }
-  inflate_set_dictionary(z->state->blocks, dictionary, length);
-  z->state->mode = BLOCKS;
-  return Z_OK;
-}
-
-/*
- * This subroutine adds the data at next_in/avail_in to the output history
- * without performing any output.  The output buffer must be "caught up";
- * i.e. no pending output (hence s->read equals s->write), and the state must
- * be BLOCKS (i.e. we should be willing to see the start of a series of
- * BLOCKS).  On exit, the output will also be caught up, and the checksum
- * will have been updated if need be.
- */
-
-int inflateIncomp(z)
-z_stream *z;
-{
-    if (z->state->mode != BLOCKS)
-	return Z_DATA_ERROR;
-    return inflate_addhistory(z->state->blocks, z);
-}
-
-
-int inflateSync(z)
-z_streamp z;
-{
-  uInt n;       /* number of bytes to look at */
-  Bytef *p;     /* pointer to bytes */
-  uInt m;       /* number of marker bytes found in a row */
-  uLong r, w;   /* temporaries to save total_in and total_out */
-
-  /* set up */
-  if (z == Z_NULL || z->state == Z_NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->mode != BAD)
-  {
-    z->state->mode = BAD;
-    z->state->sub.marker = 0;
-  }
-  if ((n = z->avail_in) == 0)
-    return Z_BUF_ERROR;
-  p = z->next_in;
-  m = z->state->sub.marker;
-
-  /* search */
-  while (n && m < 4)
-  {
-    if (*p == (Byte)(m < 2 ? 0 : 0xff))
-      m++;
-    else if (*p)
-      m = 0;
-    else
-      m = 4 - m;
-    p++, n--;
-  }
-
-  /* restore */
-  z->total_in += p - z->next_in;
-  z->next_in = p;
-  z->avail_in = n;
-  z->state->sub.marker = m;
-
-  /* return no joy or set up to restart on a new block */
-  if (m != 4)
-    return Z_DATA_ERROR;
-  r = z->total_in;  w = z->total_out;
-  inflateReset(z);
-  z->total_in = r;  z->total_out = w;
-  z->state->mode = BLOCKS;
-  return Z_OK;
-}
-
-#undef NEEDBYTE
-#undef NEXTBYTE
-/* --- inflate.c */
-
-/* +++ infblock.c */
-/* infblock.c -- interpret and process block types to last block
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "infblock.h" */
-
-/* +++ inftrees.h */
-/* inftrees.h -- header to use inftrees.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* Huffman code lookup table entry--this entry is four bytes for machines
-   that have 16-bit pointers (e.g. PC's in the small or medium model). */
-
-typedef struct inflate_huft_s FAR inflate_huft;
-
-struct inflate_huft_s {
-  union {
-    struct {
-      Byte Exop;        /* number of extra bits or operation */
-      Byte Bits;        /* number of bits in this code or subcode */
-    } what;
-    Bytef *pad;         /* pad structure to a power of 2 (4 bytes for */
-  } word;               /*  16-bit, 8 bytes for 32-bit machines) */
-  union {
-    uInt Base;          /* literal, length base, or distance base */
-    inflate_huft *Next; /* pointer to next level of table */
-  } more;
-};
-
-#ifdef DEBUG_ZLIB
-  extern uInt inflate_hufts;
-#endif
-
-extern int inflate_trees_bits OF((
-    uIntf *,                    /* 19 code lengths */
-    uIntf *,                    /* bits tree desired/actual depth */
-    inflate_huft * FAR *,       /* bits tree result */
-    z_streamp ));               /* for zalloc, zfree functions */
-
-extern int inflate_trees_dynamic OF((
-    uInt,                       /* number of literal/length codes */
-    uInt,                       /* number of distance codes */
-    uIntf *,                    /* that many (total) code lengths */
-    uIntf *,                    /* literal desired/actual bit depth */
-    uIntf *,                    /* distance desired/actual bit depth */
-    inflate_huft * FAR *,       /* literal/length tree result */
-    inflate_huft * FAR *,       /* distance tree result */
-    z_streamp ));               /* for zalloc, zfree functions */
-
-extern int inflate_trees_fixed OF((
-    uIntf *,                    /* literal desired/actual bit depth */
-    uIntf *,                    /* distance desired/actual bit depth */
-    inflate_huft * FAR *,       /* literal/length tree result */
-    inflate_huft * FAR *));     /* distance tree result */
-
-extern int inflate_trees_free OF((
-    inflate_huft *,             /* tables to free */
-    z_streamp ));               /* for zfree function */
-
-/* --- inftrees.h */
-
-/* +++ infcodes.h */
-/* infcodes.h -- header to use infcodes.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-struct inflate_codes_state;
-typedef struct inflate_codes_state FAR inflate_codes_statef;
-
-extern inflate_codes_statef *inflate_codes_new OF((
-    uInt, uInt,
-    inflate_huft *, inflate_huft *,
-    z_streamp ));
-
-extern int inflate_codes OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-extern void inflate_codes_free OF((
-    inflate_codes_statef *,
-    z_streamp ));
-
-/* --- infcodes.h */
-
-/* +++ infutil.h */
-/* infutil.h -- types and macros common to blocks and codes
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-#ifndef _INFUTIL_H
-#define _INFUTIL_H
-
-typedef enum {
-      TYPE,     /* get type bits (3, including end bit) */
-      LENS,     /* get lengths for stored */
-      STORED,   /* processing stored block */
-      TABLE,    /* get table lengths */
-      BTREE,    /* get bit lengths tree for a dynamic block */
-      DTREE,    /* get length, distance trees for a dynamic block */
-      CODES,    /* processing fixed or dynamic block */
-      DRY,      /* output remaining window bytes */
-      DONEB,    /* finished last block, done */
-      BADB}     /* got a data error--stuck here */
-inflate_block_mode;
-
-/* inflate blocks semi-private state */
-struct inflate_blocks_state {
-
-  /* mode */
-  inflate_block_mode  mode;     /* current inflate_block mode */
-
-  /* mode dependent information */
-  union {
-    uInt left;          /* if STORED, bytes left to copy */
-    struct {
-      uInt table;               /* table lengths (14 bits) */
-      uInt index;               /* index into blens (or border) */
-      uIntf *blens;             /* bit lengths of codes */
-      uInt bb;                  /* bit length tree depth */
-      inflate_huft *tb;         /* bit length decoding tree */
-    } trees;            /* if DTREE, decoding info for trees */
-    struct {
-      inflate_huft *tl;
-      inflate_huft *td;         /* trees to free */
-      inflate_codes_statef 
-         *codes;
-    } decode;           /* if CODES, current state */
-  } sub;                /* submode */
-  uInt last;            /* true if this block is the last block */
-
-  /* mode independent information */
-  uInt bitk;            /* bits in bit buffer */
-  uLong bitb;           /* bit buffer */
-  Bytef *window;        /* sliding window */
-  Bytef *end;           /* one byte after sliding window */
-  Bytef *read;          /* window read pointer */
-  Bytef *write;         /* window write pointer */
-  check_func checkfn;   /* check function */
-  uLong check;          /* check on output */
-
-};
-
-
-/* defines for inflate input/output */
-/*   update pointers and return */
-#define UPDBITS {s->bitb=b;s->bitk=k;}
-#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
-#define UPDOUT {s->write=q;}
-#define UPDATE {UPDBITS UPDIN UPDOUT}
-#define LEAVE {UPDATE return inflate_flush(s,z,r);}
-/*   get bytes and bits */
-#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
-#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
-#define NEXTBYTE (n--,*p++)
-#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define DUMPBITS(j) {b>>=(j);k-=(j);}
-/*   output bytes */
-#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
-#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
-#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
-#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
-#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;}
-#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
-/*   load local pointers */
-#define LOAD {LOADIN LOADOUT}
-
-/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
-extern uInt inflate_mask[17];
-
-/* copy as much as possible from the sliding window to the output area */
-extern int inflate_flush OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-#ifndef NO_DUMMY_DECL
-struct internal_state      {int dummy;}; /* for buggy compilers */
-#endif
-
-#endif
-/* --- infutil.h */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* Table for deflate from PKZIP's appnote.txt. */
-local const uInt border[] = { /* Order of the bit length code lengths */
-        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
-/*
-   Notes beyond the 1.93a appnote.txt:
-
-   1. Distance pointers never point before the beginning of the output
-      stream.
-   2. Distance pointers can point back across blocks, up to 32k away.
-   3. There is an implied maximum of 7 bits for the bit length table and
-      15 bits for the actual data.
-   4. If only one code exists, then it is encoded using one bit.  (Zero
-      would be more efficient, but perhaps a little confusing.)  If two
-      codes exist, they are coded using one bit each (0 and 1).
-   5. There is no way of sending zero distance codes--a dummy must be
-      sent if there are none.  (History: a pre 2.0 version of PKZIP would
-      store blocks with no distance codes, but this was discovered to be
-      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
-      zero distance codes, which is sent as one code of zero bits in
-      length.
-   6. There are up to 286 literal/length codes.  Code 256 represents the
-      end-of-block.  Note however that the static length tree defines
-      288 codes just to fill out the Huffman codes.  Codes 286 and 287
-      cannot be used though, since there is no length base or extra bits
-      defined for them.  Similarily, there are up to 30 distance codes.
-      However, static trees define 32 codes (all 5 bits) to fill out the
-      Huffman codes, but the last two had better not show up in the data.
-   7. Unzip can check dynamic Huffman blocks for complete code sets.
-      The exception is that a single code would not be complete (see #4).
-   8. The five bits following the block type is really the number of
-      literal codes sent minus 257.
-   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
-      (1+6+6).  Therefore, to output three times the length, you output
-      three codes (1+1+1), whereas to output four times the same length,
-      you only need two codes (1+3).  Hmm.
-  10. In the tree reconstruction algorithm, Code = Code + Increment
-      only if BitLength(i) is not zero.  (Pretty obvious.)
-  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
-  12. Note: length code 284 can represent 227-258, but length code 285
-      really is 258.  The last length deserves its own, short code
-      since it gets used a lot in very redundant files.  The length
-      258 is special since 258 - 3 (the min match length) is 255.
-  13. The literal/length and distance code bit lengths are read as a
-      single stream of lengths.  It is possible (and advantageous) for
-      a repeat code (16, 17, or 18) to go across the boundary between
-      the two sets of lengths.
- */
-
-
-void inflate_blocks_reset(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  if (s->checkfn != Z_NULL)
-    *c = s->check;
-  if (s->mode == BTREE || s->mode == DTREE)
-    ZFREE(z, s->sub.trees.blens);
-  if (s->mode == CODES)
-  {
-    inflate_codes_free(s->sub.decode.codes, z);
-    inflate_trees_free(s->sub.decode.td, z);
-    inflate_trees_free(s->sub.decode.tl, z);
-  }
-  s->mode = TYPE;
-  s->bitk = 0;
-  s->bitb = 0;
-  s->read = s->write = s->window;
-  if (s->checkfn != Z_NULL)
-    z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0);
-  Trace((stderr, "inflate:   blocks reset\n"));
-}
-
-
-inflate_blocks_statef *inflate_blocks_new(z, c, w)
-z_streamp z;
-check_func c;
-uInt w;
-{
-  inflate_blocks_statef *s;
-
-  if ((s = (inflate_blocks_statef *)ZALLOC
-       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
-    return s;
-  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
-  {
-    ZFREE(z, s);
-    return Z_NULL;
-  }
-  s->end = s->window + w;
-  s->checkfn = c;
-  s->mode = TYPE;
-  Trace((stderr, "inflate:   blocks allocated\n"));
-  inflate_blocks_reset(s, z, &s->check);
-  return s;
-}
-
-
-#ifdef DEBUG_ZLIB
-  extern uInt inflate_hufts;
-#endif
-int inflate_blocks(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt t;               /* temporary storage */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-
-  /* copy input/output information to locals (UPDATE macro restores) */
-  LOAD
-
-  /* process input based on current state */
-  while (1) switch (s->mode)
-  {
-    case TYPE:
-      NEEDBITS(3)
-      t = (uInt)b & 7;
-      s->last = t & 1;
-      switch (t >> 1)
-      {
-        case 0:                         /* stored */
-          Trace((stderr, "inflate:     stored block%s\n",
-                 s->last ? " (last)" : ""));
-          DUMPBITS(3)
-          t = k & 7;                    /* go to byte boundary */
-          DUMPBITS(t)
-          s->mode = LENS;               /* get length of stored block */
-          break;
-        case 1:                         /* fixed */
-          Trace((stderr, "inflate:     fixed codes block%s\n",
-                 s->last ? " (last)" : ""));
-          {
-            uInt bl, bd;
-            inflate_huft *tl, *td;
-
-            inflate_trees_fixed(&bl, &bd, &tl, &td);
-            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
-            if (s->sub.decode.codes == Z_NULL)
-            {
-              r = Z_MEM_ERROR;
-              LEAVE
-            }
-            s->sub.decode.tl = Z_NULL;  /* don't try to free these */
-            s->sub.decode.td = Z_NULL;
-          }
-          DUMPBITS(3)
-          s->mode = CODES;
-          break;
-        case 2:                         /* dynamic */
-          Trace((stderr, "inflate:     dynamic codes block%s\n",
-                 s->last ? " (last)" : ""));
-          DUMPBITS(3)
-          s->mode = TABLE;
-          break;
-        case 3:                         /* illegal */
-          DUMPBITS(3)
-          s->mode = BADB;
-          z->msg = (char*)"invalid block type";
-          r = Z_DATA_ERROR;
-          LEAVE
-      }
-      break;
-    case LENS:
-      NEEDBITS(32)
-      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
-      {
-        s->mode = BADB;
-        z->msg = (char*)"invalid stored block lengths";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-      s->sub.left = (uInt)b & 0xffff;
-      b = k = 0;                      /* dump bits */
-      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
-      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
-      break;
-    case STORED:
-      if (n == 0)
-        LEAVE
-      NEEDOUT
-      t = s->sub.left;
-      if (t > n) t = n;
-      if (t > m) t = m;
-      zmemcpy(q, p, t);
-      p += t;  n -= t;
-      q += t;  m -= t;
-      if ((s->sub.left -= t) != 0)
-        break;
-      Tracev((stderr, "inflate:       stored end, %lu total out\n",
-              z->total_out + (q >= s->read ? q - s->read :
-              (s->end - s->read) + (q - s->window))));
-      s->mode = s->last ? DRY : TYPE;
-      break;
-    case TABLE:
-      NEEDBITS(14)
-      s->sub.trees.table = t = (uInt)b & 0x3fff;
-#ifndef PKZIP_BUG_WORKAROUND
-      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
-      {
-        s->mode = BADB;
-        z->msg = (char*)"too many length or distance symbols";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-#endif
-      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
-      if (t < 19)
-        t = 19;
-      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
-      {
-        r = Z_MEM_ERROR;
-        LEAVE
-      }
-      DUMPBITS(14)
-      s->sub.trees.index = 0;
-      Tracev((stderr, "inflate:       table sizes ok\n"));
-      s->mode = BTREE;
-    case BTREE:
-      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
-      {
-        NEEDBITS(3)
-        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
-        DUMPBITS(3)
-      }
-      while (s->sub.trees.index < 19)
-        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
-      s->sub.trees.bb = 7;
-      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
-                             &s->sub.trees.tb, z);
-      if (t != Z_OK)
-      {
-        ZFREE(z, s->sub.trees.blens);
-        r = t;
-        if (r == Z_DATA_ERROR)
-          s->mode = BADB;
-        LEAVE
-      }
-      s->sub.trees.index = 0;
-      Tracev((stderr, "inflate:       bits tree ok\n"));
-      s->mode = DTREE;
-    case DTREE:
-      while (t = s->sub.trees.table,
-             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
-      {
-        inflate_huft *h;
-        uInt i, j, c;
-
-        t = s->sub.trees.bb;
-        NEEDBITS(t)
-        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
-        t = h->word.what.Bits;
-        c = h->more.Base;
-        if (c < 16)
-        {
-          DUMPBITS(t)
-          s->sub.trees.blens[s->sub.trees.index++] = c;
-        }
-        else /* c == 16..18 */
-        {
-          i = c == 18 ? 7 : c - 14;
-          j = c == 18 ? 11 : 3;
-          NEEDBITS(t + i)
-          DUMPBITS(t)
-          j += (uInt)b & inflate_mask[i];
-          DUMPBITS(i)
-          i = s->sub.trees.index;
-          t = s->sub.trees.table;
-          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
-              (c == 16 && i < 1))
-          {
-            inflate_trees_free(s->sub.trees.tb, z);
-            ZFREE(z, s->sub.trees.blens);
-            s->mode = BADB;
-            z->msg = (char*)"invalid bit length repeat";
-            r = Z_DATA_ERROR;
-            LEAVE
-          }
-          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
-          do {
-            s->sub.trees.blens[i++] = c;
-          } while (--j);
-          s->sub.trees.index = i;
-        }
-      }
-      inflate_trees_free(s->sub.trees.tb, z);
-      s->sub.trees.tb = Z_NULL;
-      {
-        uInt bl, bd;
-        inflate_huft *tl, *td;
-        inflate_codes_statef *c;
-
-        bl = 9;         /* must be <= 9 for lookahead assumptions */
-        bd = 6;         /* must be <= 9 for lookahead assumptions */
-        t = s->sub.trees.table;
-#ifdef DEBUG_ZLIB
-      inflate_hufts = 0;
-#endif
-        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
-                                  s->sub.trees.blens, &bl, &bd, &tl, &td, z);
-        ZFREE(z, s->sub.trees.blens);
-        if (t != Z_OK)
-        {
-          if (t == (uInt)Z_DATA_ERROR)
-            s->mode = BADB;
-          r = t;
-          LEAVE
-        }
-        Tracev((stderr, "inflate:       trees ok, %d * %d bytes used\n",
-              inflate_hufts, sizeof(inflate_huft)));
-        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
-        {
-          inflate_trees_free(td, z);
-          inflate_trees_free(tl, z);
-          r = Z_MEM_ERROR;
-          LEAVE
-        }
-        s->sub.decode.codes = c;
-        s->sub.decode.tl = tl;
-        s->sub.decode.td = td;
-      }
-      s->mode = CODES;
-    case CODES:
-      UPDATE
-      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
-        return inflate_flush(s, z, r);
-      r = Z_OK;
-      inflate_codes_free(s->sub.decode.codes, z);
-      inflate_trees_free(s->sub.decode.td, z);
-      inflate_trees_free(s->sub.decode.tl, z);
-      LOAD
-      Tracev((stderr, "inflate:       codes end, %lu total out\n",
-              z->total_out + (q >= s->read ? q - s->read :
-              (s->end - s->read) + (q - s->window))));
-      if (!s->last)
-      {
-        s->mode = TYPE;
-        break;
-      }
-      if (k > 7)              /* return unused byte, if any */
-      {
-        Assert(k < 16, "inflate_codes grabbed too many bytes")
-        k -= 8;
-        n++;
-        p--;                    /* can always return one */
-      }
-      s->mode = DRY;
-    case DRY:
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      s->mode = DONEB;
-    case DONEB:
-      r = Z_STREAM_END;
-      LEAVE
-    case BADB:
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-}
-
-
-int inflate_blocks_free(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  inflate_blocks_reset(s, z, c);
-  ZFREE(z, s->window);
-  ZFREE(z, s);
-  Trace((stderr, "inflate:   blocks freed\n"));
-  return Z_OK;
-}
-
-
-void inflate_set_dictionary(s, d, n)
-inflate_blocks_statef *s;
-const Bytef *d;
-uInt  n;
-{
-  zmemcpy((charf *)s->window, d, n);
-  s->read = s->write = s->window + n;
-}
-
-/*
- * This subroutine adds the data at next_in/avail_in to the output history
- * without performing any output.  The output buffer must be "caught up";
- * i.e. no pending output (hence s->read equals s->write), and the state must
- * be BLOCKS (i.e. we should be willing to see the start of a series of
- * BLOCKS).  On exit, the output will also be caught up, and the checksum
- * will have been updated if need be.
- */
-int inflate_addhistory(s, z)
-inflate_blocks_statef *s;
-z_stream *z;
-{
-    uLong b;              /* bit buffer */  /* NOT USED HERE */
-    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
-    uInt t;               /* temporary storage */
-    Bytef *p;             /* input data pointer */
-    uInt n;               /* bytes available there */
-    Bytef *q;             /* output window write pointer */
-    uInt m;               /* bytes to end of window or read pointer */
-
-    if (s->read != s->write)
-	return Z_STREAM_ERROR;
-    if (s->mode != TYPE)
-	return Z_DATA_ERROR;
-
-    /* we're ready to rock */
-    LOAD
-    /* while there is input ready, copy to output buffer, moving
-     * pointers as needed.
-     */
-    while (n) {
-	t = n;  /* how many to do */
-	/* is there room until end of buffer? */
-	if (t > m) t = m;
-	/* update check information */
-	if (s->checkfn != Z_NULL)
-	    s->check = (*s->checkfn)(s->check, q, t);
-	zmemcpy(q, p, t);
-	q += t;
-	p += t;
-	n -= t;
-	z->total_out += t;
-	s->read = q;    /* drag read pointer forward */
-/*      WWRAP  */ 	/* expand WWRAP macro by hand to handle s->read */
-	if (q == s->end) {
-	    s->read = q = s->window;
-	    m = WAVAIL;
-	}
-    }
-    UPDATE
-    return Z_OK;
-}
-
-
-/*
- * At the end of a Deflate-compressed PPP packet, we expect to have seen
- * a `stored' block type value but not the (zero) length bytes.
- */
-int inflate_packet_flush(s)
-    inflate_blocks_statef *s;
-{
-    if (s->mode != LENS)
-	return Z_DATA_ERROR;
-    s->mode = TYPE;
-    return Z_OK;
-}
-/* --- infblock.c */
-
-/* +++ inftrees.c */
-/* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-
-char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
-#ifndef NO_DUMMY_DECL
-struct internal_state  {int dummy;}; /* for buggy compilers */
-#endif
-
-/* simplify the use of the inflate_huft type with some defines */
-#define base more.Base
-#define next more.Next
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-
-local int huft_build OF((
-    uIntf *,            /* code lengths in bits */
-    uInt,               /* number of codes */
-    uInt,               /* number of "simple" codes */
-    const uIntf *,      /* list of base values for non-simple codes */
-    const uIntf *,      /* list of extra bits for non-simple codes */
-    inflate_huft * FAR*,/* result: starting table */
-    uIntf *,            /* maximum lookup bits (returns actual) */
-    z_streamp ));       /* for zalloc function */
-
-local voidpf falloc OF((
-    voidpf,             /* opaque pointer (not used) */
-    uInt,               /* number of items */
-    uInt));             /* size of item */
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
-        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
-        /* see note #13 above about 258 */
-local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
-        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
-local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
-        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-        8193, 12289, 16385, 24577};
-local const uInt cpdext[30] = { /* Extra bits for distance codes */
-        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-        12, 12, 13, 13};
-
-/*
-   Huffman code decoding is performed using a multi-level table lookup.
-   The fastest way to decode is to simply build a lookup table whose
-   size is determined by the longest code.  However, the time it takes
-   to build this table can also be a factor if the data being decoded
-   is not very long.  The most common codes are necessarily the
-   shortest codes, so those codes dominate the decoding time, and hence
-   the speed.  The idea is you can have a shorter table that decodes the
-   shorter, more probable codes, and then point to subsidiary tables for
-   the longer codes.  The time it costs to decode the longer codes is
-   then traded against the time it takes to make longer tables.
-
-   This results of this trade are in the variables lbits and dbits
-   below.  lbits is the number of bits the first level table for literal/
-   length codes can decode in one step, and dbits is the same thing for
-   the distance codes.  Subsequent tables are also less than or equal to
-   those sizes.  These values may be adjusted either when all of the
-   codes are shorter than that, in which case the longest code length in
-   bits is used, or when the shortest code is *longer* than the requested
-   table size, in which case the length of the shortest code in bits is
-   used.
-
-   There are two different values for the two tables, since they code a
-   different number of possibilities each.  The literal/length table
-   codes 286 possible values, or in a flat code, a little over eight
-   bits.  The distance table codes 30 possible values, or a little less
-   than five bits, flat.  The optimum values for speed end up being
-   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
-   The optimum values may differ though from machine to machine, and
-   possibly even between compilers.  Your mileage may vary.
- */
-
-
-/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
-#define BMAX 15         /* maximum bit length of any code */
-#define N_MAX 288       /* maximum number of codes in any set */
-
-#ifdef DEBUG_ZLIB
-  uInt inflate_hufts;
-#endif
-
-local int huft_build(b, n, s, d, e, t, m, zs)
-uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
-uInt n;                 /* number of codes (assumed <= N_MAX) */
-uInt s;                 /* number of simple-valued codes (0..s-1) */
-const uIntf *d;         /* list of base values for non-simple codes */
-const uIntf *e;         /* list of extra bits for non-simple codes */
-inflate_huft * FAR *t;  /* result: starting table */
-uIntf *m;               /* maximum lookup bits, returns actual */
-z_streamp zs;           /* for zalloc function */
-/* Given a list of code lengths and a maximum table size, make a set of
-   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
-   if the given code set is incomplete (the tables are still built in this
-   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
-   lengths), or Z_MEM_ERROR if not enough memory. */
-{
-
-  uInt a;                       /* counter for codes of length k */
-  uInt c[BMAX+1];               /* bit length count table */
-  uInt f;                       /* i repeats in table every f entries */
-  int g;                        /* maximum code length */
-  int h;                        /* table level */
-  register uInt i;              /* counter, current code */
-  register uInt j;              /* counter */
-  register int k;               /* number of bits in current code */
-  int l;                        /* bits per table (returned in m) */
-  register uIntf *p;            /* pointer into c[], b[], or v[] */
-  inflate_huft *q;              /* points to current table */
-  struct inflate_huft_s r;      /* table entry for structure assignment */
-  inflate_huft *u[BMAX];        /* table stack */
-  uInt v[N_MAX];                /* values in order of bit length */
-  register int w;               /* bits before this table == (l * h) */
-  uInt x[BMAX+1];               /* bit offsets, then code stack */
-  uIntf *xp;                    /* pointer into x */
-  int y;                        /* number of dummy codes added */
-  uInt z;                       /* number of entries in current table */
-
-
-  /* Generate counts for each bit length */
-  p = c;
-#define C0 *p++ = 0;
-#define C2 C0 C0 C0 C0
-#define C4 C2 C2 C2 C2
-  C4                            /* clear c[]--assume BMAX+1 is 16 */
-  p = b;  i = n;
-  do {
-    c[*p++]++;                  /* assume all entries <= BMAX */
-  } while (--i);
-  if (c[0] == n)                /* null input--all zero length codes */
-  {
-    *t = (inflate_huft *)Z_NULL;
-    *m = 0;
-    return Z_OK;
-  }
-
-
-  /* Find minimum and maximum length, bound *m by those */
-  l = *m;
-  for (j = 1; j <= BMAX; j++)
-    if (c[j])
-      break;
-  k = j;                        /* minimum code length */
-  if ((uInt)l < j)
-    l = j;
-  for (i = BMAX; i; i--)
-    if (c[i])
-      break;
-  g = i;                        /* maximum code length */
-  if ((uInt)l > i)
-    l = i;
-  *m = l;
-
-
-  /* Adjust last length count to fill out codes, if needed */
-  for (y = 1 << j; j < i; j++, y <<= 1)
-    if ((y -= c[j]) < 0)
-      return Z_DATA_ERROR;
-  if ((y -= c[i]) < 0)
-    return Z_DATA_ERROR;
-  c[i] += y;
-
-
-  /* Generate starting offsets into the value table for each length */
-  x[1] = j = 0;
-  p = c + 1;  xp = x + 2;
-  while (--i) {                 /* note that i == g from above */
-    *xp++ = (j += *p++);
-  }
-
-
-  /* Make a table of values in order of bit lengths */
-  p = b;  i = 0;
-  do {
-    if ((j = *p++) != 0)
-      v[x[j]++] = i;
-  } while (++i < n);
-  n = x[g];                   /* set n to length of v */
-
-
-  /* Generate the Huffman codes and for each, make the table entries */
-  x[0] = i = 0;                 /* first Huffman code is zero */
-  p = v;                        /* grab values in bit order */
-  h = -1;                       /* no tables yet--level -1 */
-  w = -l;                       /* bits decoded == (l * h) */
-  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
-  q = (inflate_huft *)Z_NULL;   /* ditto */
-  z = 0;                        /* ditto */
-
-  /* go through the bit lengths (k already is bits in shortest code) */
-  for (; k <= g; k++)
-  {
-    a = c[k];
-    while (a--)
-    {
-      /* here i is the Huffman code of length k bits for value *p */
-      /* make tables up to required level */
-      while (k > w + l)
-      {
-        h++;
-        w += l;                 /* previous table always l bits */
-
-        /* compute minimum size table less than or equal to l bits */
-        z = g - w;
-        z = z > (uInt)l ? l : z;        /* table size upper limit */
-        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
-        {                       /* too few codes for k-w bit table */
-          f -= a + 1;           /* deduct codes from patterns left */
-          xp = c + k;
-          if (j < z)
-            while (++j < z)     /* try smaller tables up to z bits */
-            {
-              if ((f <<= 1) <= *++xp)
-                break;          /* enough codes to use up j bits */
-              f -= *xp;         /* else deduct codes from patterns */
-            }
-        }
-        z = 1 << j;             /* table entries for j-bit table */
-
-        /* allocate and link in new table */
-        if ((q = (inflate_huft *)ZALLOC
-             (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
-        {
-          if (h)
-            inflate_trees_free(u[0], zs);
-          return Z_MEM_ERROR;   /* not enough memory */
-        }
-#ifdef DEBUG_ZLIB
-        inflate_hufts += z + 1;
-#endif
-        *t = q + 1;             /* link to list for huft_free() */
-        *(t = &(q->next)) = Z_NULL;
-        u[h] = ++q;             /* table starts after link */
-
-        /* connect to last table, if there is one */
-        if (h)
-        {
-          x[h] = i;             /* save pattern for backing up */
-          r.bits = (Byte)l;     /* bits to dump before this table */
-          r.exop = (Byte)j;     /* bits in this table */
-          r.next = q;           /* pointer to this table */
-          j = i >> (w - l);     /* (get around Turbo C bug) */
-          u[h-1][j] = r;        /* connect to last table */
-        }
-      }
-
-      /* set up table entry in r */
-      r.bits = (Byte)(k - w);
-      if (p >= v + n)
-        r.exop = 128 + 64;      /* out of values--invalid code */
-      else if (*p < s)
-      {
-        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
-        r.base = *p++;          /* simple code is just the value */
-      }
-      else
-      {
-        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
-        r.base = d[*p++ - s];
-      }
-
-      /* fill code-like entries with r */
-      f = 1 << (k - w);
-      for (j = i >> w; j < z; j += f)
-        q[j] = r;
-
-      /* backwards increment the k-bit code i */
-      for (j = 1 << (k - 1); i & j; j >>= 1)
-        i ^= j;
-      i ^= j;
-
-      /* backup over finished tables */
-      while ((i & ((1 << w) - 1)) != x[h])
-      {
-        h--;                    /* don't need to update q */
-        w -= l;
-      }
-    }
-  }
-
-
-  /* Return Z_BUF_ERROR if we were given an incomplete table */
-  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
-}
-
-
-int inflate_trees_bits(c, bb, tb, z)
-uIntf *c;               /* 19 code lengths */
-uIntf *bb;              /* bits tree desired/actual depth */
-inflate_huft * FAR *tb; /* bits tree result */
-z_streamp z;            /* for zfree function */
-{
-  int r;
-
-  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
-  if (r == Z_DATA_ERROR)
-    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
-  else if (r == Z_BUF_ERROR || *bb == 0)
-  {
-    inflate_trees_free(*tb, z);
-    z->msg = (char*)"incomplete dynamic bit lengths tree";
-    r = Z_DATA_ERROR;
-  }
-  return r;
-}
-
-
-int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
-uInt nl;                /* number of literal/length codes */
-uInt nd;                /* number of distance codes */
-uIntf *c;               /* that many (total) code lengths */
-uIntf *bl;              /* literal desired/actual bit depth */
-uIntf *bd;              /* distance desired/actual bit depth */
-inflate_huft * FAR *tl; /* literal/length tree result */
-inflate_huft * FAR *td; /* distance tree result */
-z_streamp z;            /* for zfree function */
-{
-  int r;
-
-  /* build literal/length tree */
-  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z);
-  if (r != Z_OK || *bl == 0)
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed literal/length tree";
-    else if (r != Z_MEM_ERROR)
-    {
-      inflate_trees_free(*tl, z);
-      z->msg = (char*)"incomplete literal/length tree";
-      r = Z_DATA_ERROR;
-    }
-    return r;
-  }
-
-  /* build distance tree */
-  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z);
-  if (r != Z_OK || (*bd == 0 && nl > 257))
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed distance tree";
-    else if (r == Z_BUF_ERROR) {
-#ifdef PKZIP_BUG_WORKAROUND
-      r = Z_OK;
-    }
-#else
-      inflate_trees_free(*td, z);
-      z->msg = (char*)"incomplete distance tree";
-      r = Z_DATA_ERROR;
-    }
-    else if (r != Z_MEM_ERROR)
-    {
-      z->msg = (char*)"empty distance tree with lengths";
-      r = Z_DATA_ERROR;
-    }
-    inflate_trees_free(*tl, z);
-    return r;
-#endif
-  }
-
-  /* done */
-  return Z_OK;
-}
-
-
-/* build fixed tables only once--keep them here */
-local int fixed_built = 0;
-#define FIXEDH 530      /* number of hufts used by fixed tables */
-local inflate_huft fixed_mem[FIXEDH];
-local uInt fixed_bl;
-local uInt fixed_bd;
-local inflate_huft *fixed_tl;
-local inflate_huft *fixed_td;
-
-
-local voidpf falloc(q, n, s)
-voidpf q;       /* opaque pointer */
-uInt n;         /* number of items */
-uInt s;         /* size of item */
-{
-  Assert(s == sizeof(inflate_huft) && n <= *(intf *)q,
-         "inflate_trees falloc overflow");
-  *(intf *)q -= n+s-s; /* s-s to avoid warning */
-  return (voidpf)(fixed_mem + *(intf *)q);
-}
-
-
-int inflate_trees_fixed(bl, bd, tl, td)
-uIntf *bl;               /* literal desired/actual bit depth */
-uIntf *bd;               /* distance desired/actual bit depth */
-inflate_huft * FAR *tl;  /* literal/length tree result */
-inflate_huft * FAR *td;  /* distance tree result */
-{
-  /* build fixed tables if not already (multiple overlapped executions ok) */
-  if (!fixed_built)
-  {
-    int k;              /* temporary variable */
-    unsigned c[288];    /* length list for huft_build */
-    z_stream z;         /* for falloc function */
-    int f = FIXEDH;     /* number of hufts left in fixed_mem */
-
-    /* set up fake z_stream for memory routines */
-    z.zalloc = falloc;
-    z.zfree = Z_NULL;
-    z.opaque = (voidpf)&f;
-
-    /* literal table */
-    for (k = 0; k < 144; k++)
-      c[k] = 8;
-    for (; k < 256; k++)
-      c[k] = 9;
-    for (; k < 280; k++)
-      c[k] = 7;
-    for (; k < 288; k++)
-      c[k] = 8;
-    fixed_bl = 7;
-    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
-
-    /* distance table */
-    for (k = 0; k < 30; k++)
-      c[k] = 5;
-    fixed_bd = 5;
-    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
-
-    /* done */
-    Assert(f == 0, "invalid build of fixed tables");
-    fixed_built = 1;
-  }
-  *bl = fixed_bl;
-  *bd = fixed_bd;
-  *tl = fixed_tl;
-  *td = fixed_td;
-  return Z_OK;
-}
-
-
-int inflate_trees_free(t, z)
-inflate_huft *t;        /* table to free */
-z_streamp z;            /* for zfree function */
-/* Free the malloc'ed tables built by huft_build(), which makes a linked
-   list of the tables it made, with the links in a dummy first entry of
-   each table. */
-{
-  register inflate_huft *p, *q, *r;
-
-  /* Reverse linked list */
-  p = Z_NULL;
-  q = t;
-  while (q != Z_NULL)
-  {
-    r = (q - 1)->next;
-    (q - 1)->next = p;
-    p = q;
-    q = r;
-  }
-  /* Go through linked list, freeing from the malloced (t[-1]) address. */
-  while (p != Z_NULL)
-  {
-    q = (--p)->next;
-    ZFREE(z,p);
-    p = q;
-  } 
-  return Z_OK;
-}
-/* --- inftrees.c */
-
-/* +++ infcodes.c */
-/* infcodes.c -- process literals and length/distance pairs
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-/* #include "infblock.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-
-/* +++ inffast.h */
-/* inffast.h -- header to use inffast.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-extern int inflate_fast OF((
-    uInt,
-    uInt,
-    inflate_huft *,
-    inflate_huft *,
-    inflate_blocks_statef *,
-    z_streamp ));
-/* --- inffast.h */
-
-/* simplify the use of the inflate_huft type with some defines */
-#define base more.Base
-#define next more.Next
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* inflate codes private state */
-struct inflate_codes_state {
-
-  /* mode */
-  enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-      START,    /* x: set up for LEN */
-      LEN,      /* i: get length/literal/eob next */
-      LENEXT,   /* i: getting length extra (have base) */
-      DIST,     /* i: get distance next */
-      DISTEXT,  /* i: getting distance extra */
-      COPY,     /* o: copying bytes in window, waiting for space */
-      LIT,      /* o: got literal, waiting for output space */
-      WASH,     /* o: got eob, possibly still output waiting */
-      END,      /* x: got eob and all data flushed */
-      BADCODE}  /* x: got error */
-    mode;               /* current inflate_codes mode */
-
-  /* mode dependent information */
-  uInt len;
-  union {
-    struct {
-      inflate_huft *tree;       /* pointer into tree */
-      uInt need;                /* bits needed */
-    } code;             /* if LEN or DIST, where in tree */
-    uInt lit;           /* if LIT, literal */
-    struct {
-      uInt get;                 /* bits to get for extra */
-      uInt dist;                /* distance back to copy from */
-    } copy;             /* if EXT or COPY, where and how much */
-  } sub;                /* submode */
-
-  /* mode independent information */
-  Byte lbits;           /* ltree bits decoded per branch */
-  Byte dbits;           /* dtree bits decoder per branch */
-  inflate_huft *ltree;          /* literal/length/eob tree */
-  inflate_huft *dtree;          /* distance tree */
-
-};
-
-
-inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-z_streamp z;
-{
-  inflate_codes_statef *c;
-
-  if ((c = (inflate_codes_statef *)
-       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
-  {
-    c->mode = START;
-    c->lbits = (Byte)bl;
-    c->dbits = (Byte)bd;
-    c->ltree = tl;
-    c->dtree = td;
-    Tracev((stderr, "inflate:       codes new\n"));
-  }
-  return c;
-}
-
-
-int inflate_codes(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt j;               /* temporary storage */
-  inflate_huft *t;      /* temporary pointer */
-  uInt e;               /* extra bits or operation */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-  Bytef *f;             /* pointer to copy strings from */
-  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
-
-  /* copy input/output information to locals (UPDATE macro restores) */
-  LOAD
-
-  /* process input and output based on current state */
-  while (1) switch (c->mode)
-  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-    case START:         /* x: set up for LEN */
-#ifndef SLOW
-      if (m >= 258 && n >= 10)
-      {
-        UPDATE
-        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
-        LOAD
-        if (r != Z_OK)
-        {
-          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
-          break;
-        }
-      }
-#endif /* !SLOW */
-      c->sub.code.need = c->lbits;
-      c->sub.code.tree = c->ltree;
-      c->mode = LEN;
-    case LEN:           /* i: get length/literal/eob next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e == 0)               /* literal */
-      {
-        c->sub.lit = t->base;
-        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-                 "inflate:         literal '%c'\n" :
-                 "inflate:         literal 0x%02x\n", t->base));
-        c->mode = LIT;
-        break;
-      }
-      if (e & 16)               /* length */
-      {
-        c->sub.copy.get = e & 15;
-        c->len = t->base;
-        c->mode = LENEXT;
-        break;
-      }
-      if ((e & 64) == 0)        /* next table */
-      {
-        c->sub.code.need = e;
-        c->sub.code.tree = t->next;
-        break;
-      }
-      if (e & 32)               /* end of block */
-      {
-        Tracevv((stderr, "inflate:         end of block\n"));
-        c->mode = WASH;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"invalid literal/length code";
-      r = Z_DATA_ERROR;
-      LEAVE
-    case LENEXT:        /* i: getting length extra (have base) */
-      j = c->sub.copy.get;
-      NEEDBITS(j)
-      c->len += (uInt)b & inflate_mask[j];
-      DUMPBITS(j)
-      c->sub.code.need = c->dbits;
-      c->sub.code.tree = c->dtree;
-      Tracevv((stderr, "inflate:         length %u\n", c->len));
-      c->mode = DIST;
-    case DIST:          /* i: get distance next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e & 16)               /* distance */
-      {
-        c->sub.copy.get = e & 15;
-        c->sub.copy.dist = t->base;
-        c->mode = DISTEXT;
-        break;
-      }
-      if ((e & 64) == 0)        /* next table */
-      {
-        c->sub.code.need = e;
-        c->sub.code.tree = t->next;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"invalid distance code";
-      r = Z_DATA_ERROR;
-      LEAVE
-    case DISTEXT:       /* i: getting distance extra */
-      j = c->sub.copy.get;
-      NEEDBITS(j)
-      c->sub.copy.dist += (uInt)b & inflate_mask[j];
-      DUMPBITS(j)
-      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
-      c->mode = COPY;
-    case COPY:          /* o: copying bytes in window, waiting for space */
-#ifndef __TURBOC__ /* Turbo C bug for following expression */
-      f = (uInt)(q - s->window) < c->sub.copy.dist ?
-          s->end - (c->sub.copy.dist - (q - s->window)) :
-          q - c->sub.copy.dist;
-#else
-      f = q - c->sub.copy.dist;
-      if ((uInt)(q - s->window) < c->sub.copy.dist)
-        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
-#endif
-      while (c->len)
-      {
-        NEEDOUT
-        OUTBYTE(*f++)
-        if (f == s->end)
-          f = s->window;
-        c->len--;
-      }
-      c->mode = START;
-      break;
-    case LIT:           /* o: got literal, waiting for output space */
-      NEEDOUT
-      OUTBYTE(c->sub.lit)
-      c->mode = START;
-      break;
-    case WASH:          /* o: got eob, possibly more output */
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      c->mode = END;
-    case END:
-      r = Z_STREAM_END;
-      LEAVE
-    case BADCODE:       /* x: got error */
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-}
-
-
-void inflate_codes_free(c, z)
-inflate_codes_statef *c;
-z_streamp z;
-{
-  ZFREE(z, c);
-  Tracev((stderr, "inflate:       codes free\n"));
-}
-/* --- infcodes.c */
-
-/* +++ infutil.c */
-/* inflate_util.c -- data and routines common to blocks and codes
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "infblock.h" */
-/* #include "inftrees.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* And'ing with mask[n] masks the lower n bits */
-uInt inflate_mask[17] = {
-    0x0000,
-    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-
-/* copy as much as possible from the sliding window to the output area */
-int inflate_flush(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt n;
-  Bytef *p;
-  Bytef *q;
-
-  /* local copies of source and destination pointers */
-  p = z->next_out;
-  q = s->read;
-
-  /* compute number of bytes to copy as far as end of window */
-  n = (uInt)((q <= s->write ? s->write : s->end) - q);
-  if (n > z->avail_out) n = z->avail_out;
-  if (n && r == Z_BUF_ERROR) r = Z_OK;
-
-  /* update counters */
-  z->avail_out -= n;
-  z->total_out += n;
-
-  /* update check information */
-  if (s->checkfn != Z_NULL)
-    z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-  /* copy as far as end of window */
-  if (p != Z_NULL) {
-    zmemcpy(p, q, n);
-    p += n;
-  }
-  q += n;
-
-  /* see if more to copy at beginning of window */
-  if (q == s->end)
-  {
-    /* wrap pointers */
-    q = s->window;
-    if (s->write == s->end)
-      s->write = s->window;
-
-    /* compute bytes to copy */
-    n = (uInt)(s->write - q);
-    if (n > z->avail_out) n = z->avail_out;
-    if (n && r == Z_BUF_ERROR) r = Z_OK;
-
-    /* update counters */
-    z->avail_out -= n;
-    z->total_out += n;
-
-    /* update check information */
-    if (s->checkfn != Z_NULL)
-      z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-    /* copy */
-    if (p != Z_NULL) {
-      zmemcpy(p, q, n);
-      p += n;
-    }
-    q += n;
-  }
-
-  /* update pointers */
-  z->next_out = p;
-  s->read = q;
-
-  /* done */
-  return r;
-}
-/* --- infutil.c */
-
-/* +++ inffast.c */
-/* inffast.c -- process literals and length/distance pairs fast
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-/* #include "infblock.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-/* #include "inffast.h" */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* simplify the use of the inflate_huft type with some defines */
-#define base more.Base
-#define next more.Next
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* macros for bit input with no checking and for returning unused bytes */
-#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
-
-/* Called with number of bytes left to write in window at least 258
-   (the maximum string length) and number of input bytes available
-   at least ten.  The ten bytes are six bytes for the longest length/
-   distance pair plus four bytes for overloading the bit buffer. */
-
-int inflate_fast(bl, bd, tl, td, s, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-inflate_blocks_statef *s;
-z_streamp z;
-{
-  inflate_huft *t;      /* temporary pointer */
-  uInt e;               /* extra bits or operation */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-  uInt ml;              /* mask for literal/length tree */
-  uInt md;              /* mask for distance tree */
-  uInt c;               /* bytes to copy */
-  uInt d;               /* distance back to copy from */
-  Bytef *r;             /* copy source pointer */
-
-  /* load input, output, bit values */
-  LOAD
-
-  /* initialize masks */
-  ml = inflate_mask[bl];
-  md = inflate_mask[bd];
-
-  /* do until not enough input or output space for fast loop */
-  do {                          /* assume called with m >= 258 && n >= 10 */
-    /* get literal/length code */
-    GRABBITS(20)                /* max bits for literal/length code */
-    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
-    {
-      DUMPBITS(t->bits)
-      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-                "inflate:         * literal '%c'\n" :
-                "inflate:         * literal 0x%02x\n", t->base));
-      *q++ = (Byte)t->base;
-      m--;
-      continue;
-    }
-    do {
-      DUMPBITS(t->bits)
-      if (e & 16)
-      {
-        /* get extra bits for length */
-        e &= 15;
-        c = t->base + ((uInt)b & inflate_mask[e]);
-        DUMPBITS(e)
-        Tracevv((stderr, "inflate:         * length %u\n", c));
-
-        /* decode distance base of block to copy */
-        GRABBITS(15);           /* max bits for distance code */
-        e = (t = td + ((uInt)b & md))->exop;
-        do {
-          DUMPBITS(t->bits)
-          if (e & 16)
-          {
-            /* get extra bits to add to distance base */
-            e &= 15;
-            GRABBITS(e)         /* get extra bits (up to 13) */
-            d = t->base + ((uInt)b & inflate_mask[e]);
-            DUMPBITS(e)
-            Tracevv((stderr, "inflate:         * distance %u\n", d));
-
-            /* do the copy */
-            m -= c;
-            if ((uInt)(q - s->window) >= d)     /* offset before dest */
-            {                                   /*  just copy */
-              r = q - d;
-              *q++ = *r++;  c--;        /* minimum count is three, */
-              *q++ = *r++;  c--;        /*  so unroll loop a little */
-            }
-            else                        /* else offset after destination */
-            {
-              e = d - (uInt)(q - s->window); /* bytes from offset to end */
-              r = s->end - e;           /* pointer to offset */
-              if (c > e)                /* if source crosses, */
-              {
-                c -= e;                 /* copy to end of window */
-                do {
-                  *q++ = *r++;
-                } while (--e);
-                r = s->window;          /* copy rest from start of window */
-              }
-            }
-            do {                        /* copy all or what's left */
-              *q++ = *r++;
-            } while (--c);
-            break;
-          }
-          else if ((e & 64) == 0)
-            e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
-          else
-          {
-            z->msg = (char*)"invalid distance code";
-            UNGRAB
-            UPDATE
-            return Z_DATA_ERROR;
-          }
-        } while (1);
-        break;
-      }
-      if ((e & 64) == 0)
-      {
-        if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
-        {
-          DUMPBITS(t->bits)
-          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-                    "inflate:         * literal '%c'\n" :
-                    "inflate:         * literal 0x%02x\n", t->base));
-          *q++ = (Byte)t->base;
-          m--;
-          break;
-        }
-      }
-      else if (e & 32)
-      {
-        Tracevv((stderr, "inflate:         * end of block\n"));
-        UNGRAB
-        UPDATE
-        return Z_STREAM_END;
-      }
-      else
-      {
-        z->msg = (char*)"invalid literal/length code";
-        UNGRAB
-        UPDATE
-        return Z_DATA_ERROR;
-      }
-    } while (1);
-  } while (m >= 258 && n >= 10);
-
-  /* not enough input or output--restore pointers and return */
-  UNGRAB
-  UPDATE
-  return Z_OK;
-}
-/* --- inffast.c */
-
-/* +++ zutil.c */
-/* zutil.c -- target dependent utility functions for the compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */
-
-/* #include "zutil.h" */
-
-#ifndef NO_DUMMY_DECL
-struct internal_state      {int dummy;}; /* for buggy compilers */
-#endif
-
-#ifndef STDC
-extern void exit OF((int));
-#endif
-
-const char *z_errmsg[10] = {
-"need dictionary",     /* Z_NEED_DICT       2  */
-"stream end",          /* Z_STREAM_END      1  */
-"",                    /* Z_OK              0  */
-"file error",          /* Z_ERRNO         (-1) */
-"stream error",        /* Z_STREAM_ERROR  (-2) */
-"data error",          /* Z_DATA_ERROR    (-3) */
-"insufficient memory", /* Z_MEM_ERROR     (-4) */
-"buffer error",        /* Z_BUF_ERROR     (-5) */
-"incompatible version",/* Z_VERSION_ERROR (-6) */
-""};
-
-
-const char *zlibVersion()
-{
-    return ZLIB_VERSION;
-}
-
-#ifdef DEBUG_ZLIB
-void z_error (m)
-    char *m;
-{
-    fprintf(stderr, "%s\n", m);
-    exit(1);
-}
-#endif
-
-#ifndef HAVE_MEMCPY
-
-void zmemcpy(dest, source, len)
-    Bytef* dest;
-    Bytef* source;
-    uInt  len;
-{
-    if (len == 0) return;
-    do {
-        *dest++ = *source++; /* ??? to be unrolled */
-    } while (--len != 0);
-}
-
-int zmemcmp(s1, s2, len)
-    Bytef* s1;
-    Bytef* s2;
-    uInt  len;
-{
-    uInt j;
-
-    for (j = 0; j < len; j++) {
-        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
-    }
-    return 0;
-}
-
-void zmemzero(dest, len)
-    Bytef* dest;
-    uInt  len;
-{
-    if (len == 0) return;
-    do {
-        *dest++ = 0;  /* ??? to be unrolled */
-    } while (--len != 0);
-}
-#endif
-
-#ifdef __TURBOC__
-#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
-/* Small and medium model in Turbo C are for now limited to near allocation
- * with reduced MAX_WBITS and MAX_MEM_LEVEL
- */
-#  define MY_ZCALLOC
-
-/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
- * and farmalloc(64K) returns a pointer with an offset of 8, so we
- * must fix the pointer. Warning: the pointer must be put back to its
- * original form in order to free it, use zcfree().
- */
-
-#define MAX_PTR 10
-/* 10*64K = 640K */
-
-local int next_ptr = 0;
-
-typedef struct ptr_table_s {
-    voidpf org_ptr;
-    voidpf new_ptr;
-} ptr_table;
-
-local ptr_table table[MAX_PTR];
-/* This table is used to remember the original form of pointers
- * to large buffers (64K). Such pointers are normalized with a zero offset.
- * Since MSDOS is not a preemptive multitasking OS, this table is not
- * protected from concurrent access. This hack doesn't work anyway on
- * a protected system like OS/2. Use Microsoft C instead.
- */
-
-voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-{
-    voidpf buf = opaque; /* just to make some compilers happy */
-    ulg bsize = (ulg)items*size;
-
-    /* If we allocate less than 65520 bytes, we assume that farmalloc
-     * will return a usable pointer which doesn't have to be normalized.
-     */
-    if (bsize < 65520L) {
-        buf = farmalloc(bsize);
-        if (*(ush*)&buf != 0) return buf;
-    } else {
-        buf = farmalloc(bsize + 16L);
-    }
-    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
-    table[next_ptr].org_ptr = buf;
-
-    /* Normalize the pointer to seg:0 */
-    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
-    *(ush*)&buf = 0;
-    table[next_ptr++].new_ptr = buf;
-    return buf;
-}
-
-void  zcfree (voidpf opaque, voidpf ptr)
-{
-    int n;
-    if (*(ush*)&ptr != 0) { /* object < 64K */
-        farfree(ptr);
-        return;
-    }
-    /* Find the original pointer */
-    for (n = 0; n < next_ptr; n++) {
-        if (ptr != table[n].new_ptr) continue;
-
-        farfree(table[n].org_ptr);
-        while (++n < next_ptr) {
-            table[n-1] = table[n];
-        }
-        next_ptr--;
-        return;
-    }
-    ptr = opaque; /* just to make some compilers happy */
-    Assert(0, "zcfree: ptr not found");
-}
-#endif
-#endif /* __TURBOC__ */
-
-
-#if defined(M_I86) && !defined(__32BIT__)
-/* Microsoft C in 16-bit mode */
-
-#  define MY_ZCALLOC
-
-#if (!defined(_MSC_VER) || (_MSC_VER < 600))
-#  define _halloc  halloc
-#  define _hfree   hfree
-#endif
-
-voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-{
-    if (opaque) opaque = 0; /* to make compiler happy */
-    return _halloc((long)items, size);
-}
-
-void  zcfree (voidpf opaque, voidpf ptr)
-{
-    if (opaque) opaque = 0; /* to make compiler happy */
-    _hfree(ptr);
-}
-
-#endif /* MSC */
-
-
-#ifndef MY_ZCALLOC /* Any system without a special alloc function */
-
-#ifndef STDC
-extern voidp  calloc OF((uInt items, uInt size));
-extern void   free   OF((voidpf ptr));
-#endif
-
-voidpf zcalloc (opaque, items, size)
-    voidpf opaque;
-    unsigned items;
-    unsigned size;
-{
-    if (opaque) items += size - size; /* make compiler happy */
-    return (voidpf)calloc(items, size);
-}
-
-void  zcfree (opaque, ptr)
-    voidpf opaque;
-    voidpf ptr;
-{
-    free(ptr);
-    if (opaque) return; /* make compiler happy */
-}
-
-#endif /* MY_ZCALLOC */
-/* --- zutil.c */
-
-/* +++ adler32.c */
-/* adler32.c -- compute the Adler-32 checksum of a data stream
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */
-
-/* #include "zlib.h" */
-
-#define BASE 65521L /* largest prime smaller than 65536 */
-#define NMAX 5552
-/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
-
-#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
-#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
-#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
-#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
-#define DO16(buf)   DO8(buf,0); DO8(buf,8);
-
-/* ========================================================================= */
-uLong adler32(adler, buf, len)
-    uLong adler;
-    const Bytef *buf;
-    uInt len;
-{
-    unsigned long s1 = adler & 0xffff;
-    unsigned long s2 = (adler >> 16) & 0xffff;
-    int k;
-
-    if (buf == Z_NULL) return 1L;
-
-    while (len > 0) {
-        k = len < NMAX ? len : NMAX;
-        len -= k;
-        while (k >= 16) {
-            DO16(buf);
-	    buf += 16;
-            k -= 16;
-        }
-        if (k != 0) do {
-            s1 += *buf++;
-	    s2 += s1;
-        } while (--k);
-        s1 %= BASE;
-        s2 %= BASE;
-    }
-    return (s2 << 16) | s1;
-}
-/* --- adler32.c */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/zlib.h linux/drivers/net/zlib.h
--- v2.5.2/linux/drivers/net/zlib.h	Tue Dec 23 10:57:31 1997
+++ linux/drivers/net/zlib.h	Wed Dec 31 16:00:00 1969
@@ -1,1010 +0,0 @@
-/*	$Id: zlib.h,v 1.2 1997/12/23 10:47:44 paulus Exp $	*/
-
-/*
- * This file is derived from zlib.h and zconf.h from the zlib-1.0.4
- * distribution by Jean-loup Gailly and Mark Adler, with some additions
- * by Paul Mackerras to aid in implementing Deflate compression and
- * decompression for PPP packets.
- */
-
-/*
- *  ==FILEVERSION 971127==
- *
- * This marker is used by the Linux installation script to determine
- * whether an up-to-date version of this file is already installed.
- */
-
-
-/* +++ zlib.h */
-/* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.0.4, Jul 24th, 1996.
-
-  Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  gzip@prep.ai.mit.edu    madler@alumni.caltech.edu
-
-
-  The data format used by the zlib library is described by RFCs (Request for
-  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
-  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
-*/
-
-#ifndef _ZLIB_H
-#define _ZLIB_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* +++ zconf.h */
-/* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */
-
-#ifndef _ZCONF_H
-#define _ZCONF_H
-
-/*
- * If you *really* need a unique prefix for all types and library functions,
- * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
- */
-#ifdef Z_PREFIX
-#  define deflateInit_	z_deflateInit_
-#  define deflate	z_deflate
-#  define deflateEnd	z_deflateEnd
-#  define inflateInit_ 	z_inflateInit_
-#  define inflate	z_inflate
-#  define inflateEnd	z_inflateEnd
-#  define deflateInit2_	z_deflateInit2_
-#  define deflateSetDictionary z_deflateSetDictionary
-#  define deflateCopy	z_deflateCopy
-#  define deflateReset	z_deflateReset
-#  define deflateParams	z_deflateParams
-#  define inflateInit2_	z_inflateInit2_
-#  define inflateSetDictionary z_inflateSetDictionary
-#  define inflateSync	z_inflateSync
-#  define inflateReset	z_inflateReset
-#  define compress	z_compress
-#  define uncompress	z_uncompress
-#  define adler32	z_adler32
-#  define crc32		z_crc32
-#  define get_crc_table z_get_crc_table
-
-#  define Byte		z_Byte
-#  define uInt		z_uInt
-#  define uLong		z_uLong
-#  define Bytef	        z_Bytef
-#  define charf		z_charf
-#  define intf		z_intf
-#  define uIntf		z_uIntf
-#  define uLongf	z_uLongf
-#  define voidpf	z_voidpf
-#  define voidp		z_voidp
-#endif
-
-#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
-#  define WIN32
-#endif
-#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
-#  ifndef __32BIT__
-#    define __32BIT__
-#  endif
-#endif
-#if defined(__MSDOS__) && !defined(MSDOS)
-#  define MSDOS
-#endif
-
-/*
- * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
- * than 64k bytes at a time (needed on systems with 16-bit int).
- */
-#if defined(MSDOS) && !defined(__32BIT__)
-#  define MAXSEG_64K
-#endif
-#ifdef MSDOS
-#  define UNALIGNED_OK
-#endif
-
-#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
-#  define STDC
-#endif
-#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC)
-#  define STDC
-#endif
-
-#ifndef STDC
-#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
-#    define const
-#  endif
-#endif
-
-/* Some Mac compilers merge all .h files incorrectly: */
-#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
-#  define NO_DUMMY_DECL
-#endif
-
-/* Maximum value for memLevel in deflateInit2 */
-#ifndef MAX_MEM_LEVEL
-#  ifdef MAXSEG_64K
-#    define MAX_MEM_LEVEL 8
-#  else
-#    define MAX_MEM_LEVEL 9
-#  endif
-#endif
-
-/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
-#ifndef MAX_WBITS
-#  define MAX_WBITS   15 /* 32K LZ77 window */
-#endif
-
-/* The memory requirements for deflate are (in bytes):
-            1 << (windowBits+2)   +  1 << (memLevel+9)
- that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
- plus a few kilobytes for small objects. For example, if you want to reduce
- the default memory requirements from 256K to 128K, compile with
-     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
- Of course this will generally degrade compression (there's no free lunch).
-
-   The memory requirements for inflate are (in bytes) 1 << windowBits
- that is, 32K for windowBits=15 (default value) plus a few kilobytes
- for small objects.
-*/
-
-                        /* Type declarations */
-
-#ifndef OF /* function prototypes */
-#  ifdef STDC
-#    define OF(args)  args
-#  else
-#    define OF(args)  ()
-#  endif
-#endif
-
-/* The following definitions for FAR are needed only for MSDOS mixed
- * model programming (small or medium model with some far allocations).
- * This was tested only with MSC; for other MSDOS compilers you may have
- * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
- * just define FAR to be empty.
- */
-#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
-   /* MSC small or medium model */
-#  define SMALL_MEDIUM
-#  ifdef _MSC_VER
-#    define FAR __far
-#  else
-#    define FAR far
-#  endif
-#endif
-#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
-#  ifndef __32BIT__
-#    define SMALL_MEDIUM
-#    define FAR __far
-#  endif
-#endif
-#ifndef FAR
-#   define FAR
-#endif
-
-typedef unsigned char  Byte;  /* 8 bits */
-typedef unsigned int   uInt;  /* 16 bits or more */
-typedef unsigned long  uLong; /* 32 bits or more */
-
-#if defined(__BORLANDC__) && defined(SMALL_MEDIUM)
-   /* Borland C/C++ ignores FAR inside typedef */
-#  define Bytef Byte FAR
-#else
-   typedef Byte  FAR Bytef;
-#endif
-typedef char  FAR charf;
-typedef int   FAR intf;
-typedef uInt  FAR uIntf;
-typedef uLong FAR uLongf;
-
-#ifdef STDC
-   typedef void FAR *voidpf;
-   typedef void     *voidp;
-#else
-   typedef Byte FAR *voidpf;
-   typedef Byte     *voidp;
-#endif
-
-
-/* Compile with -DZLIB_DLL for Windows DLL support */
-#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL)
-#  include <windows.h>
-#  define EXPORT  WINAPI
-#else
-#  define EXPORT
-#endif
-
-#endif /* _ZCONF_H */
-/* --- zconf.h */
-
-#define ZLIB_VERSION "1.0.4P"
-
-/* 
-     The 'zlib' compression library provides in-memory compression and
-  decompression functions, including integrity checks of the uncompressed
-  data.  This version of the library supports only one compression method
-  (deflation) but other algorithms may be added later and will have the same
-  stream interface.
-
-     For compression the application must provide the output buffer and
-  may optionally provide the input buffer for optimization. For decompression,
-  the application must provide the input buffer and may optionally provide
-  the output buffer for optimization.
-
-     Compression can be done in a single step if the buffers are large
-  enough (for example if an input file is mmap'ed), or can be done by
-  repeated calls of the compression function.  In the latter case, the
-  application must provide more input and/or consume the output
-  (providing more output space) before each call.
-
-     The library does not install any signal handler. It is recommended to
-  add at least a handler for SIGSEGV when decompressing; the library checks
-  the consistency of the input data whenever possible but may go nuts
-  for some forms of corrupted input.
-*/
-
-typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
-
-struct internal_state;
-
-typedef struct z_stream_s {
-    Bytef    *next_in;  /* next input byte */
-    uInt     avail_in;  /* number of bytes available at next_in */
-    uLong    total_in;  /* total nb of input bytes read so far */
-
-    Bytef    *next_out; /* next output byte should be put there */
-    uInt     avail_out; /* remaining free space at next_out */
-    uLong    total_out; /* total nb of bytes output so far */
-
-    char     *msg;      /* last error message, NULL if no error */
-    struct internal_state FAR *state; /* not visible by applications */
-
-    alloc_func zalloc;  /* used to allocate the internal state */
-    free_func  zfree;   /* used to free the internal state */
-    voidpf     opaque;  /* private data object passed to zalloc and zfree */
-
-    int     data_type;  /* best guess about the data type: ascii or binary */
-    uLong   adler;      /* adler32 value of the uncompressed data */
-    uLong   reserved;   /* reserved for future use */
-} z_stream;
-
-typedef z_stream FAR *z_streamp;
-
-/*
-   The application must update next_in and avail_in when avail_in has
-   dropped to zero. It must update next_out and avail_out when avail_out
-   has dropped to zero. The application must initialize zalloc, zfree and
-   opaque before calling the init function. All other fields are set by the
-   compression library and must not be updated by the application.
-
-   The opaque value provided by the application will be passed as the first
-   parameter for calls of zalloc and zfree. This can be useful for custom
-   memory management. The compression library attaches no meaning to the
-   opaque value.
-
-   zalloc must return Z_NULL if there is not enough memory for the object.
-   On 16-bit systems, the functions zalloc and zfree must be able to allocate
-   exactly 65536 bytes, but will not be required to allocate more than this
-   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
-   pointers returned by zalloc for objects of exactly 65536 bytes *must*
-   have their offset normalized to zero. The default allocation function
-   provided by this library ensures this (see zutil.c). To reduce memory
-   requirements and avoid any allocation of 64K objects, at the expense of
-   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
-
-   The fields total_in and total_out can be used for statistics or
-   progress reports. After compression, total_in holds the total size of
-   the uncompressed data and may be saved for use in the decompressor
-   (particularly if the decompressor wants to decompress everything in
-   a single step).
-*/
-
-                        /* constants */
-
-#define Z_NO_FLUSH      0
-#define Z_PARTIAL_FLUSH 1
-#define Z_PACKET_FLUSH	2
-#define Z_SYNC_FLUSH    3
-#define Z_FULL_FLUSH    4
-#define Z_FINISH        5
-/* Allowed flush values; see deflate() below for details */
-
-#define Z_OK            0
-#define Z_STREAM_END    1
-#define Z_NEED_DICT     2
-#define Z_ERRNO        (-1)
-#define Z_STREAM_ERROR (-2)
-#define Z_DATA_ERROR   (-3)
-#define Z_MEM_ERROR    (-4)
-#define Z_BUF_ERROR    (-5)
-#define Z_VERSION_ERROR (-6)
-/* Return codes for the compression/decompression functions. Negative
- * values are errors, positive values are used for special but normal events.
- */
-
-#define Z_NO_COMPRESSION         0
-#define Z_BEST_SPEED             1
-#define Z_BEST_COMPRESSION       9
-#define Z_DEFAULT_COMPRESSION  (-1)
-/* compression levels */
-
-#define Z_FILTERED            1
-#define Z_HUFFMAN_ONLY        2
-#define Z_DEFAULT_STRATEGY    0
-/* compression strategy; see deflateInit2() below for details */
-
-#define Z_BINARY   0
-#define Z_ASCII    1
-#define Z_UNKNOWN  2
-/* Possible values of the data_type field */
-
-#define Z_DEFLATED   8
-/* The deflate compression method (the only one supported in this version) */
-
-#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
-
-#define zlib_version zlibVersion()
-/* for compatibility with versions < 1.0.2 */
-
-                        /* basic functions */
-
-extern const char * EXPORT zlibVersion OF((void));
-/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
-   If the first character differs, the library code actually used is
-   not compatible with the zlib.h header file used by the application.
-   This check is automatically made by deflateInit and inflateInit.
- */
-
-/* 
-extern int EXPORT deflateInit OF((z_streamp strm, int level));
-
-     Initializes the internal stream state for compression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.
-   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
-   use default allocation functions.
-
-     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
-   1 gives best speed, 9 gives best compression, 0 gives no compression at
-   all (the input data is simply copied a block at a time).
-   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
-   compression (currently equivalent to level 6).
-
-     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
-   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
-   with the version assumed by the caller (ZLIB_VERSION).
-   msg is set to null if there is no error message.  deflateInit does not
-   perform any compression: this will be done by deflate().
-*/
-
-
-extern int EXPORT deflate OF((z_streamp strm, int flush));
-/*
-  Performs one or both of the following actions:
-
-  - Compress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in and avail_in are updated and
-    processing will resume at this point for the next call of deflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly. This action is forced if the parameter flush is non zero.
-    Forcing flush frequently degrades the compression ratio, so this parameter
-    should be set only when necessary (in interactive applications).
-    Some output may be provided even if flush is not set.
-
-  Before the call of deflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating avail_in or avail_out accordingly; avail_out
-  should never be zero before the call. The application can consume the
-  compressed output when it wants, for example when the output buffer is full
-  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
-  and with zero avail_out, it must be called again after making room in the
-  output buffer because there might be more output pending.
-
-    If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
-  block is terminated and flushed to the output buffer so that the
-  decompressor can get all input data available so far. For method 9, a future
-  variant on method 8, the current block will be flushed but not terminated.
-  Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
-  output is byte aligned (the compressor can clear its internal bit buffer)
-  and the current block is always terminated; this can be useful if the
-  compressor has to be restarted from scratch after an interruption (in which
-  case the internal state of the compressor may be lost).
-    If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
-  special marker is output and the compression dictionary is discarded; this
-  is useful to allow the decompressor to synchronize if one compressed block
-  has been damaged (see inflateSync below).  Flushing degrades compression and
-  so should be used only when necessary.  Using Z_FULL_FLUSH too often can
-  seriously degrade the compression. If deflate returns with avail_out == 0,
-  this function must be called again with the same value of the flush
-  parameter and more output space (updated avail_out), until the flush is
-  complete (deflate returns with non-zero avail_out).
-
-    If the parameter flush is set to Z_PACKET_FLUSH, the compression
-  block is terminated, and a zero-length stored block is output,
-  omitting the length bytes (the effect of this is that the 3-bit type
-  code 000 for a stored block is output, and the output is then
-  byte-aligned).  This is designed for use at the end of a PPP packet.
-
-    If the parameter flush is set to Z_FINISH, pending input is processed,
-  pending output is flushed and deflate returns with Z_STREAM_END if there
-  was enough output space; if deflate returns with Z_OK, this function must be
-  called again with Z_FINISH and more output space (updated avail_out) but no
-  more input data, until it returns with Z_STREAM_END or an error. After
-  deflate has returned Z_STREAM_END, the only possible operations on the
-  stream are deflateReset or deflateEnd.
-  
-    Z_FINISH can be used immediately after deflateInit if all the compression
-  is to be done in a single step. In this case, avail_out must be at least
-  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
-  Z_STREAM_END, then it must be called again as described above.
-
-    deflate() may update data_type if it can make a good guess about
-  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
-  binary. This field is only for information purposes and does not affect
-  the compression algorithm in any manner.
-
-    deflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if all input has been
-  consumed and all output has been produced (only when flush is set to
-  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
-  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
-*/
-
-
-extern int EXPORT deflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
-   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
-   prematurely (some input or output was discarded). In the error case,
-   msg may be set but then points to a static string (which must not be
-   deallocated).
-*/
-
-
-/* 
-extern int EXPORT inflateInit OF((z_streamp strm));
-
-     Initializes the internal stream state for decompression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.  If
-   zalloc and zfree are set to Z_NULL, inflateInit updates them to use default
-   allocation functions.
-
-     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_VERSION_ERROR if the zlib library version is incompatible
-   with the version assumed by the caller.  msg is set to null if there is no
-   error message. inflateInit does not perform any decompression: this will be
-   done by inflate().
-*/
-
-
-extern int EXPORT inflate OF((z_streamp strm, int flush));
-/*
-  Performs one or both of the following actions:
-
-  - Decompress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in is updated and processing
-    will resume at this point for the next call of inflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly.  inflate() provides as much output as possible, until there
-    is no more input data or no more space in the output buffer (see below
-    about the flush parameter).
-
-  Before the call of inflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating the next_* and avail_* values accordingly.
-  The application can consume the uncompressed output when it wants, for
-  example when the output buffer is full (avail_out == 0), or after each
-  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
-  must be called again after making room in the output buffer because there
-  might be more output pending.
-
-    If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
-  inflate flushes as much output as possible to the output buffer. The
-  flushing behavior of inflate is not specified for values of the flush
-  parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
-  current implementation actually flushes as much output as possible
-  anyway.  For Z_PACKET_FLUSH, inflate checks that once all the input data
-  has been consumed, it is expecting to see the length field of a stored
-  block; if not, it returns Z_DATA_ERROR.
-
-    inflate() should normally be called until it returns Z_STREAM_END or an
-  error. However if all decompression is to be performed in a single step
-  (a single call of inflate), the parameter flush should be set to
-  Z_FINISH. In this case all pending input is processed and all pending
-  output is flushed; avail_out must be large enough to hold all the
-  uncompressed data. (The size of the uncompressed data may have been saved
-  by the compressor for this purpose.) The next operation on this stream must
-  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
-  is never required, but can be used to inform inflate that a faster routine
-  may be used for the single inflate() call.
-
-    inflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if the end of the
-  compressed data has been reached and all uncompressed output has been
-  produced, Z_NEED_DICT if a preset dictionary is needed at this point (see
-  inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted,
-  Z_STREAM_ERROR if the stream structure was inconsistent (for example if
-  next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
-  Z_BUF_ERROR if no progress is possible or if there was not enough room in
-  the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the
-  application may then call inflateSync to look for a good compression block.
-  In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the
-  dictionary chosen by the compressor.
-*/
-
-
-extern int EXPORT inflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
-   was inconsistent. In the error case, msg may be set but then points to a
-   static string (which must not be deallocated).
-*/
-
-                        /* Advanced functions */
-
-/*
-    The following functions are needed only in some special applications.
-*/
-
-/*   
-extern int EXPORT deflateInit2 OF((z_streamp strm,
-                                   int  level,
-                                   int  method,
-                                   int  windowBits,
-                                   int  memLevel,
-                                   int  strategy));
-
-     This is another version of deflateInit with more compression options. The
-   fields next_in, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The method parameter is the compression method. It must be Z_DEFLATED in
-   this version of the library. (Method 9 will allow a 64K history buffer and
-   partial block flushes.)
-
-     The windowBits parameter is the base two logarithm of the window size
-   (the size of the history buffer).  It should be in the range 8..15 for this
-   version of the library (the value 16 will be allowed for method 9). Larger
-   values of this parameter result in better compression at the expense of
-   memory usage. The default value is 15 if deflateInit is used instead.
-
-     The memLevel parameter specifies how much memory should be allocated
-   for the internal compression state. memLevel=1 uses minimum memory but
-   is slow and reduces compression ratio; memLevel=9 uses maximum memory
-   for optimal speed. The default value is 8. See zconf.h for total memory
-   usage as a function of windowBits and memLevel.
-
-     The strategy parameter is used to tune the compression algorithm. Use the
-   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
-   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
-   string match).  Filtered data consists mostly of small values with a
-   somewhat random distribution. In this case, the compression algorithm is
-   tuned to compress them better. The effect of Z_FILTERED is to force more
-   Huffman coding and less string matching; it is somewhat intermediate
-   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
-   the compression ratio but not the correctness of the compressed output even
-   if it is not set appropriately.
-
-     If next_in is not null, the library will use this buffer to hold also
-   some history information; the buffer must either hold the entire input
-   data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
-   is null, the library will allocate its own history buffer (and leave next_in
-   null). next_out need not be provided here but must be provided by the
-   application for the next call of deflate().
-
-     If the history buffer is provided by the application, next_in must
-   must never be changed by the application since the compressor maintains
-   information inside this buffer from call to call; the application
-   must provide more input only by increasing avail_in. next_in is always
-   reset by the library in this case.
-
-      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
-   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
-   an invalid method). msg is set to null if there is no error message.
-   deflateInit2 does not perform any compression: this will be done by
-   deflate(). 
-*/
-                            
-extern int EXPORT deflateSetDictionary OF((z_streamp strm,
-                                           const Bytef *dictionary,
-				           uInt  dictLength));
-/*
-     Initializes the compression dictionary (history buffer) from the given
-   byte sequence without producing any compressed output. This function must
-   be called immediately after deflateInit or deflateInit2, before any call
-   of deflate. The compressor and decompressor must use exactly the same
-   dictionary (see inflateSetDictionary).
-     The dictionary should consist of strings (byte sequences) that are likely
-   to be encountered later in the data to be compressed, with the most commonly
-   used strings preferably put towards the end of the dictionary. Using a
-   dictionary is most useful when the data to be compressed is short and
-   can be predicted with good accuracy; the data can then be compressed better
-   than with the default empty dictionary. In this version of the library,
-   only the last 32K bytes of the dictionary are used.
-     Upon return of this function, strm->adler is set to the Adler32 value
-   of the dictionary; the decompressor may later use this value to determine
-   which dictionary has been used by the compressor. (The Adler32 value
-   applies to the whole dictionary even if only a subset of the dictionary is
-   actually used by the compressor.)
-
-     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state
-   is inconsistent (for example if deflate has already been called for this
-   stream). deflateSetDictionary does not perform any compression: this will
-   be done by deflate(). 
-*/
-
-extern int EXPORT deflateCopy OF((z_streamp dest,
-                                  z_streamp source));
-/*
-     Sets the destination stream as a complete copy of the source stream.  If
-   the source stream is using an application-supplied history buffer, a new
-   buffer is allocated for the destination stream.  The compressed output
-   buffer is always application-supplied. It's the responsibility of the
-   application to provide the correct values of next_out and avail_out for the
-   next call of deflate.
-
-     This function can be useful when several compression strategies will be
-   tried, for example when there are several ways of pre-processing the input
-   data with a filter. The streams that will be discarded should then be freed
-   by calling deflateEnd.  Note that deflateCopy duplicates the internal
-   compression state which can be quite large, so this strategy is slow and
-   can consume lots of memory.
-
-     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
-   (such as zalloc being NULL). msg is left unchanged in both source and
-   destination.
-*/
-
-extern int EXPORT deflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to deflateEnd followed by deflateInit,
-   but does not free and reallocate all the internal compression state.
-   The stream will keep the same compression level and any other attributes
-   that may have been set by deflateInit2.
-
-      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy));
-/*
-     Dynamically update the compression level and compression strategy.
-   This can be used to switch between compression and straight copy of
-   the input data, or to switch to a different kind of input data requiring
-   a different strategy. If the compression level is changed, the input
-   available so far is compressed with the old level (and may be flushed);
-   the new level will take effect only at the next call of deflate().
-
-     Before the call of deflateParams, the stream state must be set as for
-   a call of deflate(), since the currently available input may have to
-   be compressed and flushed. In particular, strm->avail_out must be non-zero.
-
-     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
-   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
-   if strm->avail_out was zero.
-*/
-
-extern int EXPORT deflateOutputPending OF((z_streamp strm));
-/*
-     Returns the number of bytes of output which are immediately
-   available from the compressor (i.e. without any further input
-   or flush).
-*/
-
-/*   
-extern int EXPORT inflateInit2 OF((z_streamp strm,
-                                   int  windowBits));
-
-     This is another version of inflateInit with more compression options. The
-   fields next_out, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The windowBits parameter is the base two logarithm of the maximum window
-   size (the size of the history buffer).  It should be in the range 8..15 for
-   this version of the library (the value 16 will be allowed soon). The
-   default value is 15 if inflateInit is used instead. If a compressed stream
-   with a larger window size is given as input, inflate() will return with
-   the error code Z_DATA_ERROR instead of trying to allocate a larger window.
-
-     If next_out is not null, the library will use this buffer for the history
-   buffer; the buffer must either be large enough to hold the entire output
-   data, or have at least 1<<windowBits bytes.  If next_out is null, the
-   library will allocate its own buffer (and leave next_out null). next_in
-   need not be provided here but must be provided by the application for the
-   next call of inflate().
-
-     If the history buffer is provided by the application, next_out must
-   never be changed by the application since the decompressor maintains
-   history information inside this buffer from call to call; the application
-   can only reset next_out to the beginning of the history buffer when
-   avail_out is zero and all output has been consumed.
-
-      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
-   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
-   windowBits < 8). msg is set to null if there is no error message.
-   inflateInit2 does not perform any decompression: this will be done by
-   inflate().
-*/
-
-extern int EXPORT inflateSetDictionary OF((z_streamp strm,
-				           const Bytef *dictionary,
-					   uInt  dictLength));
-/*
-     Initializes the decompression dictionary (history buffer) from the given
-   uncompressed byte sequence. This function must be called immediately after
-   a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen
-   by the compressor can be determined from the Adler32 value returned by this
-   call of inflate. The compressor and decompressor must use exactly the same
-   dictionary (see deflateSetDictionary).
-
-     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
-   expected one (incorrect Adler32 value). inflateSetDictionary does not
-   perform any decompression: this will be done by subsequent calls of
-   inflate().
-*/
-
-extern int EXPORT inflateSync OF((z_streamp strm));
-/* 
-    Skips invalid compressed data until the special marker (see deflate()
-  above) can be found, or until all available input is skipped. No output
-  is provided.
-
-    inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
-  if no more input was provided, Z_DATA_ERROR if no marker has been found,
-  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
-  case, the application may save the current current value of total_in which
-  indicates where valid compressed data was found. In the error case, the
-  application may repeatedly call inflateSync, providing more input each time,
-  until success or end of the input data.
-*/
-
-extern int EXPORT inflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to inflateEnd followed by inflateInit,
-   but does not free and reallocate all the internal decompression state.
-   The stream will keep attributes that may have been set by inflateInit2.
-
-      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-extern int inflateIncomp OF((z_stream *strm));
-/*
-     This function adds the data at next_in (avail_in bytes) to the output
-   history without performing any output.  There must be no pending output,
-   and the decompressor must be expecting to see the start of a block.
-   Calling this function is equivalent to decompressing a stored block
-   containing the data at next_in (except that the data is not output).
-*/
-
-                        /* utility functions */
-
-/*
-     The following utility functions are implemented on top of the
-   basic stream-oriented functions. To simplify the interface, some
-   default options are assumed (compression level, window size,
-   standard memory allocation functions). The source code of these
-   utility functions can easily be modified if you need special options.
-*/
-
-extern int EXPORT compress OF((Bytef *dest,   uLongf *destLen,
-			       const Bytef *source, uLong sourceLen));
-/*
-     Compresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be at least 0.1% larger than
-   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
-   compressed buffer.
-     This function can be used to compress a whole file at once if the
-   input file is mmap'ed.
-     compress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer.
-*/
-
-extern int EXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
-				 const Bytef *source, uLong sourceLen));
-/*
-     Decompresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be large enough to hold the
-   entire uncompressed data. (The size of the uncompressed data must have
-   been saved previously by the compressor and transmitted to the decompressor
-   by some mechanism outside the scope of this compression library.)
-   Upon exit, destLen is the actual size of the compressed buffer.
-     This function can be used to decompress a whole file at once if the
-   input file is mmap'ed.
-
-     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer, or Z_DATA_ERROR if the input data was corrupted.
-*/
-
-
-typedef voidp gzFile;
-
-extern gzFile EXPORT gzopen  OF((const char *path, const char *mode));
-/*
-     Opens a gzip (.gz) file for reading or writing. The mode parameter
-   is as in fopen ("rb" or "wb") but can also include a compression level
-   ("wb9").  gzopen can be used to read a file which is not in gzip format;
-   in this case gzread will directly read from the file without decompression.
-     gzopen returns NULL if the file could not be opened or if there was
-   insufficient memory to allocate the (de)compression state; errno
-   can be checked to distinguish the two cases (if errno is zero, the
-   zlib error is Z_MEM_ERROR).
-*/
-
-extern gzFile EXPORT gzdopen  OF((int fd, const char *mode));
-/*
-     gzdopen() associates a gzFile with the file descriptor fd.  File
-   descriptors are obtained from calls like open, dup, creat, pipe or
-   fileno (in the file has been previously opened with fopen).
-   The mode parameter is as in gzopen.
-     The next call of gzclose on the returned gzFile will also close the
-   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
-   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
-     gzdopen returns NULL if there was insufficient memory to allocate
-   the (de)compression state.
-*/
-
-extern int EXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
-/*
-     Reads the given number of uncompressed bytes from the compressed file.
-   If the input file was not in gzip format, gzread copies the given number
-   of bytes into the buffer.
-     gzread returns the number of uncompressed bytes actually read (0 for
-   end of file, -1 for error). */
-
-extern int EXPORT    gzwrite OF((gzFile file, const voidp buf, unsigned len));
-/*
-     Writes the given number of uncompressed bytes into the compressed file.
-   gzwrite returns the number of uncompressed bytes actually written
-   (0 in case of error).
-*/
-
-extern int EXPORT    gzflush OF((gzFile file, int flush));
-/*
-     Flushes all pending output into the compressed file. The parameter
-   flush is as in the deflate() function. The return value is the zlib
-   error number (see function gzerror below). gzflush returns Z_OK if
-   the flush parameter is Z_FINISH and all output could be flushed.
-     gzflush should be called only when strictly necessary because it can
-   degrade compression.
-*/
-
-extern int EXPORT    gzclose OF((gzFile file));
-/*
-     Flushes all pending output if necessary, closes the compressed file
-   and deallocates all the (de)compression state. The return value is the zlib
-   error number (see function gzerror below).
-*/
-
-extern const char * EXPORT gzerror OF((gzFile file, int *errnum));
-/*
-     Returns the error message for the last error which occurred on the
-   given compressed file. errnum is set to zlib error number. If an
-   error occurred in the file system and not in the compression library,
-   errnum is set to Z_ERRNO and the application may consult errno
-   to get the exact error code.
-*/
-
-                        /* checksum functions */
-
-/*
-     These functions are not related to compression but are exported
-   anyway because they might be useful in applications using the
-   compression library.
-*/
-
-extern uLong EXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
-
-/*
-     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
-   return the updated checksum. If buf is NULL, this function returns
-   the required initial value for the checksum.
-   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
-   much faster. Usage example:
-
-     uLong adler = adler32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       adler = adler32(adler, buffer, length);
-     }
-     if (adler != original_adler) error();
-*/
-
-extern uLong EXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
-/*
-     Update a running crc with the bytes buf[0..len-1] and return the updated
-   crc. If buf is NULL, this function returns the required initial value
-   for the crc. Pre- and post-conditioning (one's complement) is performed
-   within this function so it shouldn't be done by the application.
-   Usage example:
-
-     uLong crc = crc32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       crc = crc32(crc, buffer, length);
-     }
-     if (crc != original_crc) error();
-*/
-
-
-                        /* various hacks, don't look :) */
-
-/* deflateInit and inflateInit are macros to allow checking the zlib version
- * and the compiler's view of z_stream:
- */
-extern int EXPORT deflateInit_ OF((z_streamp strm, int level,
-			           const char *version, int stream_size));
-extern int EXPORT inflateInit_ OF((z_streamp strm,
-				   const char *version, int stream_size));
-extern int EXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
-				    int windowBits, int memLevel, int strategy,
-				    const char *version, int stream_size));
-extern int EXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
-				    const char *version, int stream_size));
-#define deflateInit(strm, level) \
-        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit(strm) \
-        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
-#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
-        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
-		      (strategy),           ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit2(strm, windowBits) \
-        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
-
-#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
-    struct internal_state {int dummy;}; /* hack for buggy compilers */
-#endif
-
-uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZLIB_H */
-/* --- zlib.h */
diff -u --recursive --new-file v2.5.2/linux/drivers/nubus/nubus.c linux/drivers/nubus/nubus.c
--- v2.5.2/linux/drivers/nubus/nubus.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/nubus/nubus.c	Wed Jan 23 10:54:42 2002
@@ -1039,3 +1039,5 @@
 	nubus_proc_init();
 #endif
 }
+
+subsys_initcall(nubus_init);
diff -u --recursive --new-file v2.5.2/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog
--- v2.5.2/linux/drivers/parport/ChangeLog	Mon Nov 12 09:45:32 2001
+++ linux/drivers/parport/ChangeLog	Thu Jan 17 14:07:57 2002
@@ -1,3 +1,29 @@
+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-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 -u --recursive --new-file v2.5.2/linux/drivers/parport/Config.help linux/drivers/parport/Config.help
--- v2.5.2/linux/drivers/parport/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/Config.help	Fri Jan 25 16:04:31 2002
@@ -0,0 +1,99 @@
+CONFIG_PARPORT
+  If you want to use devices connected to your machine's parallel port
+  (the connector at the computer with 25 holes), e.g. printer, ZIP
+  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
+  <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
+  the WWW.
+
+  It is possible to share a single parallel port among several devices
+  and it is safe to compile all the corresponding drivers into the
+  kernel.  If you want to compile parallel port 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
+  parport.o.  If you have more than one parallel port and want to
+  specify which port and IRQ to be used by this driver at module load
+  time, take a look at <file:Documentation/parport.txt>.
+
+  If unsure, say Y.
+
+CONFIG_PARPORT_PC
+  You should say Y here if you have a PC-style parallel port. All IBM
+  PC compatible computers and some Alphas have PC-style parallel
+  ports.
+
+  This code is also available as a module.  If you want to compile it
+  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
+  parport_pc.o.
+
+  If unsure, say Y.
+
+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
+  will be called parport_serial.o.
+
+CONFIG_PARPORT_PC_FIFO
+  Many parallel port chipsets provide hardware that can speed up
+  printing. Say Y here if you want to take advantage of that.
+
+  As well as actually having a FIFO, or DMA capability, the kernel
+  will need to know which IRQ the parallel port has.  By default,
+  parallel port interrupts will not be used, and so neither will the
+  FIFO.  See <file:Documentation/parport.txt> to find out how to
+  specify which IRQ/DMA to use.
+
+CONFIG_PARPORT_PC_SUPERIO
+  Saying Y here enables some probes for Super-IO chipsets in order to
+  find out things like base addresses, IRQ lines and DMA channels.  It
+  is safe to say N.
+
+CONFIG_PARPORT_PC_PCMCIA
+  Say Y here if you need PCMCIA support for your PC-style parallel
+  ports. If unsure, say N.
+
+CONFIG_PARPORT_OTHER
+  Say Y here if you want to be able to load driver modules to support
+  other non-standard types of parallel ports. This causes a
+  performance loss, so most people say N.
+
+CONFIG_PARPORT_AMIGA
+  Say Y here if you need support for the parallel port hardware on
+  Amiga machines. This code is also available as a module (say M),
+  called parport_amiga.o. If in doubt, saying N is the safe plan.
+
+CONFIG_PARPORT_ATARI
+  Say Y here if you need support for the parallel port hardware on
+  Atari machines. This code is also available as a module (say M),
+  called parport_atari.o. If in doubt, saying N is the safe plan.
+
+CONFIG_PARPORT_MFC3
+  Say Y here if you need parallel port support for the MFC3 card.
+  This code is also available as a module (say M), called
+  parport_mfc3.o. If in doubt, saying N is the safe plan.
+
+CONFIG_PARPORT_1284
+  If you have a printer that supports status readback or device ID, or
+  want to use a device that uses enhanced parallel port transfer modes
+  such as EPP and ECP, say Y here to enable advanced IEEE 1284
+  transfer modes. Also say Y if you want device ID information to
+  appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N.
+
+CONFIG_PARPORT_SUNBPP
+  This driver provides support for the bidirectional parallel port
+  found on many Sun machines. Note that many of the newer Ultras
+  actually have pc style hardware instead.
+
+CONFIG_PARPORT_GSC
+  Say Y here to build in low-level parallel-support for PC-style
+  hardware integrated in the LASI-Controller (on the GSC Bus) for
+  HP-PARISC workstations.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/parport/Config.in linux/drivers/parport/Config.in
--- v2.5.2/linux/drivers/parport/Config.in	Sun Nov 11 10:09:33 2001
+++ linux/drivers/parport/Config.in	Tue Jan 15 10:58:04 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c
--- v2.5.2/linux/drivers/parport/ieee1284.c	Thu Oct 25 00:07:39 2001
+++ linux/drivers/parport/ieee1284.c	Tue Jan 15 13:53:51 2002
@@ -128,7 +128,7 @@
 			return 0;
 		if (signal_pending (current))
 			return -EINTR;
-		if (current->need_resched)
+		if (need_resched())
 			break;
 		if (i >= 2)
 			udelay (5);
diff -u --recursive --new-file v2.5.2/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c
--- v2.5.2/linux/drivers/parport/ieee1284_ops.c	Thu Oct 25 00:07:39 2001
+++ linux/drivers/parport/ieee1284_ops.c	Thu Jan 17 14:07:57 2002
@@ -136,7 +136,7 @@
                 /* Let another process run if it needs to. */
 		if (time_before (jiffies, expire))
 			if (!parport_yield_blocking (dev)
-			    && current->need_resched)
+			    && need_resched())
 				schedule ();
 	}
  stop:
@@ -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 -u --recursive --new-file v2.5.2/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.5.2/linux/drivers/parport/parport_pc.c	Mon Nov 12 09:44:58 2001
+++ linux/drivers/parport/parport_pc.c	Thu Jan 17 14:07:57 2002
@@ -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 */
@@ -596,7 +598,7 @@
 		unsigned char ecrval = inb (ECONTROL (port));
 		int i = 0;
 
-		if (current->need_resched && time_before (jiffies, expire))
+		if (need_resched() && time_before (jiffies, expire))
 			/* Can't yield the port. */
 			schedule ();
 
@@ -622,7 +624,7 @@
 			}
 			ecrval = inb (ECONTROL (port));
 			if (!(ecrval & (1<<2))) {
-				if (current->need_resched &&
+				if (need_resched() &&
 				    time_before (jiffies, expire))
 					schedule ();
 
@@ -746,8 +748,7 @@
 		}
 		/* Is serviceIntr set? */
 		if (!(inb (ECONTROL (port)) & (1<<2))) {
-			if (current->need_resched)
-				schedule ();
+			cond_resched();
 
 			goto false_alarm;
 		}
@@ -758,9 +759,7 @@
 		count = get_dma_residue(port->dma);
 		release_dma_lock(dmaflag);
 
-		if (current->need_resched)
-			/* Can't yield the port. */
-			schedule ();
+		cond_resched(); /* Can't yield the port. */
 
 		/* Anyone else waiting for the port? */
 		if (port->waithead) {
@@ -1093,7 +1092,7 @@
 		long int expire = jiffies + port->cad->timeout;
 		unsigned char ecrval = inb (ECONTROL (port));
 
-		if (current->need_resched && time_before (jiffies, expire))
+		if (need_resched() && time_before (jiffies, expire))
 			/* Can't yield the port. */
 			schedule ();
 
@@ -1130,7 +1129,7 @@
 			}
 			ecrval = inb (ECONTROL (port));
 			if (!(ecrval & (1<<2))) {
-				if (current->need_resched &&
+				if (need_resched() &&
 				    time_before (jiffies, expire)) {
 					schedule ();
 				}
@@ -1780,6 +1779,7 @@
 	return ok;
 }
 
+#ifdef CONFIG_PARPORT_PC_FIFO
 static int __devinit parport_ECP_supported(struct parport *pb)
 {
 	int i;
@@ -1905,6 +1905,7 @@
 
 	return 1;
 }
+#endif
 
 static int __devinit parport_ECPPS2_supported(struct parport *pb)
 {
@@ -2004,7 +2005,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 +2456,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 +3009,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 +3026,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 -u --recursive --new-file v2.5.2/linux/drivers/pci/Config.help linux/drivers/pci/Config.help
--- v2.5.2/linux/drivers/pci/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pci/Config.help	Fri Jan 25 16:03:24 2002
@@ -0,0 +1,12 @@
+CONFIG_PCI_NAMES
+  By default, the kernel contains a database of all known PCI device
+  names to make the information in /proc/pci, /proc/ioports and
+  similar files comprehensible to the user. This database increases
+  size of the kernel image by about 80KB, but it gets freed after the
+  system boots up, so it doesn't take up kernel memory. Anyway, if you
+  are building an installation floppy or kernel for an embedded system
+  where kernel image size really matters, you can disable this feature
+  and you'll get device ID numbers instead of names.
+
+  When in doubt, say Y.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/pci/Makefile linux/drivers/pci/Makefile
--- v2.5.2/linux/drivers/pci/Makefile	Sun Sep  9 10:50:48 2001
+++ linux/drivers/pci/Makefile	Thu Jan 24 22:03:39 2002
@@ -13,7 +13,7 @@
 
 export-objs := pci.o
 
-obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o
+obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o pci-driver.o
 obj-$(CONFIG_PROC_FS) += proc.o
 
 ifndef CONFIG_SPARC64
diff -u --recursive --new-file v2.5.2/linux/drivers/pci/pci-driver.c linux/drivers/pci/pci-driver.c
--- v2.5.2/linux/drivers/pci/pci-driver.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pci/pci-driver.c	Thu Jan 24 22:03:39 2002
@@ -0,0 +1,36 @@
+/*
+ * drivers/pci/pci-driver.c - default PCI driver.
+ *
+ */
+
+#include <linux/pci.h>
+
+static int pci_device_suspend(struct device * dev, u32 stage, u32 state)
+{
+	struct pci_dev * pci_dev = (struct pci_dev *)list_entry(dev,struct pci_dev,dev);
+	int error = 0;
+
+	if (pci_dev->driver) {
+		if (stage == SUSPEND_SAVE_STATE && pci_dev->driver->save_state)
+			error = pci_dev->driver->save_state(pci_dev,state);
+		else if (stage == SUSPEND_POWER_DOWN && pci_dev->driver->suspend)
+			error = pci_dev->driver->suspend(pci_dev,state);
+	}
+	return error;
+}
+
+static int pci_device_resume(struct device * dev, u32 stage)
+{
+	struct pci_dev * pci_dev = (struct pci_dev *)list_entry(dev,struct pci_dev,dev);
+
+	if (pci_dev->driver) {
+		if (stage == RESUME_POWER_ON && pci_dev->driver->resume)
+			pci_dev->driver->resume(pci_dev);
+	}
+	return 0;
+}
+
+struct device_driver pci_device_driver = {
+	suspend:	pci_device_suspend,
+	resume:		pci_device_resume,
+};
diff -u --recursive --new-file v2.5.2/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.5.2/linux/drivers/pci/pci.c	Tue Nov 20 21:53:29 2001
+++ linux/drivers/pci/pci.c	Thu Jan 24 22:03:39 2002
@@ -38,6 +38,8 @@
 LIST_HEAD(pci_root_buses);
 LIST_HEAD(pci_devices);
 
+extern struct device_driver pci_device_driver;
+
 /**
  * pci_find_slot - locate PCI device from a given PCI slot
  * @bus: number of PCI bus on which desired PCI device resides
@@ -1085,6 +1087,13 @@
 	child->ops = parent->ops;
 	child->sysdata = parent->sysdata;
 
+	/* init generic fields */
+	child->iobus.self = &dev->dev;
+	child->iobus.parent = &parent->iobus;
+	dev->dev.subordinate = &child->iobus;
+
+	strcpy(child->iobus.name,dev->dev.name);
+
 	/*
 	 * Set up the primary, secondary and subordinate
 	 * bus numbers.
@@ -1180,6 +1189,7 @@
 		pci_write_config_word(dev, PCI_COMMAND, cr);
 	}
 	sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+
 	return max;
 }
 
@@ -1293,8 +1303,14 @@
 	dev->dma_mask = 0xffffffff;
 	if (pci_setup_device(dev) < 0) {
 		kfree(dev);
-		dev = NULL;
+		return NULL;
 	}
+
+	/* now put in global tree */
+	strcpy(dev->dev.name,dev->name);
+	strcpy(dev->dev.bus_id,dev->slot_name);
+
+	device_register(&dev->dev);
 	return dev;
 }
 
@@ -1345,10 +1361,17 @@
 	DBG("Scanning bus %02x\n", bus->number);
 	max = bus->secondary;
 
+	/* we should know for sure what the bus number is, so set the bus ID
+	 * for the bus and make sure it's registered in the device tree */
+	sprintf(bus->iobus.bus_id,"pci%d",bus->number);
+	iobus_register(&bus->iobus);
+
 	/* Create a device template */
 	memset(&dev0, 0, sizeof(dev0));
 	dev0.bus = bus;
 	dev0.sysdata = bus->sysdata;
+	dev0.dev.parent = &bus->iobus;
+	dev0.dev.driver = &pci_device_driver;
 
 	/* Go find them, Rover! */
 	for (devfn = 0; devfn < 0x100; devfn += 8) {
@@ -1403,8 +1426,14 @@
 	}
 
 	b = pci_alloc_bus();
+	if (!b)
+		return NULL;
 	list_add_tail(&b->node, &pci_root_buses);
 
+	sprintf(b->iobus.bus_id,"pci%d",bus);
+	strcpy(b->iobus.name,"Host/PCI Bridge");
+	iobus_register(&b->iobus);
+
 	b->number = b->secondary = bus;
 	b->resource[0] = &ioport_resource;
 	b->resource[1] = &iomem_resource;
@@ -1929,7 +1958,7 @@
 }
 
 
-void __devinit  pci_init(void)
+static int __devinit pci_init(void)
 {
 	struct pci_dev *dev;
 
@@ -1942,6 +1971,7 @@
 #ifdef CONFIG_PM
 	pm_register(PM_PCI_DEV, 0, pci_pm_callback);
 #endif
+	return 0;
 }
 
 static int __devinit  pci_setup(char *str)
@@ -1958,6 +1988,8 @@
 	}
 	return 1;
 }
+
+subsys_initcall(pci_init);
 
 __setup("pci=", pci_setup);
 
diff -u --recursive --new-file v2.5.2/linux/drivers/pcmcia/Config.help linux/drivers/pcmcia/Config.help
--- v2.5.2/linux/drivers/pcmcia/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/Config.help	Fri Jan 25 16:03:25 2002
@@ -0,0 +1,53 @@
+CONFIG_PCMCIA
+  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+  computer.  These are credit-card size devices such as network cards,
+  modems or hard drives often used with laptops computers.  There are
+  actually two varieties of these cards: the older 16 bit PCMCIA cards
+  and the newer 32 bit CardBus cards.  If you want to use CardBus
+  cards, you need to say Y here and also to "CardBus support" below.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).  Please also read the PCMCIA-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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read <file:Documentation/modules.txt>.
+
+CONFIG_CARDBUS
+  CardBus is a bus mastering architecture for PC-cards, which allows
+  for 32 bit PC-cards (the original PCMCIA standard specifies only
+  a 16 bit wide bus). Many newer PC-cards are actually CardBus cards.
+
+  This option enables support for CardBus PC Cards, as well as support
+  for CardBus host bridges.  Virtually all modern PCMCIA bridges are
+  CardBus compatible.  A "bridge" is the hardware inside your computer
+  that PCMCIA cards are plugged into.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+  for location).
+
+  If unsure, say Y.
+
+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.
+
+CONFIG_I82365
+  Say Y here to include support for ISA-bus PCMCIA host bridges that
+  are register compatible with the Intel i82365.  These are found on
+  older laptops and ISA-bus card readers for desktop systems.  A
+  "bridge" is the hardware inside your computer that PCMCIA cards are
+  plugged into. If unsure, say N.
+
+CONFIG_TCIC
+  Say Y here to include support for the Databook TCIC family of PCMCIA
+  host bridges. These are only found on a handful of old systems.
+  "Bridge" is the name used for the hardware inside your computer that
+  PCMCIA cards are plugged into. If unsure, say N.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- v2.5.2/linux/drivers/pcmcia/ds.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/pcmcia/ds.c	Wed Jan 23 10:54:42 2002
@@ -966,12 +966,9 @@
     return 0;
 }
 
-#ifdef MODULE
+late_initcall(init_pcmcia_ds);
 
-int __init init_module(void)
-{
-    return init_pcmcia_ds();
-}
+#ifdef MODULE
 
 void __exit cleanup_module(void)
 {
diff -u --recursive --new-file v2.5.2/linux/drivers/pcmcia/hd64465_ss.c linux/drivers/pcmcia/hd64465_ss.c
--- v2.5.2/linux/drivers/pcmcia/hd64465_ss.c	Tue Jul 10 20:16:30 2001
+++ linux/drivers/pcmcia/hd64465_ss.c	Tue Jan 15 10:56:35 2002
@@ -673,6 +673,10 @@
 	     */
 	    DPRINTK("remap_page_range(vaddr=0x%08lx, paddr=0x%08lx, size=0x%08lxx)\n",
 	    	vaddrbase + pstart, paddrbase + pstart, psize);
+#error This does not work.  Firstly remap_page_range() uses current->mm for
+#error the address space, which is wrong for kernel mappings.  remap_page_range
+#error also does flush_{cache,tlb}_range() which ONLY works for user mappings.
+#error Next, remap_page_range() now wants to take a vm_area_struct arg.
 	    remap_page_range(vaddrbase + pstart, paddrbase + pstart, psize, prot);
 	    
 	    /*
diff -u --recursive --new-file v2.5.2/linux/drivers/pnp/Config.help linux/drivers/pnp/Config.help
--- v2.5.2/linux/drivers/pnp/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pnp/Config.help	Tue Jan 29 18:24:01 2002
@@ -0,0 +1,45 @@
+CONFIG_PNP
+  Plug and Play (PnP) is a standard for peripherals which allows those
+  peripherals to be configured by software, e.g. assign IRQ's or other
+  parameters. No jumpers on the cards are needed, instead the values
+  are provided to the cards from the BIOS, from the operating system,
+  or using a user-space utility.
+
+  Say Y here if you would like Linux to configure your Plug and Play
+  devices. You should then also say Y to "ISA Plug and Play support",
+  below. Alternatively, you can say N here and configure your PnP
+  devices using the user space utilities contained in the isapnptools
+  package.
+
+  This support is also available 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>.
+
+CONFIG_ISAPNP
+  Say Y here if you would like support for ISA Plug and Play devices.
+  Some information is in <file:Documentation/isapnp.txt>.
+
+  This support is also available as a module called isapnp.o ( =
+  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>.
+
+  If unsure, say Y.
+
+CONFIG_PNPBIOS
+  Linux uses the PNPBIOS as defined in "Plug and Play BIOS
+  Specification Version 1.0A May 5, 1994" to autodetect built-in
+  mainboard resources (e.g. parallel port resources).
+
+  Other features (e.g. change resources, ESCD, event notification,
+  Docking station information, ISAPNP services) are not used.
+
+  Note: ACPI is expected to supersede PNPBIOS some day, currently it
+  co-exists nicely.
+
+  See latest pcmcia-cs (stand-alone package) for a nice "lspnp" tools,
+  or have a look at /proc/bus/pnp.
+
+  If unsure, say Y.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/pnp/Config.in linux/drivers/pnp/Config.in
--- v2.5.2/linux/drivers/pnp/Config.in	Thu Oct 25 14:01:51 2001
+++ linux/drivers/pnp/Config.in	Tue Jan 29 18:24:01 2002
@@ -8,4 +8,8 @@
 
 dep_tristate '  ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   dep_bool '  PNPBIOS support (EXPERIMENTAL)' CONFIG_PNPBIOS $CONFIG_PNP
+fi
+
 endmenu
diff -u --recursive --new-file v2.5.2/linux/drivers/pnp/Makefile linux/drivers/pnp/Makefile
--- v2.5.2/linux/drivers/pnp/Makefile	Mon Mar 26 15:36:30 2001
+++ linux/drivers/pnp/Makefile	Tue Jan 29 18:24:01 2002
@@ -10,15 +10,22 @@
 
 O_TARGET := pnp.o
 
-export-objs := isapnp.o
-list-multi := isa-pnp.o
+export-objs := isapnp.o pnpbios_core.o
+multi-objs := isa-pnp.o pnpbios.o
 
-proc-$(CONFIG_PROC_FS) = isapnp_proc.o
-isa-pnp-objs := isapnp.o quirks.o $(proc-y)
+isa-pnp-proc-$(CONFIG_PROC_FS) = isapnp_proc.o
+pnpbios-proc-$(CONFIG_PROC_FS) = pnpbios_proc.o
+
+isa-pnp-objs := isapnp.o quirks.o $(isa-pnp-proc-y)
+pnpbios-objs := pnpbios_core.o $(pnpbios-proc-y)
 
 obj-$(CONFIG_ISAPNP) += isa-pnp.o
+obj-$(CONFIG_PNPBIOS) += pnpbios.o
 
 include $(TOPDIR)/Rules.make
 
 isa-pnp.o: $(isa-pnp-objs)
 	$(LD) $(LD_RFLAG) -r -o $@ $(isa-pnp-objs)
+
+pnpbios.o: $(pnpbios-objs)
+	$(LD) $(LD_RFLAG) -r -o $@ $(pnpbios-objs)
diff -u --recursive --new-file v2.5.2/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c
--- v2.5.2/linux/drivers/pnp/isapnp.c	Mon Nov 12 10:02:54 2001
+++ linux/drivers/pnp/isapnp.c	Tue Jan 29 18:24:01 2002
@@ -892,6 +892,7 @@
 		case _STAG_END:
 			if (size > 0)
 				isapnp_skip_bytes(size);
+			isapnp_config_prepare(dev);
 			return 1;
 		default:
 			printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->devfn, card->number);
@@ -2356,12 +2357,9 @@
 	return 0;
 }
 
-#ifdef MODULE
+subsys_initcall(isapnp_init);
 
-int init_module(void)
-{
-	return isapnp_init();
-}
+#ifdef MODULE
 
 void cleanup_module(void)
 {
diff -u --recursive --new-file v2.5.2/linux/drivers/pnp/pnpbios_core.c linux/drivers/pnp/pnpbios_core.c
--- v2.5.2/linux/drivers/pnp/pnpbios_core.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pnp/pnpbios_core.c	Tue Jan 29 18:24:01 2002
@@ -0,0 +1,1276 @@
+/*
+ * PnP BIOS services
+ * 
+ * Originally (C) 1998 Christian Schmidt <schmidt@digadd.de>
+ * Modifications (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
+ * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net>
+ * Modifications (c) 2001 by Thomas Hood <jdthood@mail.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; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * References:
+ *   Compaq Computer Corporation, Phoenix Technologies Ltd., Intel Corporation
+ *   Plug and Play BIOS Specification, Version 1.0A, May 5, 1994
+ *   Plug and Play BIOS Clarification Paper, October 6, 1994
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/kernel.h>
+#include <linux/pnpbios.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <asm/desc.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/kmod.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <asm/system.h>
+
+
+/*
+ *
+ * PnP BIOS INTERFACE
+ *
+ */
+
+/* PnP BIOS signature: "$PnP" */
+#define PNP_SIGNATURE   (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))
+
+#pragma pack(1)
+union pnp_bios_expansion_header {
+	struct {
+		u32 signature;    /* "$PnP" */
+		u8 version;	  /* in BCD */
+		u8 length;	  /* length in bytes, currently 21h */
+		u16 control;	  /* system capabilities */
+		u8 checksum;	  /* all bytes must add up to 0 */
+
+		u32 eventflag;    /* phys. address of the event flag */
+		u16 rmoffset;     /* real mode entry point */
+		u16 rmcseg;
+		u16 pm16offset;   /* 16 bit protected mode entry */
+		u32 pm16cseg;
+		u32 deviceID;	  /* EISA encoded system ID or 0 */
+		u16 rmdseg;	  /* real mode data segment */
+		u32 pm16dseg;	  /* 16 bit pm data segment base */
+	} fields;
+	char chars[0x21];	  /* To calculate the checksum */
+};
+#pragma pack()
+
+static struct {
+	u16	offset;
+	u16	segment;
+} pnp_bios_callpoint;
+
+static union pnp_bios_expansion_header * pnp_bios_hdr = NULL;
+
+/* The PnP BIOS entries in the GDT */
+#define PNP_GDT    (0x0060)
+#define PNP_CS32   (PNP_GDT+0x00)	/* segment for calling fn */
+#define PNP_CS16   (PNP_GDT+0x08)	/* code segment for BIOS */
+#define PNP_DS     (PNP_GDT+0x10)	/* data segment for BIOS */
+#define PNP_TS1    (PNP_GDT+0x18)	/* transfer data segment */
+#define PNP_TS2    (PNP_GDT+0x20)	/* another data segment */
+
+/* 
+ * These are some opcodes for a "static asmlinkage"
+ * As this code is *not* executed inside the linux kernel segment, but in a
+ * alias at offset 0, we need a far return that can not be compiled by
+ * default (please, prove me wrong! this is *really* ugly!) 
+ * This is the only way to get the bios to return into the kernel code,
+ * because the bios code runs in 16 bit protected mode and therefore can only
+ * return to the caller if the call is within the first 64kB, and the linux
+ * kernel begins at offset 3GB...
+ */
+
+asmlinkage void pnp_bios_callfunc(void);
+
+__asm__(
+	".text			\n"
+	__ALIGN_STR "\n"
+	SYMBOL_NAME_STR(pnp_bios_callfunc) ":\n"
+	"	pushl %edx	\n"
+	"	pushl %ecx	\n"
+	"	pushl %ebx	\n"
+	"	pushl %eax	\n"
+	"	lcallw " SYMBOL_NAME_STR(pnp_bios_callpoint) "\n"
+	"	addl $16, %esp	\n"
+	"	lret		\n"
+	".previous		\n"
+);
+
+#define Q_SET_SEL(selname, address, size) \
+set_base (gdt [(selname) >> 3], __va((u32)(address))); \
+set_limit (gdt [(selname) >> 3], size)
+
+#define Q2_SET_SEL(selname, address, size) \
+set_base (gdt [(selname) >> 3], (u32)(address)); \
+set_limit (gdt [(selname) >> 3], size)
+
+/*
+ * At some point we want to use this stack frame pointer to unwind
+ * after PnP BIOS oopses. 
+ */
+ 
+u32 pnp_bios_fault_esp;
+u32 pnp_bios_fault_eip;
+u32 pnp_bios_is_utter_crap = 0;
+
+static spinlock_t pnp_bios_lock;
+
+static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
+                                u16 arg4, u16 arg5, u16 arg6, u16 arg7)
+{
+	unsigned long flags;
+	u16 status;
+
+	/*
+	 * PnP BIOSes are generally not terribly re-entrant.
+	 * Also, don't rely on them to save everything correctly.
+	 */
+	if(pnp_bios_is_utter_crap)
+		return PNP_FUNCTION_NOT_SUPPORTED;
+
+	/* On some boxes IRQ's during PnP BIOS calls are deadly.  */
+	spin_lock_irqsave(&pnp_bios_lock, flags);
+	__cli();
+	__asm__ __volatile__(
+	        "pushl %%ebp\n\t"
+		"pushl %%edi\n\t"
+		"pushl %%esi\n\t"
+		"pushl %%ds\n\t"
+		"pushl %%es\n\t"
+		"pushl %%fs\n\t"
+		"pushl %%gs\n\t"
+		"pushfl\n\t"
+		"movl %%esp, pnp_bios_fault_esp\n\t"
+		"movl $1f, pnp_bios_fault_eip\n\t"
+		"lcall %5,%6\n\t"
+		"1:popfl\n\t"
+		"popl %%gs\n\t"
+		"popl %%fs\n\t"
+		"popl %%es\n\t"
+		"popl %%ds\n\t"
+	        "popl %%esi\n\t"
+		"popl %%edi\n\t"
+		"popl %%ebp\n\t"
+		: "=a" (status)
+		: "0" ((func) | (((u32)arg1) << 16)),
+		  "b" ((arg2) | (((u32)arg3) << 16)),
+		  "c" ((arg4) | (((u32)arg5) << 16)),
+		  "d" ((arg6) | (((u32)arg7) << 16)),
+		  "i" (PNP_CS32),
+		  "i" (0)
+		: "memory"
+	);
+	spin_unlock_irqrestore(&pnp_bios_lock, flags);
+	
+	/* If we get here and this is set then the PnP BIOS faulted on us. */
+	if(pnp_bios_is_utter_crap)
+	{
+		printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue.\n");
+		printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"nobiospnp\" option to operate stably.\n");
+		printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n");
+	}
+
+	return status;
+}
+
+
+/*
+ *
+ * UTILITY FUNCTIONS
+ *
+ */
+
+void *pnpbios_kmalloc(size_t size, int f)
+{
+	void *p = kmalloc( size, f );
+	if ( p == NULL )
+		printk(KERN_ERR "PnPBIOS: kmalloc() failed.\n");
+	return p;
+}
+
+/*
+ * Call this only after init time
+ */
+static int pnp_bios_present(void)
+{
+	return (pnp_bios_hdr != NULL);
+}
+
+/* Forward declaration */
+static void update_devlist( u8 nodenum, struct pnp_bios_node *data );
+
+
+/*
+ *
+ * PnP BIOS ACCESS FUNCTIONS
+ *
+ */
+
+#define PNP_GET_NUM_SYS_DEV_NODES       0x00
+#define PNP_GET_SYS_DEV_NODE            0x01
+#define PNP_SET_SYS_DEV_NODE            0x02
+#define PNP_GET_EVENT                   0x03
+#define PNP_SEND_MESSAGE                0x04
+#define PNP_GET_DOCKING_STATION_INFORMATION 0x05
+#define PNP_SET_STATIC_ALLOCED_RES_INFO 0x09
+#define PNP_GET_STATIC_ALLOCED_RES_INFO 0x0a
+#define PNP_GET_APM_ID_TABLE            0x0b
+#define PNP_GET_PNP_ISA_CONFIG_STRUC    0x40
+#define PNP_GET_ESCD_INFO               0x41
+#define PNP_READ_ESCD                   0x42
+#define PNP_WRITE_ESCD                  0x43
+
+/*
+ * Call PnP BIOS with function 0x00, "get number of system device nodes"
+ */
+static int __pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_dev_node_info));
+	status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0);
+	data->no_nodes &= 0xff;
+	return status;
+}
+
+int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
+{
+	int status = __pnp_bios_dev_node_info( data );
+	if ( status )
+		printk(KERN_WARNING "PnPBIOS: dev_node_info: Unexpected status 0x%x\n", status);
+	return status;
+}
+
+/*
+ * Note that some PnP BIOSes (e.g., on Sony Vaio laptops) die a horrible
+ * death if they are asked to access the "current" configuration.
+ * Therefore, if it's a matter of indifference, it's better to call
+ * get_dev_node() and set_dev_node() with boot=1 rather than with boot=0.
+ */
+
+/* 
+ * Call PnP BIOS with function 0x01, "get system device node"
+ * Input: *nodenum = desired node, 
+ *        boot = whether to get nonvolatile boot (!=0)
+ *               or volatile current (0) config
+ * Output: *nodenum=next node or 0xff if no more nodes
+ */
+static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	if ( !boot & pnpbios_dont_use_current_config )
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, nodenum, sizeof(char));
+	Q2_SET_SEL(PNP_TS2, data, 64 * 1024);
+	status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0);
+	return status;
+}
+
+int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
+{
+	int status;
+	status =  __pnp_bios_get_dev_node( nodenum, boot, data );
+	if ( status )
+		printk(KERN_WARNING "PnPBIOS: get_dev_node: Unexpected 0x%x\n", status);
+	return status;
+}
+
+
+/*
+ * Call PnP BIOS with function 0x02, "set system device node"
+ * Input: *nodenum = desired node, 
+ *        boot = whether to set nonvolatile boot (!=0)
+ *               or volatile current (0) config
+ */
+static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	if ( !boot & pnpbios_dont_use_current_config )
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, /* *((u16 *) data)*/ 65536);
+	status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0);
+	return status;
+}
+
+int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
+{
+	int status;
+	status =  __pnp_bios_set_dev_node( nodenum, boot, data );
+	if ( status ) {
+		printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected set_dev_node status 0x%x\n", status);
+		return status;
+	}
+	if ( !boot ) {
+		/* Update devlist */
+		u8 thisnodenum = nodenum;
+		status =  __pnp_bios_get_dev_node( &nodenum, boot, data );
+		if ( status ) {
+			printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected get_dev_node status 0x%x\n", status);
+			return status;
+		}
+		update_devlist( thisnodenum, data );
+	}
+	return status;
+}
+
+#if needed
+/*
+ * Call PnP BIOS with function 0x03, "get event"
+ */
+static int pnp_bios_get_event(u16 *event)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, event, sizeof(u16));
+	status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0);
+	return status;
+}
+#endif
+
+#if needed
+/* 
+ * Call PnP BIOS with function 0x04, "send message"
+ */
+static int pnp_bios_send_message(u16 message)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0);
+	return status;
+}
+#endif
+
+#ifdef CONFIG_HOTPLUG
+/*
+ * Call PnP BIOS with function 0x05, "get docking station information"
+ */
+static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_docking_station_info));
+	status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
+	return status;
+}
+#endif
+
+#if needed
+/*
+ * Call PnP BIOS with function 0x09, "set statically allocated resource
+ * information"
+ */
+static int pnp_bios_set_stat_res(char *info)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, info, *((u16 *) info));
+	status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
+	return status;
+}
+#endif
+
+#if needed
+/*
+ * Call PnP BIOS with function 0x0a, "get statically allocated resource
+ * information"
+ */
+static int pnp_bios_get_stat_res(char *info)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, info, 64 * 1024);
+	status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
+	return status;
+}
+#endif
+
+#if needed
+/*
+ * Call PnP BIOS with function 0x0b, "get APM id table"
+ */
+static int pnp_bios_apm_id_table(char *table, u16 *size)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, table, *size);
+	Q2_SET_SEL(PNP_TS2, size, sizeof(u16));
+	status = call_pnp_bios(PNP_GET_APM_ID_TABLE, 0, PNP_TS2, 0, PNP_TS1, PNP_DS, 0, 0);
+	return status;
+}
+#endif
+
+#if needed
+/*
+ * Call PnP BIOS with function 0x40, "get isa pnp configuration structure"
+ */
+static int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_isa_config_struc));
+	status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
+	return status;
+}
+#endif
+
+#if needed
+/*
+ * Call PnP BIOS with function 0x41, "get ESCD info"
+ */
+static int pnp_bios_escd_info(struct escd_info_struc *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return ESCD_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, sizeof(struct escd_info_struc));
+	status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS);
+	return status;
+}
+#endif
+
+#if needed
+/*
+ * Call PnP BIOS function 0x42, "read ESCD"
+ * nvram_base is determined by calling escd_info
+ */
+static int pnp_bios_read_escd(char *data, u32 nvram_base)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return ESCD_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
+	set_base(gdt[PNP_TS2 >> 3], nvram_base);
+	set_limit(gdt[PNP_TS2 >> 3], 64 * 1024);
+	status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0);
+	return status;
+}
+#endif
+
+#if needed
+/*
+ * Call PnP BIOS function 0x43, "write ESCD"
+ */
+static int pnp_bios_write_escd(char *data, u32 nvram_base)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return ESCD_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
+	set_base(gdt[PNP_TS2 >> 3], nvram_base);
+	set_limit(gdt[PNP_TS2 >> 3], 64 * 1024);
+	status = call_pnp_bios(PNP_WRITE_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0);
+	return status;
+}
+#endif
+
+
+/*
+ *
+ * DOCKING FUNCTIONS
+ *
+ */
+
+#ifdef CONFIG_HOTPLUG
+
+static int unloading = 0;
+static struct completion unload_sem;
+
+/*
+ * (Much of this belongs in a shared routine somewhere)
+ */
+ 
+static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
+{
+	char *argv [3], **envp, *buf, *scratch;
+	int i = 0, value;
+
+	if (!hotplug_path [0])
+		return -ENOENT;
+	if (!current->fs->root) {
+		return -EAGAIN;
+	}
+	if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+	if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) {
+		kfree (envp);
+		return -ENOMEM;
+	}
+
+	/* only one standardized param to hotplug command: type */
+	argv [0] = hotplug_path;
+	argv [1] = "dock";
+	argv [2] = 0;
+
+	/* minimal command environment */
+	envp [i++] = "HOME=/";
+	envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+
+#ifdef	DEBUG
+	/* hint that policy agent should enter no-stdout debug mode */
+	envp [i++] = "DEBUG=kernel";
+#endif
+	/* extensible set of named bus-specific parameters,
+	 * supporting multiple driver selection algorithms.
+	 */
+	scratch = buf;
+
+	/* action:  add, remove */
+	envp [i++] = scratch;
+	scratch += sprintf (scratch, "ACTION=%s", dock?"add":"remove") + 1;
+
+	/* Report the ident for the dock */
+	envp [i++] = scratch;
+	scratch += sprintf (scratch, "DOCK=%x/%x/%x",
+		info->location_id, info->serial, info->capabilities);
+	envp[i] = 0;
+	
+	value = call_usermodehelper (argv [0], argv, envp);
+	kfree (buf);
+	kfree (envp);
+	return 0;
+}
+
+/*
+ * Poll the PnP docking at regular intervals
+ */
+static int pnp_dock_thread(void * unused)
+{
+	static struct pnp_docking_station_info now;
+	int docked = -1, d;
+	daemonize();
+	reparent_to_init();
+	strcpy(current->comm, "kpnpbios");
+	while(!unloading && !signal_pending(current))
+	{
+		int err;
+		
+		/*
+		 * Poll every 2 seconds
+		 */
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ*2);
+		if(signal_pending(current))
+			break;
+
+		err = pnp_bios_dock_station_info(&now);
+
+		switch(err)
+		{
+			/*
+			 * No dock to manage
+			 */
+			case PNP_FUNCTION_NOT_SUPPORTED:
+				complete_and_exit(&unload_sem, 0);
+			case PNP_SYSTEM_NOT_DOCKED:
+				d = 0;
+				break;
+			case PNP_SUCCESS:
+				d = 1;
+				break;
+			default:
+				printk(KERN_WARNING "PnPBIOS: pnp_dock_thread: Unexpected status 0x%x returned by BIOS.\n", err);
+				continue;
+		}
+		if(d != docked)
+		{
+			if(pnp_dock_event(d, &now)==0)
+			{
+				docked = d;
+#if 0
+				printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
+#endif
+			}
+		}
+	}	
+	complete_and_exit(&unload_sem, 0);
+}
+
+#endif   /* CONFIG_HOTPLUG */
+
+
+/*
+ *
+ * NODE DATA PARSING FUNCTIONS
+ *
+ */
+
+static void add_irqresource(struct pci_dev *dev, int irq)
+{
+	int i = 0;
+	while (!(dev->irq_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_IRQ) i++;
+	if (i < DEVICE_COUNT_IRQ) {
+		dev->irq_resource[i].start = (unsigned long) irq;
+		dev->irq_resource[i].flags = IORESOURCE_IRQ;  // Also clears _UNSET flag
+	}
+}
+
+static void add_dmaresource(struct pci_dev *dev, int dma)
+{
+	int i = 0;
+	while (!(dev->dma_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_DMA) i++;
+	if (i < DEVICE_COUNT_DMA) {
+		dev->dma_resource[i].start = (unsigned long) dma;
+		dev->dma_resource[i].flags = IORESOURCE_DMA;  // Also clears _UNSET flag
+	}
+}
+
+static void add_ioresource(struct pci_dev *dev, int io, int len)
+{
+	int i = 0;
+	while (!(dev->resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_RESOURCE) i++;
+	if (i < DEVICE_COUNT_RESOURCE) {
+		dev->resource[i].start = (unsigned long) io;
+		dev->resource[i].end = (unsigned long)(io + len - 1);
+		dev->resource[i].flags = IORESOURCE_IO;  // Also clears _UNSET flag
+	}
+}
+
+static void add_memresource(struct pci_dev *dev, int mem, int len)
+{
+	int i = 0;
+	while (!(dev->resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_RESOURCE) i++;
+	if (i < DEVICE_COUNT_RESOURCE) {
+		dev->resource[i].start = (unsigned long) mem;
+		dev->resource[i].end = (unsigned long)(mem + len - 1);
+		dev->resource[i].flags = IORESOURCE_MEM;  // Also clears _UNSET flag
+	}
+}
+
+static void node_resource_data_to_dev(struct pnp_bios_node *node, struct pci_dev *dev)
+{
+	unsigned char *p = node->data, *lastp=NULL;
+	int i;
+
+	/*
+	 * First, set resource info to default values
+	 */
+	for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
+		dev->resource[i].start = 0;  // "disabled"
+		dev->resource[i].flags = IORESOURCE_UNSET;
+	}
+	for (i=0;i<DEVICE_COUNT_IRQ;i++) {
+		dev->irq_resource[i].start = (unsigned long)-1;  // "disabled"
+		dev->irq_resource[i].flags = IORESOURCE_UNSET;
+	}
+	for (i=0;i<DEVICE_COUNT_DMA;i++) {
+		dev->dma_resource[i].start = (unsigned long)-1;  // "disabled"
+		dev->dma_resource[i].flags = IORESOURCE_UNSET;
+	}
+
+	/*
+	 * Fill in dev resource info
+	 */
+        while ( (char *)p < ((char *)node->data + node->size )) {
+        	if(p==lastp) break;
+
+                if( p[0] & 0x80 ) {// large item
+			switch (p[0] & 0x7f) {
+			case 0x01: // memory
+			{
+				int io = *(short *) &p[4];
+				int len = *(short *) &p[10];
+				add_memresource(dev, io, len);
+				break;
+			}
+			case 0x02: // device name
+			{
+				int len = *(short *) &p[1];
+				memcpy(dev->name, p + 3, len >= 80 ? 79 : len);
+				break;
+			}
+			case 0x05: // 32-bit memory
+			{
+				int io = *(int *) &p[4];
+				int len = *(int *) &p[16];
+				add_memresource(dev, io, len);
+				break;
+			}
+			case 0x06: // fixed location 32-bit memory
+			{
+				int io = *(int *) &p[4];
+				int len = *(int *) &p[8];
+				add_memresource(dev, io, len);
+				break;
+			}
+			} /* switch */
+                        lastp = p+3;
+                        p = p + p[1] + p[2]*256 + 3;
+                        continue;
+                }
+                if ((p[0]>>3) == 0x0f) // end tag
+                        break;
+                switch (p[0]>>3) {
+                case 0x04: // irq
+                {
+                        int i, mask, irq = -1;
+                        mask= p[1] + p[2]*256;
+                        for (i=0;i<16;i++, mask=mask>>1)
+                                if(mask & 0x01) irq=i;
+			add_irqresource(dev, irq);
+                        break;
+                }
+                case 0x05: // dma
+                {
+                        int i, mask, dma = -1;
+                        mask = p[1];
+                        for (i=0;i<8;i++, mask = mask>>1)
+                                if(mask & 0x01) dma=i;
+			add_dmaresource(dev, dma);
+                        break;
+                }
+                case 0x08: // io
+                {
+			int io= p[2] + p[3] *256;
+			int len = p[7];
+			add_ioresource(dev, io, len);
+                        break;
+                }
+		case 0x09: // fixed location io
+		{
+			int io = p[1] + p[2] * 256;
+			int len = p[3];
+			add_ioresource(dev, io, len);
+			break;
+		}
+                } /* switch */
+                lastp=p+1;
+                p = p + (p[0] & 0x07) + 1;
+
+        } /* while */
+
+        return;
+}
+
+
+/*
+ *
+ * DEVICE LIST MANAGEMENT FUNCTIONS
+ *
+ *
+ * Some of these are exported to give public access
+ *
+ * Question: Why maintain a device list when the PnP BIOS can 
+ * list devices for us?  Answer: Some PnP BIOSes can't report
+ * the current configuration, only the boot configuration.
+ * The boot configuration can be changed, so we need to keep
+ * a record of what the configuration was when we booted;
+ * presumably it continues to describe the current config.
+ * For those BIOSes that can change the current config, we
+ * keep the information in the devlist up to date.
+ *
+ * Note that it is currently assumed that the list does not
+ * grow or shrink in size after init time, and slot_name
+ * never changes.  The list is protected by a spinlock.
+ */
+
+static LIST_HEAD(pnpbios_devices);
+
+static spinlock_t pnpbios_devices_lock;
+
+static int inline insert_device(struct pci_dev *dev)
+{
+
+	/*
+	 * FIXME: Check for re-add of existing node;
+	 * return -1 if node already present
+	 */
+
+	/* We don't lock because we only do this at init time */
+	list_add_tail(&dev->global_list, &pnpbios_devices);
+
+	return 0;
+}
+
+#define HEX(id,a) hex[((id)>>a) & 15]
+#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
+//
+static void inline pnpid32_to_pnpid(u32 id, char *str)
+{
+	const char *hex = "0123456789abcdef";
+
+	id = be32_to_cpu(id);
+	str[0] = CHAR(id, 26);
+	str[1] = CHAR(id, 21);
+	str[2] = CHAR(id,16);
+	str[3] = HEX(id, 12);
+	str[4] = HEX(id, 8);
+	str[5] = HEX(id, 4);
+	str[6] = HEX(id, 0);
+	str[7] = '\0';
+
+	return;
+}                                              
+//
+#undef CHAR
+#undef HEX 
+
+/*
+ * Build a linked list of pci_devs in order of ascending node number
+ * Called only at init time.
+ */
+static void __init build_devlist(void)
+{
+	int i;
+	int nodenum;
+	int nodes_got = 0;
+	int devs = 0;
+	struct pnp_bios_node *node;
+	struct pnp_dev_node_info node_info;
+	struct pci_dev *dev;
+	
+	if (!pnp_bios_present ())
+		return;
+
+	if (pnp_bios_dev_node_info(&node_info) != 0)
+		return;
+
+	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node)
+		return;
+
+	for(i=0,nodenum=0; i<0xff && nodenum!=0xff; i++) {
+		int thisnodenum = nodenum;
+		/* For now we build the list from the "boot" config
+		 * because asking for the "current" config causes
+		 * some BIOSes to crash.                          */
+		if (pnp_bios_get_dev_node((u8 *)&nodenum, (char )1 , node)) {
+			printk(KERN_WARNING "PnPBIOS: PnP BIOS reported error on attempt to get dev node.\n");
+			break;
+		}
+		/* The BIOS returns with nodenum = the next node number */
+		if (nodenum < thisnodenum) {
+			printk(KERN_WARNING "PnPBIOS: Node number is out of sequence. Naughty BIOS!\n");
+			break;
+		}
+		nodes_got++;
+		dev =  pnpbios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+		if (!dev)
+			break;
+		memset(dev,0,sizeof(struct pci_dev));
+		dev->devfn=thisnodenum;
+		memcpy(dev->name,"PNPBIOS",8);
+		pnpid32_to_pnpid(node->eisa_id,dev->slot_name);
+		node_resource_data_to_dev(node,dev);
+		if(insert_device(dev)<0)
+			kfree(dev);
+		else
+			devs++;
+	}
+	kfree(node);
+
+	printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver.\n",
+		nodes_got, nodes_got != 1 ? "s" : "", devs);
+}
+
+static struct pci_dev *find_device_by_nodenum( u8 nodenum )
+{
+	struct pci_dev *dev;
+
+	pnpbios_for_each_dev(dev) {
+		if(dev->devfn == nodenum)
+			return dev;
+	}
+
+	return NULL;
+}
+
+static void update_devlist( u8 nodenum, struct pnp_bios_node *data )
+{
+	unsigned long flags;
+	struct pci_dev *dev;
+
+	spin_lock_irqsave(&pnpbios_devices_lock, flags);
+	dev = find_device_by_nodenum( nodenum );
+	if ( dev ) {
+		node_resource_data_to_dev(data,dev);
+	}
+	spin_unlock_irqrestore(&pnpbios_devices_lock, flags);
+
+	return;
+}
+
+
+/*
+ *
+ * DRIVER REGISTRATION FUNCTIONS
+ *
+ *
+ * Exported to give public access
+ *
+ */
+
+static LIST_HEAD(pnpbios_drivers);
+
+static const struct pnpbios_device_id *
+match_device(const struct pnpbios_device_id *ids, const struct pci_dev *dev)
+{
+	while (*ids->id)
+	{
+		if(memcmp(ids->id, dev->slot_name, 7)==0)
+			return ids;
+		ids++;
+	}
+	return NULL;
+}
+
+static int announce_device(struct pnpbios_driver *drv, struct pci_dev *dev)
+{
+	const struct pnpbios_device_id *id;
+	struct pci_dev tmpdev;
+	int ret;
+
+	if (drv->id_table) {
+		id = match_device(drv->id_table, dev);
+		if (!id)
+			return 0;
+	} else
+		id = NULL;
+
+	memcpy( &tmpdev, dev, sizeof(struct pci_dev));
+	tmpdev.global_list.prev = NULL;
+	tmpdev.global_list.next = NULL;
+
+	dev_probe_lock();
+	/* Obviously, probe() should not call any pnpbios functions */
+	ret = drv->probe(&tmpdev, id);
+	dev_probe_unlock();
+	if (ret < 1)
+		return 0;
+
+	dev->driver = (void *)drv;
+
+	return 1;
+}
+
+/**
+ * pnpbios_register_driver - register a new pci driver
+ * @drv: the driver structure to register
+ * 
+ * Adds the driver structure to the list of registered drivers
+ *
+ * For each device in the pnpbios device list that matches one of
+ * the ids in drv->id_table, calls the driver's "probe" function with
+ * arguments (1) a pointer to a *temporary* struct pci_dev containing
+ * resource info for the device, and (2) a pointer to the id string
+ * of the device.  Expects the probe function to return 1 if the
+ * driver claims the device (otherwise 0) in which case, marks the
+ * device as having this driver.
+ * 
+ * Returns the number of pci devices which were claimed by the driver
+ * during registration.  The driver remains registered even if the
+ * return value is zero.
+ */
+int pnpbios_register_driver(struct pnpbios_driver *drv)
+{
+	struct pci_dev *dev;
+	unsigned long flags;
+	int count = 0;
+
+	list_add_tail(&drv->node, &pnpbios_drivers);
+	spin_lock_irqsave(&pnpbios_devices_lock, flags);
+	pnpbios_for_each_dev(dev) {
+		if (!pnpbios_dev_driver(dev))
+			count += announce_device(drv, dev);
+	}
+	spin_unlock_irqrestore(&pnpbios_devices_lock, flags);
+	return count;
+}
+
+EXPORT_SYMBOL(pnpbios_register_driver);
+
+/**
+ * pnpbios_unregister_driver - unregister a pci driver
+ * @drv: the driver structure to unregister
+ * 
+ * Deletes the driver structure from the list of registered PnPBIOS
+ * drivers, gives it a chance to clean up by calling its "remove"
+ * function for each device it was responsible for, and marks those
+ * devices as driverless.
+ */
+void pnpbios_unregister_driver(struct pnpbios_driver *drv)
+{
+	unsigned long flags;
+	struct pci_dev *dev;
+
+	list_del(&drv->node);
+	spin_lock_irqsave(&pnpbios_devices_lock, flags);
+	pnpbios_for_each_dev(dev) {
+		if (dev->driver == (void *)drv) {
+			if (drv->remove)
+				drv->remove(dev);
+			dev->driver = NULL;
+		}
+	}
+	spin_unlock_irqrestore(&pnpbios_devices_lock, flags);
+}
+
+EXPORT_SYMBOL(pnpbios_unregister_driver);
+
+
+/*
+ *
+ * RESOURCE RESERVATION FUNCTIONS
+ *
+ *
+ * Used only at init time
+ *
+ */
+
+static void __init reserve_ioport_range(char *pnpid, int start, int end)
+{
+	struct resource *res;
+	char *regionid;
+
+	regionid = pnpbios_kmalloc(16, GFP_KERNEL);
+	if ( regionid == NULL )
+		return;
+	sprintf(regionid, "PnPBIOS %s", pnpid);
+	res = request_region(start,end-start+1,regionid);
+	if ( res == NULL )
+		kfree( regionid );
+	else
+		res->flags &= ~IORESOURCE_BUSY;
+	/*
+	 * Failures at this point are usually harmless. pci quirks for
+	 * example do reserve stuff they know about too, so we may well
+	 * have double reservations.
+	 */
+	printk(KERN_INFO
+		"PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved.\n",
+		pnpid, start, end,
+		NULL != res ? "has been" : "could not be"
+	);
+
+	return;
+}
+
+static void __init reserve_resources_of_dev( struct pci_dev *dev )
+{
+	int i;
+
+	for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
+		if ( dev->resource[i].flags & IORESOURCE_UNSET )
+			/* end of resources */
+			break;
+		if (dev->resource[i].flags & IORESOURCE_IO) {
+			/* ioport */
+			if ( dev->resource[i].start == 0 )
+				/* disabled */
+				/* Do nothing */
+				continue;
+			if ( dev->resource[i].start < 0x100 )
+				/*
+				 * Below 0x100 is only standard PC hardware
+				 * (pics, kbd, timer, dma, ...)
+				 * We should not get resource conflicts there,
+				 * and the kernel reserves these anyway
+				 * (see arch/i386/kernel/setup.c).
+				 * So, do nothing
+				 */
+				continue;
+			if ( dev->resource[i].end < dev->resource[i].start )
+				/* invalid endpoint */
+				/* Do nothing */
+				continue;
+			reserve_ioport_range(
+				dev->slot_name,
+				dev->resource[i].start,
+				dev->resource[i].end
+			);
+		} else if (dev->resource[i].flags & IORESOURCE_MEM) {
+			/* iomem */
+			/* For now do nothing */
+			continue;
+		} else {
+			/* Neither ioport nor iomem */
+			/* Do nothing */
+			continue;
+		}
+	}
+
+	return;
+}
+
+static void __init reserve_resources( void )
+{
+	struct pci_dev *dev;
+
+	pnpbios_for_each_dev(dev) {
+		if (
+			0 != strcmp(dev->slot_name,"PNP0c01") &&  /* memory controller */
+			0 != strcmp(dev->slot_name,"PNP0c02")     /* system peripheral: other */
+		) {
+			continue;
+		}  
+		reserve_resources_of_dev(dev);
+	}
+
+	return;
+}
+
+
+/* 
+ *
+ * INIT AND EXIT
+ *
+ */
+
+extern int is_sony_vaio_laptop;
+
+static int pnpbios_disabled; /* = 0 */
+static int dont_reserve_resources; /* = 0 */
+int pnpbios_dont_use_current_config; /* = 0 */
+
+#ifndef MODULE
+static int __init pnpbios_setup(char *str)
+{
+	int invert;
+
+	while ((str != NULL) && (*str != '\0')) {
+		if (strncmp(str, "off", 3) == 0)
+			pnpbios_disabled=1;
+		if (strncmp(str, "on", 2) == 0)
+			pnpbios_disabled=0;
+		invert = (strncmp(str, "no-", 3) == 0);
+		if (invert)
+			str += 3;
+		if (strncmp(str, "curr", 4) == 0)
+			pnpbios_dont_use_current_config = invert;
+		if (strncmp(str, "res", 3) == 0)
+			dont_reserve_resources = invert;
+		str = strchr(str, ',');
+		if (str != NULL)
+			str += strspn(str, ", \t");
+	}
+
+	return 1;
+}
+
+__setup("pnpbios=", pnpbios_setup);
+#endif
+
+subsys_initcall(pnpbios_init);
+
+void __init pnpbios_init(void)
+{
+	union pnp_bios_expansion_header *check;
+	u8 sum;
+	int i, length;
+
+	spin_lock_init(&pnp_bios_lock);
+	spin_lock_init(&pnpbios_devices_lock);
+
+	if(pnpbios_disabled) {
+		printk(KERN_INFO "PnPBIOS: Disabled.\n");
+		return;
+	}
+
+	if ( is_sony_vaio_laptop )
+		pnpbios_dont_use_current_config = 1;
+
+	/*
+ 	 * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
+	 * structure and, if one is found, sets up the selectors and
+	 * entry points
+	 */
+	for (check = (union pnp_bios_expansion_header *) __va(0xf0000);
+	     check < (union pnp_bios_expansion_header *) __va(0xffff0);
+	     ((void *) (check)) += 16) {
+		if (check->fields.signature != PNP_SIGNATURE)
+			continue;
+		length = check->fields.length;
+		if (!length)
+			continue;
+		for (sum = 0, i = 0; i < length; i++)
+			sum += check->chars[i];
+		if (sum)
+			continue;
+		if (check->fields.version < 0x10) {
+			printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported.\n",
+			       check->fields.version >> 4,
+			       check->fields.version & 15);
+			continue;
+		}
+		printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p.\n", check);
+		printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x.\n",
+                       check->fields.version >> 4, check->fields.version & 15,
+		       check->fields.pm16cseg, check->fields.pm16offset,
+		       check->fields.pm16dseg);
+		Q2_SET_SEL(PNP_CS32, &pnp_bios_callfunc, 64 * 1024);
+		Q_SET_SEL(PNP_CS16, check->fields.pm16cseg, 64 * 1024);
+		Q_SET_SEL(PNP_DS, check->fields.pm16dseg, 64 * 1024);
+		pnp_bios_callpoint.offset = check->fields.pm16offset;
+		pnp_bios_callpoint.segment = PNP_CS16;
+		pnp_bios_hdr = check;
+		break;
+	}
+	build_devlist();
+	if ( ! dont_reserve_resources )
+		reserve_resources();
+#ifdef CONFIG_PROC_FS
+	pnpbios_proc_init();
+#endif
+#ifdef CONFIG_HOTPLUG	
+	init_completion(&unload_sem);
+	if(kernel_thread(pnp_dock_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL)>0)
+		unloading = 0;
+#endif		
+}
+
+#ifdef MODULE
+
+MODULE_LICENSE("GPL");
+
+/* We have to run it early and not as a module. */
+module_init(pnpbios_init);
+
+#ifdef CONFIG_HOTPLUG
+static void pnpbios_exit(void)
+{
+	/* free_resources() ought to go here */
+	/* pnpbios_proc_done() */
+	unloading = 1;
+	wait_for_completion(&unload_sem);
+}
+
+module_exit(pnpbios_exit);
+
+#endif
+#endif
diff -u --recursive --new-file v2.5.2/linux/drivers/pnp/pnpbios_proc.c linux/drivers/pnp/pnpbios_proc.c
--- v2.5.2/linux/drivers/pnp/pnpbios_proc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pnp/pnpbios_proc.c	Tue Jan 29 18:24:01 2002
@@ -0,0 +1,151 @@
+/*
+ * pnp_proc.c: /proc/bus/pnp interface for Plug and Play devices
+ *
+ * Written by David Hinds, dahinds@users.sourceforge.net
+ */
+
+//#include <pcmcia/config.h>
+#define __NO_VERSION__
+//#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/pnpbios.h>
+
+static struct proc_dir_entry *proc_pnp = NULL;
+static struct proc_dir_entry *proc_pnp_boot = NULL;
+static struct pnp_dev_node_info node_info;
+
+static int proc_read_devices(char *buf, char **start, off_t pos,
+                             int count, int *eof, void *data)
+{
+	struct pnp_bios_node *node;
+	int i;
+	u8 nodenum;
+	char *p = buf;
+
+	if (pos != 0) {
+	    *eof = 1;
+	    return 0;
+	}
+	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return -ENOMEM;
+	for (i=0,nodenum=0;i<0xff && nodenum!=0xff; i++) {
+		if ( pnp_bios_get_dev_node(&nodenum, 1, node) )
+			break;
+		p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
+			     node->handle, node->eisa_id,
+			     node->type_code[0], node->type_code[1],
+			     node->type_code[2], node->flags);
+	}
+	kfree(node);
+	return (p-buf);
+}
+
+static int proc_read_node(char *buf, char **start, off_t pos,
+                          int count, int *eof, void *data)
+{
+	struct pnp_bios_node *node;
+	int boot = (long)data >> 8;
+	u8 nodenum = (long)data;
+	int len;
+
+	if (pos != 0) {
+	    *eof = 1;
+	    return 0;
+	}
+	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return -ENOMEM;
+	if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+		return -EIO;
+	len = node->size - sizeof(struct pnp_bios_node);
+	memcpy(buf, node->data, len);
+	kfree(node);
+	return len;
+}
+
+static int proc_write_node(struct file *file, const char *buf,
+                           unsigned long count, void *data)
+{
+	struct pnp_bios_node *node;
+	int boot = (long)data >> 8;
+	u8 nodenum = (long)data;
+
+	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return -ENOMEM;
+	if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+		return -EIO;
+	if (count != node->size - sizeof(struct pnp_bios_node))
+		return -EINVAL;
+	memcpy(node->data, buf, count);
+	if (pnp_bios_set_dev_node(node->handle, boot, node) != 0)
+	    return -EINVAL;
+	kfree(node);
+	return count;
+}
+
+/*
+ * When this is called, pnpbios functions are assumed to
+ * work and the pnpbios_dont_use_current_config flag
+ * should already have been set to the appropriate value
+ */
+void pnpbios_proc_init( void )
+{
+	struct pnp_bios_node *node;
+	struct proc_dir_entry *ent;
+	char name[3];
+	int i;
+	u8 nodenum;
+
+	if (pnp_bios_dev_node_info(&node_info) != 0) return;
+	
+	proc_pnp = proc_mkdir("pnp", proc_bus);
+	if (!proc_pnp) return;
+	proc_pnp_boot = proc_mkdir("boot", proc_pnp);
+	if (!proc_pnp_boot) return;
+	create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);
+	
+	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return;
+	for (i=0,nodenum = 0; i<0xff && nodenum != 0xff; i++) {
+		if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0)
+			break;
+		sprintf(name, "%02x", node->handle);
+		if ( !pnpbios_dont_use_current_config ) {
+			ent = create_proc_entry(name, 0, proc_pnp);
+			if (ent) {
+				ent->read_proc = proc_read_node;
+				ent->write_proc = proc_write_node;
+				ent->data = (void *)(long)(node->handle);
+			}
+		}
+		ent = create_proc_entry(name, 0, proc_pnp_boot);
+		if (ent) {
+			ent->read_proc = proc_read_node;
+			ent->write_proc = proc_write_node;
+			ent->data = (void *)(long)(node->handle+0x100);
+		}
+	}
+	kfree(node);
+}
+
+void pnpbios_proc_done(void)
+{
+	int i;
+	char name[3];
+	
+	if (!proc_pnp) return;
+
+	for (i=0; i<0xff; i++) {
+		sprintf(name, "%02x", i);
+		if ( !pnpbios_dont_use_current_config )
+			remove_proc_entry(name, proc_pnp);
+		remove_proc_entry(name, proc_pnp_boot);
+	}
+	remove_proc_entry("boot", proc_pnp);
+	remove_proc_entry("devices", proc_pnp);
+	remove_proc_entry("pnp", proc_bus);
+}
diff -u --recursive --new-file v2.5.2/linux/drivers/s390/Config.help linux/drivers/s390/Config.help
--- v2.5.2/linux/drivers/s390/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/Config.help	Fri Jan 25 16:04:19 2002
@@ -0,0 +1,439 @@
+CONFIG_BLK_DEV_RAM
+  Saying Y here will allow you to use a portion of your RAM memory as
+  a block device, so that you can make file systems on it, read and
+  write to it and do all the other things that you can do with normal
+  block devices (such as hard drives). It is usually used to load and
+  store a copy of a minimal root file system off of a floppy into RAM
+  during the initial install of Linux.
+
+  Note that the kernel command line option "ramdisk=XX" is now
+  obsolete. For details, read <file:Documentation/ramdisk.txt>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M and read <file:Documentation/modules.txt>. The module will be
+  called rd.o.
+
+  Most normal users won't need the RAM disk functionality, and can
+  thus say N here.
+
+CONFIG_BLK_DEV_RAM_SIZE
+  The default value is 4096. Only change this if you know what are
+  you doing. If you are using IBM S/390, then set this to 8192.
+
+CONFIG_BLK_DEV_INITRD
+  The initial RAM disk is a RAM disk that is loaded by the boot loader
+  (loadlin or lilo) and that is mounted as root before the normal boot
+  procedure. It is typically used to load modules needed to mount the
+  "real" root file system, etc. See <file:Documentation/initrd.txt>
+  for details.
+
+CONFIG_BLK_DEV_LOOP
+  Saying Y here will allow you to use a regular file as a block
+  device; you can then create a file system on that block device and
+  mount it just as you would mount other block devices such as hard
+  drive partitions, CD-ROM drives or floppy drives. The loop devices
+  are block special device files with major number 7 and typically
+  called /dev/loop0, /dev/loop1 etc.
+
+  This is useful if you want to check an ISO 9660 file system before
+  burning the CD, or if you want to use floppy images without first
+  writing them to floppy. Furthermore, some Linux distributions avoid
+  the need for a dedicated Linux partition by keeping their complete
+  root file system inside a DOS FAT file using this loop device
+  driver.
+
+  The loop device driver can also be used to "hide" a file system in a
+  disk partition, floppy, or regular file, either using encryption
+  (scrambling the data) or steganography (hiding the data in the low
+  bits of, say, a sound file). This is also safe if the file resides
+  on a remote file server. If you want to do this, you will first have
+  to acquire and install a kernel patch from
+  <ftp://ftp.kerneli.org/pub/kerneli/>, and then you need to
+  say Y to this option.
+
+  Note that alternative ways to use encrypted file systems are
+  provided by the cfs package, which can be gotten from
+  <ftp://ftp.kerneli.org/pub/kerneli/net-source/>, and the newer tcfs
+  package, available at <http://tcfs.dia.unisa.it/>. You do not need
+  to say Y here if you want to use one of these. However, using cfs
+  requires saying Y to "NFS file system support" below while using
+  tcfs requires applying a kernel patch. An alternative steganography
+  solution is provided by StegFS, also available from
+  <ftp://ftp.kerneli.org/pub/kerneli/net-source/>.
+
+  To use the loop device, you need the losetup utility and a recent
+  version of the mount program, both contained in the util-linux
+  package. The location and current version number of util-linux is
+  contained in the file <file:Documentation/Changes>.
+
+  Note that this loop device has nothing to do with the loopback
+  device used for network connections from the machine to itself.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called loop.o.
+
+  Most users will answer N here.
+
+CONFIG_BLK_DEV_NBD
+  Saying Y here will allow your computer to be a client for network
+  block devices, i.e. it will be able to use block devices exported by
+  servers (mount file systems on them etc.). Communication between
+  client and server works over TCP/IP networking, but to the client
+  program this is hidden: it looks like a regular local file access to
+  a block device special file such as /dev/nd0.
+
+  Network block devices also allows you to run a block-device in
+  userland (making server and client physically the same computer,
+  communicating using the loopback network device).
+
+  Read <file:Documentation/nbd.txt> for more information, especially
+  about where to find the server code, which runs in user space and
+  does not need special kernel support.
+
+  Note that this has nothing to do with the network file systems NFS
+  or Coda; you can say N here even if you intend to use NFS or Coda.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called nbd.o.
+
+  If unsure, say N.
+
+CONFIG_HOTPLUG
+  Say Y here if you want to plug devices into your computer while
+  the system is running, and be able to use them quickly.  In many
+  cases, the devices can likewise be unplugged at any time too.
+
+  One well known example of this is PCMCIA- or PC-cards, credit-card
+  size devices such as network cards, modems or hard drives which are
+  plugged into slots found on all modern laptop computers.  Another
+  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.
+  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.
+
+CONFIG_NETDEVICES
+  You can say N here if you don't intend to connect your Linux box to
+  any other computer at all or if all your connections will be over a
+  telephone line with a modem either via UUCP (UUCP is a protocol to
+  forward mail and news between unix hosts over telephone lines; read
+  the UUCP-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell
+  account or a BBS, even using term (term is a program which gives you
+  almost full Internet connectivity if you have a regular dial up
+  shell account on some Internet connected Unix computer. Read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  You'll have to say Y if your computer contains a network card that
+  you want to use under Linux (make sure you know its name because you
+  will be asked for it and read the Ethernet-HOWTO (especially if you
+  plan to use more than one network card under Linux)) or if you want
+  to use SLIP (Serial Line Internet Protocol is the protocol used to
+  send Internet traffic over telephone lines or null modem cables) or
+  CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending Internet traffic over amateur radio links).
+
+  Make sure to read the NET-3-HOWTO. Eventually, you will have to read
+  Olaf Kirch's excellent and free book "Network Administrator's
+  Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If
+  unsure, say Y.
+
+CONFIG_DUMMY
+  This is essentially a bit-bucket device (i.e. traffic you send to
+  this device is consigned into oblivion) with a configurable IP
+  address. It is most commonly used in order to make your currently
+  inactive SLIP address seem like a real address for local programs.
+  If you use SLIP or PPP, you might want to say Y here. Since this
+  thing often comes in handy, the default is Y. It won't enlarge your
+  kernel either. What a deal. Read about it in the Network
+  Administrator's Guide, available from
+  <http://www.linuxdoc.org/docs.html#guide>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called dummy.o.  If you want to use more than one dummy
+  device at a time, you need to compile this driver as a module.
+  Instead of 'dummy', the devices will then be called 'dummy0',
+  'dummy1' etc.
+
+CONFIG_BONDING
+  Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet
+  Channels together. This is called 'Etherchannel' by Cisco,
+  'Trunking' by Sun, and 'Bonding' in Linux.
+
+  If you have two Ethernet connections to some other computer, you can
+  make them behave like one double speed connection using this driver.
+  Naturally, this has to be supported at the other end as well, either
+  with a similar Bonding Linux driver, a Cisco 5500 switch or a
+  SunTrunking SunSoft driver.
+
+  This is similar to the EQL driver, but it merges Ethernet segments
+  instead of serial lines.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called bonding.o.
+
+CONFIG_EQUALIZER
+  If you have two serial connections to some other computer (this
+  usually requires two modems and two telephone lines) and you use
+  SLIP (the protocol for sending Internet traffic over telephone
+  lines) or PPP (a better SLIP) on them, you can make them behave like
+  one double speed connection using this driver.  Naturally, this has
+  to be supported at the other end as well, either with a similar EQL
+  Linux driver or with a Livingston Portmaster 2e.
+
+  Say Y if you want this and read
+  <file:Documentation/networking/eql.txt>.  You may also want to read
+  section 6.2 of the NET-3-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called eql.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.  If
+  unsure, say N.
+
+CONFIG_TUN
+  TUN/TAP provides packet reception and transmission for user space
+  programs.  It can be viewed as a simple Point-to-Point or Ethernet
+  device, which instead of receiving packets from a physical media,
+  receives them from user space program and instead of sending packets
+  via physical media writes them to the user space program.
+
+  When a program opens /dev/net/tun, driver creates and registers
+  corresponding net device tunX or tapX.  After a program closed above
+  devices, driver will automatically delete tunXX or tapXX device and
+  all routes corresponding to it.
+
+  Please read <file:Documentation/networking/tuntap.txt> for more
+  information.
+
+  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 tun.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+  If you don't know what to use this for, you don't need it.
+
+CONFIG_NET_ETHERNET
+  Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
+  type of Local Area Network (LAN) in universities and companies.
+
+  Common varieties of Ethernet are: 10BASE-2 or Thinnet (10 Mbps over
+  coaxial cable, linking computers in a chain), 10BASE-T or twisted
+  pair (10 Mbps over twisted pair cable, linking computers to central
+  hubs), 10BASE-F (10 Mbps over optical fiber links, using hubs),
+  100BASE-TX (100 Mbps over two twisted pair cables, using hubs),
+  100BASE-T4 (100 Mbps over 4 standard voice-grade twisted pair
+  cables, using hubs), 100BASE-FX (100 Mbps over optical fiber links)
+  [the 100BASE varieties are also known as Fast Ethernet], and Gigabit
+  Ethernet (1 Gbps over optical fiber or short copper links).
+
+  If your Linux machine will be connected to an Ethernet and you have
+  an Ethernet network interface card (NIC) installed in your computer,
+  say Y here and read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. You will then also have
+  to say Y to the driver for your particular NIC.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about Ethernet network cards. If unsure, say N.
+
+CONFIG_TR
+  Token Ring is IBM's way of communication on a local network; the
+  rest of the world uses Ethernet. To participate on a Token Ring
+  network, you need a special Token ring network card. If you are
+  connected to such a Token Ring network and want to use your Token
+  Ring card under Linux, say Y here and to the driver for your
+  particular card below and read the Token-Ring mini-HOWTO, available
+  from <http://www.linuxdoc.org/docs.html#howto>. Most people can
+  say N here.
+
+CONFIG_FDDI
+  Fiber Distributed Data Interface is a high speed local area network
+  design; essentially a replacement for high speed Ethernet. FDDI can
+  run over copper or fiber. If you are connected to such a network and
+  want a driver for the FDDI card in your computer, say Y here (and
+  then also Y to the driver for your FDDI card, below). Most people
+  will say N.
+
+CONFIG_UNIX98_PTYS
+  A pseudo terminal (PTY) is a software device consisting of two
+  halves: a master and a slave. The slave device behaves identical to
+  a physical terminal; the master device is used by a process to
+  read data from and write data to the slave, thereby emulating a
+  terminal. Typical programs for the master side are telnet servers
+  and xterms.
+
+  Linux has traditionally used the BSD-like names /dev/ptyxx for
+  masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
+  has a number of problems. The GNU C library glibc 2.1 and later,
+  however, supports the Unix98 naming standard: in order to acquire a
+  pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
+  terminal is then made available to the process and the pseudo
+  terminal slave can be accessed as /dev/pts/<number>. What was
+  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
+
+  The entries in /dev/pts/ are created on the fly by a virtual
+  file system; therefore, if you say Y here you should say Y to
+  "/dev/pts file system for Unix98 PTYs" as well.
+
+  If you want to say Y here, you need to have the C library glibc 2.1
+  or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
+  Read the instructions in <file:Documentation/Changes> pertaining to
+  pseudo terminals. It's safe to say N.
+
+CONFIG_UNIX98_PTY_COUNT
+  The maximum number of Unix98 PTYs that can be used at any one time.
+  The default is 256, and should be enough for desktop systems. Server
+  machines which support incoming telnet/rlogin/ssh connections and/or
+  serve several X terminals may want to increase this: every incoming
+  connection and every xterm uses up one PTY.
+
+  When not in use, each additional set of 256 PTYs occupy
+  approximately 8 KB of kernel memory on 32-bit architectures.
+
+CONFIG_DASD
+  Enable this option if you want to access DASDs directly utilizing
+  S/390s channel subsystem commands. This is necessary for running
+  natively on a single image or an LPAR.
+
+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.
+
+CONFIG_DASD_CKD
+  CKD devices are currently unsupported.
+
+CONFIG_DASD_FBA
+  FBA devices are currently unsupported.
+
+CONFIG_TN3215
+  Include support for IBM 3215 line-mode terminals.
+
+CONFIG_TN3215_CONSOLE
+  Include support for using an IBM 3215 line-mode terminal as a
+  Linux system console.
+
+CONFIG_TN3270
+  Include support for IBM 3270 line-mode terminals.
+
+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.
+
+CONFIG_HWC
+  Include support for IBM HWC line-mode terminals.
+
+CONFIG_HWC_CONSOLE
+  Include support for using an IBM HWC line-mode terminal as the Linux
+  system console.
+
+CONFIG_S390_TAPE
+  Select this option if you want to access channel-attached tape
+  devices on IBM S/390 or zSeries.
+  If you select this option you will also want to select at
+  least one of the tape interface options and one of the tape
+  hardware options in order to access a tape device.
+  This option is also available as a module. The module will be
+  called tape390.o and include all selected interfaces and
+  hardware drivers.
+
+CONFIG_S390_TAPE_CHAR
+  Select this option if you want to access your channel-attached
+  tape devices using the character device interface.
+  This interface is similar to other Linux tape devices like
+  SCSI-Tapes (st) and the floppy tape device (ftape).
+  If unsure, say "Y".
+
+CONFIG_S390_TAPE_BLOCK
+  Select this option if you want to access your channel-attached tape
+  devices using the block device interface.  This interface is similar
+  to CD-ROM devices on other platforms.  The tapes can only be
+  accessed read-only when using this interface.  Have a look at
+  Documentation/s390/TAPE for further information about creating
+  volumes for and using this interface.  It is safe to say "Y" here.
+
+CONFIG_S390_TAPE_3490
+  Select this option if you want to access IBM 3480 magnetic
+  tape subsystems and 100% compatibles.
+  It is safe to say "Y" here.
+
+CONFIG_S390_TAPE_3480
+  Select this option if you want to access IBM 3490 magnetic
+  tape subsystems and 100% compatibles.
+
+CONFIG_CTC
+  Select this option if you want to use channel-to-channel networking
+  on IBM S/390 or zSeries. This device driver supports real CTC
+  coupling using ESCON. It also supports virtual CTCs when running
+  under VM. It will use the channel device configuration if this is
+  available.  This option is also available as a module which will be
+  called ctc.o.  If you do not know what it is, it's safe to say "Y".
+
+CONFIG_DASD_DIAG
+  Select this option if you want to use CMS reserved Disks under VM
+  with the Diagnose250 command.  If you are not running under VM or
+  unsure what it is, say "N".
+
+CONFIG_BLK_DEV_XPRAM
+  Select this option if you want to use your expanded storage on S/390
+  or zSeries as a disk.  This is useful as a _fast_ swap device if you
+  want to access more than 2G of memory when running in 31 bit mode.
+  This option is also available as a module which will be called
+  xpram.o.  If unsure, say "N".
+
+CONFIG_IUCV
+  Select this option if you want to use inter-user communication
+  vehicle networking under VM or VIF.  This option is also available
+  as a module which will be called iucv.o. If unsure, say "Y".
+
+CONFIG_CHANDEV
+  The channel device layer is a layer to provide a consistent
+  interface for configuration & default machine check (devices
+  appearing & disappearing) handling on Linux for s/390 & z/Series
+  channel devices.
+
+  s/390 & z/Series channel devices include among others
+
+  lcs (the most common ethernet/token ring/fddi standard on
+  zSeries)
+  ctc/escon hi speed like serial link standard on zSeries
+  claw used to talk to cisco routers.
+  qeth gigabit ethernet.
+
+  These devices use two channels one read & one write for
+  configuration & communication (& a third channel, the data
+  channel the case of gigabit ethernet). The motivation
+  behind developing this layer was that there was a lot of
+  duplicate code among the channel device drivers for
+  configuration.
+
+  Also the lcs & ctc drivers tended to fight over
+  3088/08's & 3088/1F's which could be either 2216/3172
+  channel attached lcs compatible devices or escon/ctc pipes
+  had to be configured separately as they couldn't autodetect,
+  this is now simplified by doing the configuration in a single
+  place (the channel device layer).
+
+  This layer isn't invasive & it is quite okay to use channel
+  drivers which don't use the channel device layer in
+  conjunction with drivers which do.
+
+  For more info see the chandev manpage usually distributed in
+  <file:Documentation/s390/chandev.8> in the Linux source tree.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/sbus/audio/Config.help linux/drivers/sbus/audio/Config.help
--- v2.5.2/linux/drivers/sbus/audio/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/audio/Config.help	Fri Jan 25 16:04:13 2002
@@ -0,0 +1,24 @@
+CONFIG_SPARCAUDIO
+  This driver provides support for the build-in sound devices on most
+  Sun machines. If you want to be able to use this, select this option
+  and one or more of the lowlevel drivers below. See
+  <http://www.dementia.org/~shadow/sparcaudio.html> for more
+  information.
+
+CONFIG_SPARCAUDIO_AMD7930
+  This driver supports the AMD 7930 chip found on sun4c, 4/6xx, and
+  SparcClassic systems.
+
+CONFIG_SPARCAUDIO_CS4231
+  This driver supports the Crystal Semiconductor CS4231 chip found on
+  the SS4, SS5, and Ultras.
+
+CONFIG_SPARCAUDIO_DBRI
+  This driver supports the DBRI audio interface found on the SS10,
+  SS20, Sparcbook 3, and Voyager systems.
+
+CONFIG_SPARCAUDIO_DUMMY
+  This is a pseudo-driver used for debugging and testing the
+  sparcaudio subsystem. Say N unless you want to work on this
+  subsystem.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/sbus/char/Config.help linux/drivers/sbus/char/Config.help
--- v2.5.2/linux/drivers/sbus/char/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/Config.help	Fri Jan 25 16:04:12 2002
@@ -0,0 +1,84 @@
+CONFIG_APM_RTC_IS_GMT
+  Say Y here if your RTC (Real Time Clock a.k.a. hardware clock)
+  stores the time in GMT (Greenwich Mean Time). Say N if your RTC
+  stores localtime.
+
+  It is in fact recommended to store GMT in your RTC, because then you
+  don't have to worry about daylight savings time changes. The only
+  reason not to use GMT in your RTC is if you also run a broken OS
+  that doesn't understand GMT.
+
+CONFIG_RTC
+  If you say Y here and create a character special file /dev/rtc with
+  major number 10 and minor number 135 using mknod ("man mknod"), you
+  will get access to the real time clock (or hardware clock) built
+  into your computer.
+
+  Every PC has such a clock built in. It can be used to generate
+  signals from as low as 1Hz up to 8192Hz, and can also be used
+  as a 24 hour alarm. It reports status information via the file
+  /proc/driver/rtc and its behaviour is set by various ioctls on
+  /dev/rtc.
+
+  If you run Linux on a multiprocessor machine and said Y to
+  "Symmetric Multi Processing" above, you should say Y here to read
+  and set the RTC in an SMP compatible fashion.
+
+  If you think you have a use for such a device (such as periodic data
+  sampling), then say Y here, and read <file:Documentation/rtc.txt>
+  for details.
+
+  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 is called rtc.o. If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SUN_OPENPROMIO
+  This driver provides user programs with an interface to the SPARC
+  PROM device tree. The driver implements a SunOS-compatible
+  interface and a NetBSD-compatible interface.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M and read <file:Documentation/modules.txt>. If unsure, say Y.
+
+CONFIG_SUN_MOSTEK_RTC
+  The Mostek RTC chip is used on all known Sun computers except
+  some JavaStations. For a JavaStation you need to say Y both here
+  and to "Enhanced Real Time Clock Support".
+
+  Say Y here unless you are building a special purpose kernel.
+
+CONFIG_OBP_FLASH
+  The OpenBoot PROM on Ultra systems is flashable. If you want to be
+  able to upgrade the OBP firmware, say Y here.
+
+CONFIG_SUN_JSFLASH
+  If you say Y here, you will be able to boot from your JavaStation's
+  Flash memory.
+
+CONFIG_SAB82532
+  This driver supports the serial ports on newer (PCI) Ultra systems.
+  Say Y if you want to be able to use your serial ports.
+
+CONFIG_SUN_VIDEOPIX
+  Say Y here to support the Videopix Frame Grabber from Sun
+  Microsystems, commonly found on SPARCstations.  This card, which is
+  based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and
+  SVIDEO signals.
+
+CONFIG_SUN_BPP
+  Say Y here to support Sun's obsolete variant of IEEE1284
+  bidirectional parallel port protocol as /dev/bppX.  Can be built on
+  x86 machines.
+
+CONFIG_SUN_AURORA
+  The Aurora Multiboard is a multi-port high-speed serial controller.
+  If you have one of these, say Y.
+
+CONFIG_TADPOLE_TS102_UCTRL
+  Say Y here to directly support the TS102 Microcontroller interface
+  on the Tadpole Sparcbook 3.  This device handles power-management
+  events, and can also notice the attachment/detachment of external
+  monitors and mice.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c
--- v2.5.2/linux/drivers/sbus/char/envctrl.c	Wed Oct 10 23:42:47 2001
+++ linux/drivers/sbus/char/envctrl.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.24 2001/10/08 22:19:51 davem Exp $
+/* $Id: envctrl.c,v 1.25 2002/01/15 09:01:26 davem Exp $
  * envctrl.c: Temperature and Fan monitoring on Machines providing it.
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
@@ -776,24 +776,19 @@
 static void envctrl_init_adc(struct i2c_child_t *pchild, int node)
 {
 	char chnls_desc[CHANNEL_DESC_SZ];
-	int i, len, j = 0;
-	char *ptr;
+	int i = 0, len;
+	char *pos = chnls_desc;
 
-	/* Firmware describe channels into a stream separated by a '\0'.
-	 * Replace all '\0' with a space.
-	 */
-        len = prom_getproperty(node, "channels-description", chnls_desc,
+	/* Firmware describe channels into a stream separated by a '\0'. */
+	len = prom_getproperty(node, "channels-description", chnls_desc,
 			       CHANNEL_DESC_SZ);
-        for (i = 0; i < len; i++) {
-                if (chnls_desc[i] == '\0')
-                        chnls_desc[i] = ' ';
-        }
-
-	ptr = strtok(chnls_desc, " ");
-	while (ptr != NULL) {
-		envctrl_set_mon(pchild, ptr, j);
-		ptr = strtok(NULL, " ");
-		j++;
+	chnls_desc[CHANNEL_DESC_SZ - 1] = '\0';
+
+	while (len > 0) {
+		int l = strlen(pos) + 1;
+		envctrl_set_mon(pchild, pos, i++);
+		len -= l;
+		pos += l;
 	}
 
 	/* Get optional properties. */
diff -u --recursive --new-file v2.5.2/linux/drivers/sbus/char/flash.c linux/drivers/sbus/char/flash.c
--- v2.5.2/linux/drivers/sbus/char/flash.c	Wed Oct 10 23:42:47 2001
+++ linux/drivers/sbus/char/flash.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: flash.c,v 1.24 2001/10/08 22:19:51 davem Exp $
+/* $Id: flash.c,v 1.25 2001/12/21 04:56:16 davem Exp $
  * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -74,7 +74,7 @@
 	pgprot_val(vma->vm_page_prot) |= _PAGE_E;
 	vma->vm_flags |= (VM_SHM | VM_LOCKED);
 
-	if (remap_page_range(vma->vm_start, addr, size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, addr, size, vma->vm_page_prot))
 		return -EAGAIN;
 		
 	return 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c
--- v2.5.2/linux/drivers/sbus/char/vfc_dev.c	Sun Aug 12 10:38:48 2001
+++ linux/drivers/sbus/char/vfc_dev.c	Tue Jan 15 10:56:35 2002
@@ -632,7 +632,7 @@
 	vma->vm_flags |=
 		(VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
 	map_offset = (unsigned int) (long)dev->phys_regs;
-	ret = io_remap_page_range(vma->vm_start, map_offset, map_size, 
+	ret = io_remap_page_range(vma, vma->vm_start, map_offset, map_size, 
 				  vma->vm_page_prot, dev->which_io);
 
 	if(ret)
diff -u --recursive --new-file v2.5.2/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- v2.5.2/linux/drivers/sbus/char/zs.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/sbus/char/zs.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.70 2002/01/08 16:00:16 davem Exp $
+/* $Id: zs.c,v 1.71 2002/01/12 07:04:54 davem Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,10 @@
  *
  * Fixed to use tty_get_baud_rate().
  *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
+ *
+ * /proc/tty/driver/serial now exists and is readable.
+ *   Alex Buell <alex.buell@tahallah.demon.co.uk>, 2001-12-23
+ *
  */
 
 #include <linux/errno.h>
@@ -1653,6 +1657,81 @@
 }
 
 /*
+ *
+ * line_info - returns information about each channel
+ *
+ */
+static inline int line_info(char *buf, struct sun_serial *info)
+{
+	unsigned char status;
+	char stat_buf[30];
+	int ret;
+
+	ret = sprintf(buf, "%d: uart:Zilog8530 port:%x irq:%d",
+		info->line, info->port, info->irq);
+
+	cli();
+	status = sbus_readb(&info->zs_channel->control);
+	ZSDELAY();
+	ZSLOG(REGCTRL, status, 0);
+	sti();
+
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if (info->curregs[5] & RTS)
+		strcat(stat_buf, "|RTS");
+	if (status & CTS)
+		strcat(stat_buf, "|CTS");
+	if (info->curregs[5] & DTR)
+		strcat(stat_buf, "|DTR");
+	if (status & SYNC)
+		strcat(stat_buf, "|DSR");
+	if (status & DCD)
+		strcat(stat_buf, "|CD");
+
+	ret += sprintf(buf + ret, " baud:%d %s\n", info->zs_baud, stat_buf + 1);
+	return ret;
+}
+
+/*
+ *
+ * zs_read_proc() - called when /proc/tty/driver/serial is read.
+ *
+ */
+int zs_read_proc(char *page, char **start, off_t off, int count,
+                 int *eof, void *data)
+{
+	char *revision = "$Revision: 1.71 $";
+	char *version, *p;
+	int i, len = 0, l;
+	off_t begin = 0;
+
+	version = strchr(revision, ' ');
+	p = strchr(++version, ' ');
+	*p = '\0';
+	len += sprintf(page, "serinfo:1.0 driver:%s\n", version);
+	*p = ' ';
+
+	for (i = 0; i < NUM_CHANNELS && len < 4000; i++) {
+		l = line_info(page + len, &zs_soft[i]);
+		len += l;
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+	}
+
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (off-begin);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
  * ------------------------------------------------------------
  * zs_open() and friends
  * ------------------------------------------------------------
@@ -1887,7 +1966,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.70 $";
+	char *revision = "$Revision: 1.71 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2398,8 +2477,8 @@
 	serial_driver.hangup = zs_hangup;
 
 	/* I'm too lazy, someone write versions of this for us. -DaveM */
-	serial_driver.read_proc = 0;
-	serial_driver.proc_entry = 0;
+	/* I just did. :-) -AIB 2001-12-23 */
+	serial_driver.read_proc = zs_read_proc;
 
 	/*
 	 * The callout device is just like normal device except for
@@ -2409,6 +2488,8 @@
 	callout_driver.name = "cua/%d";
 	callout_driver.major = TTYAUX_MAJOR;
 	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+	callout_driver.read_proc = 0;
+	callout_driver.proc_entry = 0;
 
 	if (tty_register_driver(&serial_driver))
 		panic("Couldn't register serial driver\n");
diff -u --recursive --new-file v2.5.2/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- v2.5.2/linux/drivers/sbus/sbus.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/sbus/sbus.c	Thu Jan 24 22:04:21 2002
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.98 2002/01/05 01:13:43 davem Exp $
+/* $Id: sbus.c,v 1.100 2002/01/24 15:36:24 davem Exp $
  * sbus.c:  SBus support routines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -284,7 +284,7 @@
 extern void firetruck_init(void);
 extern void rs_init(void);
 
-void __init sbus_init(void)
+static int __init sbus_init(void)
 {
 	int nd, this_sbus, sbus_devs, topnd, iommund;
 	unsigned int sbus_clock;
@@ -297,7 +297,8 @@
 #endif
 
 #ifdef CONFIG_SUN4
-	return sun4_dvma_init();
+	sun4_dvma_init();
+	return 0;
 #endif
 
 	topnd = prom_getchild(prom_root_node);
@@ -316,7 +317,7 @@
 				firetruck_init();
 #endif
 			}
-			return;
+			return 0;
 #else
 			prom_printf("YEEE, UltraSparc sbus not found\n");
 			prom_halt();
@@ -337,7 +338,7 @@
                                 prom_printf("Neither SBUS nor PCI found.\n");
                                 prom_halt();
                         }
-                        return;
+                        return 0;
 #else
 			/* No reason to run further - the data access trap will occur. */
 			panic("sbus not found");
@@ -508,4 +509,8 @@
 		clock_probe();
 	}
 #endif
+
+	return 0;
 }
+
+subsys_initcall(sbus_init);
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/3w-xxxx.c linux/drivers/scsi/3w-xxxx.c
--- v2.5.2/linux/drivers/scsi/3w-xxxx.c	Fri Nov  9 14:05:02 2001
+++ linux/drivers/scsi/3w-xxxx.c	Mon Jan 28 14:36:58 2002
@@ -1326,7 +1326,7 @@
 	TW_Command *command_packet;
 	if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags))
 		return;
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(tw_dev->host->host_lock, flags);
 
 	if (tw_dev->tw_pci_dev->irq == irq) {
 		spin_lock(&tw_dev->tw_lock);
@@ -1475,7 +1475,7 @@
 		}
 		spin_unlock(&tw_dev->tw_lock);
 	}
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
 	clear_bit(TW_IN_INTR, &tw_dev->flags);
 }	/* End tw_interrupt() */
 
@@ -1902,9 +1902,7 @@
 		return 0;
 	}
 
-	spin_unlock_irq(&io_request_lock);
 	ret = tw_findcards(tw_host);
-	spin_lock_irq(&io_request_lock);
 
 	return ret;
 } /* End tw_scsi_detect() */
@@ -1929,9 +1927,9 @@
 	}
 
 	/* We have to let AEN requests through before the reset */
-	spin_unlock_irq(&io_request_lock);
+	spin_unlock_irq(tw_dev->host->host_lock);
 	mdelay(TW_AEN_WAIT_TIME);
-	spin_lock_irq(&io_request_lock);
+	spin_lock_irq(tw_dev->host->host_lock);
 
 	spin_lock(&tw_dev->tw_lock);
 	tw_dev->num_aborts++;
@@ -1993,9 +1991,9 @@
 	}
 
 	/* We have to let AEN requests through before the reset */
-	spin_unlock_irq(&io_request_lock);
+	spin_unlock_irq(tw_dev->host->host_lock);
 	mdelay(TW_AEN_WAIT_TIME);
-	spin_lock_irq(&io_request_lock);
+	spin_lock_irq(tw_dev->host->host_lock);
 
 	spin_lock(&tw_dev->tw_lock);
 	tw_dev->num_resets++;
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- v2.5.2/linux/drivers/scsi/53c7,8xx.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/53c7,8xx.c	Mon Jan 28 14:36:58 2002
@@ -1108,9 +1108,9 @@
 
     if (!search) {
 #ifdef __powerpc__
-	if (request_irq(host->irq, do_NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL)) 
+	if (request_irq(host->irq, do_NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", host)) 
 #else
-	if (request_irq(host->irq, do_NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))
+	if (request_irq(host->irq, do_NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", host))
 #endif
 	  {
 	  
@@ -4360,9 +4360,11 @@
 do_NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs) {
     unsigned long flags;
 
-    spin_lock_irqsave(&io_request_lock, flags);
+    struct Scsi_Host *dev = dev_id;
+    
+    spin_lock_irqsave(dev->host_lock, flags);
     NCR53c7x0_intr(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/53c700.c linux/drivers/scsi/53c700.c
--- v2.5.2/linux/drivers/scsi/53c700.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/53c700.c	Mon Jan 28 14:36:58 2002
@@ -1508,18 +1508,7 @@
 	__u8 pun = 0xff, lun = 0xff;
 	unsigned long flags;
 
-	/* Unfortunately, we have to take the io_request_lock here
-	 * rather than the host lock hostdata->lock because we're
-	 * looking to exclude queuecommand from messing with the
-	 * registers while we're processing the interrupt.  Since
-	 * queuecommand is called holding io_request_lock, and we have
-	 * to take io_request_lock before we call the command
-	 * scsi_done, we would get a deadlock if we took
-	 * hostdata->lock here and in queuecommand (because the order
-	 * of locking in queuecommand: 1) io_request_lock then 2)
-	 * hostdata->lock would be the reverse of taking it in this
-	 * routine */
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(host->host_lock, flags);
 	if((istat = NCR_700_readb(host, ISTAT_REG))
 	      & (SCSI_INT_PENDING | DMA_INT_PENDING)) {
 		__u32 dsps;
@@ -1764,7 +1753,7 @@
 		}
 	}
  out_unlock:
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(host->host_lock, flags);
 }
 
 /* FIXME: Need to put some proc information in and plumb it
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c
--- v2.5.2/linux/drivers/scsi/AM53C974.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/AM53C974.c	Mon Jan 28 14:36:58 2002
@@ -1021,10 +1021,11 @@
 static void do_AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
-
-	spin_lock_irqsave(&io_request_lock, flags);
+	struct Scsi_Host *dev = dev_id;
+	
+	spin_lock_irqsave(dev->host_lock, flags);
 	AM53C974_intr(irq, dev_id, regs);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 /************************************************************************
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h
--- v2.5.2/linux/drivers/scsi/BusLogic.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/BusLogic.h	Mon Jan 28 14:36:58 2002
@@ -1531,7 +1531,7 @@
 void BusLogic_AcquireHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
 				       ProcessorFlags_T *ProcessorFlags)
 {
-  spin_lock_irqsave(&HostAdapter->SCSI_Host->host_lock, *ProcessorFlags);
+  spin_lock_irqsave(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags);
 }
 
 
@@ -1544,7 +1544,7 @@
 void BusLogic_ReleaseHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
 				       ProcessorFlags_T *ProcessorFlags)
 {
-  spin_unlock_irqrestore(&HostAdapter->SCSI_Host->host_lock, *ProcessorFlags);
+  spin_unlock_irqrestore(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags);
 }
 
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/Config.help linux/drivers/scsi/Config.help
--- v2.5.2/linux/drivers/scsi/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/Config.help	Fri Jan 25 16:04:16 2002
@@ -0,0 +1,1380 @@
+CONFIG_BLK_DEV_3W_XXXX_RAID
+  3ware is the only hardware ATA-Raid product in Linux to date.
+  This card is 2,4, or 8 channel master mode support only.
+  SCSI support required!!!
+
+  <http://www.3ware.com/>
+
+  Please read the comments at the top of
+  <file:drivers/scsi/3w-xxxx.c>.
+
+CONFIG_WARPENGINE_SCSI
+  Support for MacroSystem Development's WarpEngine Amiga SCSI-2
+  controller. Info at
+  <http://www.lysator.liu.se/amiga/ar/guide/ar310.guide?FEATURE5>.
+
+CONFIG_JAZZ_ESP
+  This is the driver for the onboard SCSI host adapter of MIPS Magnum
+  4000, Acer PICA, Olivetti M700-10 and a few other identical OEM
+  systems.
+
+CONFIG_BLK_DEV_SD
+  If you want to use a SCSI hard disk or the SCSI or parallel port
+  version of the IOMEGA ZIP drive under Linux, say Y and read the
+  SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. This is NOT for SCSI
+  CD-ROMs.
+
+  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 sd_mod.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.  Do not compile this driver as a
+  module if your root file system (the one containing the directory /)
+  is located on a SCSI disk. In this case, do not compile the driver
+  for your SCSI host adapter (below) as a module either.
+
+CONFIG_SD_EXTRA_DEVS
+  This controls the amount of additional space allocated in tables for
+  drivers that are loaded as modules after the kernel is booted.  In
+  the event that the SCSI core itself was loaded as a module, this
+  value is the number of additional disks that can be loaded after the
+  first host driver is loaded.
+
+  Admittedly this isn't pretty, but there are tons of race conditions
+  involved with resizing the internal arrays on the fly.  Someday this
+  flag will go away, and everything will work automatically.
+
+  If you don't understand what's going on, go with the default.
+
+CONFIG_CHR_DEV_ST
+  If you want to use a SCSI tape drive under Linux, say Y and read the
+  SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, and
+  <file:drivers/scsi/README.st> in the kernel source.  This is NOT for
+  SCSI CD-ROMs.
+
+  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 st.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_CHR_DEV_OSST
+  The OnStream SC-x0 SCSI tape drives can not be driven by the
+  standard st driver, but instead need this special osst driver and
+  use the  /dev/osstX char device nodes (major 206).  Via usb-storage
+  and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives
+  as well.  Note that there is also a second generation of OnStream
+  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
+  <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/>
+  Please also have a look at the standard st docu, as most of it
+  applies to osst as well.
+
+  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 osst.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_BLK_DEV_SR
+  If you want to use a SCSI CD-ROM under Linux, say Y and read the
+  SCSI-HOWTO and the CD-ROM-HOWTO at
+  <http://www.linuxdoc.org/docs.html#howto>. Also make sure to say Y
+  or M to "ISO 9660 CD-ROM file system support" later.
+
+  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 sr_mod.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>.
+
+CONFIG_SR_EXTRA_DEVS
+  This controls the amount of additional space allocated in tables for
+  drivers that are loaded as modules after the kernel is booted. In
+  the event that the SCSI core itself was loaded as a module, this
+  value is the number of additional CD-ROMs that can be loaded after
+  the first host driver is loaded.
+
+  Admittedly this isn't pretty, but there are tons of race conditions
+  involved with resizing the internal arrays on the fly.  Someday this
+  flag will go away, and everything will work automatically.
+
+  If you don't understand what's going on, go with the default.
+
+CONFIG_BLK_DEV_SR_VENDOR
+  This enables the usage of vendor specific SCSI commands. This is
+  required to support multisession CDs with old NEC/TOSHIBA cdrom
+  drives (and HP Writers). If you have such a drive and get the first
+  session only, try saying Y here; everybody else says N.
+
+CONFIG_CHR_DEV_SG
+  If you want to use SCSI scanners, synthesizers or CD-writers or just
+  about anything having "SCSI" in its name other than hard disks,
+  CD-ROMs or tapes, say Y here. These won't be supported by the kernel
+  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 Cdrtools
+  (<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html>)
+  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.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> and
+  <file:Documentation/scsi.txt>. The module will be called sg.o. If unsure,
+  say N.
+
+CONFIG_SCSI_MULTI_LUN
+  If you have a SCSI device that supports more than one LUN (Logical
+  Unit Number), e.g. a CD jukebox, and only one LUN is detected, you
+  can say Y here to force the SCSI driver to probe for multiple LUNs.
+  A SCSI device with multiple LUNs acts logically like multiple SCSI
+  devices. The vast majority of SCSI devices have only one LUN, and
+  so most people can say N here and should in fact do so, because it
+  is safer.
+
+CONFIG_SCSI_CONSTANTS
+  The error messages regarding your SCSI hardware will be easier to
+  understand if you say Y here; it will enlarge your kernel by about
+  12 KB. If in doubt, say Y.
+
+CONFIG_SCSI_LOGGING
+  This turns on a logging facility that can be used to debug a number
+  of SCSI related problems.
+
+  If you say Y here, no logging output will appear by default, but you
+  can enable logging by saying Y to "/proc file system support" and
+  "Sysctl support" below and executing the command
+
+     echo "scsi log token [level]" > /proc/scsi/scsi
+
+  at boot time after the /proc file system has been mounted.
+
+  There are a number of things that can be used for 'token' (you can
+  find them in the source: <file:drivers/scsi/scsi.c>), and this
+  allows you to select the types of information you want, and the
+  level allows you to select the level of verbosity.
+
+  If you say N here, it may be harder to track down some types of SCSI
+  problems. If you say Y here your kernel will be somewhat larger, but
+  there should be no noticeable performance impact as long as you have
+  logging turned off.
+
+CONFIG_SCSI_DECNCR
+  Say Y here to support the NCR53C94 SCSI controller chips on IOASIC
+  based TURBOchannel DECstations and TURBOchannel PMAZ-A cards.
+
+CONFIG_SCSI_ADVANSYS
+  This is a driver for all SCSI host adapters manufactured by
+  AdvanSys. It is documented in the kernel source in
+  <file:drivers/scsi/advansys.c>.
+
+  This driver is also available 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>.  The module will be called
+  advansys.o.
+
+CONFIG_SCSI_AHA152X
+  This is a driver for the AHA-1510, AHA-1520, AHA-1522, and AHA-2825
+  SCSI host adapters. It also works for the AVA-1505, but the IRQ etc.
+  must be manually specified in this case.
+
+  It is explained in section 3.3 of the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. You might also want to
+  read the file <file:drivers/scsi/README.aha152x>.
+
+  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 aha152x.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_AHA1542
+  This is support for a SCSI host adapter.  It is explained in section
+  3.4 of the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  Note that Trantor was
+  purchased by Adaptec, and some former Trantor products are being
+  sold under the Adaptec name.  If it doesn't work out of the box, you
+  may have to change some settings in <file:drivers/scsi/aha1542.h>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called aha1542.o.
+
+CONFIG_SCSI_AHA1740
+  This is support for a SCSI host adapter.  It is explained in section
+  3.5 of the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  If it doesn't work out
+  of the box, you may have to change some settings in
+  <file:drivers/scsi/aha1740.h>.
+
+  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 aha1740.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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
+  driver by Deanna Bonds.  See <file:drivers/scsi/README.dpti>.
+
+  This driver is also available 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>.  The module will be called
+  dpt_i2o.o.
+
+CONFIG_SCSI_AIC7XXX_OLD
+  WARNING This driver is an older aic7xxx driver and is no longer
+  under active development.  Adaptec, Inc. is writing a new driver to
+  take the place of this one, and it is recommended that whenever
+  possible, people should use the new Adaptec written driver instead
+  of this one.  This driver will eventually be phased out entirely.
+
+  This is support for the various aic7xxx based Adaptec SCSI
+  controllers. These include the 274x EISA cards; 284x VLB cards;
+  2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and
+  motherboard based SCSI controllers from Adaptec. It does not support
+  the AAA-13x RAID controllers from Adaptec, nor will it likely ever
+  support them. It does not support the 2920 cards from Adaptec that
+  use the Future Domain SCSI controller chip. For those cards, you
+  need the "Future Domain 16xx SCSI support" driver.
+
+  In general, if the controller is based on an Adaptec SCSI controller
+  chip from the aic777x series or the aic78xx series, this driver
+  should work. The only exception is the 7810 which is specifically
+  not supported (that's the RAID controller chip on the AAA-13x
+  cards).
+
+  Note that the AHA2920 SCSI host adapter is *not* supported by this
+  driver; choose "Future Domain 16xx SCSI support" instead if you have
+  one of those.
+
+  Information on the configuration options for this controller can be
+  found by checking the help file for each of the available
+  configuration options. You should read
+  <file:drivers/scsi/aic7xxx_old/README.aic7xxx> at a minimum before
+  contacting the maintainer with any questions.  The SCSI-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>, can also
+  be of great help.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called aic7xxx_old.o.
+
+CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
+  This option causes the aic7xxx driver to attempt to use Tagged
+  Command Queueing (TCQ) on all devices that claim to support it.
+
+  TCQ is a feature of SCSI-2 which improves performance: the host
+  adapter can send several SCSI commands to a device's queue even if
+  previous commands haven't finished yet.  Because the device is
+  intelligent, it can optimize its operations (like head positioning)
+  based on its own request queue.  Not all devices implement this
+  correctly.
+
+  If you say Y here, you can still turn off TCQ on troublesome devices
+  with the use of the tag_info boot parameter.  See the file
+  <file:drivers/scsi/README.aic7xxx> for more information on that and
+  other aic7xxx setup commands.  If this option is turned off, you may
+  still enable TCQ on known good devices by use of the tag_info boot
+  parameter.
+
+  If you are unsure about your devices then it is safest to say N
+  here.
+
+  However, TCQ can increase performance on some hard drives by as much
+  as 50% or more, so it is recommended that if you say N here, you
+  should at least read the <file:drivers/scsi/README.aic7xxx> file so
+  you will know how to enable this option manually should your drives
+  prove to be safe in regards to TCQ.
+
+  Conversely, certain drives are known to lock up or cause bus resets
+  when TCQ is enabled on them.  If you have a Western Digital
+  Enterprise SCSI drive for instance, then don't even bother to enable
+  TCQ on it as the drive will become unreliable, and it will actually
+  reduce performance.
+
+CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
+  Specify the number of commands you would like to allocate per SCSI
+  device when Tagged Command Queueing (TCQ) is enabled on that device.
+
+  Reasonable figures are in the range of 8 to 24 commands per device,
+  but depending on hardware could be increased or decreased from that
+  figure. If the number is too high for any particular device, the
+  driver will automatically compensate usually after only 10 minutes
+  of uptime. It will not hinder performance if some of your devices
+  eventually have their command depth reduced, but is a waste of
+  memory if all of your devices end up reducing this number down to a
+  more reasonable figure.
+
+  NOTE: Certain very broken drives are known to lock up when given
+  more commands than they like to deal with. Quantum Fireball drives
+  are the most common in this category. For the Quantum Fireball
+  drives it is suggested to use no more than 8 commands per device.
+
+  Default: 8
+
+CONFIG_AIC7XXX_OLD_PROC_STATS
+  This option tells the driver to keep track of how many commands have
+  been sent to each particular device and report that information to
+  the user via the /proc/scsi/aic7xxx/n file, where n is the number of
+  the aic7xxx controller you want the information on. This adds a
+  small amount of overhead to each and every SCSI command the aic7xxx
+  driver handles, so if you aren't really interested in this
+  information, it is best to leave it disabled. This will only work if
+  you also say Y to "/proc file system support", below.
+
+  If unsure, say N.
+
+CONFIG_SCSI_IPS
+  This is support for the IBM ServeRAID hardware RAID controllers.
+  See <http://www.developer.ibm.com/welcome/netfinity/serveraid.html>
+  for more information.  If this driver does not work correctly
+  without modification please contact the author by email at
+  ipslinux@us.ibm.com.
+
+  You can build this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  but only a single instance may be loaded. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+  The module will be called ips.o.
+
+CONFIG_SCSI_BUSLOGIC
+  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
+  <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),
+  but only a single instance may be loaded. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+  The module will be called BusLogic.o.
+
+CONFIG_SCSI_OMIT_FLASHPOINT
+  This option allows you to omit the FlashPoint support from the
+  BusLogic SCSI driver. The FlashPoint SCCB Manager code is
+  substantial, so users of MultiMaster Host Adapters may wish to omit
+  it.
+
+CONFIG_SCSI_CPQFCTS
+  Say Y here to compile in support for the Compaq StorageWorks Fibre
+  Channel 64-bit/66Mhz Host Bus Adapter.
+
+CONFIG_SCSI_DMX3191D
+  This is support for Domex DMX3191D SCSI Host Adapters.
+
+  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 dmx3191d.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_DTC3280
+  This is support for DTC 3180/3280 SCSI Host Adapters.  Please read
+  the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, and the file
+  <file:drivers/scsi/README.dtc3x80>.
+
+  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 dtc.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_EATA_DMA
+  This is support for the EATA-DMA protocol compliant SCSI Host
+  Adapters like the SmartCache III/IV, SmartRAID controller families
+  and the DPT PM2011B and PM2012B controllers.
+
+  Note that this driver is obsolete; if you have one of the above
+  SCSI Host Adapters, you should normally say N here and Y to "EATA
+  ISA/EISA/PCI support", below.  Please read the SCSI-HOWTO, available
+  from <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called eata_dma.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_EATA_PIO
+  This driver supports all EATA-PIO protocol compliant SCSI Host
+  Adapters like the DPT PM2001 and the PM2012A.  EATA-DMA compliant
+  host adapters could also use this driver but are discouraged from
+  doing so, since this driver only supports hard disks and lacks
+  numerous features.  You might want to have a look at the SCSI-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called eata_pio.o.
+
+CONFIG_SCSI_U14_34F
+  This is support for the UltraStor 14F and 34F SCSI-2 host adapters.
+  The source at <file:drivers/scsi/u14-34f.c> contains some
+  information about this hardware.  If the driver doesn't work out of
+  the box, you may have to change some settings in
+  <file: drivers/scsi/u14-34f.c>.  Read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  Note that there is also
+  another driver for the same hardware: "UltraStor SCSI support",
+  below.  You should say Y to both only if you want 24F support as
+  well.
+
+  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 u14-34f.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_U14_34F_LINKED_COMMANDS
+  This option enables elevator sorting for all probed SCSI disks and
+  CD-ROMs. It definitely reduces the average seek distance when doing
+  random seeks, but this does not necessarily result in a noticeable
+  performance improvement: your mileage may vary...
+
+  The safe answer is N.
+
+CONFIG_SCSI_U14_34F_MAX_TAGS
+  This specifies how many SCSI commands can be maximally queued for
+  each probed SCSI device. You should reduce the default value of 8
+  only if you have disks with buggy or limited tagged command support.
+  Minimum is 2 and maximum is 14. This value is also the window size
+  used by the elevator sorting option above. The effective value used
+  by the driver for each probed SCSI device is reported at boot time.
+
+CONFIG_SCSI_FUTURE_DOMAIN
+  This is support for Future Domain's 16-bit SCSI host adapters
+  (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and
+  other adapters based on the Future Domain chipsets (Quantum
+  ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board).
+  It is explained in section 3.7 of the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip
+  and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI
+  controller support"). This Future Domain driver works with the older
+  Adaptec AHA-2920A boards with a Future Domain chip on them.
+
+  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 fdomain.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_FD_MCS
+  This is support for Future Domain MCS 600/700 MCA SCSI adapters.
+  Some PS/2 computers are equipped with IBM Fast SCSI Adapter/A which
+  is identical to the MCS 700 and hence also supported by this driver.
+  This driver also supports the Reply SB16/SCSI card (the SCSI part).
+  It supports multiple adapters in the same system.
+
+  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 fd_mcs.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_GENERIC_NCR5380
+  This is the generic NCR family of SCSI controllers, not to be
+  confused with the NCR 53c7 or 8xx controllers.  It is explained in
+  section 3.8 of the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  If it doesn't work out
+  of the box, you may have to change some settings in
+  <file:drivers/scsi/g_NCR5380.h>.
+
+  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 g_NCR5380.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_GENERIC_NCR53C400
+  This enables certain optimizations for the NCR53c400 SCSI cards.
+  You might as well try it out.  Note that this driver will only probe
+  for the Trantor T130B in its default configuration; you might have
+  to pass a command line option to the kernel at boot time if it does
+  not detect your card.  See the file
+  <file:drivers/scsi/README.g_NCR5380> for details.
+
+CONFIG_SCSI_G_NCR5380_PORT
+  The NCR5380 and NCR53c400 SCSI controllers come in two varieties:
+  port or memory mapped. You should know what you have. The most
+  common card, Trantor T130B, uses port mapped mode.
+
+CONFIG_SCSI_NCR_D700
+  This is a driver for the MicroChannel Dual 700 card produced by
+  NCR and commonly used in 345x/35xx/4100 class machines.  It always
+  tries to negotiate sync and uses tag command queueing.
+
+  Unless you have an NCR manufactured machine, the chances are that
+  you do not have this SCSI card, so say N.
+
+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
+  based on the 710 chip using 700 emulation mode.
+
+  Unless you know you have a 53c700 or 53c710 based lasi, say N here
+
+CONFIG_SCSI_NCR53C7xx
+  This is a driver for the 53c7 and 8xx NCR family of SCSI
+  controllers, not to be confused with the NCR 5380 controllers.  It
+  is explained in section 3.8 of the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  If it doesn't work out
+  of the box, you may have to change some settings in
+  <file:drivers/scsi/53c7,8xx.h>.  Please read
+  <file:drivers/scsi/README.ncr53c7xx> for the available boot time
+  command line options.
+
+  Note: there is another driver for the 53c8xx family of controllers
+  ("NCR53C8XX SCSI support" below).  If you want to use them both, you
+  need to say M to both and build them as modules, but only one may be
+  active at a time. If you have a 53c8xx board, it's better to use the
+  other driver.
+
+  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 53c7,8xx.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_NCR53C7xx_sync
+  In general, this is good; however, it is a bit dangerous since there
+  are some broken SCSI devices out there. Take your chances. Safe bet
+  is N.
+
+CONFIG_SCSI_NCR53C7xx_FAST
+  This will enable 10MHz FAST-SCSI transfers with your host
+  adapter. Some systems have problems with that speed, so it's safest
+  to say N here.
+
+CONFIG_SCSI_NCR53C7xx_DISCONNECT
+  This enables the disconnect/reconnect feature of the NCR SCSI
+  controller. When you say Y here, a slow SCSI device will not lock
+  the SCSI bus while processing a request, allowing simultaneous use
+  of e.g. a SCSI hard disk and SCSI tape or CD-ROM drive, and
+  providing much better performance when using slow and fast SCSI
+  devices at the same time. Some devices, however, do not operate
+  properly with this option enabled, and will cause your SCSI system
+  to hang, which might cause a system crash. The safe answer
+  therefore is to say N.
+
+CONFIG_SCSI_SYM53C8XX_2
+  This driver supports the whole NCR53C8XX/SYM53C8XX family of 
+  PCI-SCSI controllers. It also supports the subset of LSI53C10XX 
+  Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS 
+  language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI 
+  controllers.
+
+  If your system has problems using this new major version of the
+  SYM53C8XX driver, you may switch back to driver version 1.
+
+  Please read <file:drivers/scsi/sym53c8xx_2/Documentation.txt> for more
+  information.
+
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE
+  This option only applies to PCI-SCSI chip that are PCI DAC capable 
+  (875A, 895A, 896, 1010-33, 1010-66, 1000).
+
+  When set to 0, only PCI 32 bit DMA addressing (SAC) will be performed.
+  When set to 1, 40 bit DMA addressing (with upper 24 bits of address 
+  set to zero) is supported. The addressable range is here 1 TB.
+  When set to 2, full 64 bits of address for DMA are supported, but only
+  16 segments of 4 GB can be addressed. The addressable range is so 
+  limited to 64 GB.
+
+  The safest value is 0 (32 bit DMA addressing) that is guessed to still 
+  fit most of real machines.
+
+  The preferred value 1 (40 bit DMA addressing) should make happy 
+  properly engineered PCI DAC capable host bridges. You may configure
+  this option for Intel platforms with more than 4 GB of memory.
+
+  The still experimental value 2 (64 bit DMA addressing with 16 x 4GB 
+  segments limitation) can be used on systems that require PCI address 
+  bits past bit 39 to be set for the addressing of memory using PCI 
+  DAC cycles.
+
+CONFIG_SCSI_SYM53C8XX_IOMAPPED
+  If you say Y here, the driver will preferently use normal IO rather than 
+  memory mapped IO.
+
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS
+  This option allows you to specify the maximum number of commands
+  that can be queued to any device, when tagged command queuing is
+  possible. The driver supports up to 256 queued commands per device.
+  This value is used as a compiled-in hard limit.
+
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS
+  This is the default value of the command queue depth the driver will 
+  announce to the generic SCSI layer for devices that support tagged 
+  command queueing. This value can be changed from the boot command line.
+  This is a soft limit that cannot exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS.
+
+CONFIG_SCSI_NCR53C8XX
+  This is the BSD ncr driver adapted to Linux for the NCR53C8XX family
+  of PCI-SCSI controllers.  This driver supports parity checking,
+  tagged command queuing and fast synchronous data transfers up to 80
+  MB/s with wide FAST-40 LVD devices and controllers.
+
+  Recent versions of the 53C8XX chips are better supported by the
+  option "SYM53C8XX SCSI support", below.
+
+  Note: there is yet another driver for the 53c8xx family of
+  controllers ("NCR53c7,8xx SCSI support" above).  If you want to use
+  them both, you need to say M to both and build them as modules, but
+  only one may be active at a time.  If you have a 53c8xx board, you
+  probably do not want to use the "NCR53c7,8xx SCSI support".
+
+  Please read <file:drivers/scsi/README.ncr53c8xx> for more
+  information.
+
+CONFIG_SCSI_SYM53C8XX
+  This driver supports all the features of recent 53C8XX chips (used
+  in PCI SCSI controllers), notably the hardware phase mismatch
+  feature of the SYM53C896.
+
+  Older versions of the 53C8XX chips are not supported by this
+  driver.  If your system uses either a 810 rev. < 16, a 815, or a 825
+  rev. < 16 PCI SCSI processor, you must use the generic NCR53C8XX
+  driver ("NCR53C8XX SCSI support" above) or configure both the
+  NCR53C8XX and this SYM53C8XX drivers either as module or linked to
+  the kernel image.
+
+  When both drivers are linked into the kernel, the SYM53C8XX driver
+  is called first at initialization and you can use the 'excl=ioaddr'
+  driver boot option to exclude attachment of adapters by the
+  SYM53C8XX driver.  For example, entering
+  'sym53c8xx=excl:0xb400,excl=0xc000' at the lilo prompt prevents
+  adapters at io address 0xb400 and 0xc000 from being attached by the
+  SYM53C8XX driver, thus allowing the NCR53C8XX driver to attach them.
+  The 'excl' option is also supported by the NCR53C8XX driver.
+
+  Please read <file:drivers/scsi/README.ncr53c8xx> for more
+  information.
+
+CONFIG_SCSI_NCR53C8XX_SYNC
+  The SCSI Parallel Interface-2 Standard defines 5 classes of transfer
+  rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80.  The numbers
+  are respectively the maximum data transfer rates in mega-transfers
+  per second for each class.  For example, a FAST-20 Wide 16 device is
+  able to transfer data at 20 million 16 bit packets per second for a
+  total rate of 40 MB/s.
+
+  You may specify 0 if you want to only use asynchronous data
+  transfers. This is the safest and slowest option. Otherwise, specify
+  a value between 5 and 80, depending on the capability of your SCSI
+  controller.  The higher the number, the faster the data transfer.
+  Note that 80 should normally be ok since the driver decreases the
+  value automatically according to the controller's capabilities.
+
+  Your answer to this question is ignored for controllers with NVRAM,
+  since the driver will get this information from the user set-up.  It
+  also can be overridden using a boot setup option, as follows
+  (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate
+  for FAST-20 synchronous data transfer (20 mega-transfers per
+  second).
+
+  The normal answer therefore is not to go with the default but to
+  select the maximum value 80 allowing the driver to use the maximum
+  value supported by each controller. If this causes problems with
+  your SCSI devices, you should come back and decrease the value.
+
+  There is no safe option other than using good cabling, right
+  terminations and SCSI conformant devices.
+
+CONFIG_SCSI_NCR53C8XX_IOMAPPED
+  If you say Y here, the driver will use normal IO, as opposed to
+  memory mapped IO. Memory mapped IO has less latency than normal IO
+  and works for most Intel-based hardware. Under Linux/Alpha only
+  normal IO is currently supported by the driver and so, this option
+  has no effect on those systems.
+
+  The normal answer therefore is N; try Y only if you encounter SCSI
+  related problems.
+
+CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
+  This option is only provided for safety if you suspect some SCSI
+  device of yours to not support properly the target-disconnect
+  feature. In that case, you would say Y here. In general however, to
+  not allow targets to disconnect is not reasonable if there is more
+  than 1 device on a SCSI bus. The normal answer therefore is N.
+
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS
+  "Tagged command queuing" is a feature of SCSI-2 which improves
+  performance: the host adapter can send several SCSI commands to a
+  device's queue even if previous commands haven't finished yet.
+  Because the device is intelligent, it can optimize its operations
+  (like head positioning) based on its own request queue. Some SCSI
+  devices don't implement this properly; if you want to disable this
+  feature, enter 0 or 1 here (it doesn't matter which).
+
+  The default value is 8 and should be supported by most hard disks.
+  This value can be overridden from the boot command line using the
+  'tags' option as follows (example):
+  'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to
+  4, set queue depth to 16 for target 2 and target 3 on controller 0
+  and set queue depth to 10 for target 0 / lun 2 on controller 1.
+
+  The normal answer therefore is to go with the default 8 and to use
+  a boot command line option for devices that need to use a different
+  command queue depth.
+
+  There is no safe option other than using good SCSI devices.
+
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS
+  This option allows you to specify the maximum number of commands
+  that can be queued to any device, when tagged command queuing is
+  possible. The default value is 32. Minimum is 2, maximum is 64.
+  Modern hard disks are able to support 64 tags and even more, but
+  do not seem to be faster when more than 32 tags are being used.
+
+  So, the normal answer here is to go with the default value 32 unless
+  you are using very large hard disks with large cache (>= 1 MB) that
+  are able to take advantage of more than 32 tagged commands.
+
+  There is no safe option and the default answer is recommended.
+
+CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
+  This option allows you to enable some features depending on GPIO
+  wiring. These General Purpose Input/Output pins can be used for
+  vendor specific features or implementation of the standard SYMBIOS
+  features. Genuine SYMBIOS controllers use GPIO0 in output for
+  controller LED and GPIO3 bit as a flag indicating
+  singled-ended/differential interface. The Tekram DC-390U/F boards
+  uses a different GPIO wiring.
+
+  Your answer to this question is ignored if all your controllers have
+  NVRAM, since the driver is able to detect the board type from the
+  NVRAM format.
+
+  If all the controllers in your system are genuine SYMBIOS boards or
+  use BIOS and drivers from SYMBIOS, you would want to say Y here,
+  otherwise N. N is the safe answer.
+
+CONFIG_SCSI_NCR53C8XX_PROFILE
+  This option allows you to enable profiling information gathering.
+  These statistics are not very accurate due to the low frequency
+  of the kernel clock (100 Hz on i386) and have performance impact
+  on systems that use very fast devices.
+
+  The normal answer therefore is N.
+
+CONFIG_SCSI_NCR53C8XX_PQS_PDS
+  Say Y here if you have a special SCSI adapter produced by NCR
+  corporation called a PCI Quad SCSI or PCI Dual SCSI. You do not need
+  this if you do not have one of these adapters. However, since this
+  device is detected as a specific PCI device, this option is quite
+  safe.
+
+  The common answer here is N, but answering Y is safe.
+
+CONFIG_SCSI_IBMMCA
+  This is support for the IBM SCSI adapter found in many of the PS/2
+  series computers.  These machines have an MCA bus, so you need to
+  answer Y to "MCA support" as well and read
+  <file:Documentation/mca.txt>.
+
+  If the adapter isn't found during boot (a common problem for models
+  56, 57, 76, and 77) you'll need to use the 'ibmmcascsi=<pun>' kernel
+  option, where <pun> is the id of the SCSI subsystem (usually 7, but
+  if that doesn't work check your reference diskette).  Owners of
+  model 95 with a LED-matrix-display can in addition activate some
+  activity info like under OS/2, but more informative, by setting
+  'ibmmcascsi=display' as an additional kernel parameter.  Try "man
+  bootparam" or see the documentation of your boot loader about how to
+  pass options to the kernel.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ibmmca.o.
+
+CONFIG_IBMMCA_SCSI_ORDER_STANDARD
+  In the PC-world and in most modern SCSI-BIOS-setups, SCSI-hard disks
+  are assigned to the drive letters, starting with the lowest SCSI-id
+  (physical number -- pun) to be drive C:, as seen from DOS and
+  similar operating systems. When looking into papers describing the
+  ANSI-SCSI-standard, this assignment of drives appears to be wrong.
+  The SCSI-standard follows a hardware-hierarchy which says that id 7
+  has the highest priority and id 0 the lowest. Therefore, the host
+  adapters are still today everywhere placed as SCSI-id 7 by default.
+  In the SCSI-standard, the drive letters express the priority of the
+  disk. C: should be the hard disk, or a partition on it, with the
+  highest priority. This must therefore be the disk with the highest
+  SCSI-id (e.g. 6) and not the one with the lowest! IBM-BIOS kept the
+  original definition of the SCSI-standard as also industrial- and
+  process-control-machines, like VME-CPUs running under realtime-OSes
+  (e.g. LynxOS, OS9) do.
+
+  If you like to run Linux on your MCA-machine with the same
+  assignment of hard disks as seen from e.g. DOS or OS/2 on your
+  machine, which is in addition conformant to the SCSI-standard, you
+  must say Y here. This is also necessary for MCA-Linux users who want
+  to keep downward compatibility to older releases of the
+  IBM-MCA-SCSI-driver (older than driver-release 2.00 and older than
+  June 1997).
+
+  If you like to have the lowest SCSI-id assigned as drive C:, as
+  modern SCSI-BIOSes do, which does not conform to the standard, but
+  is widespread and common in the PC-world of today, you must say N
+  here. If unsure, say Y.
+
+CONFIG_IBMMCA_SCSI_DEV_RESET
+  By default, SCSI-devices are reset when the machine is powered on.
+  However, some devices exist, like special-control-devices,
+  SCSI-CNC-machines, SCSI-printer or scanners of older type, that do
+  not reset when switched on. If you say Y here, each device connected
+  to your SCSI-bus will be issued a reset-command after it has been
+  probed, while the kernel is booting. This may cause problems with
+  more modern devices, like hard disks, which do not appreciate these
+  reset commands, and can cause your system to hang. So say Y only if
+  you know that one of your older devices needs it; N is the safe
+  answer.
+
+CONFIG_SCSI_MCA_53C9X
+  Some MicroChannel machines, notably the NCR 35xx line, use a SCSI
+  controller based on the NCR 53C94.  This driver will allow use of
+  the controller on the 3550, and very possibly others.
+
+  If you want to compile this as a module (= code which can be
+  inserted and removed from the running kernel whenever you want), say
+  M here and read <file:Documentation/modules.txt>.  The module will
+  be called mca_53c9x.o.
+
+CONFIG_SCSI_IN2000
+  This is support for an ISA bus SCSI host adapter.  You'll find more
+  information in <file:drivers/scsi/README.in2000>. If it doesn't work
+  out of the box, you may have to change the jumpers for IRQ or
+  address selection.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called in2000.o.
+
+CONFIG_SCSI_INITIO
+  This is support for the Initio 91XXU(W) SCSI host adapter.  Please
+  read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called initio.o.
+
+CONFIG_SCSI_PAS16
+  This is support for a SCSI host adapter.  It is explained in section
+  3.10 of the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  If it doesn't work out
+  of the box, you may have to change some settings in
+  <file:drivers/scsi/pas16.h>.
+
+  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 pas16.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_INIA100
+  This is support for the Initio INI-A100U2W SCSI host adapter.
+  Please read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called a100u2w.o.
+
+CONFIG_SCSI_PCI2000
+  This is support for the PCI2000I EIDE interface card which acts as a
+  SCSI host adapter.  Please read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module called pci2000.o ( = 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>.
+
+CONFIG_SCSI_PCI2220I
+  This is support for the PCI2220i EIDE interface card which acts as a
+  SCSI host adapter.  Please read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module called pci2220i.o ( = 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>.
+
+CONFIG_SCSI_PSI240I
+  This is support for the PSI240i EIDE interface card which acts as a
+  SCSI host adapter.  Please read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module called psi240i.o ( = 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>.
+
+CONFIG_SCSI_QLOGIC_FAS
+  This is a driver for the ISA, VLB, and PCMCIA versions of the Qlogic
+  FastSCSI! cards as well as any other card based on the FASXX chip
+  (including the Control Concepts SCSI/IDE/SIO/PIO/FDC cards).
+
+  This driver does NOT support the PCI versions of these cards. The
+  PCI versions are supported by the Qlogic ISP driver ("Qlogic ISP
+  SCSI support"), below.
+
+  Information about this driver is contained in
+  <file:drivers/scsi/README.qlogicfas>.  You should also read the
+  SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called qlogicfas.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_QLOGIC_ISP
+  This driver works for all QLogic PCI SCSI host adapters (IQ-PCI,
+  IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card.  (This latter
+  card is supported by the "AM53/79C974 PCI SCSI" driver.)
+
+  If you say Y here, make sure to choose "BIOS" at the question "PCI
+  access mode".
+
+  Please read the file <file:drivers/scsi/README.qlogicisp>.  You
+  should also read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called qlogicisp.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_QLOGIC_FC
+  This is a driver for the QLogic ISP2100 SCSI-FCP host adapter.
+
+  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 qlogicfc.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_QLOGIC_1280
+  Say Y if you have a QLogic ISP1x80/1x160 SCSI host adapter.
+
+  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 qla1280.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_SEAGATE
+  These are 8-bit SCSI controllers; the ST-01 is also supported by
+  this driver.  It is explained in section 3.9 of the SCSI-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.  If it
+  doesn't work out of the box, you may have to change some settings in
+  <file:drivers/scsi/seagate.h>.
+
+  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 seagate.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_T128
+  This is support for a SCSI host adapter. It is explained in section
+  3.11 of the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  If it doesn't work out
+  of the box, you may have to change some settings in
+  <file:drivers/scsi/t128.h>.  Note that Trantor was purchased by
+  Adaptec, and some former Trantor products are being sold under the
+  Adaptec name.
+
+  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 t128.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_ULTRASTOR
+  This is support for the UltraStor 14F, 24F and 34F SCSI-2 host
+  adapter family.  This driver is explained in section 3.12 of the
+  SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  If it doesn't work out
+  of the box, you may have to change some settings in
+  <file:drivers/scsi/ultrastor.h>.
+
+  Note that there is also another driver for the same hardware:
+  "UltraStor 14F/34F support", above.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ultrastor.o.
+
+CONFIG_SCSI_7000FASST
+  This driver supports the Western Digital 7000 SCSI host adapter
+  family.  Some information is in the source:
+  <file:drivers/scsi/wd7000.c>.
+
+  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 wd7000.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_ACARD
+  This driver supports the ACARD 870U/W SCSI host adapter.
+
+  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 atp870u.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_EATA
+  This driver supports all EATA/DMA-compliant SCSI host adapters.  DPT
+  ISA and all EISA I/O addresses are probed looking for the "EATA"
+  signature.  If you chose "BIOS" at the question "PCI access mode",
+  the addresses of all the PCI SCSI controllers reported by the PCI
+  subsystem are probed as well.
+
+  You want to read the start of <file:drivers/scsi/eata.c> and the
+  SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  Note that there is also another driver for the same hardware
+  available: "EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti,
+  Alphatronix) support". You should say Y to only one of them.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called eata.o.
+
+CONFIG_SCSI_EATA_TAGGED_QUEUE
+  This is a feature of SCSI-2 which improves performance: the host
+  adapter can send several SCSI commands to a device's queue even if
+  previous commands haven't finished yet. Most EATA adapters negotiate
+  this feature automatically with the device, even if your answer is
+  N. The safe answer is N.
+
+CONFIG_SCSI_EATA_LINKED_COMMANDS
+  This option enables elevator sorting for all probed SCSI disks and
+  CD-ROMs. It definitely reduces the average seek distance when doing
+  random seeks, but this does not necessarily result in a noticeable
+  performance improvement: your mileage may vary...
+  The safe answer is N.
+
+CONFIG_SCSI_EATA_MAX_TAGS
+  This specifies how many SCSI commands can be maximally queued for
+  each probed SCSI device. You should reduce the default value of 16
+  only if you have disks with buggy or limited tagged command support.
+  Minimum is 2 and maximum is 62. This value is also the window size
+  used by the elevator sorting option above. The effective value used
+  by the driver for each probed SCSI device is reported at boot time.
+
+CONFIG_SCSI_NCR53C406A
+  This is support for the NCR53c406a SCSI host adapter.  For user
+  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>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called NCR53c406.o.
+
+CONFIG_SCSI_SYM53C416
+  This is support for the sym53c416 SCSI host adapter, the SCSI
+  adapter that comes with some HP scanners. This driver requires that
+  the sym53c416 is configured first using some sort of PnP
+  configuration program (e.g. isapnp) or by a PnP aware BIOS. If you
+  are using isapnp then you need to compile this driver as a module
+  and then load it using insmod after isapnp has run. The parameters
+  of the configured card(s) should be passed to the driver. The format
+  is:
+
+    insmod sym53c416 sym53c416=<base>,<irq> [sym53c416_1=<base>,<irq>]
+
+  There is support for up to four adapters. If you want to compile
+  this driver as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want), say M here and
+  read <file:Documentation/modules.txt>. The module will be called
+  sym53c416.o.
+
+CONFIG_SCSI_SIM710
+  This is a simple driver for NCR53c710 based SCSI host adapters.
+
+  More complex drivers for this chip are available ("NCR53c7,8xx SCSI
+  support", above), but they require that the scsi chip be able to do
+  DMA block moves between memory and on-chip registers, which can
+  cause problems under certain conditions.  This driver is designed to
+  avoid these problems and is intended to work with any Intel machines
+  using 53c710 chips, including various Compaq and NCR machines.
+
+  Please read the comments at the top of the file
+  <file:drivers/scsi/sim710.c> for more information.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called sim710.o.
+
+CONFIG_SCSI_DC390T
+  This driver supports PCI SCSI host adapters based on the Am53C974A
+  chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard
+  PCscsi/PCnet (Am53/79C974) solutions.
+
+  Documentation can be found in <file:drivers/scsi/README.tmscsim>.
+
+  Note that this driver does NOT support Tekram DC390W/U/F, which are
+  based on NCR/Symbios chips. Use "NCR53C8XX SCSI support" for those.
+  Also note that there is another generic Am53C974 driver,
+  "AM53/79C974 PCI SCSI support" below.  You can pick either one.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called tmscsim.o.
+
+CONFIG_SCSI_DC390T_NOGENSUPP
+  If you say N here, the DC390(T) SCSI driver relies on the DC390
+  EEPROM to get initial values for its settings, such as speed,
+  termination, etc.  If it can't find this EEPROM, it will use
+  defaults or the user supplied boot/module parameters.  For details
+  on driver configuration see <file:drivers/scsi/README.tmscsim>.
+
+  If you say Y here and if no EEPROM is found, the driver gives up and
+  thus only supports Tekram DC390(T) adapters.  This can be useful if
+  you have a DC390(T) and another Am53C974 based adapter, which, for
+  some reason, you want to drive with the other AM53C974 driver.
+
+  If unsure, say N.
+
+CONFIG_SCSI_AM53C974
+  This is support for the AM53/79C974 SCSI host adapters.  Please read
+  <file:drivers/scsi/README.AM53C974> for details.  Also, the
+  SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, is for you.
+
+  Note that there is another driver for AM53C974 based adapters:
+  "Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support", above.  You
+  can pick either one.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called AM53C974.o.
+
+CONFIG_SCSI_MEGARAID
+  This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490
+  and 467 SCSI host adapters.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called megaraid.o.
+
+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 <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).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+CONFIG_SCSI_PPA
+  This driver supports older versions of IOMEGA's parallel port ZIP
+  drive (a 100 MB removable media device).
+
+  Note that you can say N here if you have the SCSI version of the ZIP
+  drive: it will be supported automatically if you said Y to the
+  generic "SCSI disk support", above.
+
+  If you have the ZIP Plus drive or a more recent parallel port ZIP
+  drive (if the supplied cable with the drive is labeled "AutoDetect")
+  then you should say N here and Y to "IOMEGA parallel port (imm -
+  newer drives)", below.
+
+  For more information about this driver and how to use it you should
+  read the file <file:drivers/scsi/README.ppa>.  You should also read
+  the SCSI-HOWTO, which is available from
+  <http://www.linuxdoc.org/docs.html#howto>.  If you use this driver,
+  you will still be able to use the parallel port for other tasks,
+  such as a printer; it is safe to compile both drivers into the
+  kernel.
+
+  This driver is also available as a module which can be inserted in
+  and removed from the running kernel whenever you want.  To compile
+  this driver as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called ppa.o.
+
+CONFIG_SCSI_IMM
+  This driver supports newer versions of IOMEGA's parallel port ZIP
+  drive (a 100 MB removable media device).
+
+  Note that you can say N here if you have the SCSI version of the ZIP
+  drive: it will be supported automatically if you said Y to the
+  generic "SCSI disk support", above.
+
+  If you have the ZIP Plus drive or a more recent parallel port ZIP
+  drive (if the supplied cable with the drive is labeled "AutoDetect")
+  then you should say Y here; if you have an older ZIP drive, say N
+  here and Y to "IOMEGA Parallel Port (ppa - older drives)", above.
+
+  For more information about this driver and how to use it you should
+  read the file <file:drivers/scsi/README.ppa>.  You should also read
+  the SCSI-HOWTO, which is available from
+  <http://www.linuxdoc.org/docs.html#howto>.  If you use this driver,
+  you will still be able to use the parallel port for other tasks,
+  such as a printer; it is safe to compile both drivers into the
+  kernel.
+
+  This driver is also available as a module which can be inserted in
+  and removed from the running kernel whenever you want.  To compile
+  this driver as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called imm.o.
+
+CONFIG_SCSI_IZIP_EPP16
+  EPP (Enhanced Parallel Port) is a standard for parallel ports which
+  allows them to act as expansion buses that can handle up to 64
+  peripheral devices.
+
+  Some parallel port chipsets are slower than their motherboard, and
+  so we have to control the state of the chipset's FIFO queue every
+  now and then to avoid data loss. This will be done if you say Y
+  here.
+
+  Generally, saying Y is the safe option and slows things down a bit.
+
+CONFIG_SCSI_IZIP_SLOW_CTR
+  Some parallel ports are known to have excessive delays between
+  changing the parallel port control register and good data being
+  available on the parallel port data/status register. This option
+  forces a small delay (1.0 usec to be exact) after changing the
+  control register to let things settle out. Enabling this option may
+  result in a big drop in performance but some very old parallel ports
+  (found in 386 vintage machines) will not work properly.
+
+  Generally, saying N is fine.
+
+CONFIG_SCSI_DEBUG
+  This is a host adapter simulator that can be programmed to simulate
+  a large number of conditions that could occur on a real bus. The
+  advantage is that many hard to reproduce problems can be tested in a
+  controlled environment where there is reduced risk of losing
+  important data. This is primarily of use to people trying to debug
+  the middle and upper layers of the SCSI subsystem. If unsure, say N.
+
+CONFIG_A4000T_SCSI
+  Support for the NCR53C710 SCSI controller on the Amiga 4000T.
+
+CONFIG_A4091_SCSI
+  Support for the NCR53C710 chip on the Amiga 4091 Z3 SCSI2 controller
+  (1993).  Very obscure -- the 4091 was part of an Amiga 4000 upgrade
+  plan at the time the Amiga business was sold to DKB.
+
+CONFIG_A3000_SCSI
+  If you have an Amiga 3000 and have SCSI devices connected to the
+  built-in SCSI controller, say Y. Otherwise, say N. 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 is
+  called wd33c93.o. If you want to compile it as a module, say M here
+  and read <file:Documentation/modules.txt>.
+
+CONFIG_A2091_SCSI
+  If you have a Commodore A2091 SCSI controller, say Y. Otherwise,
+  say N. 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 is called wd33c93.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GVP11_SCSI
+  If you have a Great Valley Products Series II SCSI controller,
+  answer Y. Also say Y if you have a later model of GVP SCSI
+  controller (such as the GVP A4008 or a Combo board). Otherwise,
+  answer N. This driver does NOT work for the T-Rex series of
+  accelerators from TekMagic and GVP-M.
+
+  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 gvp11.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_CYBERSTORM_SCSI
+  If you have an Amiga with an original (MkI) Phase5 Cyberstorm
+  accelerator board and the optional Cyberstorm SCSI controller,
+  answer Y. Otherwise, say N.
+
+CONFIG_CYBERSTORMII_SCSI
+  If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board
+  and the optional Cyberstorm SCSI controller, say Y. Otherwise,
+  answer N.
+
+CONFIG_BLZ2060_SCSI
+  If you have an Amiga with a Phase5 Blizzard 2060 accelerator board
+  and want to use the onboard SCSI controller, say Y. Otherwise,
+  answer N.
+
+CONFIG_BLZ1230_SCSI
+  If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard
+  1260 accelerator, and the optional SCSI module, say Y. Otherwise,
+  say N.
+
+CONFIG_BLZ603EPLUS_SCSI
+  If you have an Amiga 1200 with a Phase5 Blizzard PowerUP 603e+
+  accelerator, say Y. Otherwise, say N.
+
+CONFIG_FASTLANE_SCSI
+  If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use
+  one in the near future, say Y to this question. Otherwise, say N.
+
+CONFIG_OKTAGON_SCSI
+  If you have the BSC Oktagon SCSI disk controller for the Amiga, say
+  Y to this question.  If you're in doubt about whether you have one,
+  see the picture at
+  <http://amiga.multigraph.com/photos/oktagon.html>.
+
+CONFIG_SCSI_MESH
+  Many Power Macintoshes and clones have a MESH (Macintosh Enhanced
+  SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the
+  other Power Macintoshes do). Say Y to include support for this SCSI
+  adaptor. This driver is also available as a module called mesh.o
+  ( = 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>.
+
+CONFIG_SCSI_MESH_SYNC_RATE
+  On Power Macintoshes (and clones) where the MESH SCSI bus adaptor
+  drives a bus which is entirely internal to the machine (such as the
+  7500, 7600, 8500, etc.), the MESH is capable of synchronous
+  operation at up to 10 MB/s. On machines where the SCSI bus
+  controlled by the MESH can have external devices connected, it is
+  usually rated at 5 MB/s. 5 is a safe value here unless you know the
+  MESH SCSI bus is internal only; in that case you can say 10. Say 0
+  to disable synchronous operation.
+
+CONFIG_SCSI_MAC53C94
+  On Power Macintoshes (and clones) with two SCSI buses, the external
+  SCSI bus is usually controlled by a 53C94 SCSI bus adaptor. Older
+  machines which only have one SCSI bus, such as the 7200, also use
+  the 53C94. Say Y to include support for the 53C94.
+
+  This driver is also available as a module called mac53c94.o ( = 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>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v2.5.2/linux/drivers/scsi/NCR5380.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/scsi/NCR5380.c	Mon Jan 28 14:36:58 2002
@@ -692,9 +692,9 @@
 	}
 	restore_flags(flags);
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(instance->host_lock, flags);
 	run_main();
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(instance->host_lock, flags);
 }
 #endif				/* def USLEEP */
 
@@ -745,7 +745,7 @@
 	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)
+		if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", instance)
 					  == 0))
 			trying_irqs |= mask;
 
@@ -1271,7 +1271,7 @@
 	 * this should prevent any race conditions.
 	 */
 
-	spin_unlock_irq(&io_request_lock);
+	spin_unlock_irq(instance->host_lock);
 	
 	save_flags(flags);
 	
@@ -1424,7 +1424,7 @@
 				break;
 		}		/* for instance */
 	} while (!done);
-	spin_lock_irq(&io_request_lock);
+	spin_lock_irq(instance->host_lock);
   /* 	cli();*/
 	main_running = 0;
 }
@@ -1521,10 +1521,10 @@
 							{
 								unsigned long timeout = jiffies + NCR_TIMEOUT;
 
-								spin_unlock_irq(&io_request_lock);
+								spin_unlock_irq(instance->host_lock);
 								while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK
 								       && time_before(jiffies, timeout));
-								spin_lock_irq(&io_request_lock);
+								spin_lock_irq(instance->host_lock);
 								
 								if (time_after_eq(jiffies, timeout) )
 									printk("scsi%d: timeout at NCR5380.c:%d\n",
@@ -1554,10 +1554,12 @@
 
 static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) {
 	unsigned long flags;
-
-	 spin_lock_irqsave(&io_request_lock, flags);
+	 
+	 struct Scsi_Host *dev = dev_id;
+	
+	 spin_lock_irqsave(dev->host_lock, flags);
 	 NCR5380_intr(irq, dev_id, regs);
-	 spin_unlock_irqrestore(&io_request_lock, flags);
+	 spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 #endif
@@ -1669,12 +1671,12 @@
 	{
 		unsigned long timeout = jiffies + 2 * NCR_TIMEOUT;
 
-		spin_unlock_irq(&io_request_lock);
+		spin_unlock_irq(instance->host_lock);
 
 		while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
 		       && time_before(jiffies,timeout));
 
-		spin_lock_irq(&io_request_lock);
+		spin_lock_irq(instance->host_lock);
 		       
 		if (time_after_eq(jiffies,timeout)) {
 			printk("scsi: arbitration timeout at %d\n", __LINE__);
@@ -1834,10 +1836,10 @@
 	hostdata->selecting = 0; /* clear this pointer, because we passed the
 				waiting period */
 #else
-	spin_unlock_irq(&io_request_lock);
+	spin_unlock_irq(instance->host_lock);
 	while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) &
 					(SR_BSY | SR_IO)));
-	spin_lock_irq(&io_request_lock);
+	spin_lock_irq(instance->host_lock);
 #endif
 	if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) ==
 	    (SR_SEL | SR_IO)) {
@@ -1905,9 +1907,9 @@
 	{
 		unsigned long timeout = jiffies + NCR_TIMEOUT;
 
-		spin_unlock_irq(&io_request_lock);
+		spin_unlock_irq(instance->host_lock);
 		while (!(NCR5380_read(STATUS_REG) & SR_REQ) && time_before(jiffies, timeout));
-		spin_lock_irq(&io_request_lock);
+		spin_lock_irq(instance->host_lock);
 		
 		if (time_after_eq(jiffies, timeout)) {
 			printk("scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__);
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/NCR53C9x.c linux/drivers/scsi/NCR53C9x.c
--- v2.5.2/linux/drivers/scsi/NCR53C9x.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/NCR53C9x.c	Mon Jan 28 14:36:58 2002
@@ -3546,9 +3546,10 @@
 	struct NCR_ESP *esp;
 	unsigned long flags;
 	int again;
+	struct Scsi_Host *dev = dev_id;
 
 	/* Handle all ESP interrupts showing at this IRQ level. */
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(dev->host_lock, flags);
 repeat:
 	again = 0;
 	for_each_esp(esp) {
@@ -3572,7 +3573,7 @@
 	}
 	if(again)
 		goto repeat;
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 #else
 /* For SMP we only service one ESP on the list list at our IRQ level! */
@@ -3580,9 +3581,10 @@
 {
 	struct NCR_ESP *esp;
 	unsigned long flags;
-
+	struct Scsi_Host *dev = dev_id;
+	
 	/* Handle all ESP interrupts showing at this IRQ level. */
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(dev->host_lock, flags);
 	for_each_esp(esp) {
 		if(((esp)->irq & 0xf) == irq) {
 			if(esp->dma_irq_p(esp)) {
@@ -3599,7 +3601,7 @@
 		}
 	}
 out:
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 #endif
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c
--- v2.5.2/linux/drivers/scsi/NCR53c406a.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/NCR53c406a.c	Mon Jan 28 14:36:58 2002
@@ -537,7 +537,7 @@
     DEB(printk("NCR53c406a: using port_base %x\n", port_base));
     
     if(irq_level > 0) {
-        if(request_irq(irq_level, do_NCR53c406a_intr, 0, "NCR53c406a", NULL)){
+        if(request_irq(irq_level, do_NCR53c406a_intr, 0, "NCR53c406a", shpnt)){
             printk("NCR53c406a: unable to allocate IRQ %d\n", irq_level);
             goto err_release;
         }
@@ -780,10 +780,11 @@
      static void
 do_NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs){
     unsigned long flags;
-
-    spin_lock_irqsave(&io_request_lock, flags);
+    struct Scsi_Host * dev = dev_id;
+    
+    spin_lock_irqsave(dev->host_lock, flags);
     NCR53c406a_intr(0, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
      static void
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/README.st linux/drivers/scsi/README.st
--- v2.5.2/linux/drivers/scsi/README.st	Fri Nov  9 13:52:21 2001
+++ linux/drivers/scsi/README.st	Wed Jan 23 15:30:47 2002
@@ -2,7 +2,7 @@
 The driver is currently maintained by Kai M{kisara (email
 Kai.Makisara@metla.fi)
 
-Last modified: Thu Nov  1 22:41:59 2001 by makisara@kai.makisara.local
+Last modified: Tue Jan 22 21:08:57 2002 by makisara
 
 
 BASICS
@@ -86,6 +86,11 @@
 
 The compile options are defined in the file linux/drivers/scsi/st_options.h.
 
+4. If the open option O_NONBLOCK is used, open succeeds even if the
+drive is not ready. If O_NONBLOCK is not used, the driver waits for
+the drive to become ready. If this does not happen in ST_BLOCK_SECONDS
+seconds, open fails with the errno value EIO.
+
 
 BSD AND SYS V SEMANTICS
 
@@ -327,12 +332,19 @@
 	   0xffffff means that the default is not used any more.
 	MT_ST_DEF_DENSITY
 	MT_ST_DEF_DRVBUFFER
+	   Used to set or clear the density (8 bits), and drive buffer
+	   state (3 bits). If the value is MT_ST_CLEAR_DEFAULT
+	   (0xfffff) the default will not be used any more. Otherwise
+	   the lowermost bits of the value contain the new value of
+	   the parameter.
 	MT_ST_DEF_COMPRESSION
-	   Used to set or clear the density (8 bits), drive buffer
-	   state (3 bits), and compression (single bit). If the value is
-	   MT_ST_CLEAR_DEFAULT (0xfffff), the default will not be used
-	   any more. Otherwise the lower-most bits of the value contain
-	   the new value of the parameter.
+	   The compression default will not be used if the value of
+	   the lowermost byte is 0xff. Otherwise the lowermost bit
+	   contains the new default. If the bits 8-15 are set to a
+	   non-zero number, and this number is not 0xff, the number is
+	   used as the compression algorithm. The value
+	   MT_ST_CLEAR_DEFAULT can be used to clear the compression
+	   default.
 	MT_ST_SET_TIMEOUT
 	   Set the normal timeout in seconds for this device. The
 	   default is 900 seconds (15 minutes). The timeout should be
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/a2091.c linux/drivers/scsi/a2091.c
--- v2.5.2/linux/drivers/scsi/a2091.c	Thu Oct 25 13:53:48 2001
+++ linux/drivers/scsi/a2091.c	Mon Jan 28 14:36:58 2002
@@ -40,9 +40,9 @@
 		continue;
 
 	if (status & ISTR_INTS) {
-		spin_lock_irqsave(&io_request_lock, flags);
+		spin_lock_irqsave(instance->host_lock, flags);
 		wd33c93_intr (instance);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		spin_unlock_irqrestore(instance->host_lock, flags);
 	}
     }
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/a3000.c linux/drivers/scsi/a3000.c
--- v2.5.2/linux/drivers/scsi/a3000.c	Thu Oct 25 13:53:48 2001
+++ linux/drivers/scsi/a3000.c	Mon Jan 28 14:36:58 2002
@@ -30,14 +30,15 @@
 {
 	unsigned long flags;
 	unsigned int status = DMA(a3000_host)->ISTR;
-
+	struct Scsi_Host *dev = dummy;
+	
 	if (!(status & ISTR_INT_P))
 		return;
 	if (status & ISTR_INTS)
 	{
-		spin_lock_irqsave(&io_request_lock, flags);
+		spin_lock_irqsave(dev->host_lock, flags);
 		wd33c93_intr (a3000_host);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		spin_unlock_irqrestore(dev->host_lock, flags);
 	} else
 		printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n",
 		       status);
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.5.2/linux/drivers/scsi/advansys.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/advansys.c	Mon Jan 28 14:36:59 2002
@@ -1,4 +1,4 @@
-#define ASC_VERSION "3.3G"    /* AdvanSys Driver Version */
+#define ASC_VERSION "3.3GG"    /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
@@ -670,6 +670,9 @@
          1. Return an error from narrow boards if passed a 16 byte
             CDB. The wide board can already handle 16 byte CDBs.
 
+     3.3GG (01/02/02):
+	 1. hacks for lk 2.5 series (D. Gilbert)
+
   I. Known Problems/Fix List (XXX)
 
      1. Need to add memory mapping workaround. Test the memory mapping.
@@ -3610,6 +3613,23 @@
 #define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b))
 #endif /* CONFIG_PROC_FS */
 
+/*
+ * XXX - Release and acquire the io_request_lock. These macros are needed
+ * because the 2.4 kernel SCSI mid-level driver holds the 'io_request_lock'
+ * on entry to SCSI low-level drivers.
+ *
+ * These definitions and all code that uses code should be removed when the
+ * SCSI mid-level driver no longer holds the 'io_request_lock' on entry to
+ * SCSI low-level driver detect, queuecommand, and reset entrypoints.
+ *
+ * The interrupt flags values doesn't matter in the macros because the
+ * SCSI mid-level will save and restore the flags values before and after
+ * calling advansys_detect, advansys_queuecommand, and advansys_reset where
+ * these macros are used. We do want interrupts enabled after the lock is
+ * released so an explicit sti() is done. The driver only needs interrupts
+ * disabled when it acquires the per board lock.
+ */
+
 /* Asc Library return codes */
 #define ASC_TRUE        1
 #define ASC_FALSE       0
@@ -4054,6 +4074,7 @@
         ADVEEP_38C1600_CONFIG adv_38C1600_eep;  /* 38C1600 EEPROM config. */
     } eep_config;
     ulong                last_reset;            /* Saved last reset time */
+    spinlock_t lock;                            /* Board spinlock */
 #ifdef CONFIG_PROC_FS
     /* /proc/scsi/advansys/[0...] */
     char                 *prtbuf;               /* /proc print buffer */
@@ -4206,7 +4227,7 @@
 STATIC void       advansys_interrupt(int, void *, struct pt_regs *);
 STATIC void       advansys_select_queue_depths(struct Scsi_Host *,
                                                Scsi_Device *);
-STATIC void       asc_scsi_done_list(Scsi_Cmnd *);
+STATIC void       asc_scsi_done_list(Scsi_Cmnd *, int from_isr);
 STATIC int        asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC int        asc_build_req(asc_board_t *, Scsi_Cmnd *);
 STATIC int        adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **);
@@ -4799,6 +4820,9 @@
             memset(boardp, 0, sizeof(asc_board_t));
             boardp->id = asc_board_count - 1;
 
+            /* Initialize spinlock. */
+            boardp->lock = SPIN_LOCK_UNLOCKED; /* replaced by host_lock dpg */
+
             /*
              * Handle both narrow and wide boards.
              *
@@ -5511,7 +5535,7 @@
                 }
             } else {
                 ADV_CARR_T      *carrp;
-                int             req_cnt;
+                int             req_cnt = 0;
                 adv_req_t       *reqp = NULL;
                 int             sg_cnt = 0;
 
@@ -5845,7 +5869,9 @@
     boardp = ASC_BOARDP(shp);
     ASC_STATS(shp, queuecommand);
 
-    spin_lock_irqsave(&shp->host_lock, flags);
+    /* host_lock taken by mid-level prior to call but need to protect */
+    /* against own ISR */
+    spin_lock_irqsave(boardp->lock, flags);
 
     /*
      * Block new commands while handling a reset or abort request.
@@ -5862,7 +5888,7 @@
          * handling.
          */
         asc_enqueue(&boardp->done, scp, ASC_BACK);
-        spin_unlock_irqrestore(&shp->host_lock, flags);
+	spin_unlock_irqrestore(&boardp->lock, flags);
         return 0;
     }
 
@@ -5902,11 +5928,11 @@
     default:
         done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
         /* Interrupts could be enabled here. */
-        asc_scsi_done_list(done_scp);
+        asc_scsi_done_list(done_scp, 0);
         break;
     }
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
-    spin_unlock_irqrestore(&shp->host_lock, flags);
     return 0;
 }
 
@@ -5952,13 +5978,13 @@
     /*
      * Check for re-entrancy.
      */
-    spin_lock_irqsave(&shp->host_lock, flags);
+    spin_lock_irqsave(&boardp->lock, flags);
     if (boardp->flags & ASC_HOST_IN_RESET) {
-        spin_unlock_irqrestore(&shp->host_lock, flags);
+	spin_unlock_irqrestore(&boardp->lock, flags);
         return FAILED;
     }
     boardp->flags |= ASC_HOST_IN_RESET;
-    spin_unlock_irqrestore(&shp->host_lock, flags);
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
     if (ASC_NARROW_BOARD(boardp)) {
         /*
@@ -5989,11 +6015,7 @@
         }
 
         ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
-
-        /*
-         * Acquire the board lock.
-         */
-        spin_lock_irqsave(&shp->host_lock, flags);
+	spin_lock_irqsave(&boardp->lock, flags);
 
     } else {
         /*
@@ -6020,14 +6042,9 @@
             ret = FAILED;
             break;
         }
-        /*
-         * Acquire the board lock and ensure all requests completed by the
-         * microcode have been processed by calling AdvISR().
-         */
-        spin_lock_irqsave(&shp->host_lock, flags);
+	spin_lock_irqsave(&boardp->lock, flags);
         (void) AdvISR(adv_dvc_varp);
     }
-
     /* Board lock is held. */
 
     /*
@@ -6088,15 +6105,13 @@
 
     /* Clear reset flag. */
     boardp->flags &= ~ASC_HOST_IN_RESET;
-
-    /* Release the board. */
-    spin_unlock_irqrestore(&shp->host_lock, flags);
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
     /*
      * Complete all the 'done_scp' requests.
      */
     if (done_scp != NULL) {
-        asc_scsi_done_list(done_scp);
+        asc_scsi_done_list(done_scp, 0);
     }
 
     ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
@@ -6259,6 +6274,7 @@
     asc_board_t     *boardp;
     Scsi_Cmnd       *done_scp = NULL, *last_scp = NULL;
     Scsi_Cmnd       *new_last_scp;
+    struct Scsi_Host *shp;
 
     ASC_DBG(1, "advansys_interrupt: begin\n");
 
@@ -6267,17 +6283,17 @@
      * AscISR() will call asc_isr_callback().
      */
     for (i = 0; i < asc_board_count; i++) {
-	struct Scsi_Host *shp = asc_host[i];
+	shp = asc_host[i];
         boardp = ASC_BOARDP(shp);
         ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
             i, (ulong) boardp);
-        spin_lock_irqsave(&shp->host_lock, flags);
+        spin_lock_irqsave(&boardp->lock, flags);
         if (ASC_NARROW_BOARD(boardp)) {
             /*
              * Narrow Board
              */
-            if (AscIsIntPending(asc_host[i]->io_port)) {
-                ASC_STATS(asc_host[i], interrupt);
+            if (AscIsIntPending(shp->io_port)) {
+                ASC_STATS(shp, interrupt);
                 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
                 AscISR(&boardp->dvc_var.asc_dvc_var);
             }
@@ -6287,7 +6303,7 @@
              */
             ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
             if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
-                ASC_STATS(asc_host[i], interrupt);
+                ASC_STATS(shp, interrupt);
             }
         }
 
@@ -6327,7 +6343,7 @@
                 }
             }
         }
-        spin_unlock_irqrestore(&shp->host_lock, flags);
+        spin_unlock_irqrestore(&boardp->lock, flags);
     }
 
     /*
@@ -6336,7 +6352,8 @@
      *
      * Complete all requests on the done list.
      */
-    asc_scsi_done_list(done_scp);
+
+    asc_scsi_done_list(done_scp, 1);
 
     ASC_DBG(1, "advansys_interrupt: end\n");
     return;
@@ -6383,9 +6400,10 @@
  * Interrupts can be enabled on entry.
  */
 STATIC void
-asc_scsi_done_list(Scsi_Cmnd *scp)
+asc_scsi_done_list(Scsi_Cmnd *scp, int from_isr)
 {
     Scsi_Cmnd    *tscp;
+    ulong	  flags = 0;
 
     ASC_DBG(2, "asc_scsi_done_list: begin\n");
     while (scp != NULL) {
@@ -6394,7 +6412,11 @@
         REQPNEXT(scp) = NULL;
         ASC_STATS(scp->host, done);
         ASC_ASSERT(scp->scsi_done != NULL);
+	if (from_isr)
+	    spin_lock_irqsave(scp->host->host_lock, flags);
         scp->scsi_done(scp);
+	if (from_isr)
+	    spin_unlock_irqrestore(scp->host->host_lock, flags);
         scp = tscp;
     }
     ASC_DBG(2, "asc_scsi_done_list: done\n");
@@ -6728,7 +6750,9 @@
         slp = (struct scatterlist *) scp->request_buffer;
         for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
             asc_sg_head.sg_list[sgcnt].addr =
-                cpu_to_le32(virt_to_bus(slp->address));
+                cpu_to_le32(virt_to_bus(slp->address ? 
+		(unsigned char *)slp->address :
+		(unsigned char *)page_address(slp->page) + slp->offset));
             asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
         }
@@ -6986,7 +7010,9 @@
         for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
         {
             sg_block->sg_list[i].sg_addr =
-                cpu_to_le32(virt_to_bus(slp->address));
+                cpu_to_le32(virt_to_bus(slp->address ? 
+		(unsigned char *)slp->address :
+                (unsigned char *)page_address(slp->page) + slp->offset));
             sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v2.5.2/linux/drivers/scsi/aha152x.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/aha152x.c	Mon Jan 28 14:36:59 2002
@@ -1349,9 +1349,9 @@
 
 		printk(KERN_INFO "aha152x%d: trying software interrupt, ", HOSTNO);
 		SETPORT(DMACNTRL0, SWINT|INTEN);
-		spin_unlock_irq(&shpnt->host_lock);
+		spin_unlock_irq(shpnt->host_lock);
 		mdelay(1000);
-		spin_lock_irq(&shpnt->host_lock);
+		spin_lock_irq(shpnt->host_lock);
 		free_irq(shpnt->irq, shpnt);
 
 		if (!HOSTDATA(shpnt)->swint) {
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v2.5.2/linux/drivers/scsi/aha1542.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/aha1542.c	Mon Jan 28 14:36:59 2002
@@ -425,9 +425,9 @@
 	if (!shost)
 		panic("Splunge!");
 
-	spin_lock_irqsave(&shost->host_lock, flags);
+	spin_lock_irqsave(shost->host_lock, flags);
 	aha1542_intr_handle(shost, dev_id, regs);
-	spin_unlock_irqrestore(&shost->host_lock, flags);
+	spin_unlock_irqrestore(shost->host_lock, flags);
 }
 
 /* A "high" level interrupt handler */
@@ -1475,9 +1475,9 @@
 	 * check for timeout, and if we are doing something like this
 	 * we are pretty desperate anyways.
 	 */
-	spin_unlock_irq(&SCpnt->host->host_lock);
+	spin_unlock_irq(SCpnt->host->host_lock);
 	scsi_sleep(4 * HZ);
-	spin_lock_irq(&SCpnt->host->host_lock);
+	spin_lock_irq(SCpnt->host->host_lock);
 
 	WAIT(STATUS(SCpnt->host->io_port),
 	     STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
@@ -1539,9 +1539,9 @@
 	 * check for timeout, and if we are doing something like this
 	 * we are pretty desperate anyways.
 	 */
-	spin_unlock_irq(&SCpnt->host->host_lock);
+	spin_unlock_irq(SCpnt->host->host_lock);
 	scsi_sleep(4 * HZ);
-	spin_lock_irq(&SCpnt->host->host_lock);
+	spin_lock_irq(SCpnt->host->host_lock);
 
 	WAIT(STATUS(SCpnt->host->io_port),
 	     STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/aha1740.c linux/drivers/scsi/aha1740.c
--- v2.5.2/linux/drivers/scsi/aha1740.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/aha1740.c	Mon Jan 28 14:36:59 2002
@@ -224,7 +224,7 @@
 
     if (!host)
 	panic("aha1740.c: Irq from unknown host!\n");
-    spin_lock_irqsave(&host->host_lock, flags);
+    spin_lock_irqsave(host->host_lock, flags);
     base = host->io_port;
     number_serviced = 0;
 
@@ -299,7 +299,7 @@
 	number_serviced++;
     }
 
-    spin_unlock_irqrestore(&host->host_lock, flags);
+    spin_unlock_irqrestore(host->host_lock, flags);
 }
 
 int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/aic7xxx/Config.help linux/drivers/scsi/aic7xxx/Config.help
--- v2.5.2/linux/drivers/scsi/aic7xxx/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/Config.help	Fri Jan 25 16:03:37 2002
@@ -0,0 +1,39 @@
+CONFIG_SCSI_AIC7XXX
+  This driver supports all of Adaptec's PCI based SCSI controllers
+  (not the hardware RAID controllers though) as well as the aic7770
+  based EISA and VLB SCSI controllers (the 274x and 284x series).
+  This is an Adaptec sponsored driver written by Justin Gibbs.  It is
+  intended to replace the previous aic7xxx driver maintained by Doug
+  Ledford since Doug is no longer maintaining that driver.
+
+CONFIG_AIC7XXX_CMDS_PER_DEVICE
+  Specify the number of commands you would like to allocate per SCSI
+  device when Tagged Command Queueing (TCQ) is enabled on that device.
+
+  This is an upper bound value for the number of tagged transactions
+  to be used for any device.  The aic7xxx driver will automatically
+  vary this number based on device behavior.  For devices with a
+  fixed maximum, the driver will eventually lock to this maximum
+  and display a console message inidicating this value.
+
+  Note: Unless you experience some type of device failure, the default
+	value, no enforced limit, should work for you.
+
+  Default: 253
+
+CONFIG_AIC7XXX_RESET_DELAY_MS
+  The number of milliseconds to delay after an initial bus reset.
+  The bus settle delay following all error recovery actions is
+  dictated by the SCSI layer and is not affected by this value.
+
+  Default: 15000 (15 seconds)
+
+CONFIG_AIC7XXX_BUILD_FIRMWARE
+  This option should only be enabled if you are modifying the firmware
+  source to the aic7xxx driver and wish to have the generated firmware
+  include files updated during a normal kernel build.  The assembler
+  for the firmware requires lex and yacc or their equivalents, as well
+  as the db v1 library.  You may have to install additional packages
+  or modify the assembler make file or the files it includes if your
+  build environment is different than that of the author.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
--- v2.5.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Thu Jan 17 13:59:33 2002
@@ -1700,6 +1700,7 @@
 			       cmd->request_buffer,
 			       cmd->request_bufflen,
 			       scsi_to_pci_dma_dir(cmd->sc_data_direction));
+			scb->sg_count = 0;
 			scb->sg_count = ahc_linux_map_seg(ahc, scb,
 							  sg, addr,
 							  cmd->request_bufflen);
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c
--- v2.5.2/linux/drivers/scsi/aic7xxx_old.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/aic7xxx_old.c	Tue Jan 15 10:52:11 2002
@@ -4127,7 +4127,7 @@
   unsigned long cpu_flags = 0;
   struct aic7xxx_scb *scb;
 
-  spin_lock_irqsave(&p->host->host_lock, cpu_flags);
+  spin_lock_irqsave(p->host->host_lock, cpu_flags);
   p->dev_timer_active &= ~(0x01 << MAX_TARGETS);
   if ( (p->dev_timer_active & (0x01 << p->scsi_id)) &&
        time_after_eq(jiffies, p->dev_expires[p->scsi_id]) )
@@ -4184,7 +4184,7 @@
   }
 
   aic7xxx_run_waiting_queues(p);
-  spin_unlock_irqrestore(&p->host->host_lock, cpu_flags);
+  spin_unlock_irqrestore(p->host->host_lock, cpu_flags);
 }
 
 /*+F*************************************************************************
@@ -7011,7 +7011,7 @@
   p = (struct aic7xxx_host *)dev_id;
   if(!p)
     return;
-  spin_lock_irqsave(&p->host->host_lock, cpu_flags);
+  spin_lock_irqsave(p->host->host_lock, cpu_flags);
   p->flags |= AHC_IN_ISR;
   do
   {
@@ -7020,7 +7020,7 @@
   aic7xxx_done_cmds_complete(p);
   aic7xxx_run_waiting_queues(p);
   p->flags &= ~AHC_IN_ISR;
-  spin_unlock_irqrestore(&p->host->host_lock, cpu_flags);
+  spin_unlock_irqrestore(p->host->host_lock, cpu_flags);
 }
 
 /*+F*************************************************************************
@@ -11148,7 +11148,7 @@
   disable_irq(p->irq);
   aic7xxx_print_card(p);
   aic7xxx_print_scratch_ram(p);
-  spin_unlock_irq(&p->host->host_lock);
+  spin_unlock_irq(p->host->host_lock);
   for(;;) barrier();
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c
--- v2.5.2/linux/drivers/scsi/atp870u.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/atp870u.c	Mon Jan 28 14:36:59 2002
@@ -433,7 +433,7 @@
 			/*
 			 *	Complete the command
 			 */
-			spin_lock_irqsave(&io_request_lock, flags);
+			spin_lock_irqsave(workrequ->host->host_lock, flags);
 			(*workrequ->scsi_done) (workrequ);
 
 			/*
@@ -441,7 +441,7 @@
 			 */
 			dev->id[target_id].curr_req = 0;
 			dev->working--;
-			spin_unlock_irqrestore(&io_request_lock, flags);
+			spin_unlock_irqrestore(workrequ->host->host_lock, flags);
 			/*
 			 *	Take it back wide
 			 */
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/blz1230.c linux/drivers/scsi/blz1230.c
--- v2.5.2/linux/drivers/scsi/blz1230.c	Thu Oct 25 13:53:49 2001
+++ linux/drivers/scsi/blz1230.c	Mon Jan 28 14:36:59 2002
@@ -137,7 +137,7 @@
 		esp->irq = IRQ_AMIGA_PORTS;
 		esp->slot = board+REAL_BLZ1230_ESP_ADDR;
 		if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
-				 "Blizzard 1230 SCSI IV", esp_intr))
+				 "Blizzard 1230 SCSI IV", esp->ehost))
 			goto err_out;
 
 		/* Figure out our scsi ID on the bus */
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/blz2060.c linux/drivers/scsi/blz2060.c
--- v2.5.2/linux/drivers/scsi/blz2060.c	Thu Oct 25 13:53:49 2001
+++ linux/drivers/scsi/blz2060.c	Mon Jan 28 14:36:59 2002
@@ -115,7 +115,7 @@
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
-			    "Blizzard 2060 SCSI", esp_intr);
+			    "Blizzard 2060 SCSI", esp->ehost);
 
 		/* Figure out our scsi ID on the bus */
 		esp->scsi_id = 7;
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/cpqfcTSinit.c linux/drivers/scsi/cpqfcTSinit.c
--- v2.5.2/linux/drivers/scsi/cpqfcTSinit.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/cpqfcTSinit.c	Mon Jan 28 14:36:59 2002
@@ -242,7 +242,7 @@
   cpqfcHBAdata->notify_wt = &sem;
 
   /* must unlock before kernel_thread(), for it may cause a reschedule. */
-  spin_unlock_irq(&HostAdapter->host_lock);
+  spin_unlock_irq(HostAdapter->host_lock);
   kernel_thread((int (*)(void *))cpqfcTSWorkerThread, 
                           (void *) HostAdapter, 0);
   /*
@@ -250,7 +250,7 @@
 
    */
   down (&sem);
-  spin_lock_irq(&HostAdapter->host_lock);
+  spin_lock_irq(HostAdapter->host_lock);
   cpqfcHBAdata->notify_wt = NULL;
 
   LEAVE("launch_FC_worker_thread");
@@ -407,7 +407,7 @@
  
       // start our kernel worker thread
 
-      spin_lock_irq(&HostAdapter->host_lock);
+      spin_lock_irq(HostAdapter->host_lock);
       launch_FCworker_thread(HostAdapter);
 
 
@@ -447,16 +447,16 @@
 	
 	unsigned long stop_time;
 
-	spin_unlock_irq(&HostAdapter->host_lock);
+	spin_unlock_irq(HostAdapter->host_lock);
 	stop_time = jiffies + 4*HZ;
         while ( time_before(jiffies, stop_time) ) 
 	  	schedule();  // (our worker task needs to run)
 
       }
       
-      spin_lock_irq(&HostAdapter->host_lock);
+      spin_lock_irq(HostAdapter->host_lock);
       NumberOfAdapters++; 
-      spin_unlock_irq(&HostAdapter->host_lock);
+      spin_unlock_irq(HostAdapter->host_lock);
     } // end of while()
   }
 
@@ -1596,9 +1596,9 @@
   int retval;
   Scsi_Device *SDpnt = Cmnd->device;
   // printk("   ENTERING cpqfcTS_eh_device_reset() \n");
-  spin_unlock_irq(&Cmnd->host->host_lock);
+  spin_unlock_irq(Cmnd->host->host_lock);
   retval = cpqfcTS_TargetDeviceReset( SDpnt, 0);
-  spin_lock_irq(&Cmnd->host->host_lock);
+  spin_lock_irq(Cmnd->host->host_lock);
   return retval;
 }
 
@@ -1653,7 +1653,7 @@
   UCHAR IntPending;
   
   ENTER("intr_handler");
-  spin_lock_irqsave( &HostAdapter->host_lock, flags);
+  spin_lock_irqsave( HostAdapter->host_lock, flags);
   // is this our INT?
   IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address);
 
@@ -1702,7 +1702,7 @@
       }
     }      
   }
-  spin_unlock_irqrestore( &HostAdapter->host_lock, flags);
+  spin_unlock_irqrestore( HostAdapter->host_lock, flags);
   LEAVE("intr_handler");
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/cpqfcTSworker.c linux/drivers/scsi/cpqfcTSworker.c
--- v2.5.2/linux/drivers/scsi/cpqfcTSworker.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/cpqfcTSworker.c	Mon Jan 28 14:36:59 2002
@@ -200,7 +200,7 @@
     PCI_TRACE( 0x90)
     // first, take the IO lock so the SCSI upper layers can't call
     // into our _quecommand function (this also disables INTs)
-    spin_lock_irqsave( &HostAdapter->host_lock, flags); // STOP _que function
+    spin_lock_irqsave( HostAdapter->host_lock, flags); // STOP _que function
     PCI_TRACE( 0x90)
          
     CPQ_SPINLOCK_HBA( cpqfcHBAdata)
@@ -214,7 +214,7 @@
     PCI_TRACE( 0x90)
 
     // release the IO lock (and re-enable interrupts)
-    spin_unlock_irqrestore( &HostAdapter->host_lock, flags);
+    spin_unlock_irqrestore( HostAdapter->host_lock, flags);
 
     // disable OUR HBA interrupt (keep them off as much as possible
     // during error recovery)
@@ -3051,7 +3051,7 @@
     goto Skip;
 
   // STOP _que function
-  spin_lock_irqsave( &cpqfcHBAdata->HostAdapter->host_lock, flags); 
+  spin_lock_irqsave( cpqfcHBAdata->HostAdapter->host_lock, flags); 
 
   PCI_TRACE( 0xA8)
 
@@ -3059,7 +3059,7 @@
   cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing
   
   // release the IO lock (and re-enable interrupts)
-  spin_unlock_irqrestore( &cpqfcHBAdata->HostAdapter->host_lock, flags);
+  spin_unlock_irqrestore( cpqfcHBAdata->HostAdapter->host_lock, flags);
   
   // Ensure no contention from  _quecommand or Worker process 
   CPQ_SPINLOCK_HBA( cpqfcHBAdata)
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/cyberstorm.c linux/drivers/scsi/cyberstorm.c
--- v2.5.2/linux/drivers/scsi/cyberstorm.c	Thu Oct 25 13:53:50 2001
+++ linux/drivers/scsi/cyberstorm.c	Mon Jan 28 14:36:59 2002
@@ -136,7 +136,7 @@
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
-			    "CyberStorm SCSI", esp_intr);
+			    "CyberStorm SCSI", esp->ehost);
 		/* Figure out our scsi ID on the bus */
 		/* The DMA cond flag contains a hardcoded jumper bit
 		 * which can be used to select host number 6 or 7.
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/cyberstormII.c linux/drivers/scsi/cyberstormII.c
--- v2.5.2/linux/drivers/scsi/cyberstormII.c	Thu Oct 25 13:53:50 2001
+++ linux/drivers/scsi/cyberstormII.c	Mon Jan 28 14:36:59 2002
@@ -130,7 +130,7 @@
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
-			    "CyberStorm SCSI Mk II", esp_intr);
+			    "CyberStorm SCSI Mk II", esp->ehost);
 
 		/* Figure out our scsi ID on the bus */
 		esp->scsi_id = 7;
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/dec_esp.c linux/drivers/scsi/dec_esp.c
--- v2.5.2/linux/drivers/scsi/dec_esp.c	Sun Sep  9 10:52:35 2001
+++ linux/drivers/scsi/dec_esp.c	Mon Jan 28 14:36:59 2002
@@ -189,10 +189,10 @@
 		esp_initialize(esp);
 
 		if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, 
-				"NCR 53C94 SCSI", NULL))
+				"NCR 53C94 SCSI", esp->ehost))
 			goto err_dealloc;
 		if (request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, 
-				"JUNKIO SCSI DMA", NULL))
+				"JUNKIO SCSI DMA", esp->ehost))
 			goto err_free_irq;
  			
 	}
@@ -253,7 +253,7 @@
 			esp->dma_advance_sg = 0;
 
  			if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, 
- 					 "PMAZ_AA", NULL)) {
+ 					 "PMAZ_AA", esp->ehost)) {
  				esp_deallocate(esp);
  				release_tc_card(slot);
  				continue;
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/dpt_i2o.c linux/drivers/scsi/dpt_i2o.c
--- v2.5.2/linux/drivers/scsi/dpt_i2o.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/dpt_i2o.c	Mon Jan 28 14:36:59 2002
@@ -1158,12 +1158,12 @@
 	timeout *= HZ;
 	if((status = adpt_i2o_post_this(pHba, msg, len)) == 0){
 		set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irq(&pHba->host->host_lock);
+		spin_unlock_irq(pHba->host->host_lock);
 		if (!timeout)
 			schedule();
 		else
 			schedule_timeout(timeout*HZ);
-		spin_lock_irq(&pHba->host->host_lock);
+		spin_lock_irq(pHba->host->host_lock);
 	}
 	wq_write_lock_irq(&adpt_wq_i2o_post.lock);
 	__remove_wait_queue(&adpt_wq_i2o_post, &wait);
@@ -1701,7 +1701,7 @@
 	}
 
 	do {
-		spin_lock_irqsave(&pHba->host->host_lock, flags);
+		spin_lock_irqsave(pHba->host->host_lock, flags);
 		// This state stops any new commands from enterring the
 		// controller while processing the ioctl
 //		pHba->state |= DPTI_STATE_IOCTL;
@@ -1709,7 +1709,7 @@
 //		the queue empties and stops.  We need a way to restart the queue
 		rcode = adpt_i2o_post_wait(pHba, msg, size, FOREVER);
 //		pHba->state &= ~DPTI_STATE_IOCTL;
-		spin_unlock_irqrestore(&pHba->host->host_lock, flags);
+		spin_unlock_irqrestore(pHba->host->host_lock, flags);
 	} while(rcode == -ETIMEDOUT);  
 
 	if(rcode){
@@ -1947,9 +1947,9 @@
 		break;
 		}
 	case I2ORESETCMD:
-		spin_lock_irqsave(&pHba->host->host_lock, flags);
+		spin_lock_irqsave(pHba->host->host_lock, flags);
 		adpt_hba_reset(pHba);
-		spin_unlock_irqrestore(&pHba->host->host_lock, flags);
+		spin_unlock_irqrestore(pHba->host->host_lock, flags);
 		break;
 	case I2ORESCANCMD:
 		adpt_rescan(pHba);
@@ -1996,7 +1996,7 @@
 		printk(KERN_WARNING"adpt_isr: NULL dev_id\n");
 		return;
 	}
-	spin_lock_irqsave(&pHba->host->host_lock, flags);
+	spin_lock_irqsave(pHba->host->host_lock, flags);
 	while( readl(pHba->irq_mask) & I2O_INTERRUPT_PENDING_B) {
 		m = readl(pHba->reply_port);
 		if(m == EMPTY_QUEUE){
@@ -2061,7 +2061,7 @@
 		wmb();
 		rmb();
 	}
-out:	spin_unlock_irqrestore(&pHba->host->host_lock, flags);
+out:	spin_unlock_irqrestore(pHba->host->host_lock, flags);
 }
 
 static s32 adpt_scsi_to_i2o(adpt_hba* pHba, Scsi_Cmnd* cmd, struct adpt_device* d)
@@ -2334,13 +2334,13 @@
 	s32 rcode;
 	ulong flags;
 
-	spin_lock_irqsave(&pHba->host->host_lock, flags);
+	spin_lock_irqsave(pHba->host->host_lock, flags);
 	if ((rcode=adpt_i2o_lct_get(pHba)) < 0)
 		goto out;
 	if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0)
 		goto out;
 	rcode = 0;
-out:	spin_unlock_irqrestore(&pHba->host->host_lock, flags);
+out:	spin_unlock_irqrestore(pHba->host->host_lock, flags);
 	return rcode;
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/dtc.c linux/drivers/scsi/dtc.c
--- v2.5.2/linux/drivers/scsi/dtc.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/dtc.c	Mon Jan 28 14:36:59 2002
@@ -259,7 +259,7 @@
 /* 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")) {
+	 if (request_irq(instance->irq, do_dtc_intr, SA_INTERRUPT, "dtc", instance)) {
 	 printk("scsi%d : IRQ%d not free, interrupts disabled\n",
 	      instance->host_no, instance->irq);
 	 instance->irq = IRQ_NONE;
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v2.5.2/linux/drivers/scsi/eata.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/eata.c	Mon Jan 28 14:36:59 2002
@@ -1712,10 +1712,10 @@
 
    HD(j)->in_reset = TRUE;
 
-   spin_unlock_irq(&sh[j]->host_lock);
+   spin_unlock_irq(sh[j]->host_lock);
    time = jiffies;
    while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
-   spin_lock_irq(&sh[j]->host_lock);
+   spin_lock_irq(sh[j]->host_lock);
 
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
@@ -2171,9 +2171,9 @@
    /* Check if the interrupt must be processed by this handler */
    if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
 
-   spin_lock_irqsave(&sh[j]->host_lock, spin_flags);
+   spin_lock_irqsave(sh[j]->host_lock, spin_flags);
    ihdlr(irq, j);
-   spin_unlock_irqrestore(&sh[j]->host_lock, spin_flags);
+   spin_unlock_irqrestore(sh[j]->host_lock, spin_flags);
 }
 
 int eata2x_release(struct Scsi_Host *shpnt) {
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c
--- v2.5.2/linux/drivers/scsi/eata_dma.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/eata_dma.c	Mon Jan 28 14:36:59 2002
@@ -229,10 +229,11 @@
 void do_eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
 {
     unsigned long flags;
-
-    spin_lock_irqsave(&io_request_lock, flags);
+    struct Scsi_Host *dev = dev_id;
+    
+    spin_lock_irqsave(dev->host_lock, flags);
     eata_int_handler(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
@@ -1503,7 +1504,7 @@
 	if (reg_IRQ[i] >= 1){       /* exchange the interrupt handler which  */
 	    free_irq(i, NULL);      /* we used for probing with the real one */
 	    request_irq(i, (void *)(do_eata_int_handler), SA_INTERRUPT|SA_SHIRQ, 
-			"eata_dma", NULL);
+			"eata_dma", first_HBA); /* Check it */
 	}
     }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c
--- v2.5.2/linux/drivers/scsi/eata_pio.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/eata_pio.c	Mon Jan 28 14:36:59 2002
@@ -110,10 +110,11 @@
 void do_eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
 {
     unsigned long flags;
-
-    spin_lock_irqsave(&io_request_lock, flags);
+    struct Scsi_Host *dev = dev_id;
+    
+    spin_lock_irqsave(dev->host_lock, flags);
     eata_pio_int_handler(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
@@ -704,34 +705,36 @@
 	return (FALSE);
     }
     
+    request_region(base, 8, "eata_pio");
+    
+    size = sizeof(hostdata) + (sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
+    
+    sh = scsi_register(tpnt, size);
+    if(sh == NULL)
+    {
+    	release_region(base, 8);
+    	return FALSE;
+    }
+    
     if (!reg_IRQ[gc->IRQ]) {    /* Interrupt already registered ? */
 	if (!request_irq(gc->IRQ, do_eata_pio_int_handler, SA_INTERRUPT, 
-			 "EATA-PIO", NULL)){
+			 "EATA-PIO", sh)){
 	    reg_IRQ[gc->IRQ]++;
 	    if (!gc->IRQ_TR)
 		reg_IRQL[gc->IRQ] = TRUE;   /* IRQ is edge triggered */
 	} else {
 	    printk("Couldn't allocate IRQ %d, Sorry.\n", gc->IRQ);
+	    release_region(base, 8);
 	    return (FALSE);
 	}
     } else {            /* More than one HBA on this IRQ */
 	if (reg_IRQL[gc->IRQ] == TRUE) {
 	    printk("Can't support more than one HBA on this IRQ,\n"
 		   "  if the IRQ is edge triggered. Sorry.\n");
+	    release_region(base, 8);
 	    return (FALSE);
 	} else
 	    reg_IRQ[gc->IRQ]++;
-    }
-    
-    request_region(base, 8, "eata_pio");
-    
-    size = sizeof(hostdata) + (sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
-    
-    sh = scsi_register(tpnt, size);
-    if(sh == NULL)
-    {
-    	release_region(base, 8);
-    	return FALSE;
     }
     
     hd = SD(sh);                   
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
--- v2.5.2/linux/drivers/scsi/esp.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/esp.c	Mon Jan 28 14:36:59 2002
@@ -1,4 +1,4 @@
-/* $Id: esp.c,v 1.100 2001/12/11 04:55:48 davem Exp $
+/* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $
  * esp.c:  EnhancedScsiProcessor Sun SCSI driver code.
  *
  * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
@@ -813,7 +813,7 @@
 	 * sanely maintain.
 	 */
 	if (request_irq(esp->ehost->irq, esp_intr,
-			SA_SHIRQ, "ESP SCSI", esp)) {
+			SA_SHIRQ, "ESP SCSI", esp->ehost)) {
 		printk("esp%d: Cannot acquire irq line\n",
 		       esp->esp_id);
 		return -1;
@@ -1918,7 +1918,7 @@
 	unsigned long flags;
 	int don;
 
-	spin_lock_irqsave(&esp->ehost->host_lock, flags);
+	spin_lock_irqsave(esp->ehost->host_lock, flags);
 
 	ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
 	esp_dump_state(esp);
@@ -1934,7 +1934,7 @@
 		esp->msgout_len = 1;
 		esp->msgout_ctr = 0;
 		esp_cmd(esp, ESP_CMD_SATN);
-		spin_unlock_irqrestore(&esp->ehost->host_lock, flags);
+		spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 		return SCSI_ABORT_PENDING;
 	}
 
@@ -1963,7 +1963,7 @@
 				if (don)
 					ESP_INTSON(esp->dregs);
 
-				spin_unlock_irqrestore(&esp->ehost->host_lock, flags);
+				spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 				return SCSI_ABORT_SUCCESS;
 			}
 		}
@@ -1977,7 +1977,7 @@
 	if (esp->current_SC) {
 		if (don)
 			ESP_INTSON(esp->dregs);
-		spin_unlock_irqrestore(&esp->ehost->host_lock, flags);
+		spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 		return SCSI_ABORT_BUSY;
 	}
 
@@ -1990,7 +1990,7 @@
 
 	if (don)
 		ESP_INTSON(esp->dregs);
-	spin_unlock_irqrestore(&esp->ehost->host_lock, flags);
+	spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 	return SCSI_ABORT_SNOOZE;
 }
 
@@ -2052,9 +2052,9 @@
 	struct esp *esp = (struct esp *) SCptr->host->hostdata;
 	unsigned long flags;
 
-	spin_lock_irqsave(&esp->ehost->host_lock, flags);
+	spin_lock_irqsave(esp->ehost->host_lock, flags);
 	(void) esp_do_resetbus(esp);
-	spin_unlock_irqrestore(&esp->ehost->host_lock, flags);
+	spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 
 	return SCSI_RESET_PENDING;
 }
@@ -4321,7 +4321,7 @@
 	struct esp *esp = dev_id;
 	unsigned long flags;
 
-	spin_lock_irqsave(&esp->ehost->host_lock, flags);
+	spin_lock_irqsave(esp->ehost->host_lock, flags);
 	if (ESP_IRQ_P(esp->dregs)) {
 		ESP_INTSOFF(esp->dregs);
 
@@ -4331,7 +4331,7 @@
 
 		ESP_INTSON(esp->dregs);
 	}
-	spin_unlock_irqrestore(&esp->ehost->host_lock, flags);
+	spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 }
 
 int esp_revoke(Scsi_Device* SDptr)
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/fastlane.c linux/drivers/scsi/fastlane.c
--- v2.5.2/linux/drivers/scsi/fastlane.c	Thu Oct 25 13:53:51 2001
+++ linux/drivers/scsi/fastlane.c	Mon Jan 28 14:36:59 2002
@@ -167,7 +167,7 @@
 		esp->irq = IRQ_AMIGA_PORTS;
 		esp->slot = board+FASTLANE_ESP_ADDR;
 		if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
-				"Fastlane SCSI", esp_intr)) {
+				"Fastlane SCSI", esp->ehost)) {
 			printk(KERN_WARNING "Fastlane: Could not get IRQ%d, aborting.\n", IRQ_AMIGA_PORTS);
 			goto err_unmap;
 		}			
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/fd_mcs.c linux/drivers/scsi/fd_mcs.c
--- v2.5.2/linux/drivers/scsi/fd_mcs.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/fd_mcs.c	Mon Jan 28 14:36:59 2002
@@ -740,9 +740,9 @@
 #if EVERY_ACCESS
       printk( " AFAIL " );
 #endif
-      spin_lock_irqsave(&io_request_lock, flags);
+      spin_lock_irqsave(shpnt->host_lock, flags);
       my_done( shpnt, DID_BUS_BUSY << 16 );
-      spin_unlock_irqrestore(&io_request_lock, flags);
+      spin_unlock_irqrestore(shpnt->host_lock, flags);
       return;
     }
     current_SC->SCp.phase = in_selection;
@@ -766,9 +766,9 @@
 #if EVERY_ACCESS
 	printk( " SFAIL " );
 #endif
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(shpnt->host_lock, flags);
 	my_done( shpnt, DID_NO_CONNECT << 16 );
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(shpnt->host_lock, flags);
 	return;
       } else {
 #if EVERY_ACCESS
@@ -1117,11 +1117,11 @@
 #if EVERY_ACCESS
     printk( "BEFORE MY_DONE. . ." );
 #endif
-    spin_lock_irqsave(&io_request_lock, flags);
+    spin_lock_irqsave(shpnt->host_lock, flags);
     my_done( shpnt,
 	     (current_SC->SCp.Status & 0xff)
 	     | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) );
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    spin_unlock_irqrestore(shpnt->host_lock, flags);
 #if EVERY_ACCESS
     printk( "RETURNING.\n" );
 #endif
@@ -1342,9 +1342,9 @@
   restore_flags( flags );
    
   /* Aborts are not done well. . . */
-  spin_lock_irqsave(&io_request_lock, flags);
+  spin_lock_irqsave(shpnt->host_lock, flags);
   my_done( shpnt, DID_ABORT << 16 );
-  spin_unlock_irqrestore(&io_request_lock, flags);
+  spin_unlock_irqrestore(shpnt->host_lock, flags);
 
   return SCSI_ABORT_SUCCESS;
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- v2.5.2/linux/drivers/scsi/fdomain.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/fdomain.c	Mon Jan 28 14:36:59 2002
@@ -1266,9 +1266,9 @@
 #if EVERY_ACCESS
 	 printk( " AFAIL " );
 #endif
-         spin_lock_irqsave(&current_SC->host->host_lock, flags);
+         spin_lock_irqsave(current_SC->host->host_lock, flags);
 	 my_done( DID_BUS_BUSY << 16 );
-         spin_unlock_irqrestore(&current_SC->host->host_lock, flags);
+         spin_unlock_irqrestore(current_SC->host->host_lock, flags);
 	 return;
       }
       current_SC->SCp.phase = in_selection;
@@ -1292,9 +1292,9 @@
 #if EVERY_ACCESS
 	    printk( " SFAIL " );
 #endif
-            spin_lock_irqsave(&current_SC->host->host_lock, flags);
+            spin_lock_irqsave(current_SC->host->host_lock, flags);
 	    my_done( DID_NO_CONNECT << 16 );
-            spin_unlock_irqrestore(&current_SC->host->host_lock, flags);
+            spin_unlock_irqrestore(current_SC->host->host_lock, flags);
 	    return;
 	 } else {
 #if EVERY_ACCESS
@@ -1639,10 +1639,10 @@
 #if EVERY_ACCESS
       printk( "BEFORE MY_DONE. . ." );
 #endif
-      spin_lock_irqsave(&current_SC->host->host_lock, flags);
+      spin_lock_irqsave(current_SC->host->host_lock, flags);
       my_done( (current_SC->SCp.Status & 0xff)
 	       | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) );
-      spin_unlock_irqrestore(&current_SC->host->host_lock, flags);
+      spin_unlock_irqrestore(current_SC->host->host_lock, flags);
 #if EVERY_ACCESS
       printk( "RETURNING.\n" );
 #endif
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c
--- v2.5.2/linux/drivers/scsi/gdth.c	Fri Nov  9 14:05:06 2001
+++ linux/drivers/scsi/gdth.c	Mon Jan 28 18:48:08 2002
@@ -629,19 +629,19 @@
 #define GDTH_LOCK_HA(ha,flags)          spin_lock_irqsave(&(ha)->smp_lock,flags)
 #define GDTH_UNLOCK_HA(ha,flags)        spin_unlock_irqrestore(&(ha)->smp_lock,flags)
 
-#define GDTH_LOCK_SCSI_DONE(flags)      spin_lock_irqsave(&io_request_lock,flags)
-#define GDTH_UNLOCK_SCSI_DONE(flags)    spin_unlock_irqrestore(&io_request_lock,flags)
-#define GDTH_LOCK_SCSI_DOCMD()          spin_lock_irq(&io_request_lock)
-#define GDTH_UNLOCK_SCSI_DOCMD()        spin_unlock_irq(&io_request_lock)
+#define GDTH_LOCK_SCSI_DONE(dev, flags)      spin_lock_irqsave(dev->host_lock,flags)
+#define GDTH_UNLOCK_SCSI_DONE(flags)    spin_unlock_irqrestore(dev->host_lock,flags)
+#define GDTH_LOCK_SCSI_DOCMD(dev)          spin_lock_irq(dev->host_lock)
+#define GDTH_UNLOCK_SCSI_DOCMD(dev)        spin_unlock_irq(dev->host_lock)
 #else
 #define GDTH_INIT_LOCK_HA(ha)           do {} while (0)
 #define GDTH_LOCK_HA(ha,flags)          do {save_flags(flags); cli();} while (0)
 #define GDTH_UNLOCK_HA(ha,flags)        do {restore_flags(flags);} while (0)
 
-#define GDTH_LOCK_SCSI_DONE(flags)      do {} while (0)
-#define GDTH_UNLOCK_SCSI_DONE(flags)    do {} while (0)
-#define GDTH_LOCK_SCSI_DOCMD()          do {} while (0)
-#define GDTH_UNLOCK_SCSI_DOCMD()        do {} while (0)
+#define GDTH_LOCK_SCSI_DONE(dev, flags)      do {} while (0)
+#define GDTH_UNLOCK_SCSI_DONE(dev, flags)    do {} while (0)
+#define GDTH_LOCK_SCSI_DOCMD(dev)          do {} while (0)
+#define GDTH_UNLOCK_SCSI_DOCMD(dev)        do {} while (0)
 #endif
 
 /* LILO and modprobe/insmod parameters */
@@ -3339,9 +3339,9 @@
     if (rval == 2) {
         gdth_putq(hanum,scp,scp->SCp.this_residual);
     } else if (rval == 1) {
-        GDTH_LOCK_SCSI_DONE(flags);
+        GDTH_LOCK_SCSI_DONE(scp->host, flags);
         scp->scsi_done(scp);
-        GDTH_UNLOCK_SCSI_DONE(flags);
+        GDTH_UNLOCK_SCSI_DONE(scp->host,flags);
     }
     gdth_next(hanum);
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/gvp11.c linux/drivers/scsi/gvp11.c
--- v2.5.2/linux/drivers/scsi/gvp11.c	Thu Oct 25 13:53:51 2001
+++ linux/drivers/scsi/gvp11.c	Mon Jan 28 14:36:59 2002
@@ -40,9 +40,9 @@
 	if (!(status & GVP11_DMAC_INT_PENDING))
 	    continue;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(instance->host_lock, flags);
 	wd33c93_intr (instance);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(instance->host_lock, flags);
     }
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c
--- v2.5.2/linux/drivers/scsi/ibmmca.c	Tue May  1 16:05:00 2001
+++ linux/drivers/scsi/ibmmca.c	Mon Jan 28 18:48:08 2002
@@ -41,8 +41,8 @@
 /* current version of this driver-source: */
 #define IBMMCA_SCSI_DRIVER_VERSION "4.0b"
 
-#define IBMLOCK spin_lock_irqsave(&io_request_lock, flags);
-#define IBMUNLOCK spin_unlock_irqrestore(&io_request_lock, flags);
+#define IBMLOCK(dev) spin_lock_irqsave(dev->host_lock, flags);
+#define IBMUNLOCK(dev) spin_unlock_irqrestore(dev->host_lock, flags);
 
 /* driver configuration */
 #define IM_MAX_HOSTS     8 /* maximum number of host adapters */
@@ -505,14 +505,14 @@
    Scsi_Cmnd *cmd;
    int lastSCSI;
 
-   IBMLOCK
+   IBMLOCK(dev_id)
    /* search for one adapter-response on shared interrupt */
    for (host_index=0;
 	hosts[host_index] && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST);
 	host_index++);
    /* return if some other device on this IRQ caused the interrupt */
    if (!hosts[host_index]) {
-      IBMUNLOCK
+      IBMUNLOCK(dev_id)
       return;
    }
 
@@ -521,15 +521,15 @@
    if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT)||
        (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT)) {
       reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS;
-      IBMUNLOCK
+      IBMUNLOCK(dev_id)
       return;
    }
 
    /*must wait for attention reg not busy, then send EOI to subsystem */
    while (1) {
       if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) break;
-      IBMUNLOCK /* cycle interrupt */
-      IBMLOCK
+      IBMUNLOCK(dev_id) /* cycle interrupt */
+      IBMLOCK(dev_id)
    }
    ihost_index=host_index;
    /*get command result and logical device */
@@ -539,7 +539,7 @@
    /* get the last_scsi_command here */
    lastSCSI = last_scsi_command(ihost_index)[ldn];
    outb (IM_EOI | ldn, IM_ATTN_REG(ihost_index));
-   IBMUNLOCK
+   IBMUNLOCK(dev_id)
    /*these should never happen (hw fails, or a local programming bug) */
    if (!global_command_error_excuse) {
       switch (cmd_result) {
@@ -731,14 +731,14 @@
    unsigned long flags;
    /* must wait for attention reg not busy */
    while (1) {
-      IBMLOCK
+      IBMLOCK(hosts[host_index])
       if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY)) break;
-      IBMUNLOCK
+      IBMUNLOCK(hosts[host_index])
    }
    /* write registers and enable system interrupts */
    outl (cmd_reg, IM_CMD_REG(host_index));
    outb (attn_reg, IM_ATTN_REG(host_index));
-   IBMUNLOCK
+   IBMUNLOCK(hosts[host_index])
    return;
 }
 
@@ -1442,7 +1442,7 @@
    unsigned int pos[8];
    unsigned long flags;
 
-   IBMLOCK
+   IBMLOCK(dev)
    shpnt = dev; /* assign host-structure to local pointer */
    len = 0; /* set filled text-buffer index to 0 */
    /* get the _special contents of the hostdata structure */
@@ -1496,7 +1496,7 @@
    while ( len % sizeof( int ) != ( sizeof ( int ) - 1 ) )
      len += sprintf (buf+len, " ");
    len += sprintf (buf+len, "\n");
-   IBMUNLOCK
+   IBMUNLOCK(shpnt)
    return len;
 }
 
@@ -2192,7 +2192,7 @@
 #ifdef IM_DEBUG_PROBE
    printk("IBM MCA SCSI: Abort subroutine called...\n");
 #endif
-   IBMLOCK
+   IBMLOCK(cmd->host)
    shpnt = cmd->host;
    /* search for the right hostadapter */
    for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
@@ -2201,7 +2201,7 @@
       cmd->result = DID_NO_CONNECT << 16;
       if (cmd->scsi_done) (cmd->scsi_done) (cmd);
       shpnt = cmd->host;
-      IBMUNLOCK
+      IBMUNLOCK(shpnt)
 #ifdef IM_DEBUG_PROBE
       printk("IBM MCA SCSI: Abort adapter selection failed!\n");
 #endif
@@ -2224,7 +2224,7 @@
 
    /*if cmd for this ldn has already finished, no need to abort */
    if (!ld(host_index)[ldn].cmd) {
-      IBMUNLOCK
+      IBMUNLOCK(shpnt)
       return SCSI_ABORT_NOT_RUNNING;
    }
 
@@ -2244,13 +2244,13 @@
    while (1) {
       if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
 	break;
-      IBMUNLOCK
-      IBMLOCK
+      IBMUNLOCK(shpnt)
+      IBMLOCK(shpnt)
    }
    /* write registers and enable system interrupts */
    outl (imm_command, IM_CMD_REG(host_index));
    outb (IM_IMM_CMD | ldn, IM_ATTN_REG(host_index));
-   IBMUNLOCK
+   IBMUNLOCK(shpnt)
 #ifdef IM_DEBUG_PROBE
    printk("IBM MCA SCSI: Abort queued to adapter...\n");
 #endif
@@ -2262,21 +2262,21 @@
 
    /*if abort went well, call saved done, then return success or error */
    if (cmd->result == (DID_ABORT << 16)) {
-      IBMLOCK
+      IBMLOCK(shpnt)
       cmd->result |= DID_ABORT << 16;
       if (cmd->scsi_done) (cmd->scsi_done) (cmd);
       ld(host_index)[ldn].cmd = NULL;
-      IBMUNLOCK
+      IBMUNLOCK(shpnt)
 #ifdef IM_DEBUG_PROBE
       printk("IBM MCA SCSI: Abort finished with success.\n");
 #endif
       return SCSI_ABORT_SUCCESS;
    } else {
-      IBMLOCK
+      IBMLOCK(shpnt)
       cmd->result |= DID_NO_CONNECT << 16;
       if (cmd->scsi_done) (cmd->scsi_done) (cmd);
       ld(host_index)[ldn].cmd = NULL;
-      IBMUNLOCK
+      IBMUNLOCK(shpnt)
 #ifdef IM_DEBUG_PROBE
       printk("IBM MCA SCSI: Abort failed.\n");
 #endif
@@ -2297,7 +2297,7 @@
       printk("IBM MCA SCSI: Reset called with NULL-command!\n");
       return(SCSI_RESET_SNOOZE);
    }
-   IBMLOCK
+   IBMLOCK(cmd->host)
    ticks = IM_RESET_DELAY*HZ;
    shpnt = cmd->host;
    /* search for the right hostadapter */
@@ -2308,7 +2308,7 @@
 
    if (local_checking_phase_flag(host_index)) {
       printk("IBM MCA SCSI: unable to reset while checking devices.\n");
-      IBMUNLOCK
+      IBMUNLOCK(shpnt)
       return SCSI_RESET_SNOOZE;
    }
 
@@ -2324,8 +2324,8 @@
    while (1) {
       if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
 	break;
-      IBMUNLOCK
-      IBMLOCK
+      IBMUNLOCK(shpnt)
+      IBMLOCK(shpnt)
    }
    /*write registers and enable system interrupts */
    outl (imm_command, IM_CMD_REG(host_index));
@@ -2342,7 +2342,7 @@
       printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
 	     IM_RESET_DELAY);
       reset_status(host_index) = IM_RESET_FINISHED_FAIL;
-      IBMUNLOCK
+      IBMUNLOCK(shpnt)
       return SCSI_RESET_ERROR;
    }
 
@@ -2360,13 +2360,13 @@
    /* if reset failed, just return an error */
    if (reset_status(host_index) == IM_RESET_FINISHED_FAIL) {
       printk("IBM MCA SCSI: reset failed.\n");
-      IBMUNLOCK
+      IBMUNLOCK(shpnt)
       return SCSI_RESET_ERROR;
    }
 
    /* so reset finished ok - call outstanding done's, and return success */
    printk ("IBM MCA SCSI: Reset successfully completed.\n");
-   IBMUNLOCK
+   IBMUNLOCK(shpnt)
    for (i = 0; i < MAX_LOG_DEV; i++) {
       cmd_aid = ld(host_index)[i].cmd;
       if (cmd_aid && cmd_aid->scsi_done) {
@@ -2454,8 +2454,8 @@
    unsigned long flags;
    int max_pun;
 
-   IBMLOCK
    for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++);
+   IBMLOCK(hosts[i]) /* Check it */
    shpnt = hosts[i];
    host_index = i;
    if (!shpnt) {
@@ -2537,7 +2537,7 @@
    *start = buffer + offset;
    len -= offset;
    if (len > length) len = length;
-   IBMUNLOCK
+   IBMUNLOCK(shpnt)
    return len;
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.5.2/linux/drivers/scsi/ide-scsi.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/ide-scsi.c	Tue Jan 15 11:27:47 2002
@@ -530,28 +530,33 @@
 	return 0;
 }
 
+int idescsi_reinit(ide_drive_t *drive);
+
 /*
  *	IDE subdriver functions, registered with ide.c
  */
 static ide_driver_t idescsi_driver = {
-	"ide-scsi",		/* name */
-	IDESCSI_VERSION,	/* version */
-	ide_scsi,		/* media */
-	0,			/* busy */
-	1,			/* supports_dma */
-	0,			/* supports_dsc_overlap */
-	idescsi_cleanup,	/* cleanup */
-	idescsi_do_request,	/* do_request */
-	idescsi_end_request,	/* end_request */
-	NULL,			/* ioctl */
-	idescsi_open,		/* open */
-	idescsi_ide_release,	/* release */
-	NULL,			/* media_change */
-	NULL,			/* revalidate */
-	NULL,			/* pre_reset */
-	NULL,			/* capacity */
-	NULL,			/* special */
-	NULL			/* proc */
+	name:			"ide-scsi",
+	version:		IDESCSI_VERSION,
+	media:			ide_scsi,
+	busy:			0,
+	supports_dma:		1,
+	supports_dsc_overlap:	0,
+	cleanup:		idescsi_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
+	do_request:		idescsi_do_request,
+	end_request:		idescsi_end_request,
+	ioctl:			NULL,
+	open:			idescsi_open,
+	release:		idescsi_ide_release,
+	media_change:		NULL,
+	revalidate:		NULL,
+	pre_reset:		NULL,
+	capacity:		NULL,
+	special:		NULL,
+	proc:			NULL,
+	driver_reinit:		idescsi_reinit,
 };
 
 int idescsi_init (void);
@@ -562,6 +567,43 @@
 	NULL
 };
 
+int idescsi_reinit (ide_drive_t *drive)
+{
+#if 0
+	idescsi_scsi_t *scsi;
+	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
+	int i, failed, id;
+
+	if (!idescsi_initialized)
+		return 0;
+	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
+		idescsi_drives[i] = NULL;
+
+	MOD_INC_USE_COUNT;
+	for (i = 0; media[i] != 255; i++) {
+		failed = 0;
+		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+
+			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
+				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
+				continue;
+			}
+			if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) {
+				printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
+				kfree (scsi);
+				continue;
+			}
+			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
+				idescsi_setup (drive, scsi, id);
+			failed--;
+		}
+	}
+	ide_register_module(&idescsi_module);
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
 /*
  *	idescsi_init will register the driver for each scsi.
  */
@@ -592,7 +634,7 @@
 				continue;
 			}
 			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
-			idescsi_setup (drive, scsi, id);
+				idescsi_setup (drive, scsi, id);
 			failed--;
 		}
 	}
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/imm.c linux/drivers/scsi/imm.c
--- v2.5.2/linux/drivers/scsi/imm.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/imm.c	Mon Jan 28 14:36:59 2002
@@ -940,10 +940,10 @@
     if (cmd->SCp.phase > 0)
 	imm_pb_release(cmd->host->unique_id);
 
-    spin_lock_irqsave(&host->host_lock, flags);
+    spin_lock_irqsave(host->host_lock, flags);
     tmp->cur_cmd = 0;
     cmd->scsi_done(cmd);
-    spin_unlock_irqrestore(&host->host_lock, flags);
+    spin_unlock_irqrestore(host->host_lock, flags);
     return;
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/in2000.h linux/drivers/scsi/in2000.h
--- v2.5.2/linux/drivers/scsi/in2000.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/in2000.h	Mon Jan 28 14:36:59 2002
@@ -393,8 +393,8 @@
 # define in2000__INITFUNC(function) __initfunc(function)
 # define in2000__INIT __init
 # define in2000__INITDATA __initdata
-# define CLISPIN_LOCK(host,flags)   spin_lock_irqsave(&host->host_lock, flags)
-# define CLISPIN_UNLOCK(host,flags) spin_unlock_irqrestore(&host->host_lock, \
+# define CLISPIN_LOCK(host,flags)   spin_lock_irqsave(host->host_lock, flags)
+# define CLISPIN_UNLOCK(host,flags) spin_unlock_irqrestore(host->host_lock, \
 							   flags)
 
 int in2000_detect(Scsi_Host_Template *) in2000__INIT;
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/ini9100u.c linux/drivers/scsi/ini9100u.c
--- v2.5.2/linux/drivers/scsi/ini9100u.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/ini9100u.c	Mon Jan 28 14:36:59 2002
@@ -699,113 +699,121 @@
 static void i91u_intr0(int irqno, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
-
+	struct Scsi_Host *dev = dev_id;
+	
 	if (tul_hcs[0].HCS_Intr != irqno)
 		return;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(dev->host_lock, flags);
 
 	tul_isr(&tul_hcs[0]);
 
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 static void i91u_intr1(int irqno, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
-
+	struct Scsi_Host *dev = dev_id;
+	
 	if (tul_hcs[1].HCS_Intr != irqno)
 		return;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(dev->host_lock, flags);
 
 	tul_isr(&tul_hcs[1]);
 
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 static void i91u_intr2(int irqno, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
-
+	struct Scsi_Host *dev = dev_id;
+	
 	if (tul_hcs[2].HCS_Intr != irqno)
 		return;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(dev->host_lock, flags);
 
 	tul_isr(&tul_hcs[2]);
 
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 static void i91u_intr3(int irqno, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
-
+	struct Scsi_Host *dev = dev_id;
+	
 	if (tul_hcs[3].HCS_Intr != irqno)
 		return;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(dev->host_lock, flags);
 
 	tul_isr(&tul_hcs[3]);
 
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 static void i91u_intr4(int irqno, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
-
+	struct Scsi_Host *dev = dev_id;
+	
 	if (tul_hcs[4].HCS_Intr != irqno)
 		return;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(dev->host_lock, flags);
 
 	tul_isr(&tul_hcs[4]);
 
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 static void i91u_intr5(int irqno, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
-
+	struct Scsi_Host *dev = dev_id;
+	
 	if (tul_hcs[5].HCS_Intr != irqno)
 		return;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(dev->host_lock, flags);
 
 	tul_isr(&tul_hcs[5]);
 
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 static void i91u_intr6(int irqno, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
-
+	struct Scsi_Host *dev = dev_id;
+	
 	if (tul_hcs[6].HCS_Intr != irqno)
 		return;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(dev->host_lock, flags);
 
 	tul_isr(&tul_hcs[6]);
 
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 static void i91u_intr7(int irqno, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
-
+	struct Scsi_Host *dev = dev_id;
+	
 	if (tul_hcs[7].HCS_Intr != irqno)
 		return;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(dev->host_lock, flags);
 
 	tul_isr(&tul_hcs[7]);
 
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 /* 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c
--- v2.5.2/linux/drivers/scsi/inia100.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/inia100.c	Mon Jan 28 14:36:59 2002
@@ -717,19 +717,19 @@
 }
 
 
-static void subIntr(ORC_HCS * pHCB, int irqno)
+static void subIntr(ORC_HCS * pHCB, int irqno, struct Scsi_Host *dev)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(dev->host_lock, flags);
 
 	if (pHCB->HCS_Intr != irqno) {
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		spin_unlock_irqrestore(dev->host_lock, flags);
 		return;
 	}
 	orc_interrupt(pHCB);
 
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 /*
@@ -737,42 +737,42 @@
  */
 static void inia100_intr0(int irqno, void *dev_id, struct pt_regs *regs)
 {
-	subIntr(&orc_hcs[0], irqno);
+	subIntr(&orc_hcs[0], irqno, dev_id);
 }
 
 static void inia100_intr1(int irqno, void *dev_id, struct pt_regs *regs)
 {
-	subIntr(&orc_hcs[1], irqno);
+	subIntr(&orc_hcs[1], irqno, dev_id);
 }
 
 static void inia100_intr2(int irqno, void *dev_id, struct pt_regs *regs)
 {
-	subIntr(&orc_hcs[2], irqno);
+	subIntr(&orc_hcs[2], irqno, dev_id);
 }
 
 static void inia100_intr3(int irqno, void *dev_id, struct pt_regs *regs)
 {
-	subIntr(&orc_hcs[3], irqno);
+	subIntr(&orc_hcs[3], irqno, dev_id);
 }
 
 static void inia100_intr4(int irqno, void *dev_id, struct pt_regs *regs)
 {
-	subIntr(&orc_hcs[4], irqno);
+	subIntr(&orc_hcs[4], irqno, dev_id);
 }
 
 static void inia100_intr5(int irqno, void *dev_id, struct pt_regs *regs)
 {
-	subIntr(&orc_hcs[5], irqno);
+	subIntr(&orc_hcs[5], irqno, dev_id);
 }
 
 static void inia100_intr6(int irqno, void *dev_id, struct pt_regs *regs)
 {
-	subIntr(&orc_hcs[6], irqno);
+	subIntr(&orc_hcs[6], irqno, dev_id);
 }
 
 static void inia100_intr7(int irqno, void *dev_id, struct pt_regs *regs)
 {
-	subIntr(&orc_hcs[7], irqno);
+	subIntr(&orc_hcs[7], irqno, dev_id);
 }
 
 /* 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c
--- v2.5.2/linux/drivers/scsi/ips.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/ips.c	Mon Jan 28 14:36:59 2002
@@ -1769,13 +1769,13 @@
       char      *kern_area;
       u_int32_t  datasize;
 
-      spin_unlock_irq(&SC->host->host_lock);
+      spin_unlock_irq(SC->host->host_lock);
 
       /* wait for the command to finish */
       down(&ha->ioctl_sem);
 
       /* reobtain the lock */
-      spin_lock_irq(&SC->host->host_lock);
+      spin_lock_irq(SC->host->host_lock);
 
       /* command finished -- copy back */
       user_area = *((char **) &SC->cmnd[4]);
@@ -1916,24 +1916,24 @@
 
    METHOD_TRACE("do_ipsintr", 2);
 
-   spin_lock_irqsave(&host->host_lock, cpu_flags);
+   spin_lock_irqsave(host->host_lock, cpu_flags);
 
    if (test_and_set_bit(IPS_IN_INTR, &ha->flags)) {
-      spin_unlock_irqrestore(&host->host_lock, cpu_flags);
+      spin_unlock_irqrestore(host->host_lock, cpu_flags);
 
       return ;
    }
 
    if (!ha) {
       clear_bit(IPS_IN_INTR, &ha->flags);
-      spin_unlock_irqrestore(&host->host_lock, cpu_flags);
+      spin_unlock_irqrestore(host->host_lock, cpu_flags);
 
       return;
    }
 
    if (!ha->active) {
       clear_bit(IPS_IN_INTR, &ha->flags);
-      spin_unlock_irqrestore(&host->host_lock, cpu_flags);
+      spin_unlock_irqrestore(host->host_lock, cpu_flags);
 
       return;
    }
@@ -1942,7 +1942,7 @@
 
    clear_bit(IPS_IN_INTR, &ha->flags);
 
-   spin_unlock_irqrestore(&host->host_lock, cpu_flags);
+   spin_unlock_irqrestore(host->host_lock, cpu_flags);
 
    /* start the next command */
    ips_next(ha, IPS_INTR_ON);
@@ -2487,7 +2487,7 @@
             task.data = (void *) &flash_data;
 
             /* Unlock the per-board lock */
-            spin_unlock_irq(&SC->host->host_lock);
+            spin_unlock_irq(SC->host->host_lock);
 
             queue_task(&task, &tq_immediate);
             mark_bh(IMMEDIATE_BH);
@@ -2496,7 +2496,7 @@
             down(&ha->flash_ioctl_sem);
 
             /* Obtain the per-board lock */
-            spin_lock_irq(&SC->host->host_lock);
+            spin_lock_irq(SC->host->host_lock);
 
             return (flash_data.retcode);
          }
@@ -2604,7 +2604,7 @@
             task.data = (void *) &flash_data;
 
             /* Unlock the per-board lock */
-            spin_unlock_irq(&SC->host->host_lock);
+            spin_unlock_irq(SC->host->host_lock);
 
             queue_task(&task, &tq_immediate);
             mark_bh(IMMEDIATE_BH);
@@ -2613,7 +2613,7 @@
             down(&ha->flash_ioctl_sem);
 
             /* Obtain the per-board lock */
-            spin_lock_irq(&SC->host->host_lock);
+            spin_lock_irq(SC->host->host_lock);
 
             return (flash_data.retcode);
          }
@@ -3585,7 +3585,7 @@
     * this command won't time out
     */
    if (intr == IPS_INTR_ON) {
-       spin_lock_irqsave(&host->host_lock, cpu_flags2);
+       spin_lock_irqsave(host->host_lock, cpu_flags2);
        intr_status = IPS_INTR_IORL;
    } else {
        intr_status = intr;
@@ -3610,7 +3610,7 @@
    }
 
    if (intr == IPS_INTR_ON)
-       spin_unlock_irqrestore(&host->host_lock, cpu_flags2);
+       spin_unlock_irqrestore(host->host_lock, cpu_flags2);
 
 #ifndef NO_IPS_CMDLINE
    /*
@@ -6625,7 +6625,7 @@
           * We were called under the HA lock so we can assume that interrupts
           * are masked.
           */
-         spin_lock(&host->host_lock);
+         spin_lock(host->host_lock);
 
          while (test_and_set_bit(IPS_IN_INTR, &ha->flags))
             udelay(1000);
@@ -6634,7 +6634,7 @@
 
          clear_bit(IPS_IN_INTR, &ha->flags);
 
-         spin_unlock(&host->host_lock);
+         spin_unlock(host->host_lock);
       }
 
       udelay(1000); /* 1 milisecond */
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/jazz_esp.c linux/drivers/scsi/jazz_esp.c
--- v2.5.2/linux/drivers/scsi/jazz_esp.c	Thu Oct 25 13:53:51 2001
+++ linux/drivers/scsi/jazz_esp.c	Mon Jan 28 14:36:59 2002
@@ -120,7 +120,7 @@
 	
 	esp->irq = JAZZ_SCSI_IRQ;
 	request_irq(JAZZ_SCSI_IRQ, esp_intr, SA_INTERRUPT, "JAZZ SCSI",
-	            NULL);
+	            esp->ehost);
 
 	/*
 	 * FIXME, look if the scsi id is availabe from NVRAM
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/mac53c94.c linux/drivers/scsi/mac53c94.c
--- v2.5.2/linux/drivers/scsi/mac53c94.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/scsi/mac53c94.c	Mon Jan 28 14:36:59 2002
@@ -292,10 +292,11 @@
 do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
 	unsigned long flags;
-
-	spin_lock_irqsave(&io_request_lock, flags);
+	struct Scsi_Host *dev = ((struct fsc_state *) dev_id)->current_req->host;
+	
+	spin_lock_irqsave(dev->host_lock, flags);
 	mac53c94_interrupt(irq, dev_id, ptregs);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 static void
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/mac_esp.c linux/drivers/scsi/mac_esp.c
--- v2.5.2/linux/drivers/scsi/mac_esp.c	Thu Oct 25 13:53:51 2001
+++ linux/drivers/scsi/mac_esp.c	Mon Jan 28 14:36:59 2002
@@ -417,9 +417,9 @@
 
 			esp->irq = IRQ_MAC_SCSI;
 
-			request_irq(IRQ_MAC_SCSI, esp_intr, 0, "Mac ESP SCSI", esp);
+			request_irq(IRQ_MAC_SCSI, esp_intr, 0, "Mac ESP SCSI", esp->ehost);
 #if 0	/* conflicts with IOP ADB */
-			request_irq(IRQ_MAC_SCSIDRQ, fake_drq, 0, "Mac ESP DRQ", esp);
+			request_irq(IRQ_MAC_SCSIDRQ, fake_drq, 0, "Mac ESP DRQ", esp->ehost);
 #endif
 
 			if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) {
@@ -433,7 +433,7 @@
 
 			esp->irq = IRQ_MAC_SCSIDRQ;
 #if 0	/* conflicts with IOP ADB */
-			request_irq(IRQ_MAC_SCSIDRQ, esp_intr, 0, "Mac ESP SCSI 2", esp);
+			request_irq(IRQ_MAC_SCSIDRQ, esp_intr, 0, "Mac ESP SCSI 2", esp->ehost);
 #endif
 
 			esp->cfreq = 25000000;
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/mca_53c9x.c linux/drivers/scsi/mca_53c9x.c
--- v2.5.2/linux/drivers/scsi/mca_53c9x.c	Thu Oct 25 13:53:51 2001
+++ linux/drivers/scsi/mca_53c9x.c	Mon Jan 28 14:36:59 2002
@@ -153,7 +153,7 @@
 			esp->slot = slot;
 
 			if (request_irq(esp->irq, esp_intr, 0,
-			 "NCR 53c9x SCSI", esp_intr))
+			 "NCR 53c9x SCSI", esp->ehost))
 			{
 				printk("Unable to request IRQ %d.\n", esp->irq);
 				esp_deallocate(esp);
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.5.2/linux/drivers/scsi/megaraid.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/megaraid.c	Mon Jan 28 18:48:08 2002
@@ -586,10 +586,10 @@
 #define DRIVER_LOCK(p)
 #define DRIVER_UNLOCK(p)
 #define IO_LOCK_T unsigned long io_flags = 0
-#define IO_LOCK(host) spin_lock_irqsave(&(host)->host_lock,io_flags)
-#define IO_UNLOCK(host) spin_unlock_irqrestore(&(host)->host_lock,io_flags)
-#define IO_LOCK_IRQ(host) spin_lock_irq(&(host)->host_lock)
-#define IO_UNLOCK_IRQ(host) spin_unlock_irq(&(host)->host_lock)
+#define IO_LOCK(host) spin_lock_irqsave(host->host_lock,io_flags)
+#define IO_UNLOCK(host) spin_unlock_irqrestore(host->host_lock,io_flags)
+#define IO_LOCK_IRQ(host) spin_lock_irq(host->host_lock)
+#define IO_UNLOCK_IRQ(host) spin_unlock_irq(host->host_lock)
 
 #define queue_task_irq(a,b)     queue_task(a,b)
 #define queue_task_irq_off(a,b) queue_task(a,b)
@@ -614,8 +614,8 @@
 #define DRIVER_LOCK(p)
 #define DRIVER_UNLOCK(p)
 #define IO_LOCK_T unsigned long io_flags = 0
-#define IO_LOCK(host) spin_lock_irqsave(&io_request_lock,io_flags);
-#define IO_UNLOCK(host) spin_unlock_irqrestore(&io_request_lock,io_flags);
+#define IO_LOCK(host) spin_lock_irqsave(host->host_lock,io_flags);
+#define IO_UNLOCK(host) spin_unlock_irqrestore(host->host_lock,io_flags);
 
 #define pci_free_consistent(a,b,c,d)
 #define pci_unmap_single(a,b,c,d)
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/mesh.c linux/drivers/scsi/mesh.c
--- v2.5.2/linux/drivers/scsi/mesh.c	Tue Sep 18 14:23:14 2001
+++ linux/drivers/scsi/mesh.c	Mon Jan 28 14:36:59 2002
@@ -795,15 +795,15 @@
 	unsigned long flags;
 
 	for (;;) {
-		spin_lock_irqsave(&io_request_lock, flags);
+		spin_lock_irqsave(ms->host->host_lock, flags);
 		cmd = ms->completed_q;
 		if (cmd == NULL) {
-			spin_unlock_irqrestore(&io_request_lock, flags);
+			spin_unlock_irqrestore(ms->host->host_lock, flags);
 			break;
 		}
 		ms->completed_q = (Scsi_Cmnd *) cmd->host_scribble;
 		(*cmd->scsi_done)(cmd);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		spin_unlock_irqrestore(ms->host->host_lock, flags);
 	}
 }
 #endif /* MESH_NEW_STYLE_EH */
@@ -1458,10 +1458,11 @@
 do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
 	unsigned long flags;
-
-	spin_lock_irqsave(&io_request_lock, flags);
+	struct Scsi_Host *dev = ((struct mech_state *)dev_id)->host;
+	
+	spin_lock_irqsave(dev->host_lock, flags);
 	mesh_interrupt(irq, dev_id, ptregs);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 static void handle_error(struct mesh_state *ms)
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/oktagon_esp.c linux/drivers/scsi/oktagon_esp.c
--- v2.5.2/linux/drivers/scsi/oktagon_esp.c	Thu Oct 25 13:53:51 2001
+++ linux/drivers/scsi/oktagon_esp.c	Mon Jan 28 14:36:59 2002
@@ -198,7 +198,7 @@
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
-			    "BSC Oktagon SCSI", esp_intr);
+			    "BSC Oktagon SCSI", esp->ehost);
 
 		/* Figure out our scsi ID on the bus */
 		esp->scsi_id = 7;
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/pas16.c linux/drivers/scsi/pas16.c
--- v2.5.2/linux/drivers/scsi/pas16.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/pas16.c	Mon Jan 28 14:36:59 2002
@@ -451,7 +451,7 @@
 	    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)) {
+	    if (request_irq(instance->irq, do_pas16_intr, SA_INTERRUPT, "pas16", instance)) {
 		printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
 		    instance->host_no, instance->irq);
 		instance->irq = IRQ_NONE;
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c
--- v2.5.2/linux/drivers/scsi/pci2000.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/pci2000.c	Mon Jan 28 14:36:59 2002
@@ -296,7 +296,7 @@
 		goto out;
 		}
 
-	spin_lock_irqsave(&shost->host_lock, flags);
+	spin_lock_irqsave(shost->host_lock, flags);
 	padapter = HOSTDATA(shost);
 
 	tag0 = tag & 0x7F;															// mask off the error bit
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c
--- v2.5.2/linux/drivers/scsi/pci2220i.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/pci2220i.c	Mon Jan 28 14:36:59 2002
@@ -1162,7 +1162,7 @@
      * Disable interrupts, if they aren't already disabled and acquire
      * the I/O spinlock.
      */
-    spin_lock_irqsave (&host->host_lock, flags);
+    spin_lock_irqsave (host->host_lock, flags);
 	DEB (printk ("\nPCI2220I: Timeout expired "));
 
 	if ( padapter->failinprog )
@@ -1296,7 +1296,7 @@
      * which will enable interrupts if and only if they were
      * enabled on entry.
      */
-    spin_unlock_irqrestore (&host->host_lock, flags);
+    spin_unlock_irqrestore (host->host_lock, flags);
 	}
 /****************************************************************
  *	Name:			SetReconstruct	:LOCAL
@@ -1344,7 +1344,7 @@
      * Disable interrupts, if they aren't already disabled and acquire
      * the I/O spinlock.
      */
-    spin_lock_irqsave(&host->host_lock, flags);
+    spin_lock_irqsave(host->host_lock, flags);
 
 	if ( padapter->SCpnt )
 		goto reconTimerExpiry;
@@ -1568,7 +1568,7 @@
      * which will enable interrupts if and only if they were
      * enabled on entry.
      */
-    spin_unlock_irqrestore(&host->host_lock, flags);
+    spin_unlock_irqrestore(host->host_lock, flags);
 	}
 /****************************************************************
  *	Name:	Irq_Handler	:LOCAL
@@ -1617,7 +1617,7 @@
 		goto out;
 		}
 
-	spin_lock_irqsave(&shost->host_lock, flags);
+	spin_lock_irqsave(shost->host_lock, flags);
 	padapter = HOSTDATA(shost);
 	pdev = padapter->pdev;
 	SCpnt = padapter->SCpnt;
@@ -2020,7 +2020,7 @@
 
 	OpDone (padapter, zl);
 irq_return:
-    spin_unlock_irqrestore(&shost->host_lock, flags);
+    spin_unlock_irqrestore(shost->host_lock, flags);
 out:;
 	}
 /****************************************************************
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/pcmcia/Config.help linux/drivers/scsi/pcmcia/Config.help
--- v2.5.2/linux/drivers/scsi/pcmcia/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/pcmcia/Config.help	Fri Jan 25 16:03:20 2002
@@ -0,0 +1,46 @@
+CONFIG_SCSI_PCMCIA
+  Say Y here if you intend to attach a PCMCIA or CardBus card to your
+  computer which acts as a SCSI host adapter. These are credit card
+  size devices often used with laptops.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions PCMCIA SCSI host adapters.
+
+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.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
+  whenever you want). If you want to compile it as a module, say M
+  here and read <file:Documentation/modules.txt>.
+
+CONFIG_PCMCIA_AHA152X
+  Say Y here if you intend to attach this type of PCMCIA SCSI host
+  adapter to your computer.
+
+  This driver is also available as a module called aha152x_cs.o ( =
+  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>.
+
+CONFIG_PCMCIA_QLOGIC
+  Say Y here if you intend to attach this type of PCMCIA SCSI host
+  adapter to your computer.
+
+  This driver is also available as a module called qlogic_cs.o ( =
+  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>.
+
+CONFIG_PCMCIA_FDOMAIN
+  Say Y here if you intend to attach this type of PCMCIA SCSI host
+  adapter to your computer.
+
+  This driver is also available as a module called fdomain_cs.o ( =
+  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>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v2.5.2/linux/drivers/scsi/ppa.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/ppa.c	Mon Jan 28 14:36:59 2002
@@ -119,7 +119,6 @@
      * unlock to allow the lowlevel parport driver to probe
      * the irqs
      */
-    spin_unlock_irq(&io_request_lock);
     pb = parport_enumerate();
 
     printk("ppa: Version %s\n", PPA_VERSION);
@@ -128,7 +127,6 @@
 
     if (!pb) {
 	printk("ppa: parport reports no devices.\n");
-	spin_lock_irq(&io_request_lock);
 	return 0;
     }
   retry_entry:
@@ -154,7 +152,7 @@
 		      "pardevice is owning the port for too longtime!\n",
 			   i);
 		    parport_unregister_device(ppa_hosts[i].dev);
-		    spin_lock_irq(&io_request_lock);
+		    spin_lock_irq(ppa_hosts[i].cur_cmd->host->host_lock);
 		    return 0;
 		}
 	    }
@@ -223,13 +221,13 @@
 	    printk("  supported by the imm (ZIP Plus) driver. If the\n");
 	    printk("  cable is marked with \"AutoDetect\", this is what has\n");
 	    printk("  happened.\n");
-	    spin_lock_irq(&io_request_lock);
+	    spin_lock_irq(hreg->host_lock);
 	    return 0;
 	}
 	try_again = 1;
 	goto retry_entry;
     } else {
-	spin_lock_irq(&io_request_lock);
+	spin_lock_irq(hreg->host_lock);
 	return 1;		/* return number of hosts detected */
     }
 }
@@ -847,9 +845,9 @@
 
     tmp->cur_cmd = 0;
     
-    spin_lock_irqsave(&io_request_lock, flags);
+    spin_lock_irqsave(cmd->host->host_lock, flags);
     cmd->scsi_done(cmd);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    spin_unlock_irqrestore(cmd->host->host_lock, flags);
     return;
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/psi240i.c linux/drivers/scsi/psi240i.c
--- v2.5.2/linux/drivers/scsi/psi240i.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/psi240i.c	Mon Jan 28 14:36:59 2002
@@ -370,10 +370,11 @@
 static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
 	{
 	unsigned long flags;
-
-	spin_lock_irqsave(&io_request_lock, flags);
+	struct Scsi_Host *dev = dev_id;
+	
+	spin_lock_irqsave(dev->host_lock, flags);
 	Irq_Handler(irq, dev_id, regs);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 	}
 /****************************************************************
  *	Name:	Psi240i_QueueCommand
@@ -602,7 +603,7 @@
 
 		save_flags (flags);
 		cli ();
-		if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", NULL) )
+		if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", pshost) )
 			{
 			printk ("Unable to allocate IRQ for PSI-240I controller.\n");
 			restore_flags (flags);
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/qla1280.c linux/drivers/scsi/qla1280.c
--- v2.5.2/linux/drivers/scsi/qla1280.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/qla1280.c	Mon Jan 28 14:36:59 2002
@@ -1523,11 +1523,11 @@
         return;
     }
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
-    spin_lock_irqsave(&io_request_lock, cpu_flags);
+    spin_lock_irqsave(ha->host->host_lock, cpu_flags);
     if(test_and_set_bit(QLA1280_IN_ISR_BIT, &ha->flags))
     {
         COMTRACE('X')
-        spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+        spin_unlock_irqrestore(ha->host->host_lock, cpu_flags);
         return;
     }
     ha->isr_count++;
@@ -1548,7 +1548,7 @@
         qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last);
 
     clear_bit(QLA1280_IN_ISR_BIT, &ha->flags);
-    spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+    spin_unlock_irqrestore(ha->host->host_lock, cpu_flags);
 #else  /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) */
 
     if( test_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags) )
@@ -1619,7 +1619,7 @@
 
     COMTRACE('p')  
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95)
-    spin_lock_irqsave(&io_request_lock, cpu_flags);
+    spin_lock_irqsave(ha->host->host_lock, cpu_flags);
 #endif
     if (ha->flags.isp_abort_needed)
         qla1280_abort_isp(ha);
@@ -1631,7 +1631,7 @@
         qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last);
     ha->flags.dpc_sched = FALSE;
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95)
-    spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+    spin_unlock_irqrestore(ha->host->host_lock, cpu_flags);
 #endif
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/qlogicfas.c linux/drivers/scsi/qlogicfas.c
--- v2.5.2/linux/drivers/scsi/qlogicfas.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/qlogicfas.c	Mon Jan 28 14:36:59 2002
@@ -469,9 +469,9 @@
 	unsigned long flags;
 	struct Scsi_Host *host = dev_id;
 
-	spin_lock_irqsave(&host->host_lock, flags);
+	spin_lock_irqsave(host->host_lock, flags);
 	ql_ihandl(irq, dev_id, regs);
-	spin_unlock_irqrestore(&host->host_lock, flags);
+	spin_unlock_irqrestore(host->host_lock, flags);
 }
 #endif
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c
--- v2.5.2/linux/drivers/scsi/qlogicfc.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/qlogicfc.c	Tue Jan 15 10:52:11 2002
@@ -1375,7 +1375,7 @@
 	hostdata->explore_timer.data = 0;
 	del_timer(&hostdata->explore_timer);
 
-	spin_lock_irqsave(&host->host_lock, flags);
+	spin_lock_irqsave(host->host_lock, flags);
 
 	if (hostdata->adapter_state & AS_REDO_FABRIC_PORTDB || hostdata->adapter_state & AS_REDO_LOOP_PORTDB) {
 		isp2x00_make_portdb(host);
@@ -1422,7 +1422,7 @@
 		hostdata->adapter_state = AS_LOOP_GOOD;
 	}
 
-	spin_unlock_irqrestore(&host->host_lock, flags);
+	spin_unlock_irqrestore(host->host_lock, flags);
 
 }
 
@@ -1433,9 +1433,9 @@
 	struct Scsi_Host *host = dev_id;
 	unsigned long flags;
 
-	spin_lock_irqsave(&host->host_lock, flags);
+	spin_lock_irqsave(host->host_lock, flags);
 	isp2x00_intr_handler(irq, dev_id, regs);
-	spin_unlock_irqrestore(&host->host_lock, flags);
+	spin_unlock_irqrestore(host->host_lock, flags);
 }
 
 void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.5.2/linux/drivers/scsi/qlogicisp.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/qlogicisp.c	Tue Jan 15 10:52:11 2002
@@ -973,9 +973,9 @@
 	struct Scsi_Host *host = dev_id;
 	unsigned long flags;
 
-	spin_lock_irqsave(&host->host_lock, flags);
+	spin_lock_irqsave(host->host_lock, flags);
 	isp1020_intr_handler(irq, dev_id, regs);
-	spin_unlock_irqrestore(&host->host_lock, flags);
+	spin_unlock_irqrestore(host->host_lock, flags);
 }
 
 void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c
--- v2.5.2/linux/drivers/scsi/qlogicpti.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/qlogicpti.c	Tue Jan 15 10:52:11 2002
@@ -1138,11 +1138,12 @@
 		int ok = host_byte(Cmnd->result) == DID_OK;
 		if (Cmnd->cmnd[0] == 0x12 && ok) {
 			unsigned char *iqd;
-			if (Cmnd->use_sg == 0) {
-				iqd = ((unsigned char *)Cmnd->buffer);
-			} else {
-				iqd = ((struct scatterlist *) Cmnd->request_buffer)->address;
-			}
+
+			if (Cmnd->use_sg != 0)
+				BUG();
+
+			iqd = ((unsigned char *)Cmnd->buffer);
+
 			/* tags handled in midlayer */
 			/* enable sync mode? */
 			if (iqd[7] & 0x10) {
@@ -1445,7 +1446,7 @@
 	spin_unlock(&qpti->lock);
 
 	if (dq != NULL) {
-		spin_lock(&qpti->qhost->host_lock);
+		spin_lock(qpti->qhost->host_lock);
 		do {
 			Scsi_Cmnd *next;
 
@@ -1453,7 +1454,7 @@
 			dq->scsi_done(dq);
 			dq = next;
 		} while (dq != NULL);
-		spin_unlock(&qpti->qhost->host_lock);
+		spin_unlock(qpti->qhost->host_lock);
 	}
 	__restore_flags(flags);
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- v2.5.2/linux/drivers/scsi/scsi_debug.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/scsi_debug.c	Thu Jan 17 13:59:33 2002
@@ -3,8 +3,19 @@
  *
  *  Copyright (C) 1992  Eric Youngdale
  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
- *  to make sure that we are not getting blocks mixed up, and panic if
+ *  to make sure that we are not getting blocks mixed up, and PANIC if
  *  anything out of the ordinary is seen.
+ *
+ *  This version is more generic, simulating a variable number of disk 
+ *  (or disk like devices) sharing a common amount of RAM (default 8 MB
+ *  but can be set at driver/module load time).
+ *
+ *  For documentation see http://www.torque.net/sg/sdebug.html
+ *
+ *   D. Gilbert (dpg) work for MOD device test [20010421]
+ *   dpg, work for devfs large number of disks [20010809]
+ *   dpg, make more generic [20011123]
+ *   dpg, forked for lk 2.5 series [20011216, 20020101]
  */
 
 #include <linux/config.h>
@@ -18,7 +29,9 @@
 #include <linux/string.h>
 #include <linux/genhd.h>
 #include <linux/fs.h>
+#include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -27,201 +40,187 @@
 #include "scsi.h"
 #include "hosts.h"
 
-#include "sd.h"
-
 #include<linux/stat.h>
 
-/* A few options that we want selected */
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+static char scsi_debug_version_str[] = "Version: 1.57 (20011216)";
 
-#define NR_HOSTS_PRESENT 1
-#define NR_FAKE_DISKS   3
-#define N_HEAD          255
-#define N_SECTOR        63
-#define N_CYLINDER      524
+#ifndef SCSI_CMD_READ_16
+#define SCSI_CMD_READ_16 0x88
+#endif
+#ifndef SCSI_CMD_WRITE_16
+#define SCSI_CMD_WRITE_16 0x8a
+#endif
+
+/* A few options that we want selected */
+#define DEF_NR_FAKE_DEVS   1
+#define DEF_DEV_SIZE_MB   8
+#define DEF_FAKE_BLK0   0
+
+static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS;
+
+#define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
+#define N_HEAD          8
+#define N_SECTOR        32
 #define DISK_READONLY(TGT)      (0)
-#define DISK_REMOVEABLE(TGT)    (1)
-#define DEVICE_TYPE(TGT) (TGT == 2 ? TYPE_TAPE : TYPE_DISK);
+#define DISK_REMOVEABLE(TGT)    (0)
+#define DEVICE_TYPE(TGT) (TYPE_DISK);
+
+#define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1)
+
+static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
+#define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024)
+#define STORE_ELEM_ORDER 1
+#define STORE_ELEM_SIZE (PAGE_SIZE * (1 << STORE_ELEM_ORDER))
+#define STORE_ELEMENTS ((STORE_SIZE / STORE_ELEM_SIZE) + 1)
+
+/* default sector size is 512 bytes, 2**9 bytes */
+#define POW2_SECT_SIZE 9
+#define SECT_SIZE (1 << POW2_SECT_SIZE)
+
+#define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD))
+
+static int scsi_debug_fake_blk0 = DEF_FAKE_BLK0;
 
 /* Do not attempt to use a timer to simulate a real disk with latency */
 /* Only use this in the actual kernel, not in the simulator. */
 #define IMMEDIATE
 
-/* Skip some consistency checking.  Good for benchmarking */
-#define SPEEDY
-/* Read return zeros. Undefine for benchmarking */
-#define CLEAR
-
-/* Number of real scsi disks that will be detected ahead of time */
-static int NR_REAL = -1;
-
-#define NR_BLK_DEV  12
-#ifndef MAJOR_NR
-#define MAJOR_NR 8
-#endif
+#define SDEBUG_SG_ADDRESS
+
 #define START_PARTITION 4
 
 /* Time to wait before completing a command */
 #define DISK_SPEED     (HZ/10)	/* 100ms */
 #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
-#define SIZE(TGT) (TGT == 2 ? 2248 : 512)
+#define SECT_SIZE_PER(TGT) SECT_SIZE
+#define SECT_PER_ELEM (STORE_ELEM_SIZE / SECT_SIZE)
 
 static int starts[] =
 {N_SECTOR,
  N_HEAD * N_SECTOR,		/* Single cylinder */
  N_HEAD * N_SECTOR * 4,
- CAPACITY, 0};
+ 0 /* CAPACITY */, 0};
 static int npart = 0;
 
-#include "scsi_debug.h"
-#ifdef DEBUG
-#define DEB(x) x
-#else
-#define DEB(x)
-#endif
+typedef struct scsi_debug_store_elem {
+	unsigned char * p;
+} Sd_store_elem;
+
+static Sd_store_elem * store_arr = 0;
+
+typedef struct sdebug_dev_info {
+	Scsi_Device * sdp;
+	unsigned short host_no;
+	unsigned short id;
+	char reset;
+	char sb_index;
+} Sdebug_dev_info;
+static Sdebug_dev_info * devInfop;
+
+static int num_aborts = 0;
+static int num_dev_resets = 0;
+static int num_bus_resets = 0;
+static int num_host_resets = 0;
 
-#ifdef SPEEDY
-#define VERIFY1_DEBUG(RW)
-#define VERIFY_DEBUG(RW)
-#else
+static spinlock_t mailbox_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t sdebug_atomic_rw = RW_LOCK_UNLOCKED;
 
-#define VERIFY1_DEBUG(RW)                           \
-    if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");};         \
-    start = 0;                          \
-    if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1];        \
-    if (bh){                            \
-	if (bh->b_size != 1024) panic ("Wrong bh size");    \
-	if ((bh->b_blocknr << 1) + start != block)          \
-	{   printk("Wrong bh block# %d %d ",bh->b_blocknr, block);  \
-	    panic ("Wrong bh block#"); \
-	};  \
-	if (bh->b_dev != SCpnt->request.rq_dev)  \
-	    panic ("Bad bh target"); \
-    };
-
-#define VERIFY_DEBUG(RW)                            \
-    if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");};    \
-    start = 0;                          \
-    if ((MINOR(SCpnt->request.rq_dev) & 0xf) > npart) panic ("Bad partition");    \
-    if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1];        \
-    if (SCpnt->request.cmd != RW) panic ("Wrong  operation");       \
-    if (SCpnt->request.sector + start != block) panic("Wrong block.");  \
-    if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks");   \
-    if (SCpnt->request.bh){                         \
-	if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
-	if ((SCpnt->request.bh->b_blocknr << 1) + start != block)           \
-	{   printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block);  \
-	    panic ("Wrong bh block#"); \
-	};  \
-	if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \
-	    panic ("Bad bh target");\
-    };
-#endif
+#include "scsi_debug.h"
 
 typedef void (*done_fct_t) (Scsi_Cmnd *);
 
-static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] =
-{NULL,};
+static volatile done_fct_t * do_done = 0;
 
 struct Scsi_Host * SHpnt = NULL;
 
+static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+			   int num, int * errstsp, Sdebug_dev_info * devip);
+static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+			    int num, int * errstsp, Sdebug_dev_info * devip);
 static void scsi_debug_send_self_command(struct Scsi_Host * shpnt);
 static void scsi_debug_intr_handle(unsigned long);
+static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
+static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+			    int asc, int asq, int inbandLen);
+static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip);
 
-static struct timer_list timeout[SCSI_DEBUG_MAILBOXES];
-
-Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES] =
-{NULL,};
-static char SCrst[SCSI_DEBUG_MAILBOXES] =
-{0,};
+static struct timer_list * timeout = 0;
+static Scsi_Cmnd ** SCint = 0;
 
 /*
  * Semaphore used to simulate bus lockups.
  */
 static int scsi_debug_lockup = 0;
 
-static char sense_buffer[128] =
-{0,};
+#define NUM_SENSE_BUFFS 4
+#define SENSE_BUFF_LEN 32
+static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN];
 
-static void scsi_dump(Scsi_Cmnd * SCpnt, int flag)
+static int made_block0 = 0;
+
+static void scsi_debug_mkblock0(unsigned char * buff, int bufflen,
+				Scsi_Cmnd * SCpnt)
 {
 	int i;
-#if 0
-	unsigned char *pnt;
-#endif
-	unsigned int *lpnt;
-	struct scatterlist *sgpnt = NULL;
-	printk("use_sg: %d", SCpnt->use_sg);
-	if (SCpnt->use_sg) {
-		sgpnt = (struct scatterlist *) SCpnt->buffer;
-		for (i = 0; i < SCpnt->use_sg; i++) {
-			printk(":%p %d\n", sgpnt[i].address, sgpnt[i].length);
-		};
-	} else {
-		printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer,
-		       SCpnt->bufflen);
-		lpnt = (int *) SCpnt->request.buffer;
-		if (lpnt)
-			printk(" (Alt %x) ", lpnt[15]);
-	};
-	lpnt = (unsigned int *) SCpnt;
-	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
-		if ((i & 7) == 0)
-			printk("\n");
-		printk("%x ", *lpnt++);
-	};
-	printk("\n");
-	if (flag == 0)
-		return;
-#if 0
-	printk("\n");
-	lpnt = (unsigned int *) sgpnt[0].address;
-	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
-		if ((i & 7) == 0)
-			printk("\n");
-		printk("%x ", *lpnt++);
-	};
-	printk("\n");
-#endif
+	struct partition *p;
+
+	memset(buff, 0, bufflen);
+	*((unsigned short *) (buff + 510)) = 0xAA55;
+	p = (struct partition *) (buff + 0x1be);
+	i = 0;
+	while (starts[i + 1]) {
+		int start_cyl, end_cyl;
+
+		start_cyl = starts[i] / N_HEAD / N_SECTOR;
+		end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
+		p->boot_ind = 0;
+
+		p->head = (i == 0 ? 1 : 0);
+		p->sector = 1 | ((start_cyl >> 8) << 6);
+		p->cyl = (start_cyl & 0xff);
+
+		p->end_head = N_HEAD - 1;
+		p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
+		p->end_cyl = (end_cyl & 0xff);
+
+		p->start_sect = starts[i];
+		p->nr_sects = starts[i + 1] - starts[i];
+		p->sys_ind = 0x83;	/* Linux ext2 partition */
+		p++;
+		i++;
+	}
+	if (!npart)
+		npart = i;
+	made_block0 = 1;
+	i = (bufflen > STORE_ELEM_SIZE) ? STORE_ELEM_SIZE : bufflen;
+	memcpy(store_arr[0].p, buff, i);
 }
 
 int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
 	unchar *cmd = (unchar *) SCpnt->cmnd;
-	struct partition *p;
 	int block;
-	struct buffer_head *bh = NULL;
+	int upper_blk;
 	unsigned char *buff;
-	int nbytes, sgcount;
 	int scsi_debug_errsts;
-	struct scatterlist *sgpnt;
 	int target = SCpnt->target;
 	int bufflen = SCpnt->request_bufflen;
-	unsigned long flags;
-	int i;
-	sgcount = 0;
-	sgpnt = NULL;
-
-#ifdef CONFIG_SMP
-        /*
-         * The io_request_lock *must* be held at this point.
-         */
-        if( io_request_lock.lock == 0 )
-        {
-                printk("Warning - io_request_lock is not held in queuecommand\n");
-        }
-#endif
+	unsigned long iflags;
+	int i, num, capac;
+	Sdebug_dev_info * devip = NULL;
+	char * sbuff;
 
 	/*
-	 * If we are being notified of the mid-level reposessing a command due to timeout,
-	 * just return.
+	 * If we are being notified of the mid-level reposessing a command
+	 * due to timeout, just return.
 	 */
 	if (done == NULL) {
 		return 0;
 	}
-	DEB(if (target >= NR_FAKE_DISKS) {
-	    SCpnt->result = DID_TIME_OUT << 16; done(SCpnt); return 0;
-	    }
-	);
 
 	buff = (unsigned char *) SCpnt->request_buffer;
 
@@ -229,249 +228,201 @@
          * If a command comes for the ID of the host itself, just print
          * a silly message and return.
          */
-        if( target == 7 ) {
+        if(target == 7) {
                 printk("How do you do!\n");
                 SCpnt->result = 0;
                 done(SCpnt);
                 return 0;
         }
 
-	if (target >= NR_FAKE_DISKS || SCpnt->lun != 0) {
+	if ((target > 7) || (SCpnt->lun != 0)) {
 		SCpnt->result = DID_NO_CONNECT << 16;
 		done(SCpnt);
 		return 0;
 	}
-	if (SCrst[target] != 0 && !scsi_debug_lockup) {
-		SCrst[target] = 0;
-		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
-		SCpnt->sense_buffer[0] = 0x70;
-		SCpnt->sense_buffer[2] = UNIT_ATTENTION;
-		SCpnt->result = (CHECK_CONDITION << 1);
-		done(SCpnt);
+#if 0
+	printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n",
+	       (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
+	       SCpnt->device, (int)(unsigned char)*cmd);
+#endif
+	if (NULL == SCpnt->device->hostdata) {
+		devip = devInfoReg(SCpnt->device);
+		if (NULL == devip) {
+			SCpnt->result = DID_NO_CONNECT << 16;
+			done(SCpnt);
+			return 0;
+		}
+		SCpnt->device->hostdata = devip;
 	}
+	devip = SCpnt->device->hostdata;
+
 	switch (*cmd) {
-	case REQUEST_SENSE:
+	case REQUEST_SENSE:	/* mandatory */
 		SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
-#ifndef DEBUG
-		{
-			int i;
-			printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen);
-			for (i = 0; i < 12; i++)
-				printk("%d ", sense_buffer[i]);
-			printk("\n");
-		};
-#endif
-		memset(buff, 0, bufflen);
-		memcpy(buff, sense_buffer, bufflen);
-		memset(sense_buffer, 0, sizeof(sense_buffer));
+		if (devip) {
+			sbuff = &sense_buffers[(int)devip->sb_index][0];
+			devip->sb_index = 0; 
+		}
+		else
+		    sbuff = &sense_buffers[0][0]; 
+		memcpy(buff, sbuff, (bufflen < SENSE_BUFF_LEN) ? 
+				     bufflen : SENSE_BUFF_LEN);
+		memset(sbuff, 0, SENSE_BUFF_LEN);
+		sbuff[0] = 0x70;
 		SCpnt->result = 0;
 		done(SCpnt);
 		return 0;
 	case START_STOP:
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
 		SCSI_LOG_LLQUEUE(3, printk("START_STOP\n"));
 		scsi_debug_errsts = 0;
 		break;
 	case ALLOW_MEDIUM_REMOVAL:
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
 		if (cmd[4]) {
-			SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited..."));
+			SCSI_LOG_LLQUEUE(2, printk(
+					"Medium removal inhibited..."));
 		} else {
-			SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled..."));
+			SCSI_LOG_LLQUEUE(2, 
+					printk("Medium removal enabled..."));
 		}
 		scsi_debug_errsts = 0;
 		break;
-	case INQUIRY:
+	case INQUIRY:     /* mandatory */
 		SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen));
 		memset(buff, 0, bufflen);
 		buff[0] = DEVICE_TYPE(target);
-		buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
-		buff[2] = 1;
-		buff[4] = 33 - 5;
-		memcpy(&buff[8], "Foo Inc", 7);
-		memcpy(&buff[16], "XYZZY", 5);
-		memcpy(&buff[32], "1", 1);
+		buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;	
+				/* Removable disk */
+		buff[2] = 2;	/* claim SCSI 2 */
+		buff[4] = 36 - 5;
+		memcpy(&buff[8], "Linux   ", 8);
+		memcpy(&buff[16], "scsi_debug      ", 16);
+		memcpy(&buff[32], "0002", 4);
+		scsi_debug_errsts = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)
+		if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
+			SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+#endif
+		break;
+	case SEND_DIAGNOSTIC:     /* mandatory */
+		SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n"));
+		if (buff)
+			memset(buff, 0, bufflen);
 		scsi_debug_errsts = 0;
 		break;
-	case TEST_UNIT_READY:
+	case TEST_UNIT_READY:     /* mandatory */
 		SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen));
 		if (buff)
 			memset(buff, 0, bufflen);
 		scsi_debug_errsts = 0;
 		break;
 	case READ_CAPACITY:
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
 		SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n"));
                 SHpnt = SCpnt->host;
-		if (NR_REAL < 0)
-			NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
 		memset(buff, 0, bufflen);
-		buff[0] = (CAPACITY >> 24);
-		buff[1] = (CAPACITY >> 16) & 0xff;
-		buff[2] = (CAPACITY >> 8) & 0xff;
-		buff[3] = CAPACITY & 0xff;
+		capac = CAPACITY - 1;
+		buff[0] = (capac >> 24);
+		buff[1] = (capac >> 16) & 0xff;
+		buff[2] = (capac >> 8) & 0xff;
+		buff[3] = capac & 0xff;
 		buff[4] = 0;
 		buff[5] = 0;
-		buff[6] = (SIZE(target) >> 8) & 0xff;	/* 512 byte sectors */
-		buff[7] = SIZE(target) & 0xff;
+		buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+		buff[7] = SECT_SIZE_PER(target) & 0xff;
 
 		scsi_debug_errsts = 0;
 		break;
+	case SCSI_CMD_READ_16:	/* SBC-2 */
+	case READ_12:
 	case READ_10:
 	case READ_6:
-#ifdef DEBUG
-		printk("Read...");
-#endif
-		if ((*cmd) == READ_10)
-			block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
-		else
-			block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
-		VERIFY_DEBUG(READ);
-#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
-		{
-			int delay = SCSI_SETUP_LATENCY;
-
-			delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
-			if (delay)
-				usleep(delay);
-		};
-#endif
-
-#ifdef DEBUG
-		printk("(r%d)", SCpnt->request.nr_sectors);
-#endif
-		nbytes = bufflen;
-		if (SCpnt->use_sg) {
-			sgcount = 0;
-			sgpnt = (struct scatterlist *) buff;
-			buff = sgpnt[sgcount].address;
-			bufflen = sgpnt[sgcount].length;
-			bh = SCpnt->request.bh;
-		};
-		scsi_debug_errsts = 0;
-		do {
-			VERIFY1_DEBUG(READ);
-			/* For the speedy test, we do not even want to fill the buffer with anything */
-#ifdef CLEAR
-			memset(buff, 0, bufflen);
-#endif
-			/* If this is block 0, then we want to read the partition table for this
-			 * device.  Let's make one up */
-			if (block == 0) {
-				int i;
-				memset(buff, 0, bufflen);
-				*((unsigned short *) (buff + 510)) = 0xAA55;
-				p = (struct partition *) (buff + 0x1be);
-				i = 0;
-				while (starts[i + 1]) {
-					int start_cyl, end_cyl;
-
-					start_cyl = starts[i] / N_HEAD / N_SECTOR;
-					end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
-					p->boot_ind = 0;
-
-					p->head = (i == 0 ? 1 : 0);
-					p->sector = 1 | ((start_cyl >> 8) << 6);
-					p->cyl = (start_cyl & 0xff);
-
-					p->end_head = N_HEAD - 1;
-					p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
-					p->end_cyl = (end_cyl & 0xff);
-
-					p->start_sect = starts[i];
-					p->nr_sects = starts[i + 1] - starts[i];
-					p->sys_ind = 0x81;	/* Linux partition */
-					p++;
-					i++;
-				};
-				if (!npart)
-					npart = i;
-				scsi_debug_errsts = 0;
-				break;
-			};
-#ifdef DEBUG
-			if (SCpnt->use_sg)
-				printk("Block %x (%d %d)\n", block, SCpnt->request.nr_sectors,
-				       SCpnt->request.current_nr_sectors);
-#endif
-
-#if 0
-			/* Simulate a disk change */
-			if (block == 0xfff0) {
-				sense_buffer[0] = 0x70;
-				sense_buffer[2] = UNIT_ATTENTION;
-				starts[0] += 10;
-				starts[1] += 10;
-				starts[2] += 10;
-
-#ifdef DEBUG
-				{
-					int i;
-					printk("scsi_debug: Filling sense buffer:");
-					for (i = 0; i < 12; i++)
-						printk("%d ", sense_buffer[i]);
-					printk("\n");
-				};
-#endif
-				scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
-				break;
-			}	/* End phony disk change code */
-#endif
-
-#ifdef CLEAR
-			memcpy(buff, &target, sizeof(target));
-			memcpy(buff + sizeof(target), cmd, 24);
-			memcpy(buff + 60, &block, sizeof(block));
-			memcpy(buff + 64, SCpnt, sizeof(Scsi_Cmnd));
-#endif
-			nbytes -= bufflen;
-			if (SCpnt->use_sg) {
-#ifdef CLEAR
-				memcpy(buff + 128, bh, sizeof(struct buffer_head));
-#endif
-				block += bufflen >> 9;
-				bh = bh->b_reqnext;
-				sgcount++;
-				if (nbytes) {
-					if (!bh)
-						panic("Too few blocks for linked request.");
-					buff = sgpnt[sgcount].address;
-					bufflen = sgpnt[sgcount].length;
-				};
-			}
-		} while (nbytes);
-
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
+		upper_blk = 0;
+		if ((*cmd) == SCSI_CMD_READ_16) {
+			upper_blk = cmd[5] + (cmd[4] << 8) + 
+				    (cmd[3] << 16) + (cmd[2] << 24);
+			block = cmd[9] + (cmd[8] << 8) + 
+				(cmd[7] << 16) + (cmd[6] << 24);
+			num = cmd[13] + (cmd[12] << 8) + 
+				(cmd[11] << 16) + (cmd[10] << 24);
+		}
+		else if ((*cmd) == READ_12) {
+			block = cmd[5] + (cmd[4] << 8) + 
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[9] + (cmd[8] << 8) + 
+				(cmd[7] << 16) + (cmd[6] << 24);
+		}
+		else if ((*cmd) == READ_10) {
+			block = cmd[5] + (cmd[4] << 8) + 
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[8] + (cmd[7] << 8);
+		}
+		else {
+			block = cmd[3] + (cmd[2] << 8) + 
+				((cmd[1] & 0x1f) << 16);
+			num = cmd[4];
+		}
+		if (scsi_debug_read(SCpnt, upper_blk, block, num, 
+				    &scsi_debug_errsts, devip))
+			break;
 		SCpnt->result = 0;
-		(done) (SCpnt);
+/* calls bottom half in upper layers before return from scsi_do_...() */
+		(done) (SCpnt);	
 		return 0;
-
-		if (SCpnt->use_sg && !scsi_debug_errsts)
-			if (bh)
-				scsi_dump(SCpnt, 0);
-		break;
+	case SCSI_CMD_WRITE_16:	/* SBC-2 */
+	case WRITE_12:
 	case WRITE_10:
 	case WRITE_6:
-#ifdef DEBUG
-		printk("Write\n");
-#endif
-		if ((*cmd) == WRITE_10)
-			block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
-		else
-			block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
-		VERIFY_DEBUG(WRITE);
-		/*      printk("(w%d)",SCpnt->request.nr_sectors); */
-		if (SCpnt->use_sg) {
-			if ((bufflen >> 9) != SCpnt->request.nr_sectors)
-				panic("Trying to write wrong number of blocks\n");
-			sgpnt = (struct scatterlist *) buff;
-			buff = sgpnt[sgcount].address;
-		};
-#if 0
-		if (block != *((unsigned long *) (buff + 60))) {
-			printk("%x %x :", block, *((unsigned long *) (buff + 60)));
-			scsi_dump(SCpnt, 1);
-			panic("Bad block written.\n");
-		};
-#endif
-		scsi_debug_errsts = 0;
-		break;
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
+		upper_blk = 0;
+		if ((*cmd) == SCSI_CMD_WRITE_16) {
+			upper_blk = cmd[5] + (cmd[4] << 8) + 
+				    (cmd[3] << 16) + (cmd[2] << 24);
+			block = cmd[9] + (cmd[8] << 8) + 
+				(cmd[7] << 16) + (cmd[6] << 24);
+			num = cmd[13] + (cmd[12] << 8) + 
+				(cmd[11] << 16) + (cmd[10] << 24);
+		}
+		else if ((*cmd) == WRITE_12) {
+			block = cmd[5] + (cmd[4] << 8) + 
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[9] + (cmd[8] << 8) + 
+				(cmd[7] << 16) + (cmd[6] << 24);
+		}
+		else if ((*cmd) == WRITE_10) {
+			block = cmd[5] + (cmd[4] << 8) + 
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[8] + (cmd[7] << 8);
+		}
+		else {
+			block = cmd[3] + (cmd[2] << 8) + 
+				((cmd[1] & 0x1f) << 16);
+			num = cmd[4];
+		}
+		if (scsi_debug_write(SCpnt, upper_blk, block, num, 
+				     &scsi_debug_errsts, devip))
+			break;
+		SCpnt->result = 0;
+/* calls bottom half in upper layers before return from scsi_do_...() */
+		(done) (SCpnt);	
+		return 0;
 	case MODE_SENSE:
 		/*
 		 * Used to detect write protected status.
@@ -480,26 +431,36 @@
 		memset(buff, 0, 6);
 		break;
 	default:
+#if 0
 		SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd));
 		SCpnt->result = DID_NO_CONNECT << 16;
 		done(SCpnt);
 		return 0;
-	};
+#else
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
+		scsi_debug_errsts = (COMMAND_COMPLETE << 8) |
+				    (CHECK_CONDITION << 1);
+		mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14);
+		break;
+#endif
+	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&mailbox_lock, iflags);
 	for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
 		if (timeout[i].function == NULL)
 			break;
-	};
+	}
 
 	/*
-	 * If all of the slots are full, just return 1.  The new error handling scheme
-	 * allows this, and the mid-level should queue things.
+	 * If all of the slots are full, just return 1.  The new error 
+	 * handling scheme allows this, and the mid-level should queue things.
 	 */
 	if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) {
 		SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n"));
-		restore_flags(flags);
+		spin_unlock_irqrestore(&mailbox_lock, iflags);
 		return 1;
 	}
 	SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i));
@@ -511,7 +472,7 @@
 		do_done[i] = done;
 		scsi_debug_intr_handle(i);	/* No timer - do this one right away */
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&mailbox_lock, iflags);
 #else
 
 	SCpnt->result = scsi_debug_errsts;
@@ -521,19 +482,200 @@
 	SCint[i] = SCpnt;
 	do_done[i] = done;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&mailbox_lock, iflags);
 	add_timer(&timeout[i]);
 	if (!done)
-		panic("scsi_debug_queuecommand: done can't be NULL\n");
+		printk("scsi_debug_queuecommand: done can't be NULL\n");
 
 #if 0
-	printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies);
+	printk("Sending command (%d %x %d %d)...", i, done, 
+	       timeout[i].expires, jiffies);
 #endif
 #endif
 
 	return 0;
 }
 
+static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip)
+{
+	if (devip->reset) {
+		devip->reset = 0;
+		mk_sense_buffer(devip, 3, UNIT_ATTENTION, 0x29, 0, 14);
+		SCpnt->result = (COMMAND_COMPLETE << 8) | 
+				(CHECK_CONDITION << 1);
+                return 1;
+	}
+	return 0;
+}
+
+static inline 
+unsigned char * sdebug_scatg2virt(const struct scatterlist * sclp)
+{
+	if (NULL == sclp)
+		return NULL;
+	else if (sclp->page)
+		return (unsigned char *)page_address(sclp->page) + 
+		       sclp->offset;
+	else {
+#ifdef SDEBUG_SG_ADDRESS
+		return sclp->address;
+#else
+		return NULL;
+#endif
+	}
+}
+
+static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+			   int num, int * errstsp, Sdebug_dev_info * devip)
+{
+        unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
+        int nbytes, sgcount;
+        struct scatterlist *sgpnt = NULL;
+        int bufflen = SCpnt->request_bufflen;
+	unsigned long iflags;
+
+	if (upper_blk || (block + num > CAPACITY)) {
+		*errstsp = (COMMAND_COMPLETE << 8) |
+			   (CHECK_CONDITION << 1);
+		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
+		return 1;
+	}
+#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
+	{
+		int delay = SCSI_SETUP_LATENCY;
+
+		delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
+		if (delay)
+			usleep(delay);
+	}
+#endif
+
+	read_lock_irqsave(&sdebug_atomic_rw, iflags);
+        sgcount = 0;
+	nbytes = bufflen;
+	/* printk("scsi_debug_read: block=%d, tot_bufflen=%d\n", 
+	       block, bufflen); */
+	if (SCpnt->use_sg) {
+		sgcount = 0;
+		sgpnt = (struct scatterlist *) buff;
+		buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+		bufflen = sgpnt[sgcount].length;
+	}
+	*errstsp = 0;
+	do {
+		int resid, k, off, len, rem, blk;
+		unsigned char * bp;
+
+		/* If this is block 0, then we want to read the partition
+		 * table for this device.  Let's make one up */
+		if (scsi_debug_fake_blk0 && (block == 0) && (! made_block0)) {
+			scsi_debug_mkblock0(buff, bufflen, SCpnt);
+			*errstsp = 0;
+			break;
+		}
+		bp = buff;
+		blk = block;
+		for (resid = bufflen; resid > 0; resid -= len) {
+			k = blk / SECT_PER_ELEM; 
+			off = (blk % SECT_PER_ELEM) * SECT_SIZE;
+			rem = STORE_ELEM_SIZE - off;
+			len = (resid > rem) ? rem : resid;
+/* printk("sdr: blk=%d k=%d off=%d rem=%d resid"
+			       "=%d len=%d  sgcount=%d\n", blk, k, 
+				off, rem, resid, len, sgcount); */
+			memcpy(bp, store_arr[k].p + off, len);
+			bp += len;
+			blk += len / SECT_SIZE;
+		}
+#if 0
+		/* Simulate a disk change */
+		if (block == 0xfff0) {
+			sense_buffer[0] = 0x70;
+			sense_buffer[2] = UNIT_ATTENTION;
+			starts[0] += 10;
+			starts[1] += 10;
+			starts[2] += 10;
+
+			*errstsp = (COMMAND_COMPLETE << 8) | 
+				   (CHECK_CONDITION << 1);
+			read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+			return 1;
+		}	/* End phony disk change code */
+#endif
+		nbytes -= bufflen;
+		if (SCpnt->use_sg) {
+			block += bufflen >> POW2_SECT_SIZE;
+			sgcount++;
+			if (nbytes) {
+				buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+				bufflen = sgpnt[sgcount].length;
+			}
+		}
+		else if (nbytes > 0)
+			printk("sdebug_read: unexpected nbytes=%d\n", nbytes);
+	} while (nbytes);
+	read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+	return 0;
+}
+
+static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+			    int num, int * errstsp, Sdebug_dev_info * devip)
+{
+        unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
+        int nbytes, sgcount;
+        struct scatterlist *sgpnt = NULL;
+        int bufflen = SCpnt->request_bufflen;
+	unsigned long iflags;
+
+	if (upper_blk || (block + num > CAPACITY)) {
+		*errstsp = (COMMAND_COMPLETE << 8) |
+			   (CHECK_CONDITION << 1);
+		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
+		return 1;
+	}
+
+	write_lock_irqsave(&sdebug_atomic_rw, iflags);
+        sgcount = 0;
+	nbytes = bufflen;
+	if (SCpnt->use_sg) {
+		sgcount = 0;
+		sgpnt = (struct scatterlist *) buff;
+		buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+		bufflen = sgpnt[sgcount].length;
+	}
+	*errstsp = 0;
+	do {
+		int resid, k, off, len, rem, blk;
+		unsigned char * bp;
+
+		bp = buff;
+		blk = block;
+		for (resid = bufflen; resid > 0; resid -= len) {
+			k = blk / SECT_PER_ELEM; 
+			off = (blk % SECT_PER_ELEM) * SECT_SIZE;
+			rem = STORE_ELEM_SIZE - off;
+			len = (resid > rem) ? rem : resid;
+			memcpy(store_arr[k].p + off, bp, len);
+			bp += len;
+			blk += len / SECT_SIZE;
+		}
+
+		nbytes -= bufflen;
+		if (SCpnt->use_sg) {
+			block += bufflen >> POW2_SECT_SIZE;
+			sgcount++;
+			if (nbytes) {
+				buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+				bufflen = sgpnt[sgcount].length;
+			}
+		}
+		else if (nbytes > 0)
+			printk("sdebug_write: unexpected nbytes=%d\n", nbytes);
+	} while (nbytes);
+	write_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+	return 0;
+}
+
 static void scsi_debug_send_self_command(struct Scsi_Host * shpnt)
 {
 	static unsigned char cmd[6] =
@@ -581,10 +723,6 @@
 {
 	Scsi_Cmnd *SCtmp;
 	void (*my_done) (Scsi_Cmnd *);
-#ifdef DEBUG
-	int to;
-#endif
-
 #if 0
 	del_timer(&timeout[indx]);
 #endif
@@ -599,59 +737,219 @@
 		printk("scsi_debug_intr_handle: Unexpected interrupt\n");
 		return;
 	}
-#ifdef DEBUG
+#if 0
 	printk("In intr_handle...");
 	printk("...done %d %x %d %d\n", i, my_done, to, jiffies);
 	printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done);
 #endif
 
 	my_done(SCtmp);
-#ifdef DEBUG
+#if 0
 	printk("Called done.\n");
 #endif
 }
 
+static int initialized = 0;
+
+static int do_init(void)
+{
+	int sz;
+
+	starts[3] = CAPACITY;
+	sz = sizeof(Sd_store_elem) * STORE_ELEMENTS;
+	store_arr = kmalloc(sz, GFP_ATOMIC);
+	if (NULL == store_arr)
+		return 1;
+	memset(store_arr, 0, sz);
+
+	sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES;
+	do_done = kmalloc(sz, GFP_ATOMIC);
+	if (NULL == do_done)
+		goto out;
+	memset((void *)do_done, 0, sz);
+
+	sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES;
+	timeout = kmalloc(sz, GFP_ATOMIC);
+	if (NULL == timeout)
+		goto out;
+	memset(timeout, 0, sz);
+
+	sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES;
+	SCint = kmalloc(sz, GFP_ATOMIC);
+	if (NULL == SCint)
+		goto out;
+	memset(SCint, 0, sz);
+
+	return 0;
+
+out:
+	if (store_arr)
+		kfree(store_arr);
+	if (do_done)
+		kfree((void *)do_done);
+	if (timeout)
+		kfree(timeout);
+	if (SCint)
+		kfree(SCint);
+	return 1;
+}
+
+static void do_end(void)
+{
+	kfree(SCint);
+	kfree(timeout);
+	kfree((void *)do_done);
+	kfree(store_arr);
+}
+
 
 int scsi_debug_detect(Scsi_Host_Template * tpnt)
 {
-	int i;
+	int k, num, sz;
+
+	if (0 == initialized) {
+		++initialized;
+		sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs;
+		devInfop = kmalloc(sz, GFP_ATOMIC);
+		if (NULL == devInfop) {
+			printk("scsi_debug_detect: out of memory, 0.5\n");
+			return 0;
+		}
+		memset(devInfop, 0, sz);
+		if (do_init()) {
+			printk("scsi_debug_detect: out of memory, 0\n");
+			return 0;
+		}
+		for (k = 0; k < STORE_ELEMENTS; ++k) {
+			store_arr[k].p = (unsigned char *)
+				__get_free_pages(GFP_ATOMIC, STORE_ELEM_ORDER);
+			if (0 == store_arr[k].p)
+				goto detect_err;
+			memset(store_arr[k].p, 0, STORE_ELEM_SIZE);
+		}
+		for (k = 0; k < NUM_SENSE_BUFFS; ++k)
+			sense_buffers[k][0] = 0x70;
+		for (k = 0; k < NR_HOSTS_PRESENT; k++) {
+			tpnt->proc_name = "scsi_debug";	/* In the loop??? */
+			scsi_register(tpnt, 0);
+		}
+		return NR_HOSTS_PRESENT;
+	}
+	else {
+		printk("scsi_debug_detect: called again\n");
+		return 0;
+	}
 
-	for (i = 0; i < NR_HOSTS_PRESENT; i++) {
-		tpnt->proc_name = "scsi_debug";	/* Huh? In the loop??? */
-		scsi_register(tpnt, 0);
+detect_err:
+	num = k;
+	for (k = 0; k < STORE_ELEMENTS; ++k) {
+		if (0 != store_arr[k].p) {
+			free_pages((unsigned long)store_arr[k].p, 
+				   STORE_ELEM_ORDER);
+			store_arr[k].p = NULL;
+		}
 	}
-	return NR_HOSTS_PRESENT;
+	printk("scsi_debug_detect: out of memory: %d out of %d bytes\n",
+	       (int)(num * STORE_ELEM_SIZE), 
+	       (int)(scsi_debug_dev_size_mb * 1024 * 1024));
+	return 0;
+}
+
+
+static int num_releases = 0;
+
+int scsi_debug_release(struct Scsi_Host * hpnt)
+{
+	int k;
+	
+	scsi_unregister(hpnt);
+	if (++num_releases != NR_HOSTS_PRESENT)
+		return 0;
+
+	for (k = 0; k < STORE_ELEMENTS; ++k) {
+		if (0 != store_arr[k].p) {
+			free_pages((unsigned long)store_arr[k].p, 
+				   STORE_ELEM_ORDER);
+			store_arr[k].p = NULL;
+		}
+	}
+	do_end();
+	kfree(devInfop);
+	return 0;
+}
+
+static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp)
+{
+	int k;
+	unsigned short host_no, id;
+	Sdebug_dev_info * devip;
+
+	host_no = sdp->host->host_no;
+	id = (unsigned short)sdp->id;
+	for (k = 0; k < scsi_debug_num_devs; ++k) {
+		devip = &devInfop[k];
+		if (devip->sdp && (host_no == devip->host_no) &&
+		    (id == devip->id)) {
+			devip->sdp = sdp; /* overwrite previous sdp */
+			return devip;
+		}
+		if (NULL == devip->sdp) {
+			devip->sdp = sdp;
+			devip->host_no = host_no;
+			devip->id = id;
+			devip->reset = 1;
+			devip->sb_index = 0;
+			return devip;
+		}
+	}
+	return NULL;
+}
+
+static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+			    int asc, int asq, int inbandLen)
+{
+	char * sbuff;
+	if ((index < 0) || (index >= NUM_SENSE_BUFFS))
+		return;
+	if (devip)
+		devip->sb_index = index;
+	sbuff = &sense_buffers[index][0];
+	memset(sbuff, 0, SENSE_BUFF_LEN);
+	sbuff[0] = 0x70;
+	sbuff[2] = key;
+	sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0;
+	sbuff[12] = asc;
+	sbuff[13] = asq;
 }
 
 int scsi_debug_abort(Scsi_Cmnd * SCpnt)
 {
-#if 0
+#if 1
+	++num_aborts;
+	return SUCCESS;
+#else
 	int j;
 	void (*my_done) (Scsi_Cmnd *);
-	unsigned long flags;
-#endif
-
-	DEB(printk("scsi_debug_abort\n"));
-#if 0
+	unsigned long iflags;
 	SCpnt->result = SCpnt->abort_reason << 16;
 	for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) {
 		if (SCpnt == SCint[j]) {
 			my_done = do_done[j];
 			my_done(SCpnt);
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&mailbox_lock, iflags);
 			timeout[j] = 0;
 			SCint[j] = NULL;
 			do_done[j] = NULL;
-			restore_flags(flags);
-		};
-	};
-#endif
+			spin_unlock_irqrestore(&mailbox_lock, iflags);
+		}
+	}
 	return SCSI_ABORT_SNOOZE;
+#endif
 }
 
 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;
@@ -660,35 +958,130 @@
 	return 0;
 }
 
+#if 0
 int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
 {
 	int i;
-	unsigned long flags;
+	unsigned long iflags;
 
 	void (*my_done) (Scsi_Cmnd *);
 	printk("Bus unlocked by reset - %d\n", why);
 	scsi_debug_lockup = 0;
-	DEB(printk("scsi_debug_reset called\n"));
 	for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
 		if (SCint[i] == NULL)
 			continue;
 		SCint[i]->result = DID_RESET << 16;
 		my_done = do_done[i];
 		my_done(SCint[i]);
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&mailbox_lock, iflags);
 		SCint[i] = NULL;
 		do_done[i] = NULL;
 		timeout[i].function = NULL;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&mailbox_lock, iflags);
 	}
 	return SCSI_RESET_SUCCESS;
 }
+#endif
+
+int scsi_debug_device_reset(Scsi_Cmnd * SCpnt)
+{
+	Scsi_Device * sdp;
+	int k;
+
+	++num_dev_resets;
+	if (SCpnt && ((sdp = SCpnt->device))) {
+		for (k = 0; k < scsi_debug_num_devs; ++k) {
+			if (sdp->hostdata == (devInfop + k))
+				break;
+		}
+		if (k < scsi_debug_num_devs)
+			devInfop[k].reset = 1;
+	}
+	return SUCCESS;
+}
 
-const char *scsi_debug_info(void)
+int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt)
 {
-	static char buffer[] = " ";	/* looks nicer without anything here */
-	return buffer;
+	Scsi_Device * sdp;
+	struct Scsi_Host * hp;
+	int k;
+
+	++num_bus_resets;
+	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
+		for (k = 0; k < scsi_debug_num_devs; ++k) {
+			if (hp == devInfop[k].sdp->host)
+				devInfop[k].reset = 1;
+		}
+	}
+	return SUCCESS;
+}
+
+int scsi_debug_host_reset(Scsi_Cmnd * SCpnt)
+{
+	int k;
+
+	++num_host_resets;
+	for (k = 0; k < scsi_debug_num_devs; ++k)
+		devInfop[k].reset = 1;
+
+	return SUCCESS;
+}
+
+#ifndef MODULE
+static int __init scsi_debug_num_devs_setup(char *str)
+{   
+    int tmp; 
+    
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_num_devs = tmp;
+        return 1;
+    } else {
+        printk("scsi_debug_num_devs: usage scsi_debug_num_devs=<n> "
+               "(<n> can be from 1 to around 2000)\n");
+        return 0;
+    }
+}
+
+__setup("scsi_debug_num_devs=", scsi_debug_num_devs_setup);
+
+static int __init scsi_debug_dev_size_mb_setup(char *str)
+{   
+    int tmp; 
+    
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_dev_size_mb = tmp;
+        return 1;
+    } else {
+        printk("scsi_debug_dev_size_mb: usage scsi_debug_dev_size_mb=<n>\n"
+               "    (<n> is number of MB ram shared by all devs\n");
+        return 0;
+    }
+}
+
+__setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup);
+#endif
+
+MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
+MODULE_DESCRIPTION("SCSI debug adapter driver");
+MODULE_PARM(scsi_debug_num_devs, "i");
+MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate");
+MODULE_PARM(scsi_debug_dev_size_mb, "i");
+MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+static char sdebug_info[256];
+
+const char * scsi_debug_info(struct Scsi_Host * shp)
+{
+	sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, "
+		"dev_size_mb=%d\n", scsi_debug_version_str,
+		scsi_debug_num_devs, scsi_debug_dev_size_mb);
+	return sdebug_info;
 }
 
 /* scsi_debug_proc_info
@@ -738,10 +1131,20 @@
 
 	}
 	begin = 0;
-	pos = len = sprintf(buffer,
-	"This driver is not a real scsi driver, but it plays one on TV.\n"
+	pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
+	    "num_devs=%d, shared (ram) size=%d MB, sector_size=%d bytes\n" 
+	    "cylinders=%d, heads=%d, sectors=%d\n"
+	    "number of aborts=%d, device_reset=%d, bus_resets=%d, " 
+	    "host_resets=%d\n",
+	    scsi_debug_version_str, scsi_debug_num_devs, 
+	    scsi_debug_dev_size_mb, SECT_SIZE,
+	    N_CYLINDER, N_HEAD, N_SECTOR,
+	    num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
+#if 0
+	 "This driver is not a real scsi driver, but it plays one on TV.\n"
 	 "It is very handy for debugging specific problems because you\n"
 			 "can simulate a variety of error conditions\n");
+#endif
 	if (pos < offset) {
 		len = 0;
 		begin = pos;
@@ -754,44 +1157,8 @@
 	return (len);
 }
 
-#ifdef CONFIG_USER_DEBUG
-/*
- * This is a hack for the user space emulator.  It allows us to
- * "insert" arbitrary numbers of additional drivers.
- */
-void *scsi_debug_get_handle(void)
-{
-	static Scsi_Host_Template driver_copy = SCSI_DEBUG;
-	void *rtn;
-	rtn = kmalloc(sizeof(driver_copy), GFP_ATOMIC);
-	if(rtn==NULL)
-		return NULL;
-	memcpy(rtn, (void *) &driver_copy, sizeof(driver_copy));
-	return rtn;
-}
-#endif
-
 /* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = SCSI_DEBUG;
+static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE;
 
 #include "scsi_module.c"
 
-/*
- * Overrides for Emacs so that we almost follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
-MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/scsi_debug.h linux/drivers/scsi/scsi_debug.h
--- v2.5.2/linux/drivers/scsi/scsi_debug.h	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/scsi_debug.h	Thu Jan 17 13:59:33 2002
@@ -8,34 +8,41 @@
 int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int scsi_debug_abort(Scsi_Cmnd *);
 int scsi_debug_biosparam(Disk *, kdev_t, int[]);
-int scsi_debug_reset(Scsi_Cmnd *, unsigned int);
+int scsi_debug_bus_reset(Scsi_Cmnd *);
+int scsi_debug_dev_reset(Scsi_Cmnd *);
+int scsi_debug_host_reset(Scsi_Cmnd *);
 int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
+const char * scsi_debug_info(struct Scsi_Host *);
 
 #ifndef NULL
 #define NULL 0
 #endif
 
-
-#define SCSI_DEBUG_MAILBOXES 1
-
 /*
- * Allow the driver to reject commands.  Thus we accept only one, but
- * and the mid-level will queue the remainder.
+ * This driver is written for the lk 2.5 series
  */
 #define SCSI_DEBUG_CANQUEUE  255
 
-#define SCSI_DEBUG {proc_info:         scsi_debug_proc_info,	\
+#define SCSI_DEBUG_MAX_CMD_LEN 16
+
+#define SCSI_DEBUG_TEMPLATE \
+		   {proc_info:         scsi_debug_proc_info,	\
 		    name:              "SCSI DEBUG",		\
+		    info:              scsi_debug_info,		\
 		    detect:            scsi_debug_detect,	\
+		    release:           scsi_debug_release,	\
 		    queuecommand:      scsi_debug_queuecommand, \
-		    abort:             scsi_debug_abort,	\
-		    reset:             scsi_debug_reset,	\
+		    eh_abort_handler:  scsi_debug_abort,	\
+		    eh_bus_reset_handler: scsi_debug_bus_reset,	\
+		    eh_device_reset_handler: scsi_debug_device_reset,	\
+		    eh_host_reset_handler: scsi_debug_host_reset,	\
 		    bios_param:        scsi_debug_biosparam,	\
 		    can_queue:         SCSI_DEBUG_CANQUEUE,	\
 		    this_id:           7,			\
-		    sg_tablesize:      16,			\
+		    sg_tablesize:      64,			\
 		    cmd_per_lun:       3,			\
 		    unchecked_isa_dma: 0,			\
 		    use_clustering:    ENABLE_CLUSTERING,	\
 }
+
 #endif
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c
--- v2.5.2/linux/drivers/scsi/seagate.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/seagate.c	Mon Jan 28 14:36:59 2002
@@ -503,7 +503,7 @@
 	hostno = instance->host_no;
 	if (request_irq (irq, do_seagate_reconnect_intr, SA_INTERRUPT,
 			 (controller_type == SEAGATE) ? "seagate" : "tmc-8xx",
-			 NULL)) {
+			 instance)) {
 		printk ("scsi%d : unable to allocate IRQ%d\n", hostno, irq);
 		return 0;
 	}
@@ -629,10 +629,11 @@
 static void do_seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
-
-	spin_lock_irqsave (&io_request_lock, flags);
+	struct Scsi_Host *dev = dev_id;
+	
+	spin_lock_irqsave (dev->host_lock, flags);
 	seagate_reconnect_intr (irq, dev_id, regs);
-	spin_unlock_irqrestore (&io_request_lock, flags);
+	spin_unlock_irqrestore (dev->host_lock, flags);
 }
 
 static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs)
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.5.2/linux/drivers/scsi/sg.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/sg.c	Thu Jan 17 13:59:33 2002
@@ -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.5.23 (20020103)";
 #endif
- static int sg_version_num = 30120; /* 2 digits for each component */
+ static int sg_version_num = 30523; /* 2 digits for each component */
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -76,12 +76,18 @@
 #include <linux/version.h>
 #endif /* LINUX_VERSION_CODE */
 
+#define SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
+
 #define SG_ALLOW_DIO_DEF 0
 #define SG_ALLOW_DIO_CODE	/* compile out be commenting this define */
 #ifdef SG_ALLOW_DIO_CODE
 #include <linux/iobuf.h>
 #endif
 
+#define SG_NEW_KIOVEC 0	/* use alloc_kiovec(), not alloc_kiovec_sz() */
+
+#define SG_MAX_DEVS_MASK ((1U << KDEV_MINOR_BITS) - 1)
+
 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
@@ -95,14 +101,8 @@
 #define SG_SECTOR_SZ 512
 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
 
-#define SG_LOW_POOL_THRESHHOLD 30
-#define SG_MAX_POOL_SECTORS 320  /* Max. number of pool sectors to take */
-
-static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS;
-
 #define SG_HEAP_PAGE 1  /* heap from kernel via get_free_pages() */
 #define SG_HEAP_KMAL 2  /* heap from kernel via kmalloc() */
-#define SG_HEAP_POOL 3  /* heap from scsi dma pool (mid-level) */
 #define SG_USER_MEM 4   /* memory belongs to user space */
 
 #define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */
@@ -136,10 +136,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' */
@@ -182,6 +182,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 */
@@ -203,7 +204,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,
@@ -233,13 +235,15 @@
 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);
+static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp);
 #ifdef CONFIG_PROC_FS
 static int sg_last_dev(void);
 #endif
@@ -337,9 +341,8 @@
     Sg_device * sdp;
     Sg_fd * sfp;
 
-    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) {
+    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
         return -ENXIO;
-    }
     SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", minor(sdp->i_rdev)));
     sg_fasync(-1, filp, 0);   /* remove filp from async notification list */
     if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
@@ -615,6 +618,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);
@@ -681,7 +698,6 @@
     srp->my_cmdp = SRpnt;
     q = &SRpnt->sr_device->request_queue;
     SRpnt->sr_request.rq_dev = sdp->i_rdev;
-    SRpnt->sr_request.rq_status = RQ_ACTIVE;
     SRpnt->sr_sense_buffer[0] = 0;
     SRpnt->sr_cmd_len = hp->cmd_len;
     if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) {
@@ -849,7 +865,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);
@@ -1030,6 +1046,146 @@
     return (retval < 0) ? retval : 0;
 }
 
+static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp)
+{
+    return (sclp && sclp->page) ? 
+    		(unsigned char *)page_address(sclp->page) + sclp->offset :
+		NULL;
+}
+
+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 = sg_scatg2virt(sclp) + 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 = sg_scatg2virt(sclp) + 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 (0 != sclp->offset)
+	    	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)
@@ -1076,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 = mk_kdev(0, 0);  /* "sg" _disowns_ request blk */
+
     srp->my_cmdp = NULL;
     srp->done = 1;
     read_unlock(&sg_dev_arr_lock);
@@ -1121,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)
@@ -1152,6 +1316,7 @@
 	poll:		sg_poll,
 	ioctl:		sg_ioctl,
 	open:		sg_open,
+	mmap:		sg_mmap,
 	release:	sg_release,
 	fasync:		sg_fasync,
 };
@@ -1176,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;
@@ -1189,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;
     }
@@ -1212,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;
     }
 }
@@ -1238,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 *));
@@ -1250,13 +1415,13 @@
 
     for(k = 0; k < sg_template.dev_max; k++)
         if(! sg_dev_arr[k]) break;
-    if (k > MINORMASK) {
+    if (k > SG_MAX_DEVS_MASK) {
 	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);
+	       SG_MAX_DEVS_MASK);
 	return 1;
     }
     if(k < sg_template.dev_max)
@@ -1266,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;
     }
 
@@ -1293,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;
@@ -1371,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");
@@ -1417,9 +1585,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) {
@@ -1445,23 +1612,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 */
@@ -1470,13 +1638,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;
 	}
     }
@@ -1494,10 +1664,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,
@@ -1527,7 +1699,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);
@@ -1535,19 +1707,22 @@
     }
     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->page = kp->maplist[k];
+	sclp->offset = offset;
+#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
 	sclp->address = page_address(kp->maplist[k]) + offset;
-	sclp->page = NULL;
+#endif
 	sclp->length = num;
 	mem_src_arr[k] = SG_USER_MEM;
 	rem_sz -= num;
 	SCSI_LOG_TIMEOUT(5,
 	    printk("sg_build_dir: k=%d, a=0x%p, len=%d, ms=%d\n",
-	    k, sclp->address, num, mem_src_arr[k]));
+	    k, sg_scatg2virt(sclp), num, mem_src_arr[k]));
     }
     schp->k_use_sg = k;
     SCSI_LOG_TIMEOUT(5,
@@ -1569,7 +1744,7 @@
 {
     int ret_sz, mem_src;
     int blk_size = buff_size;
-    char * p = NULL;
+    unsigned char * p = NULL;
 
     if ((blk_size < 0) || (! sfp))
         return -EFAULT;
@@ -1609,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;
@@ -1627,14 +1802,17 @@
                 if (! p)
                     break;
             }
+            sclp->page = virt_to_page(p);
+            sclp->offset = (unsigned long)p & ~PAGE_MASK;
+#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
             sclp->address = p;
-	    sclp->page = NULL;
+#endif
             sclp->length = ret_sz;
 	    mem_src_arr[k] = mem_src;
 
 	    SCSI_LOG_TIMEOUT(5,
 		printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n",
-                k, sclp->address, ret_sz, mem_src));
+                k, sg_scatg2virt(sclp), ret_sz, mem_src));
         } /* end of for loop */
 	schp->k_use_sg = k;
 	SCSI_LOG_TIMEOUT(5,
@@ -1664,7 +1842,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,
@@ -1698,14 +1877,15 @@
 	struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 	char * mem_src_arr = sg_get_sgat_msa(schp);
 	ksglen = (int)sclp->length;
-	p = sclp->address;
+	p = sg_scatg2virt(sclp);
 
 	for (j = 0, k = 0; j < onum; ++j) {
 	    res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
 	    if (res) return res;
 
 	    for (; (k < schp->k_use_sg) && p;
-		 ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) {
+		 ++k, ++sclp, ksglen = (int)sclp->length, 
+		 	p = sg_scatg2virt(sclp)) {
 		ok = (SG_USER_MEM != mem_src_arr[k]);
 		if (usglen <= 0)
 		    break;
@@ -1766,7 +1946,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);
 }
 
@@ -1779,14 +1959,17 @@
         struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 	char * mem_src_arr = sg_get_sgat_msa(schp);
 
-	for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) {
+	for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
 	    mem_src = mem_src_arr[k];
 	    SCSI_LOG_TIMEOUT(5,
 		printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n",
-                       k, sclp->address, sclp->length, mem_src));
-            sg_free(sclp->address, sclp->length, mem_src);
-            sclp->address = NULL;
+                       k, sg_scatg2virt(sclp), sclp->length, mem_src));
+            sg_free(sg_scatg2virt(sclp), sclp->length, mem_src);
 	    sclp->page = NULL;
+            sclp->offset = 0;
+#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
+	    sclp->address = 0;
+#endif
             sclp->length = 0;
         }
 	sg_free(schp->buffer, schp->sglist_len, schp->buffer_mem_src);
@@ -1814,7 +1997,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,
@@ -1848,14 +2032,15 @@
 	struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 	char * mem_src_arr = sg_get_sgat_msa(schp);
 	ksglen = (int)sclp->length;
-	p = sclp->address;
+	p = sg_scatg2virt(sclp);
 
 	for (j = 0, k = 0; j < onum; ++j) {
 	    res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
 	    if (res) return res;
 
 	    for (; (k < schp->k_use_sg) && p;
-		 ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) {
+		 ++k, ++sclp, ksglen = (int)sclp->length, 
+		 	p = sg_scatg2virt(sclp)) {
 		ok = (SG_USER_MEM != mem_src_arr[k]);
 		if (usglen <= 0)
 		    break;
@@ -1896,14 +2081,14 @@
         int k, num;
         struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 
-	for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) {
+	for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
             num = (int)sclp->length;
             if (num > num_read_xfer) {
-                __copy_to_user(outp, sclp->address, num_read_xfer);
+                __copy_to_user(outp, sg_scatg2virt(sclp), num_read_xfer);
                 break;
             }
             else {
-                __copy_to_user(outp, sclp->address, num);
+                __copy_to_user(outp, sg_scatg2virt(sclp), num);
                 num_read_xfer -= num;
                 if (num_read_xfer <= 0)
                     break;
@@ -1949,7 +2134,7 @@
             if (rem <= num) {
 		if (0 == k) {
 		    req_schp->k_use_sg = 0;
-		    req_schp->buffer = sclp->address;
+		    req_schp->buffer = sg_scatg2virt(sclp);
 		}
 		else {
     		    sfp->save_scat_len = num;
@@ -2189,6 +2374,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;
@@ -2237,7 +2424,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));
@@ -2270,30 +2457,6 @@
         if (resp && retSzp) *retSzp = rqSz;
         return resp;
     }
-    if (SG_HEAP_POOL == mem_src) {
-        int num_sect = rqSz / SG_SECTOR_SZ;
-
-        if (0 != (rqSz & SG_SECTOR_MSK)) {
-            if (! retSzp)
-                return resp;
-            ++num_sect;
-            rqSz = num_sect * SG_SECTOR_SZ;
-        }
-        while (num_sect > 0) {
-            if ((num_sect <= sg_pool_secs_avail)) {
-                resp = kmalloc(rqSz, page_mask);
-                if (resp) {
-                    if (retSzp) *retSzp = rqSz;
-                    sg_pool_secs_avail -= num_sect;
-                    return resp;
-                }
-            }
-            if (! retSzp)
-                return resp;
-            num_sect /= 2;      /* try half as many */
-            rqSz = num_sect * SG_SECTOR_SZ;
-        }
-    }
     else if (SG_HEAP_PAGE == mem_src) {
         int order, a_size;
         int resSz = rqSz;
@@ -2311,7 +2474,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;
 }
 
@@ -2330,29 +2494,20 @@
 	switch (*mem_srcp)
         {
         case SG_HEAP_PAGE:
-            l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE;
+            l_ms = (size < PAGE_SIZE) ? SG_HEAP_KMAL : SG_HEAP_PAGE;
             resp = sg_low_malloc(size, low_dma, l_ms, 0);
             if (resp)
                 break;
             resp = sg_low_malloc(size, low_dma, l_ms, &size);
             if (! resp) {
-                l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL;
+                l_ms = (SG_HEAP_KMAL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_KMAL;
                 resp = sg_low_malloc(size, low_dma, l_ms, &size);
-                if (! resp) {
-                    l_ms = SG_HEAP_KMAL;
-                    resp = sg_low_malloc(size, low_dma, l_ms, &size);
-                }
             }
             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;
-            l_ms = SG_HEAP_POOL;
-            resp = sg_low_malloc(size, low_dma, l_ms, &size);
-            if (resp && retSzp) *retSzp = size;
             break;
         default:
             SCSI_LOG_TIMEOUT(1, printk("sg_malloc: bad ms=%d\n", *mem_srcp));
@@ -2365,18 +2520,19 @@
     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;
     switch (mem_src) {
-    case SG_HEAP_POOL:
-	{
-	    int num_sect = size / SG_SECTOR_SZ;
-
-	    kfree(buff);
-	    sg_pool_secs_avail += num_sect;
-	}
-	break;
     case SG_HEAP_KMAL:
 	kfree(buff);    /* size not used */
 	break;
@@ -2392,7 +2548,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;
     }
@@ -2408,14 +2564,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 = mk_kdev(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)
@@ -2427,7 +2582,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;
@@ -2477,8 +2632,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;
@@ -2671,7 +2826,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");
@@ -2680,8 +2835,7 @@
     max_dev = sg_last_dev();
     PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n",
 	       sg_template.dev_max, max_dev);
-    PRINT_PROC(" sg_pool_secs_aval=%d def_reserved_size=%d\n",
-	       sg_pool_secs_avail, sg_big_buff);
+    PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff);
     for (j = 0; j < max_dev; ++j) {
 	if ((sdp = sg_get_dev(j))) {
 	    Sg_fd * fp;
@@ -2717,8 +2871,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;
@@ -2728,8 +2884,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 -u --recursive --new-file v2.5.2/linux/drivers/scsi/sgiwd93.c linux/drivers/scsi/sgiwd93.c
--- v2.5.2/linux/drivers/scsi/sgiwd93.c	Sun Sep  9 10:52:35 2001
+++ linux/drivers/scsi/sgiwd93.c	Mon Jan 28 14:36:59 2002
@@ -66,10 +66,11 @@
 static void sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
-
-	spin_lock_irqsave(&io_request_lock, flags);
+	struct Scsi_Host *dev = dev_id;
+	
+	spin_lock_irqsave(dev->host_lock, flags);
 	wd33c93_intr((struct Scsi_Host *) dev_id);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 #undef DEBUG_DMA
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/sim710.c linux/drivers/scsi/sim710.c
--- v2.5.2/linux/drivers/scsi/sim710.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/sim710.c	Mon Jan 28 14:36:59 2002
@@ -907,9 +907,9 @@
     struct Scsi_Host *host = dev_id;
     unsigned long flags;
 
-    spin_lock_irqsave(&host->host_lock, flags);
+    spin_lock_irqsave(host->host_lock, flags);
     sim710_intr_handle(irq, host, regs);
-    spin_unlock_irqrestore(&host->host_lock, flags);
+    spin_unlock_irqrestore(host->host_lock, flags);
 }
 
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.5.2/linux/drivers/scsi/sr.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/sr.c	Thu Jan 17 13:59:33 2002
@@ -331,7 +331,7 @@
 
 	SCSI_LOG_HLQUEUE(2, printk("sr%d : %s %d/%ld 512 byte blocks.\n",
                                    devm,
-		   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+		   (rq_data_dir(&SCpnt->request) == WRITE) ? "writing" : "reading",
 				 this_count, SCpnt->request.nr_sectors));
 
 	SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.5.2/linux/drivers/scsi/st.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/st.c	Wed Jan 23 15:30:47 2002
@@ -9,19 +9,16 @@
    Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
    Michael Schaefer, J"org Weule, and Eric Youngdale.
 
-   Copyright 1992 - 2001 Kai Makisara
+   Copyright 1992 - 2002 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Sat Nov  3 19:30:55 2001 by makisara@kai.makisara.local
+   Last modified: Wed Jan 23 20:22:42 2002 by makisara
    Some small formal changes - aeb, 950809
 
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
-
-   Reminder: write_lock_irqsave() can be replaced by write_lock() when the old SCSI
-   error handling will be discarded.
  */
 
-static char *verstr = "20011103";
+static char *verstr = "20020123";
 
 #include <linux/module.h>
 
@@ -160,21 +157,19 @@
 static int append_to_buffer(const char *, ST_buffer *, int);
 static int from_buffer(ST_buffer *, char *, int);
 
-static int st_init(void);
 static int st_attach(Scsi_Device *);
 static int st_detect(Scsi_Device *);
 static void st_detach(Scsi_Device *);
 
-static struct Scsi_Device_Template st_template =
-{
-	name:"tape", 
-	tag:"st", 
-	scsi_type:TYPE_TAPE,
-	major:SCSI_TAPE_MAJOR, 
-	detect:st_detect, 
-	init:st_init,
-	attach:st_attach, 
-	detach:st_detach
+static struct Scsi_Device_Template st_template = {
+	module:		THIS_MODULE,
+	name:		"tape", 
+	tag:		"st", 
+	scsi_type:	TYPE_TAPE,
+	major:		SCSI_TAPE_MAJOR, 
+	detect:		st_detect, 
+	attach:		st_attach, 
+	detach:		st_detach
 };
 
 static int st_compression(Scsi_Tape *, int);
@@ -239,7 +234,7 @@
 		return 0;
 	}
 
-	if (driver_byte(result) & DRIVER_SENSE)
+	if ((driver_byte(result) & DRIVER_MASK) == DRIVER_SENSE)
 		scode = sense[2] & 0x0f;
 	else {
 		sense[0] = 0;
@@ -638,20 +633,96 @@
 	return 0;
 }
 
+/* Test if the drive is ready. Returns either one of the codes below or a negative system
+   error code. */
+#define CHKRES_READY       0
+#define CHKRES_NEW_SESSION 1
+#define CHKRES_NOT_READY   2
+#define CHKRES_NO_TAPE     3
+
+#define MAX_ATTENTIONS    10
+
+static int test_ready(Scsi_Tape *STp, int do_wait)
+{
+	int attentions, waits, max_wait, scode;
+	int retval = CHKRES_READY, new_session = FALSE;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	Scsi_Request *SRpnt = NULL;
+
+	max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
+
+	for (attentions=waits=0; ; ) {
+		memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
+		cmd[0] = TEST_UNIT_READY;
+		SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
+				   STp->long_timeout, MAX_READY_RETRIES, TRUE);
+
+		if (!SRpnt) {
+			retval = (STp->buffer)->syscall_result;
+			break;
+		}
+
+		if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) {
+
+			scode = (SRpnt->sr_sense_buffer[2] & 0x0f);
+
+			if (scode == UNIT_ATTENTION) { /* New media? */
+				new_session = TRUE;
+				if (attentions < MAX_ATTENTIONS) {
+					attentions++;
+					continue;
+				}
+				else {
+					retval = (-EIO);
+					break;
+				}
+			}
+
+			if (scode == NOT_READY) {
+				if (waits < max_wait) {
+					set_current_state(TASK_INTERRUPTIBLE);
+					schedule_timeout(HZ);
+					if (signal_pending(current)) {
+						retval = (-EINTR);
+						break;
+					}
+					waits++;
+					continue;
+				}
+				else {
+					if ((STp->device)->scsi_level >= SCSI_2 &&
+					    SRpnt->sr_sense_buffer[12] == 0x3a)	/* Check ASC */
+						retval = CHKRES_NO_TAPE;
+					else
+						retval = CHKRES_NOT_READY;
+					break;
+				}
+			}
+		}
+
+		retval = (STp->buffer)->syscall_result;
+		if (!retval)
+			retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY;
+		break;
+	}
+
+	if (SRpnt != NULL)
+		scsi_release_request(SRpnt);
+	return retval;
+}
+
+
 /* See if the drive is ready and gather information about the tape. Return values:
    < 0   negative error code from errno.h
    0     drive ready
    1     drive not ready (possibly no tape)
 */
-#define CHKRES_READY      0
-#define CHKRES_NOT_READY  1
-
 static int check_tape(Scsi_Tape *STp, struct file *filp)
 {
-	int i, retval, new_session = FALSE;
+	int i, retval, new_session = FALSE, do_wait;
 	unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning;
 	unsigned short st_flags = filp->f_flags;
-	Scsi_Request *SRpnt;
+	Scsi_Request *SRpnt = NULL;
 	ST_mode *STm;
 	ST_partstat *STps;
 	int dev = TAPE_NR(STp->devt);
@@ -668,32 +739,16 @@
 	}
 	STm = &(STp->modes[STp->current_mode]);
 
-	memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
-	cmd[0] = TEST_UNIT_READY;
-
 	saved_cleaning = STp->cleaning_req;
 	STp->cleaning_req = 0;
-	SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout,
-			   MAX_READY_RETRIES, TRUE);
-	if (!SRpnt) {
-		retval = (STp->buffer)->syscall_result;
-		goto err_out;
-	}
 
-	if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
-	    (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
+	do_wait = ((filp->f_flags & O_NONBLOCK) == 0);
+	retval = test_ready(STp, do_wait);
 
-		/* Flush the queued UNIT ATTENTION sense data */
-		for (i=0; i < 10; i++) {
-                        memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
-                        cmd[0] = TEST_UNIT_READY;
-                        SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
-					   STp->long_timeout, MAX_READY_RETRIES, TRUE);
-                        if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
-                            (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
-                                break;
-		}
+	if (retval < 0)
+	    goto err_out;
 
+	if (retval == CHKRES_NEW_SESSION) {
 		(STp->device)->was_reset = 0;
 		STp->partition = STp->new_partition = 0;
 		if (STp->can_partitions)
@@ -710,26 +765,23 @@
 		}
 		new_session = TRUE;
 	}
-	else
+	else {
 		STp->cleaning_req |= saved_cleaning;
 
-	if ((STp->buffer)->syscall_result != 0) {
-		if ((STp->device)->scsi_level >= SCSI_2 &&
-		    (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
-		    (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
-		    SRpnt->sr_sense_buffer[12] == 0x3a) {	/* Check ASC */
-			STp->ready = ST_NO_TAPE;
-		} else
-			STp->ready = ST_NOT_READY;
-		scsi_release_request(SRpnt);
-		SRpnt = NULL;
-		STp->density = 0;	/* Clear the erroneous "residue" */
-		STp->write_prot = 0;
-		STp->block_size = 0;
-		STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
-		STp->partition = STp->new_partition = 0;
-		STp->door_locked = ST_UNLOCKED;
-		return CHKRES_NOT_READY;
+		if (retval == CHKRES_NOT_READY || retval == CHKRES_NO_TAPE) {
+			if (retval == CHKRES_NO_TAPE)
+				STp->ready = ST_NO_TAPE;
+			else
+				STp->ready = ST_NOT_READY;
+
+			STp->density = 0;	/* Clear the erroneous "residue" */
+			STp->write_prot = 0;
+			STp->block_size = 0;
+			STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
+			STp->partition = STp->new_partition = 0;
+			STp->door_locked = ST_UNLOCKED;
+			return CHKRES_NOT_READY;
+		}
 	}
 
 	if (STp->omit_blklims)
@@ -740,6 +792,10 @@
 
 		SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->timeout,
 				   MAX_READY_RETRIES, TRUE);
+		if (!SRpnt) {
+			retval = (STp->buffer)->syscall_result;
+			goto err_out;
+		}
 
 		if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) {
 			STp->max_block = ((STp->buffer)->b_data[1] << 16) |
@@ -763,6 +819,10 @@
 
 	SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->timeout,
 			   MAX_READY_RETRIES, TRUE);
+	if (!SRpnt) {
+		retval = (STp->buffer)->syscall_result;
+		goto err_out;
+	}
 
 	if ((STp->buffer)->syscall_result != 0) {
                 DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev));
@@ -862,22 +922,21 @@
 	Scsi_Tape *STp;
 	ST_partstat *STps;
 	int dev = TAPE_NR(inode->i_rdev);
-	unsigned long flags;
 
-	write_lock_irqsave(&st_dev_arr_lock, flags);
+	write_lock(&st_dev_arr_lock);
 	STp = scsi_tapes[dev];
 	if (dev >= st_template.dev_max || STp == NULL) {
-		write_unlock_irqrestore(&st_dev_arr_lock, flags);
+		write_unlock(&st_dev_arr_lock);
 		return (-ENXIO);
 	}
 
 	if (STp->in_use) {
-		write_unlock_irqrestore(&st_dev_arr_lock, flags);
+		write_unlock(&st_dev_arr_lock);
 		DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); )
 		return (-EBUSY);
 	}
 	STp->in_use = 1;
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	write_unlock(&st_dev_arr_lock);
 	STp->rew_at_close = STp->autorew_dev = (minor(inode->i_rdev) & 0x80) == 0;
 
 	if (STp->device->host->hostt->module)
@@ -891,7 +950,7 @@
 
 	/* Allocate a buffer for this user */
 	need_dma_buffer = STp->restr_dma;
-	write_lock_irqsave(&st_dev_arr_lock, flags);
+	write_lock(&st_dev_arr_lock);
 	for (i = 0; i < st_nbr_buffers; i++)
 		if (!st_buffers[i]->in_use &&
 		    (!need_dma_buffer || st_buffers[i]->dma)) {
@@ -899,7 +958,7 @@
 			(STp->buffer)->in_use = 1;
 			break;
 		}
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	write_unlock(&st_dev_arr_lock);
 	if (i >= st_nbr_buffers) {
 		STp->buffer = new_tape_buffer(FALSE, need_dma_buffer, TRUE);
 		if (STp->buffer == NULL) {
@@ -935,6 +994,11 @@
 	retval = check_tape(STp, filp);
 	if (retval < 0)
 		goto err_out;
+	if ((filp->f_flags & O_NONBLOCK) == 0 &&
+	    retval != CHKRES_READY) {
+		retval = (-EIO);
+		goto err_out;
+	}
 	return 0;
 
  err_out:
@@ -1076,7 +1140,6 @@
 {
 	int result = 0;
 	Scsi_Tape *STp;
-	unsigned long flags;
 
 	kdev_t devt = inode->i_rdev;
 	int dev;
@@ -1091,16 +1154,16 @@
 
 	if (STp->buffer != NULL) {
 		normalize_buffer(STp->buffer);
-		write_lock_irqsave(&st_dev_arr_lock, flags);
+		write_lock(&st_dev_arr_lock);
 		(STp->buffer)->in_use = 0;
 		STp->buffer = NULL;
 	}
 	else {
-		write_lock_irqsave(&st_dev_arr_lock, flags);
+		write_lock(&st_dev_arr_lock);
 	}
 
 	STp->in_use = 0;
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	write_unlock(&st_dev_arr_lock);
 	STp->device->access_count--;
 	if (STp->device->host->hostt->module)
 		__MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
@@ -1944,6 +2007,10 @@
 			STm->default_blksize = value;
 			printk(KERN_INFO "st%d: Default block size set to %d bytes.\n",
 			       dev, STm->default_blksize);
+			if (STp->ready == ST_READY) {
+				STp->blksize_changed = FALSE;
+				set_mode_densblk(STp, STm);
+			}
 		}
 	} else if (code == MT_ST_TIMEOUTS) {
 		value = (options & ~MT_ST_OPTIONS);
@@ -1979,6 +2046,10 @@
 				STm->default_density = value & 0xff;
 				printk(KERN_INFO "st%d: Density default set to %x\n",
 				       dev, STm->default_density);
+				if (STp->ready == ST_READY) {
+					STp->density_changed = FALSE;
+					set_mode_densblk(STp, STm);
+				}
 			}
 		} else if (code == MT_ST_DEF_DRVBUFFER) {
 			if (value == MT_ST_CLEAR_DEFAULT) {
@@ -1990,6 +2061,8 @@
 				printk(KERN_INFO
                                        "st%d: Drive buffer default set to %x\n",
 				       dev, STp->default_drvbuffer);
+				if (STp->ready == ST_READY)
+					st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer);
 			}
 		} else if (code == MT_ST_DEF_COMPRESSION) {
 			if (value == MT_ST_CLEAR_DEFAULT) {
@@ -1997,9 +2070,20 @@
 				printk(KERN_INFO
                                        "st%d: Compression default disabled.\n", dev);
 			} else {
-				STm->default_compression = (value & 1 ? ST_YES : ST_NO);
-				printk(KERN_INFO "st%d: Compression default set to %x\n",
-				       dev, (value & 1));
+				if ((value & 0xff00) != 0) {
+					STp->c_algo = (value & 0xff00) >> 8;
+					printk(KERN_INFO "st%d: Compression algorithm set to 0x%x.\n",
+					       dev, STp->c_algo);
+				}
+				if ((value & 0xff) != 0xff) {
+					STm->default_compression = (value & 1 ? ST_YES : ST_NO);
+					printk(KERN_INFO "st%d: Compression default set to %x\n",
+					       dev, (value & 1));
+					if (STp->ready == ST_READY) {
+						STp->compression_changed = FALSE;
+						st_compression(STp, (STm->default_compression == ST_YES));
+					}
+				}
 			}
 		}
 	} else
@@ -2087,6 +2171,7 @@
 #define COMPRESSION_PAGE_LENGTH 16
 
 #define CP_OFF_DCE_DCC          2
+#define CP_OFF_C_ALGO           7
 
 #define DCE_MASK  0x80
 #define DCC_MASK  0x40
@@ -2122,16 +2207,22 @@
                     (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0)));
 
 	/* Check if compression can be changed */
-	if ((b_data[mpoffs + 2] & DCC_MASK) == 0) {
+	if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) {
                 DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev));
 		return (-EIO);
 	}
 
 	/* Do the change */
-	if (state)
+	if (state) {
 		b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK;
-	else
+		if (STp->c_algo != 0)
+			b_data[mpoffs + CP_OFF_C_ALGO] = STp->c_algo;
+	}
+	else {
 		b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK;
+		if (STp->c_algo != 0)
+			b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */
+	}
 
 	retval = write_mode_page(STp, COMPRESSION_PAGE);
 	if (retval) {
@@ -2171,7 +2262,7 @@
 	 */
 	if (load_code >= 1 + MT_ST_HPLOADER_OFFSET
 	    && load_code <= 6 + MT_ST_HPLOADER_OFFSET) {
-		DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n",
+		DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2d.\n",
 			    dev, (cmd[4]) ? "" : "un",
 			    load_code - MT_ST_HPLOADER_OFFSET));
 		cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
@@ -2202,12 +2293,12 @@
 
 		if (!load_code)
 			STp->rew_at_close = 0;
-		else
+		else {
 			STp->rew_at_close = STp->autorew_dev;
-
-		retval = check_tape(STp, filp);
-		if (retval > 0)
-			retval = 0;
+			retval = check_tape(STp, filp);
+			if (retval > 0)
+				retval = 0;
+		}
 	}
 	else {
 		STps = &(STp->ps[STp->partition]);
@@ -3286,7 +3377,6 @@
  new_tape_buffer(int from_initialization, int need_dma, int in_use)
 {
 	int i, priority, b_size, order, got = 0, segs = 0;
-	unsigned long flags;
 	ST_buffer *tb;
 
 	read_lock(&st_dev_arr_lock);
@@ -3381,9 +3471,9 @@
 	tb->buffer_size = got;
 	tb->writing = 0;
 
-	write_lock_irqsave(&st_dev_arr_lock, flags);
+	write_lock(&st_dev_arr_lock);
 	st_buffers[st_nbr_buffers++] = tb;
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	write_unlock(&st_dev_arr_lock);
 
 	return tb;
 }
@@ -3611,7 +3701,6 @@
 	ST_mode *STm;
 	ST_partstat *STps;
 	int i, mode, target_nbr, dev_num;
-	unsigned long flags = 0;
 	char *stp;
 
 	if (SDp->type != TYPE_TAPE)
@@ -3624,7 +3713,7 @@
 		return 1;
 	}
 
-	write_lock_irqsave(&st_dev_arr_lock, flags);
+	write_lock(&st_dev_arr_lock);
 	if (st_template.nr_dev >= st_template.dev_max) {
 		Scsi_Tape **tmp_da;
 		ST_buffer **tmp_ba;
@@ -3635,7 +3724,7 @@
 			tmp_dev_max = ST_MAX_TAPES;
 		if (tmp_dev_max <= st_template.nr_dev) {
 			SDp->attached--;
-			write_unlock_irqrestore(&st_dev_arr_lock, flags);
+			write_unlock(&st_dev_arr_lock);
 			printk(KERN_ERR "st: Too many tape devices (max. %d).\n",
 			       ST_MAX_TAPES);
 			return 1;
@@ -3649,7 +3738,7 @@
 			if (tmp_ba != NULL)
 				kfree(tmp_ba);
 			SDp->attached--;
-			write_unlock_irqrestore(&st_dev_arr_lock, flags);
+			write_unlock(&st_dev_arr_lock);
 			printk(KERN_ERR "st: Can't extend device array.\n");
 			return 1;
 		}
@@ -3682,7 +3771,7 @@
 	tpnt = kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC);
 	if (tpnt == NULL) {
 		SDp->attached--;
-		write_unlock_irqrestore(&st_dev_arr_lock, flags);
+		write_unlock(&st_dev_arr_lock);
 		printk(KERN_ERR "st: Can't allocate device descriptor.\n");
 		return 1;
 	}
@@ -3770,7 +3859,7 @@
 	init_MUTEX(&tpnt->lock);
 
 	st_template.nr_dev++;
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	write_unlock(&st_dev_arr_lock);
 	printk(KERN_WARNING
 	"Attached scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
 	       dev_num, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
@@ -3798,45 +3887,12 @@
 	return 1;
 }
 
-static int st_registered = 0;
-
-/* Driver initialization (not __init because may be called later) */
-static int st_init()
-{
-	unsigned long flags;
-
-	if (st_template.dev_noticed == 0 || st_registered)
-		return 0;
-
-	printk(KERN_INFO
-	       "st: Version %s, bufsize %d, wrt %d, max init. bufs %d, s/g segs %d\n",
-	       verstr, st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
-
-	write_lock_irqsave(&st_dev_arr_lock, flags);
-	if (!st_registered) {
-		if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) {
-			write_unlock_irqrestore(&st_dev_arr_lock, flags);
-			printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
-                               MAJOR_NR);
-			return 1;
-		}
-		st_registered++;
-	}
-
-	st_template.dev_max = 0;
-	st_nbr_buffers = 0;
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
-
-	return 0;
-}
-
 static void st_detach(Scsi_Device * SDp)
 {
 	Scsi_Tape *tpnt;
 	int i, mode;
-	unsigned long flags;
 
-	write_lock_irqsave(&st_dev_arr_lock, flags);
+	write_lock(&st_dev_arr_lock);
 	for (i = 0; i < st_template.dev_max; i++) {
 		tpnt = scsi_tapes[i];
 		if (tpnt != NULL && tpnt->device == SDp) {
@@ -3852,22 +3908,30 @@
 			SDp->attached--;
 			st_template.nr_dev--;
 			st_template.dev_noticed--;
-			write_unlock_irqrestore(&st_dev_arr_lock, flags);
+			write_unlock(&st_dev_arr_lock);
 			return;
 		}
 	}
 
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	write_unlock(&st_dev_arr_lock);
 	return;
 }
 
-
 static int __init init_st(void)
 {
 	validate_options();
 
-	st_template.module = THIS_MODULE;
-        return scsi_register_device(&st_template);
+	printk(KERN_INFO
+		"st: Version %s, bufsize %d, wrt %d, "
+		"max init. bufs %d, s/g segs %d\n",
+		verstr, st_buffer_size, st_write_threshold,
+		st_max_buffers, st_max_sg_segs);
+
+	if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0)
+		return scsi_register_device(&st_template);
+
+	printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR);
+	return 1;
 }
 
 static void __exit exit_st(void)
@@ -3876,7 +3940,6 @@
 
 	scsi_unregister_device(&st_template);
 	devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
-	st_registered--;
 	if (scsi_tapes != NULL) {
 		for (i=0; i < st_template.dev_max; ++i)
 			if (scsi_tapes[i])
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v2.5.2/linux/drivers/scsi/st.h	Fri Nov  9 13:52:21 2001
+++ linux/drivers/scsi/st.h	Wed Jan 23 15:30:47 2002
@@ -83,6 +83,7 @@
 	unsigned char cln_sense_value;
 	unsigned char cln_sense_mask;
 	unsigned char use_pf;			/* Set Page Format bit in all mode selects? */
+	unsigned char c_algo;			/* compression algorithm */
 	int tape_type;
 	int write_threshold;
 	int timeout;		/* timeout for normal commands */
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/st_options.h linux/drivers/scsi/st_options.h
--- v2.5.2/linux/drivers/scsi/st_options.h	Mon Apr 24 13:54:22 2000
+++ linux/drivers/scsi/st_options.h	Wed Jan 23 15:30:47 2002
@@ -3,7 +3,7 @@
 
    Copyright 1995-2000 Kai Makisara.
 
-   Last modified: Sat Apr 22 14:47:02 2000 by makisara@kai.makisara.local
+   Last modified: Tue Jan 22 21:52:34 2002 by makisara
 */
 
 #ifndef _ST_OPTIONS_H
@@ -99,5 +99,7 @@
    The default is BSD semantics. */
 #define ST_SYSV 0
 
+/* Time to wait for the drive to become ready if blocking open */
+#define ST_BLOCK_SECONDS     120
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/sun3x_esp.c linux/drivers/scsi/sun3x_esp.c
--- v2.5.2/linux/drivers/scsi/sun3x_esp.c	Thu Oct 25 13:53:51 2001
+++ linux/drivers/scsi/sun3x_esp.c	Mon Jan 28 14:36:59 2002
@@ -112,7 +112,7 @@
 
 	esp->irq = 2;
 	if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, 
-			"SUN3X SCSI", NULL)) {
+			"SUN3X SCSI", esp->ehost)) {
 		esp_deallocate(esp);
 		return 0;
 	}
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/sym53c416.c linux/drivers/scsi/sym53c416.c
--- v2.5.2/linux/drivers/scsi/sym53c416.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/sym53c416.c	Mon Jan 28 14:36:59 2002
@@ -337,6 +337,7 @@
 
 static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
+	struct Scsi_Host *dev = dev_id;
 	int base = 0;
 	int i;
 	unsigned long flags = 0;
@@ -359,11 +360,11 @@
 	}
 	/* Now we have the base address and we can start handling the interrupt */
 
-	spin_lock_irqsave(&io_request_lock,flags);
+	spin_lock_irqsave(dev->host_lock,flags);
 	status_reg = inb(base + STATUS_REG);
 	pio_int_reg = inb(base + PIO_INT_REG);
 	int_reg = inb(base + INT_REG);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(dev->host_lock, flags);
 
 	/* First, we handle error conditions */
 	if(int_reg & SCI)         /* SCSI Reset */
@@ -371,9 +372,9 @@
 		printk(KERN_DEBUG "sym53c416: Reset received\n");
 		current_command->SCp.phase = idle;
 		current_command->result = DID_RESET << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
+		spin_lock_irqsave(dev->host_lock, flags);
 		current_command->scsi_done(current_command);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		spin_unlock_irqrestore(dev->host_lock, flags);
 		return;
 	}
 	if(int_reg & ILCMD)       /* Illegal Command */
@@ -381,9 +382,9 @@
 		printk(KERN_WARNING "sym53c416: Illegal Command: 0x%02x.\n", inb(base + COMMAND_REG));
 		current_command->SCp.phase = idle;
 		current_command->result = DID_ERROR << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
+		spin_lock_irqsave(dev->host_lock, flags);
 		current_command->scsi_done(current_command);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		spin_unlock_irqrestore(dev->host_lock, flags);
 		return;
 	}
 	if(status_reg & GE)         /* Gross Error */
@@ -391,9 +392,9 @@
 		printk(KERN_WARNING "sym53c416: Controller reports gross error.\n");
 		current_command->SCp.phase = idle;
 		current_command->result = DID_ERROR << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
+		spin_lock_irqsave(dev->host_lock, flags);
 		current_command->scsi_done(current_command);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		spin_unlock_irqrestore(dev->host_lock, flags);
 		return;
 	}
 	if(status_reg & PE)         /* Parity Error */
@@ -401,9 +402,9 @@
 		printk(KERN_WARNING "sym53c416:SCSI parity error.\n");
 		current_command->SCp.phase = idle;
 		current_command->result = DID_PARITY << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
+		spin_lock_irqsave(dev->host_lock, flags);
 		current_command->scsi_done(current_command);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		spin_unlock_irqrestore(dev->host_lock, flags);
 		return;
 	}
 	if(pio_int_reg & (CE | OUE))
@@ -411,9 +412,9 @@
 		printk(KERN_WARNING "sym53c416: PIO interrupt error.\n");
 		current_command->SCp.phase = idle;
 		current_command->result = DID_ERROR << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
+		spin_lock_irqsave(dev->host_lock, flags);
 		current_command->scsi_done(current_command);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		spin_unlock_irqrestore(dev->host_lock, flags);
 		return;
 	}
 	if(int_reg & DIS)           /* Disconnect */
@@ -423,9 +424,9 @@
 		else
 			current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16);
 		current_command->SCp.phase = idle;
-		spin_lock_irqsave(&io_request_lock, flags);
+		spin_lock_irqsave(dev->host_lock, flags);
 		current_command->scsi_done(current_command);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		spin_unlock_irqrestore(dev->host_lock, flags);
 		return;
 	}
 	/* Now we handle SCSI phases         */
@@ -719,7 +720,7 @@
 				cli();
 				/* FIXME: Request_irq with CLI is not safe */
 				/* Request for specified IRQ */
-				if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, NULL))
+				if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, shpnt))
 				{
 					restore_flags(flags);
 					printk(KERN_ERR "sym53c416: Unable to assign IRQ %d\n", hosts[i].irq);
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h
--- v2.5.2/linux/drivers/scsi/sym53c8xx_comm.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/sym53c8xx_comm.h	Mon Jan 28 14:36:59 2002
@@ -439,9 +439,9 @@
 #define	NCR_UNLOCK_NCB(np, flags)  spin_unlock_irqrestore(&np->smp_lock, flags)
 
 #define	NCR_LOCK_SCSI_DONE(host, flags) \
-		spin_lock_irqsave(&(host)->host_lock, flags)
+		spin_lock_irqsave((host)->host_lock, flags)
 #define	NCR_UNLOCK_SCSI_DONE(host, flags) \
-		spin_unlock_irqrestore(&((host)->host_lock), flags)
+		spin_unlock_irqrestore(((host)->host_lock), flags)
 
 #else
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/t128.c linux/drivers/scsi/t128.c
--- v2.5.2/linux/drivers/scsi/t128.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/scsi/t128.c	Mon Jan 28 14:36:59 2002
@@ -248,7 +248,7 @@
 	    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)) {
+	    if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", instance)) {
 		printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
 		    instance->host_no, instance->irq);
 		instance->irq = IRQ_NONE;
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.5.2/linux/drivers/scsi/tmscsim.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/tmscsim.c	Mon Jan 28 14:36:59 2002
@@ -304,8 +304,8 @@
 #  define DC390_IFLAGS unsigned long iflags;
 #  define DC390_DFLAGS unsigned long dflags; 
 
-#  define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags)
-#  define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags)
+#  define DC390_LOCK_IO spin_lock_irqsave (((struct Scsi_Host *)dev)->host_lock, iflags)
+#  define DC390_UNLOCK_IO spin_unlock_irqrestore (((struct Scsi_Host *)dev)->host_lock, iflags)
 
 #  define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
 #  define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
@@ -331,8 +331,8 @@
 #   define DC390_AFLAGS unsigned long aflags;
 #   define DC390_IFLAGS 
 #  define DC390_DFLAGS unsigned long dflags; 
-#   define DC390_LOCK_IO /* spin_lock_irqsave (&io_request_lock, iflags) */
-#   define DC390_UNLOCK_IO /* spin_unlock_irqrestore (&io_request_lock, iflags) */
+#   define DC390_LOCK_IO(dev) /* spin_lock_irqsave (&io_request_lock, iflags) */
+#   define DC390_UNLOCK_IO(dev) /* spin_unlock_irqrestore (&io_request_lock, iflags) */
 #   define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
 #   define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
 #   define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
@@ -349,8 +349,8 @@
 #   define DC390_IFLAGS unsigned long iflags;
 #   define DC390_DFLAGS unsigned long dflags; 
     spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
-#   define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags)
-#   define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags)
+#   define DC390_LOCK_IO(dev) spin_lock_irqsave (((struct Scsi_Host *)dev)->host_lock, iflags)
+#   define DC390_UNLOCK_IO(dev) spin_unlock_irqrestore (((struct Scsi_Host *)dev)->host_lock, iflags)
 #   define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
 #   define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
 #   define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
@@ -1074,11 +1074,11 @@
 	DC390_IFLAGS
 	DC390_AFLAGS
 	DEBUG0(printk ("DC390: Debug: Waiting queue woken up by timer!\n");)
-	DC390_LOCK_IO;
+	DC390_LOCK_IO(pACB.pScsiHost);
 	DC390_LOCK_ACB;
 	dc390_Waiting_process (pACB);
 	DC390_UNLOCK_ACB;
-	DC390_UNLOCK_IO;
+	DC390_UNLOCK_IO(pACB.pScsiHost);
 }
 
 /***********************************************************************
@@ -2558,7 +2558,7 @@
   DC390_AFLAGS 
   pos[length] = 0;
 
-  DC390_LOCK_IO;
+  DC390_LOCK_IO(pACB.pScsiHost);
   DC390_LOCK_ACB;
   /* UPPERCASE */ 
   /* Don't use kernel toupper, because of 2.0.x bug: ctmp unexported */
@@ -2726,7 +2726,7 @@
   DC390_UNLOCK_ACB;
   if (needs_inquiry) 
      { dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); };
-  DC390_UNLOCK_IO;
+  DC390_UNLOCK_IO(pACB.pScsiHost);
   return (length);
 
  einv2:
@@ -2734,7 +2734,7 @@
  einv:
   /* spin_unlock (strtok_lock); */
   DC390_UNLOCK_ACB;
-  DC390_UNLOCK_IO;
+  DC390_UNLOCK_IO(pACB.pScsiHost);
   printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL"));
   return (-EINVAL);
    
@@ -2744,7 +2744,7 @@
 	printk (KERN_WARNING "DC390: Driver reset requested!\n");
 	DC390_UNLOCK_ACB;
 	DC390_reset (&cmd, 0);
-	DC390_UNLOCK_IO;
+	DC390_UNLOCK_IO(pACB.pScsiHost);
      };
   return (length);
 
@@ -2752,7 +2752,7 @@
      {
 	dc390_dumpinfo (pACB, 0, 0);
 	DC390_UNLOCK_ACB;
-	DC390_UNLOCK_IO;       
+	DC390_UNLOCK_IO(pACB.pScsiHost);       
      }
   return (length);
 	
@@ -2766,7 +2766,7 @@
 		dev, pDCB->TargetID, pDCB->TargetLUN);
 	DC390_UNLOCK_ACB;
 	dc390_inquiry (pACB, pDCB);
-	DC390_UNLOCK_IO;
+	DC390_UNLOCK_IO(pACB.pScsiHost);
      };
    return (length);
 
@@ -2781,7 +2781,7 @@
 	/* TO DO: We should make sure no pending commands are left */
 	dc390_remove_dev (pACB, pDCB);
 	DC390_UNLOCK_ACB;
-	DC390_UNLOCK_IO;
+	DC390_UNLOCK_IO(pACB.pScsiHost);
      };
    return (length);
 
@@ -2796,7 +2796,7 @@
 	dc390_initDCB (pACB, &pDCB, id, lun);
 	DC390_UNLOCK_ACB;
 	dc390_inquiry (pACB, pDCB);
-	DC390_UNLOCK_IO;
+	DC390_UNLOCK_IO(pACB.pScsiHost);
      };
    return (length);
 
@@ -2812,7 +2812,7 @@
 	DC390_UNLOCK_ACB;
 	dc390_sendstart (pACB, pDCB);
 	dc390_inquiry (pACB, pDCB);
-	DC390_UNLOCK_IO;
+	DC390_UNLOCK_IO(pACB.pScsiHost);
      };
    return (length);
 
@@ -2820,7 +2820,7 @@
    printk (KERN_WARNING "DC390: Ignore cmnd to illegal Dev(Idx) %i. Valid range: 0 - %i.\n", 
 	   dev, pACB->DCBCnt - 1);
    DC390_UNLOCK_ACB;
-   DC390_UNLOCK_IO;
+   DC390_UNLOCK_IO(pACB.pScsiHost);
    return (-EINVAL);
 	     
 	     
@@ -3041,7 +3041,7 @@
     DC390_AFLAGS DC390_IFLAGS
     PACB pACB = (PACB)(host->hostdata);
 
-    DC390_LOCK_IO;
+    DC390_LOCK_IO(host);
     DC390_LOCK_ACB;
 
     /* TO DO: We should check for outstanding commands first. */
@@ -3056,7 +3056,7 @@
     release_region(host->io_port,host->n_io_port);
     dc390_freeDCBs (host);
     DC390_UNLOCK_ACB;
-    DC390_UNLOCK_IO;
+    DC390_UNLOCK_IO(host);
     return( 1 );
 }
 #endif /* def MODULE */
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v2.5.2/linux/drivers/scsi/u14-34f.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/u14-34f.c	Mon Jan 28 14:36:59 2002
@@ -1364,10 +1364,10 @@
 
    HD(j)->in_reset = TRUE;
 
-   spin_unlock_irq(&sh[j]->host_lock);
+   spin_unlock_irq(sh[j]->host_lock);
    time = jiffies;
    while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
-   spin_lock_irq(&sh[j]->host_lock);
+   spin_lock_irq(sh[j]->host_lock);
 
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
@@ -1822,9 +1822,9 @@
    /* Check if the interrupt must be processed by this handler */
    if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
 
-   spin_lock_irqsave(&sh[j]->host_lock, spin_flags);
+   spin_lock_irqsave(sh[j]->host_lock, spin_flags);
    ihdlr(irq, j);
-   spin_unlock_irqrestore(&sh[j]->host_lock, spin_flags);
+   spin_unlock_irqrestore(sh[j]->host_lock, spin_flags);
 }
 
 int u14_34f_release(struct Scsi_Host *shpnt) {
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c
--- v2.5.2/linux/drivers/scsi/ultrastor.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/scsi/ultrastor.c	Mon Jan 28 14:36:59 2002
@@ -500,7 +500,11 @@
     config.mscp_free = ~0;
 #endif
 
-    if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", NULL)) {
+    /*
+     * Brrr, &config.mscp[0].SCint->host) it is something magical....
+     * XXX and FIXME
+     */
+    if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", &config.mscp[0].SCint->host)) {
 	printk("Unable to allocate IRQ%u for UltraStor controller.\n",
 	       config.interrupt);
 	return FALSE;
@@ -570,12 +574,7 @@
 	  printk("U24F: invalid IRQ\n");
 	  return FALSE;
 	}
-      if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", NULL))
-	{
-	  printk("Unable to allocate IRQ%u for UltraStor controller.\n",
-		 config.interrupt);
-	  return FALSE;
-	}
+
       /* BIOS addr set */
       /* base port set */
       config.port_address = addr;
@@ -605,6 +604,13 @@
              free_irq(config.interrupt, do_ultrastor_interrupt);
              return FALSE;
       }
+      
+      if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", shpnt))
+	{
+	  printk("Unable to allocate IRQ%u for UltraStor controller.\n",
+		 config.interrupt);
+	  return FALSE;
+	}
 
       shpnt->irq = config.interrupt;
       shpnt->dma_channel = config.dma_channel;
@@ -1159,10 +1165,11 @@
 static void do_ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     unsigned long flags;
-
-    spin_lock_irqsave(&io_request_lock, flags);
+    struct Scsi_Host *dev = dev_id;
+    
+    spin_lock_irqsave(dev->host_lock, flags);
     ultrastor_interrupt(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    spin_unlock_irqrestore(dev->host_lock, flags);
 }
 
 MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v2.5.2/linux/drivers/scsi/wd7000.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/wd7000.c	Mon Jan 28 14:36:59 2002
@@ -866,18 +866,18 @@
     save_flags (flags);
     cli ();
     while (busy) {		/* someone else is allocating */
-	spin_unlock_irq(&host->host_lock);
+	spin_unlock_irq(host->host_lock);
 	for (now = jiffies; now == jiffies; );	/* wait a jiffy */
-	spin_lock_irq(&host->host_lock);
+	spin_lock_irq(host->host_lock);
     }
     busy = 1;			/* not busy now; it's our turn */
 
     while (freescbs < needed) {
 	timeout = jiffies + WAITnexttimeout;
 	do {
-	    spin_unlock_irq(&host->host_lock);
+	    spin_unlock_irq(host->host_lock);
 	    for (now = jiffies; now == jiffies; );	/* wait a jiffy */
-	    spin_lock_irq(&host->host_lock);
+	    spin_lock_irq(host->host_lock);
 	} while (freescbs < needed && time_before_eq(jiffies, timeout));
 	/*
 	 *  If we get here with enough free Scbs, we can take them.
@@ -1144,9 +1144,9 @@
     unsigned long flags;
     struct Scsi_Host *host = dev_id;
 
-    spin_lock_irqsave(&host->host_lock, flags);
+    spin_lock_irqsave(host->host_lock, flags);
     wd7000_intr_handle(irq, dev_id, regs);
-    spin_unlock_irqrestore(&host->host_lock, flags);
+    spin_unlock_irqrestore(host->host_lock, flags);
 }
 
 
diff -u --recursive --new-file v2.5.2/linux/drivers/sgi/Config.help linux/drivers/sgi/Config.help
--- v2.5.2/linux/drivers/sgi/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/Config.help	Fri Jan 25 16:03:59 2002
@@ -0,0 +1,38 @@
+CONFIG_SGI_SERIAL
+  If you want to use your SGI's built-in serial ports under Linux,
+  answer Y.
+
+CONFIG_SGI_NEWPORT_GFX
+  If you have an SGI machine and you want to compile the graphics
+  drivers, say Y here. This will include the code for the
+  /dev/graphics and /dev/gfx drivers into the kernel for supporting
+  virtualized access to your graphics hardware.
+
+CONFIG_SGI_DS1286
+  If you say Y here and create a character special file /dev/rtc with
+  major number 10 and minor number 135 using mknod ("man mknod"), you
+  will get access to the real time clock built into your computer.
+  Every SGI has such a clock built in. It reports status information
+  via the file /proc/rtc and its behaviour is set by various ioctls on
+  /dev/rtc.
+
+CONFIG_SERIAL_CONSOLE
+  If you say Y here, it will be possible to use a serial port as the
+  system console (the system console is the device which receives all
+  kernel messages and warnings and which allows logins in single user
+  mode). This could be useful if some terminal or printer is connected
+  to that serial port.
+
+  Even if you say Y here, the currently visible virtual console
+  (/dev/tty0) will still be used as the system console by default, but
+  you can alter that using a kernel command line option such as
+  "console=ttyS1". (Try "man bootparam" or see the documentation of
+  your boot loader (lilo or loadlin) about how to pass options to the
+  kernel at boot time.)
+
+  If you don't have a VGA card installed and you say Y here, the
+  kernel will automatically use the first serial line, /dev/ttyS0, as
+  system console.
+
+  If unsure, say N.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c
--- v2.5.2/linux/drivers/sgi/char/graphics.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/sgi/char/graphics.c	Tue Jan 15 10:56:35 2002
@@ -231,7 +231,7 @@
 		/* FIXME: save graphics context here, dump it to rendering
 		 * node? */
 
-		remove_mapping(cards[board].g_user, vma->vm_start, vma->vm_end);
+		remove_mapping(vma, cards[board].g_user, vma->vm_start, vma->vm_end);
 	}
 
 	cards [board].g_user = current;
@@ -241,7 +241,7 @@
 
 	virt_add = address & PAGE_MASK;
 	phys_add = cards[board].g_regs + virt_add - vma->vm_start;
-	remap_page_range(virt_add, phys_add, PAGE_SIZE, vma->vm_page_prot);
+	remap_page_range(vma, virt_add, phys_add, PAGE_SIZE, vma->vm_page_prot);
 
 	pgd = pgd_offset(current->mm, address);
 	pmd = pmd_offset(pgd, address);
diff -u --recursive --new-file v2.5.2/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c
--- v2.5.2/linux/drivers/sgi/char/shmiq.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/sgi/char/shmiq.c	Tue Jan 15 10:56:35 2002
@@ -348,7 +348,7 @@
 	/* Init the shared memory input queue */
 	spin_unlock( &shmiqs [minor].shmiq_lock );
 	memset (shmiqs [minor].shmiq_vaddr, 0, size);
-	error = vmap_page_range (vma->vm_start, size, mem);
+	error = vmap_page_range (vma, vma->vm_start, size, mem);
 	return error;
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/Config.help linux/drivers/sound/Config.help
--- v2.5.2/linux/drivers/sound/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/Config.help	Fri Jan 25 16:04:17 2002
@@ -0,0 +1,723 @@
+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/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.
+
+  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 gameport.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SOUND_OSS
+  OSS is the Open Sound System suite of sound card drivers.  They make
+  sound programming easier since they provide a common API.  Say Y or
+  M here (the module will be called sound.o) if you haven't found a
+  driver for your sound card above, then pick your driver from the
+  list below.
+
+CONFIG_SOUND_DMAP
+  Linux can often have problems allocating DMA buffers for ISA sound
+  cards on machines with more than 16MB of RAM. This is because ISA
+  DMA buffers must exist below the 16MB boundary and it is quite
+  possible that a large enough free block in this region cannot be
+  found after the machine has been running for a while. If you say Y
+  here the DMA buffers (64Kb) will be allocated at boot time and kept
+  until the shutdown. This option is only useful if you said Y to
+  "OSS sound modules", above. If you said M to "OSS sound modules"
+  then you can get the persistent DMA buffer functionality by passing
+  the command-line argument "dmabuf=1" to the sound.o module.
+
+  Say Y unless you have 16MB or more RAM or a PCI sound card.
+
+CONFIG_SOUND_SGALAXY
+  This module initializes the older non Plug and Play sound galaxy
+  cards from Aztech. It supports the Waverider Pro 32 - 3D and the
+  Galaxy Washington 16.
+
+  If you compile the driver into the kernel, you have to add
+  "sgalaxy=<io>,<irq>,<dma>,<dma2>,<sgbase>" to the kernel command
+  line.
+
+CONFIG_SOUND_AD1816
+  Say M here if you have a sound card based on the Analog Devices
+  AD1816(A) chip.
+
+  If you compile the driver into the kernel, you have to add
+  "ad1816=<io>,<irq>,<dma>,<dma2>" to the kernel command line.
+
+CONFIG_SOUND_OPL3SA1
+  Say Y or M if you have a Yamaha OPL3-SA1 sound chip, which is
+  usually built into motherboards. Read
+  <file:Documentation/sound/OPL3-SA> for details.
+
+  If you compile the driver into the kernel, you have to add
+  "opl3sa=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the kernel
+  command line.
+
+CONFIG_SOUND_PAS
+  Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio
+  16 or Logitech SoundMan 16 sound card. Answer N if you have some
+  other card made by Media Vision or Logitech since those are not
+  PAS16 compatible. Please read <file:Documentation/sound/PAS16>.
+  It is not necessary to add Sound Blaster support separately; it
+  is included in PAS support.
+
+  If you compile the driver into the kernel, you have to add
+  "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2>
+  to the kernel command line.
+
+CONFIG_PAS_JOYSTICK
+  Say Y here to enable the Pro Audio Spectrum 16's auxiliary joystick
+  port.
+
+CONFIG_SOUND_SB
+  Answer Y if you have an original Sound Blaster card made by Creative
+  Labs or a 100% hardware compatible clone (like the Thunderboard or
+  SM Games). For an unknown card you may answer Y if the card claims
+  to be Sound Blaster-compatible.
+
+  Please read the file <file:Documentation/sound/Soundblaster>.
+
+  You should also say Y here for cards based on the Avance Logic
+  ALS-007 and ALS-1X0 chips (read <file:Documentation/sound/ALS>) and
+  for cards based on ESS chips (read
+  <file:Documentation/sound/ESS1868> and
+  <file:Documentation/sound/ESS>). If you have an SB AWE 32 or SB AWE
+  64, say Y here and also to "AWE32 synth" below and read
+  <file:Documentation/sound/INSTALL.awe>. If you have an IBM Mwave
+  card, say Y here and read <file:Documentation/sound/mwave>.
+
+  If you compile the driver into the kernel and don't want to use
+  isapnp, you have to add "sb=<io>,<irq>,<dma>,<dma2>" to the kernel
+  command line.
+
+  You can say M here to compile this driver as a module; the module is
+  called sb.o.
+
+CONFIG_SOUND_GUS
+  Say Y here for any type of Gravis Ultrasound card, including the GUS
+  or GUS MAX.  See also <file:Documentation/sound/ultrasound> for more
+  information on configuring this card with modules.
+
+  If you compile the driver into the kernel, you have to add
+  "gus=<io>,<irq>,<dma>,<dma2>" to the kernel command line.
+
+CONFIG_SOUND_MPU401
+  Be careful with this question.  The MPU401 interface is supported by
+  all sound cards.  However, some natively supported cards have their
+  own driver for MPU401.  Enabling this MPU401 option with these cards
+  will cause a conflict.  Also, enabling MPU401 on a system that
+  doesn't really have a MPU401 could cause some trouble.  If your card
+  was in the list of supported cards, look at the card specific
+  instructions in the <file:Documentation/sound/README.OSS> file.  It
+  is safe to answer Y if you have a true MPU401 MIDI interface card.
+
+  If you compile the driver into the kernel, you have to add
+  "mpu401=<io>,<irq>" to the kernel command line.
+
+CONFIG_SOUND_UART6850
+  This option enables support for MIDI interfaces based on the 6850
+  UART chip. This interface is rarely found on sound cards. It's safe
+  to answer N to this question.
+
+  If you compile the driver into the kernel, you have to add
+  "uart6850=<io>,<irq>" to the kernel command line.
+
+CONFIG_SOUND_PSS
+  Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven
+  ADSP-16 or some other card based on the PSS chipset (AD1848 codec +
+  ADSP-2115 DSP chip + Echo ESC614 ASIC CHIP). For more information on
+  how to compile it into the kernel or as a module see the file
+  <file:Documentation/sound/PSS>.
+
+  If you compile the driver into the kernel, you have to add
+  "pss=<io>,<mssio>,<mssirq>,<mssdma>,<mpuio>,<mpuirq>" to the kernel
+  command line.
+
+CONFIG_PSS_MIXER
+  Answer Y for Beethoven ADSP-16. You may try to say Y also for other
+  cards if they have master volume, bass, treble, and you can't
+  control it under Linux. If you answer N for Beethoven ADSP-16, you
+  can't control master volume, bass, treble and synth volume.
+
+  If you said M to "PSS support" above, you may enable or disable this
+  PSS mixer with the module parameter pss_mixer. For more information
+  see the file <file:Documentation/sound/PSS>.
+
+CONFIG_PSS_HAVE_BOOT
+  If you have the DSPxxx.LD file or SYNTH.LD file for you card, say Y
+  to include this file. Without this file the synth device (OPL) may
+  not work.
+
+CONFIG_PSS_BOOT_FILE
+  Enter the full pathname of your DSPxxx.LD file or SYNTH.LD file,
+  starting from /.
+
+CONFIG_SOUND_MSS
+  Again think carefully before answering Y to this question.  It's
+  safe to answer Y if you have the original Windows Sound System card
+  made by Microsoft or Aztech SG 16 Pro (or NX16 Pro).  Also you may
+  say Y in case your card is NOT among these:
+
+     ATI Stereo F/X, AdLib, Audio Excell DSP16, Cardinal DSP16,
+     Ensoniq SoundScape (and compatibles made by Reveal and Spea),
+     Gravis Ultrasound, Gravis Ultrasound ACE, Gravis Ultrasound Max,
+     Gravis Ultrasound with 16 bit option, Logitech Sound Man 16,
+     Logitech SoundMan Games, Logitech SoundMan Wave, MAD16 Pro (OPTi
+     82C929), Media Vision Jazz16, MediaTriX AudioTriX Pro, Microsoft
+     Windows Sound System (MSS/WSS), Mozart (OAK OTI-601), Orchid
+     SW32, Personal Sound System (PSS), Pro Audio Spectrum 16, Pro
+     Audio Studio 16, Pro Sonic 16, Roland MPU-401 MIDI interface,
+     Sound Blaster 1.0, Sound Blaster 16, Sound Blaster 16ASP, Sound
+     Blaster 2.0, Sound Blaster AWE32, Sound Blaster Pro, TI TM4000M
+     notebook, ThunderBoard, Turtle Beach Tropez, Yamaha FM
+     synthesizers (OPL2, OPL3 and OPL4), 6850 UART MIDI Interface.
+
+  For cards having native support in VoxWare, consult the card
+  specific instructions in <file:Documentation/sound/README.OSS>.
+  Some drivers have their own MSS support and saying Y to this option
+  will cause a conflict.
+
+  If you compile the driver into the kernel, you have to add
+  "ad1848=<io>,<irq>,<dma>,<dma2>[,<type>]" to the kernel command
+  line.
+
+CONFIG_SOUND_VWSND
+  Say Y or M if you have an SGI Visual Workstation and you want to be
+  able to use its on-board audio.  Read
+  <file:Documentation/sound/vwsnd> for more info on this driver's
+  capabilities.
+
+CONFIG_SOUND_SSCAPE
+  Answer Y if you have a sound card based on the Ensoniq SoundScape
+  chipset. Such cards are being manufactured at least by Ensoniq, Spea
+  and Reveal (Reveal makes also other cards).
+
+  If you compile the driver into the kernel, you have to add
+  "sscape=<io>,<irq>,<dma>,<mpuio>,<mpuirq>" to the kernel command
+  line.
+
+CONFIG_SOUND_TRIX
+  Answer Y if you have the AudioTriX Pro sound card manufactured
+  by MediaTrix.
+
+CONFIG_TRIX_HAVE_BOOT
+  The MediaTrix AudioTrix Pro has an on-board microcontroller which
+  needs to be initialized by downloading the code from the file
+  TRXPRO.HEX in the DOS driver directory. If you don't have the
+  TRXPRO.HEX file handy you may skip this step. However, the SB and
+  MPU-401 modes of AudioTrix Pro will not work without this file!
+
+CONFIG_TRIX_BOOT_FILE
+  Enter the full pathname of your TRXPRO.HEX file, starting from /.
+
+CONFIG_SOUND_MAD16
+  Answer Y if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi
+  82C928 or 82C929 or 82C931) audio interface chip. These chips are
+  quite common so it's possible that many no-name cards have one of
+  them. In addition the MAD16 chip is used in some cards made by known
+  manufacturers such as Turtle Beach (Tropez), Reveal (some models)
+  and Diamond (latest ones). Note however that the Tropez sound cards
+  have their own driver; if you have one of those, say N here and Y or
+  M to "Full support for Turtle Beach WaveFront", below.
+
+  If you compile the driver into the kernel, you have to add
+  "mad16=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the
+  kernel command line.
+
+  See also <file:Documentation/sound/Opti> and
+  <file:Documentation/sound/MAD16> for more information on setting
+  these cards up as modules.
+
+CONFIG_SOUND_WAVEFRONT
+  Answer Y or M if you have a Tropez Plus, Tropez or Maui sound card
+  and read the files <file:Documentation/sound/Wavefront> and
+  <file:Documentation/sound/Tropez+>.
+
+CONFIG_MAD16_OLDCARD
+  Answer Y (or M) if you have an older card based on the C928 or
+  Mozart chipset and you want to have MIDI support. If you enable this
+  option you also need to enable support for Sound Blaster.
+
+CONFIG_SOUND_CS4232
+  Say Y here if you have a card based on the Crystal CS4232 chip set,
+  which uses its own Plug and Play protocol.
+
+  If you compile the driver into the kernel, you have to add
+  "cs4232=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the kernel
+  command line.
+
+  See <file:Documentation/sound/CS4232> for more information on
+  configuring this card.
+
+CONFIG_SOUND_OPL3SA2
+  Say Y or M if you have a card based on one of these Yamaha sound
+  chipsets or the "SAx", which is actually a SA3. Read
+  <file:Documentation/sound/OPL3-SA2> for more information on
+  configuring these cards.
+
+  If you compile the driver into the kernel and do not also
+  configure in the optional ISA PnP support, you will have to add
+  "opl3sa2=<io>,<irq>,<dma>,<dma2>,<mssio>,<mpuio>" to the kernel
+  command line.
+
+CONFIG_SOUND_MAUI
+  Say Y here if you have a Turtle Beach Wave Front, Maui, or Tropez
+  sound card.
+
+  If you compile the driver into the kernel, you have to add
+  "maui=<io>,<irq>" to the kernel command line.
+
+CONFIG_MAUI_HAVE_BOOT
+  Turtle Beach Maui and Tropez sound cards have a microcontroller
+  which needs to be initialized prior to use. OSWF.MOT is a file
+  distributed with the card's DOS/Windows drivers. Answer Y if you
+  have this file.
+
+CONFIG_MAUI_BOOT_FILE
+  Enter the full pathname of your OSWF.MOT file, starting from /.
+
+CONFIG_SOUND_MSNDCLAS
+  Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
+  Monterey (not for the Pinnacle or Fiji).
+
+  See <file:Documentation/sound/MultiSound> for important information
+  about this driver.  Note that it has been discontinued, but the
+  Voyetra Turtle Beach knowledge base entry for it is still available
+  at <http://www.voyetra-turtle-beach.com/site/kb_ftp/790.asp>.
+
+CONFIG_MSNDCLAS_IO
+  I/O port address for the MultiSound Classic and related cards.
+
+CONFIG_MSNDCLAS_IRQ
+  Interrupt Request line for the MultiSound Classic and related cards.
+
+CONFIG_MSNDCLAS_MEM
+  Memory-mapped I/O base address for the MultiSound Classic and
+  related cards.
+
+CONFIG_MSNDCLAS_INIT_FILE
+  The MultiSound cards have two firmware files which are required for
+  operation, and are not currently included. These files can be
+  obtained from Turtle Beach. See
+  <file:Documentation/sound/MultiSound> for information on how to
+  obtain this.
+
+CONFIG_MSNDCLAS_PERM_FILE
+  The MultiSound cards have two firmware files which are required for
+  operation, and are not currently included. These files can be
+  obtained from Turtle Beach. See
+  <file:Documentation/sound/MultiSound> for information on how to
+  obtain this.
+
+CONFIG_SOUND_MSNDPIN
+  Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji.
+  See <file:Documentation/sound/MultiSound> for important information
+  about this driver. Note that it has been discontinued, but the
+  Voyetra Turtle Beach knowledge base entry for it is still available
+  at <http://www.voyetra-turtle-beach.com/site/kb_ftp/600.asp>.
+
+CONFIG_MSNDPIN_IDE_IO0
+  CD-ROM drive 0 memory-mapped I/O base address for the MultiSound
+  Pinnacle and Fiji sound cards.
+
+CONFIG_MSNDPIN_IDE_IO1
+  CD-ROM drive 1 memory-mapped I/O base address for the MultiSound
+  Pinnacle and Fiji sound cards.
+
+CONFIG_MSNDPIN_IDE_IRQ
+  Interrupt request number for the IDE CD-ROM interface on the
+  MultiSound Pinnacle and Fiji sound cards.
+
+CONFIG_MSNDPIN_IO
+  Memory-mapped I/O base address for the primary synthesizer on
+  MultiSound Pinnacle and Fiji sound cards.
+
+CONFIG_MSNDPIN_MPU_IO
+  Memory-mapped I/O base address for the Kurzweil daughterboard
+  synthesizer on MultiSound Pinnacle and Fiji sound cards.
+
+CONFIG_MSNDPIN_MPU_IRQ
+  Iinterrupt request number for the Kurzweil daughterboard
+  synthesizer on MultiSound Pinnacle and Fiji sound cards.
+
+CONFIG_MSNDPIN_IRQ
+  Interrupt request line for the primary synthesizer on MultiSound
+  Pinnacle and Fiji sound cards.
+
+CONFIG_MSNDPIN_JOYSTICK_IO
+  Memory-mapped I/O base address for the joystick port on MultiSound
+  Pinnacle and Fiji sound cards.
+
+CONFIG_MSNDPIN_MEM
+  Memory-mapped I/O base address for the primary synthesizer on
+  MultiSound Pinnacle and Fiji sound cards.
+
+CONFIG_MSNDPIN_INIT_FILE
+  The MultiSound cards have two firmware files which are required
+  for operation, and are not currently included. These files can be
+  obtained from Turtle Beach. See
+  <file:Documentation/sound/MultiSound> for information on how to
+  obtain this.
+
+CONFIG_MSNDPIN_PERM_FILE
+  The MultiSound cards have two firmware files which are required for
+  operation, and are not currently included. These files can be
+  obtained from Turtle Beach. See
+  <file:Documentation/sound/MultiSound> for information on how to
+  obtain this.
+
+CONFIG_MSNDPIN_DIGITAL
+  If you have the S/PDIF daughter board for the Pinnacle or Fiji,
+  answer Y here; otherwise, say N. If you have this, you will be able
+  to play and record from the S/PDIF port (digital signal). See
+  <file:Documentation/sound/MultiSound> for information on how to make
+  use of this capability.
+
+CONFIG_MSNDPIN_NONPNP
+  The Pinnacle and Fiji card resources can be configured either with
+  PnP, or through a configuration port. Say Y here if your card is NOT
+  in PnP mode. For the Pinnacle, configuration in non-PnP mode allows
+  use of the IDE and joystick peripherals on the card as well; these
+  do not show up when the card is in PnP mode. Specifying zero for any
+  resource of a device will disable the device. If you are running the
+  card in PnP mode, you must say N here and use isapnptools to
+  configure the card's resources.
+
+CONFIG_MSNDPIN_CFG
+  This is the port which the Pinnacle and Fiji uses to configure the
+  card's resources when not in PnP mode. If your card is in PnP mode,
+  then be sure to say N to the previous option, "MSND Pinnacle Non-PnP
+  Mode".
+
+CONFIG_MSND_FIFOSIZE
+  Configures the size of each audio buffer, in kilobytes, for
+  recording and playing in the MultiSound drivers (both the Classic
+  and Pinnacle). Larger values reduce the chance of data overruns at
+  the expense of overall latency. If unsure, use the default.
+
+CONFIG_SOUND_YM3812
+  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+  Answering Y is usually a safe and recommended choice, however some
+  cards may have software (TSR) FM emulation. Enabling FM support with
+  these cards may cause trouble (I don't currently know of any such
+  cards, however). Please read the file
+  <file:Documentation/sound/OPL3> if your card has an OPL3 chip.
+
+  If you compile the driver into the kernel, you have to add
+  "opl3=<io>" to the kernel command line.
+
+  If unsure, say Y.
+
+CONFIG_SOUND_ACI_MIXER
+  ACI (Audio Command Interface) is a protocol used to communicate with
+  the microcontroller on some sound cards produced by miro and
+  Cardinal Technologies.  The main function of the ACI is to control
+  the mixer and to get a product identification.
+
+  This VoxWare ACI driver currently supports the ACI functions on the
+  miroSOUND PCM1-pro, PCM12 and PCM20 radio. On the PCM20 radio, ACI
+  also controls the radio tuner. This is supported in the video4linux
+  miropcm20 driver (say M or Y here and go back to "Multimedia
+  devices" -> "Radio Adapters").
+
+  This driver is also available as a module and will be called aci.o.
+
+CONFIG_SOUND_AWE32_SYNTH
+  Say Y here if you have a Sound Blaster SB32, AWE32-PnP, SB AWE64 or
+  similar sound card. See <file:Documentation/sound/README.awe>,
+  <file:Documentation/sound/AWE32> and the Soundblaster-AWE
+  mini-HOWTO, available from <http://www.linuxdoc.org/docs.html#howto>
+  for more info.
+
+CONFIG_SOUND_AEDSP16
+  Answer Y if you have a Gallant's Audio Excel DSP 16 card. This
+  driver supports Audio Excel DSP 16 but not the III nor PnP versions
+  of this card.
+
+  The Gallant's Audio Excel DSP 16 card can emulate either an SBPro or
+  a Microsoft Sound System card, so you should have said Y to either
+  "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support"
+  or "Microsoft Sound System support", above, and you need to answer
+  the "MSS emulation" and "SBPro emulation" questions below
+  accordingly. You should say Y to one and only one of these two
+  questions.
+
+  Read the <file:Documentation/sound/README.OSS> file and the head of
+  <file:drivers/sound/aedsp16.c> as well as
+  <file:Documentation/sound/AudioExcelDSP16> to get more information
+  about this driver and its configuration.
+
+CONFIG_AEDSP16_SBPRO
+  Answer Y if you want your audio card to emulate Sound Blaster Pro.
+  You should then say Y to "100% Sound Blaster compatibles
+  (SB16/32/64, ESS, Jazz16) support" and N to "Audio Excel DSP 16 (MSS
+  emulation)".
+
+  If you compile the driver into the kernel, you have to add
+  "aedsp16=<io>,<irq>,<dma>,<mssio>,<mpuio>,<mouirq>" to the kernel
+  command line.
+
+CONFIG_AEDSP16_MSS
+  Answer Y if you want your audio card to emulate Microsoft Sound
+  System. You should then say Y to "Microsoft Sound System support"
+  and say N to "Audio Excel DSP 16 (SBPro emulation)".
+
+CONFIG_SC6600
+  The SC6600 is the new version of DSP mounted on the Audio Excel DSP
+  16 cards. Find in the manual the FCC ID of your audio card and
+  answer Y if you have an SC6600 DSP.
+
+CONFIG_SC6600_JOY
+  Say Y here in order to use the joystick interface of the Audio Excel
+  DSP 16 card.
+
+CONFIG_SC6600_CDROMBASE
+  Base I/O port address for the CD-ROM interface of the Audio Excel
+  DSP 16 card.
+
+CONFIG_AEDSP16_MPU401
+  Answer Y if you want your audio card to emulate the MPU-401 midi
+  interface. You should then also say Y to "MPU-401 support".
+
+  Note that the I/O base for MPU-401 support of aedsp16 is the same
+  you have selected for "MPU-401 support". If you are using this
+  driver as a module you have to specify the MPU I/O base address with
+  the parameter 'mpu_base=0xNNN'.
+
+CONFIG_SOUND_CMPCI
+  Say Y or M if you have a PCI sound card using the CMI8338
+  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>.
+
+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>.
+
+CONFIG_SOUND_CMPCI_JOYSTICK
+  Say here in order to enable the joystick port on a sound crd using
+  the CMI8338 or the CMI8738 chipset.  Data on these chips are
+  available at <http://www.cmedia.com.tw/>.
+
+CONFIG_SOUND_CMPCI_SPEAKERS
+  Specify the number of speaker channels you want the card to drive,
+  as an integer.
+
+CONFIG_SOUND_CMPCI_SPDIFLOOP
+  Enable loopback from SPDIF in to SPDIF out.  For discussion, see
+  "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.
+
+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/>.
+
+  It is now possible to load dsp microcode patches into the EMU10K1
+  chip.  These patches are used to implement real time sound
+  processing effects which include for example: signal routing,
+  bass/treble control, AC3 passthrough, ...
+  Userspace tools to create new patches and load/unload them can be
+  found at <http://opensource.creative.com/dist.html>.
+
+CONFIG_MIDI_EMU10K1
+  Say Y if you want to be able to use the OSS /dev/sequencer
+  interface.  This code is still experimental.
+
+CONFIG_SOUND_FUSION
+  This module drives the Crystal SoundFusion devices (CS4280/46xx
+  series) when wired as native sound drivers with AC97 codecs.  If
+  this driver does not work try the CS4232 driver.
+
+CONFIG_SOUND_ES1370
+  Say Y or M if you have a PCI sound card utilizing the Ensoniq
+  ES1370 chipset, such as Ensoniq's AudioPCI (non-97). To find
+  out if your sound card uses an ES1370 without removing your
+  computer's cover, use lspci -n and look for the PCI ID
+  1274:5000. Since Ensoniq was bought by Creative Labs,
+  Sound Blaster 64/PCI models are either ES1370 or ES1371 based.
+  This driver differs slightly from OSS/Free, so PLEASE READ
+  <file:Documentation/sound/es1370>.
+
+CONFIG_SOUND_ES1371
+  Say Y or M if you have a PCI sound card utilizing the Ensoniq
+  ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if
+  your sound card uses an ES1371 without removing your computer's
+  cover, use lspci -n and look for the PCI ID 1274:1371. Since
+  Ensoniq was bought by Creative Labs, Sound Blaster 64/PCI
+  models are either ES1370 or ES1371 based. This driver differs
+  slightly from OSS/Free, so PLEASE READ
+  <file:Documentation/sound/es1371>.
+
+CONFIG_SOUND_ESSSOLO1
+  Say Y or M if you have a PCI sound card utilizing the ESS Technology
+  Solo1 chip. To find out if your sound card uses a
+  Solo1 chip without removing your computer's cover, use
+  lspci -n and look for the PCI ID 125D:1969. This driver
+  differs slightly from OSS/Free, so PLEASE READ
+  <file:Documentation/sound/solo1>.
+
+CONFIG_SOUND_SONICVIBES
+  Say Y or M if you have a PCI sound card utilizing the S3
+  SonicVibes chipset. To find out if your sound card uses a
+  SonicVibes chip without removing your computer's cover, use
+  lspci -n and look for the PCI ID 5333:CA00. This driver
+  differs slightly from OSS/Free, so PLEASE READ
+  <file:Documentation/sound/sonicvibes>.
+
+CONFIG_SOUND_TRIDENT
+  Say Y or M if you have a PCI sound card utilizing the Trident
+  4DWave-DX/NX chipset or your mother board chipset has SiS 7018
+  or ALi 5451 built-in. The SiS 7018 PCI Audio Core is embedded
+  in SiS960 Super South Bridge and SiS540/630 Single Chipset.
+  The ALi 5451 PCI Audio Core is embedded in ALi M1535, M1535D,
+  M1535+ or M1535D+ South Bridge.
+
+  Use lspci -n to find out if your sound card or chipset uses
+  Trident 4DWave or SiS 7018. PCI ID 1023:2000 or 1023:2001 stands
+  for Trident 4Dwave. PCI ID 1039:7018 stands for SiS7018. PCI ID
+  10B9:5451 stands for ALi5451.
+
+  This driver supports S/PDIF in/out (record/playback) for ALi 5451
+  embedded in ALi M1535+ and M1535D+. Note that they aren't all
+  enabled by default; you can enable them by saying Y to "/proc file
+  system support" and "Sysctl support", and after the /proc file
+  system has been mounted, executing the command
+
+	command			what is enabled
+
+  echo 0>/proc/ALi5451	pcm out is also set to S/PDIF out. (Default).
+
+  echo 1>/proc/ALi5451	use S/PDIF out to output pcm data.
+
+  echo 2>/proc/ALi5451	use S/PDIF out to output non-pcm data.
+                        (AC3...).
+
+  echo 3>/proc/ALi5451	record from Ac97 in(MIC, Line in...).
+                        (Default).
+
+  echo 4>/proc/ALi5451	no matter Ac97 settings, record from S/PDIF
+                        in.
+
+
+  This driver differs slightly from OSS/Free, so PLEASE READ the
+  comments at the top of <file:drivers/sound/trident.c>.
+
+CONFIG_SOUND_WAVEARTIST
+  Say Y here to include support for the Rockwell WaveArtist sound
+  system.  This driver is mainly for the NetWinder.
+
+CONFIG_SOUND_VIA82CXXX
+  Say Y here to include support for the audio codec found on VIA
+  82Cxxx-based chips. Typically these are built into a motherboard.
+
+  DO NOT select Sound Blaster or Adlib with this driver, unless
+  you have a Sound Blaster or Adlib card in addition to your VIA
+  audio chip.
+
+CONFIG_MIDI_VIA82CXXX
+  Answer Y to use the MIDI interface of the Via686. You may need to
+  enable this in the BIOS before it will work. This is for connection
+  to external MIDI hardware, and is not required for software playback
+  of MIDI files.
+
+CONFIG_SOUND_NM256
+  Say M here to include audio support for the NeoMagic 256AV/256ZX
+  chipsets. These are the audio chipsets found in the Sony
+  Z505S/SX/DX, some Sony F-series, and the Dell Latitude CPi and CPt
+  laptops. It includes support for an AC97-compatible mixer and an
+  apparently proprietary sound engine.
+
+  See <file:Documentation/sound/NM256> for further information.
+
+CONFIG_SOUND_MAESTRO
+  Say Y or M if you have a sound system driven by ESS's Maestro line
+  of PCI sound chips.  These include the Maestro 1, Maestro 2, and
+  Maestro 2E.  See <file:Documentation/sound/Maestro> for more
+  details.
+
+CONFIG_SOUND_MAESTRO3
+  Say Y or M if you have a sound system driven by ESS's Maestro 3
+  PCI sound chip.
+
+CONFIG_SOUND_ADLIB
+  Includes ASB 64 4D. Information on programming AdLib cards is
+  available at <http://www.itsnet.com/home/ldragon/Specs/adlib.html>.
+
+CONFIG_SOUND_CS4281
+  Picture and feature list at
+  <http://www.pcbroker.com/crystal4281.html>.
+
+CONFIG_SOUND_GUS16
+  Support for Gravis Ulstrasound (GUS) cards (other than the GUS),
+  sampling at 16-bit width.
+
+CONFIG_SOUND_GUSMAX
+  Support for Gravis Ulstrasound MAX.
+
+CONFIG_SOUND_ICH
+  Support for integral audio in Intel's I/O Controller Hub (ICH)
+  chipset, as used on the 810/820/840 motherboards.
+
+CONFIG_SOUND_TRACEINIT
+  Verbose soundcard initialization -- affects the format of autoprobe
+  and initialization messages at boot time.
+
+CONFIG_SOUND_TVMIXER
+  Support for audio mixer facilities on the BT848 TV frame-grabber
+  card.
+
+CONFIG_SOUND_VIDC
+  16-bit support for the VIDC onboard sound hardware found on Acorn
+  machines.
+
+CONFIG_SOUND_VMIDI
+  Support for MIDI loopback on port 1 or 2.
+
+CONFIG_SOUND_YMFPCI
+  Support for Yamaha cards including the YMF711, YMF715, YMF718,
+  YMF719, YMF724, Waveforce 192XG, and Waveforce 192 Digital.
+
+CONFIG_SOUND_YMFPCI_LEGACY
+  Support for YMF7xx PCI cards emulating an MP401.
+
+CONFIG_SOUND_RME96XX
+  Say Y or M if you have a Hammerfall, Hammerfall light or Hammerfall
+  DSP card from RME.
+
+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.
+  Function 0 does the video stuff (bt848 compatible), function 1 does
+  the same for audio data.  This is a driver for the audio part of
+  the chip.  If you say 'Y' here you get a oss-compatible dsp device
+  where you can record from.  If you want just watch TV you probably
+  don't need this driver as most TV cards handle sound with a short
+  cable from the TV card to your sound card's line-in.
+
+  This driver is available as a module called btaudio.o ( = 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>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- v2.5.2/linux/drivers/sound/cmpci.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/sound/cmpci.c	Wed Jan 23 15:51:23 2002
@@ -1440,7 +1440,7 @@
 
 static int cm_open_mixdev(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct cm_state *s = devs;
 
 	while (s && s->dev_mixer != minor)
@@ -1752,7 +1752,7 @@
 	if (size > (PAGE_SIZE << db->buforder))
 		goto out;
 	ret = -EINVAL;
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
 		goto out;
 	db->mapped = 1;
 	ret = 0;
@@ -2190,7 +2190,7 @@
 
 static int cm_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct cm_state *s = devs;
 	unsigned char fmtm = ~0, fmts = 0;
 
@@ -2445,7 +2445,7 @@
 
 static int cm_midi_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct cm_state *s = devs;
 	unsigned long flags;
 
@@ -2662,7 +2662,7 @@
 
 static int cm_dmfm_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct cm_state *s = devs;
 
 	while (s && s->dev_dmfm != minor)
@@ -2861,7 +2861,9 @@
 	struct cm_state *s;
 	mm_segment_t fs;
 	int i, val;
+#if defined(CONFIG_SOUND_CMPCI_MIDI) || defined(CONFIG_SOUND_CMPCI_FM)
 	unsigned char reg_mask = 0;
+#endif
 	struct {
 		unsigned short	deviceid;
 		char		*devicename;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/cs4281/cs4281m.c linux/drivers/sound/cs4281/cs4281m.c
--- v2.5.2/linux/drivers/sound/cs4281/cs4281m.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/cs4281/cs4281m.c	Tue Jan 15 10:56:35 2002
@@ -3145,7 +3145,7 @@
 	if (size > (PAGE_SIZE << db->buforder))
 		return -EINVAL;
 	if (remap_page_range
-	    (vma->vm_start, virt_to_phys(db->rawbuf), size,
+	    (vma, vma->vm_start, virt_to_phys(db->rawbuf), size,
 	     vma->vm_page_prot)) return -EAGAIN;
 	db->mapped = 1;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c
--- v2.5.2/linux/drivers/sound/cs46xx.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/cs46xx.c	Tue Jan 15 10:56:35 2002
@@ -2467,7 +2467,7 @@
 		ret = -EINVAL;
 		goto out;
 	}
-	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf),
 			     size, vma->vm_page_prot))
 	{
 		ret = -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/dmasound/Config.help linux/drivers/sound/dmasound/Config.help
--- v2.5.2/linux/drivers/sound/dmasound/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/dmasound/Config.help	Fri Jan 25 16:04:15 2002
@@ -0,0 +1,47 @@
+CONFIG_DMASOUND
+  Support built-in audio chips accessible by DMA on various machines
+  that have them.  Note that this symbol does not affect the kernel
+  directly; rather, it controls whether configuration questions
+  enabling DMA sound drivers for various specific machine
+  architectures will be used.
+
+CONFIG_DMASOUND_ATARI
+  If you want to use the internal audio of your Atari in Linux, answer
+  Y to this question. This will provide a Sun-like /dev/audio,
+  compatible with the Linux/i386 sound system. Otherwise, say N.
+
+  This driver is also available 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>.
+
+CONFIG_DMASOUND_AWACS
+  If you want to use the internal audio of your PowerMac in Linux,
+  answer Y to this question. This will provide a Sun-like /dev/audio,
+  compatible with the Linux/i386 sound system. Otherwise, say N.
+
+  This driver is also available 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>.
+
+CONFIG_DMASOUND_PAULA
+  If you want to use the internal audio of your Amiga in Linux, answer
+  Y to this question. This will provide a Sun-like /dev/audio,
+  compatible with the Linux/i386 sound system. Otherwise, say N.
+
+  This driver is also available 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>.
+
+CONFIG_DMASOUND_Q40
+  If you want to use the internal audio of your Q40 in Linux, answer
+  Y to this question. This will provide a Sun-like /dev/audio,
+  compatible with the Linux/i386 sound system. Otherwise, say N.
+
+  This driver is also available 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>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/emu10k1/audio.c linux/drivers/sound/emu10k1/audio.c
--- v2.5.2/linux/drivers/sound/emu10k1/audio.c	Tue Oct  9 10:53:17 2001
+++ linux/drivers/sound/emu10k1/audio.c	Mon Jan 21 15:50:28 2002
@@ -1098,7 +1098,7 @@
 
 static int emu10k1_audio_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct emu10k1_card *card = NULL;
 	struct list_head *entry;
 	struct emu10k1_wavedevice *wave_dev;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/emu10k1/midi.c linux/drivers/sound/emu10k1/midi.c
--- v2.5.2/linux/drivers/sound/emu10k1/midi.c	Tue Oct  9 10:53:18 2001
+++ linux/drivers/sound/emu10k1/midi.c	Mon Jan 21 15:50:28 2002
@@ -87,7 +87,7 @@
 
 static int emu10k1_midi_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct emu10k1_card *card = NULL;
 	struct emu10k1_mididevice *midi_dev;
 	struct list_head *entry;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/emu10k1/mixer.c linux/drivers/sound/emu10k1/mixer.c
--- v2.5.2/linux/drivers/sound/emu10k1/mixer.c	Tue Oct  9 10:53:18 2001
+++ linux/drivers/sound/emu10k1/mixer.c	Mon Jan 21 15:50:28 2002
@@ -640,7 +640,7 @@
 
 static int emu10k1_mixer_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct emu10k1_card *card = NULL;
 	struct list_head *entry;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.5.2/linux/drivers/sound/es1370.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/es1370.c	Tue Jan 15 10:56:35 2002
@@ -1373,7 +1373,7 @@
 		ret = -EINVAL;
 		goto out;
 	}
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) {
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) {
 		ret = -EAGAIN;
 		goto out;
 	}
@@ -1945,7 +1945,7 @@
 	if (size > (PAGE_SIZE << s->dma_dac1.buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot))
 		goto out;
 	s->dma_dac1.mapped = 1;
 	ret = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.5.2/linux/drivers/sound/es1371.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/es1371.c	Tue Jan 15 10:56:35 2002
@@ -1562,7 +1562,7 @@
 		ret = -EINVAL;
 		goto out;
 	}
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) {
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) {
 		ret = -EAGAIN;
 		goto out;
 	}
@@ -2131,7 +2131,7 @@
 	if (size > (PAGE_SIZE << s->dma_dac1.buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot))
 		goto out;
 	s->dma_dac1.mapped = 1;
 	ret = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.5.2/linux/drivers/sound/esssolo1.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/esssolo1.c	Tue Jan 15 10:56:35 2002
@@ -1245,7 +1245,7 @@
 	if (size > (PAGE_SIZE << db->buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
 		goto out;
 	db->mapped = 1;
 	ret = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- v2.5.2/linux/drivers/sound/i810_audio.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/i810_audio.c	Mon Jan 28 14:35:13 2002
@@ -14,7 +14,7 @@
  *	Analog Devices (A major AC97 codec maker)
  *	Intel Corp  (you've probably heard of them already)
  *
- * AC97 clues and assistance provided by
+ *  AC97 clues and assistance provided by
  *	Analog Devices
  *	Zach 'Fufu' Brown
  *	Jeff Garzik
@@ -63,6 +63,8 @@
  *	This is available via the 'ftsodell=1' option. 
  *
  *	If you need to force a specific rate set the clocking= option
+ *
+ *	This driver is cursed. (Ben LaHaise)
  */
  
 #include <linux/module.h>
@@ -102,15 +104,22 @@
 #ifndef PCI_DEVICE_ID_INTEL_440MX
 #define PCI_DEVICE_ID_INTEL_440MX	0x7195
 #endif
+#ifndef PCI_DEVICE_ID_SI_7012
+#define PCI_DEVICE_ID_SI_7012		0x7012
+#endif
+#ifndef PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO
+#define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO	0x01b1
+#endif
 
 static int ftsodell=0;
 static int strict_clocking=0;
-static unsigned int clocking=48000;
+static unsigned int clocking=0;
 static int spdif_locked=0;
 
 //#define DEBUG
 //#define DEBUG2
 //#define DEBUG_INTERRUPTS
+//#define DEBUG_MMAP
 
 #define ADC_RUNNING	1
 #define DAC_RUNNING	2
@@ -197,7 +206,7 @@
 #define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
 
 
-#define DRIVER_VERSION "0.04"
+#define DRIVER_VERSION "0.21"
 
 /* magic numbers to protect our data structures */
 #define I810_CARD_MAGIC		0x5072696E /* "Prin" */
@@ -220,7 +229,9 @@
 	ICH82901AB,
 	INTEL440MX,
 	INTELICH2,
-	INTELICH3
+	INTELICH3,
+	SI7012,
+	NVIDIA_NFORCE
 };
 
 static char * card_names[] = {
@@ -228,7 +239,9 @@
 	"Intel ICH 82901AB",
 	"Intel 440MX",
 	"Intel ICH2",
-	"Intel ICH3"
+	"Intel ICH3",
+	"SiS 7012",
+	"NVIDIA nForce Audio"
 };
 
 static struct pci_device_id i810_pci_tbl [] __initdata = {
@@ -242,6 +255,10 @@
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH2},
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH3,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7012,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, SI7012},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
 	{0,}
 };
 
@@ -357,39 +374,17 @@
 	struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *);
 	struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *);
 	void (*free_pcm_channel)(struct i810_card *, int chan);
+
+	/* We have a *very* long init time possibly, so use this to block */
+	/* attempts to open our devices before we are ready (stops oops'es) */
+	int initializing;
 };
 
 static struct i810_card *devs = NULL;
 
 static int i810_open_mixdev(struct inode *inode, struct file *file);
-static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
-				unsigned long arg);
-
-static inline unsigned ld2(unsigned int x)
-{
-	unsigned r = 0;
-	
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
+static int i810_ioctl_mixdev(struct inode *inode, struct file *file,
+			     unsigned int cmd, unsigned long arg);
 static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);
 static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
 
@@ -606,9 +601,8 @@
 		rate = 8000;
 		dmabuf->rate = (rate * 48000)/clocking;
 	}
-	
-	new_rate = ac97_set_dac_rate(codec, rate);
 
+        new_rate=ac97_set_dac_rate(codec, rate);
 	if(new_rate != rate) {
 		dmabuf->rate = (new_rate * 48000)/clocking;
 	}
@@ -666,47 +660,49 @@
 static inline unsigned i810_get_dma_addr(struct i810_state *state, int rec)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned int civ, offset;
-	struct i810_channel *c;
+	unsigned int civ, offset, port, port_picb, bytes = 2;
 	
 	if (!dmabuf->enable)
 		return 0;
+
 	if (rec)
-		c = dmabuf->read_channel;
+		port = state->card->iobase + dmabuf->read_channel->port;
 	else
-		c = dmabuf->write_channel;
+		port = state->card->iobase + dmabuf->write_channel->port;
+
+	if(state->card->pci_id == PCI_DEVICE_ID_SI_7012) {
+		port_picb = port + OFF_SR;
+		bytes = 1;
+	} else
+		port_picb = port + OFF_PICB;
+
 	do {
-		civ = inb(state->card->iobase+c->port+OFF_CIV);
-		offset = (civ + 1) * dmabuf->fragsize -
-			      2 * inw(state->card->iobase+c->port+OFF_PICB);
-		/* CIV changed before we read PICB (very seldom) ?
-		 * then PICB was rubbish, so try again */
-	} while (civ != inb(state->card->iobase+c->port+OFF_CIV));
+		civ = inb(port+OFF_CIV) & 31;
+		offset = inw(port_picb);
+		/* Must have a delay here! */ 
+		if(offset == 0)
+			udelay(1);
+		/* Reread both registers and make sure that that total
+		 * offset from the first reading to the second is 0.
+		 * There is an issue with SiS hardware where it will count
+		 * picb down to 0, then update civ to the next value,
+		 * then set the new picb to fragsize bytes.  We can catch
+		 * it between the civ update and the picb update, making
+		 * it look as though we are 1 fragsize ahead of where we
+		 * are.  The next to we get the address though, it will
+		 * be back in the right place, and we will suddenly think
+		 * we just went forward dmasize - fragsize bytes, causing
+		 * totally stupid *huge* dma overrun messages.  We are
+		 * assuming that the 1us delay is more than long enough
+		 * that we won't have to worry about the chip still being
+		 * out of sync with reality ;-)
+		 */
+	} while (civ != (inb(port+OFF_CIV) & 31) || offset != inw(port_picb));
 		 
-	return offset;
+	return (((civ + 1) * dmabuf->fragsize - (bytes * offset))
+		% dmabuf->dmasize);
 }
 
-//static void resync_dma_ptrs(struct i810_state *state, int rec)
-//{
-//	struct dmabuf *dmabuf = &state->dmabuf;
-//	struct i810_channel *c;
-//	int offset;
-//
-//	if(rec) {
-//		c = dmabuf->read_channel;
-//	} else {
-//		c = dmabuf->write_channel;
-//	}
-//	if(c==NULL)
-//		return;
-//	offset = inb(state->card->iobase+c->port+OFF_CIV);
-//	if(offset == inb(state->card->iobase+c->port+OFF_LVI))
-//		offset++;
-//	offset *= dmabuf->fragsize;
-//	
-//	dmabuf->hwptr=dmabuf->swptr = offset;
-//}
-	
 /* Stop recording (lock held) */
 static inline void __stop_adc(struct i810_state *state)
 {
@@ -718,7 +714,10 @@
 	// wait for the card to acknowledge shutdown
 	while( inb(card->iobase + PI_CR) != 0 ) ;
 	// now clear any latent interrupt bits (like the halt bit)
-	outb( inb(card->iobase + PI_SR), card->iobase + PI_SR );
+	if(card->pci_id == PCI_DEVICE_ID_SI_7012)
+		outb( inb(card->iobase + PI_PICB), card->iobase + PI_PICB );
+	else
+		outb( inb(card->iobase + PI_SR), card->iobase + PI_SR );
 	outl( inl(card->iobase + GLOB_STA) & INT_PI, card->iobase + GLOB_STA);
 }
 
@@ -732,21 +731,27 @@
 	spin_unlock_irqrestore(&card->lock, flags);
 }
 
-static void start_adc(struct i810_state *state)
+static inline void __start_adc(struct i810_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	struct i810_card *card = state->card;
-	unsigned long flags;
 
 	if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable &&
 	    (dmabuf->trigger & PCM_ENABLE_INPUT)) {
-		spin_lock_irqsave(&card->lock, flags);
 		dmabuf->enable |= ADC_RUNNING;
-		outb((1<<4) | (1<<2) | 1, card->iobase + PI_CR);
-		spin_unlock_irqrestore(&card->lock, flags);
+		outb((1<<4) | (1<<2) | 1, state->card->iobase + PI_CR);
 	}
 }
 
+static void start_adc(struct i810_state *state)
+{
+	struct i810_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	__start_adc(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
 /* stop playback (lock held) */
 static inline void __stop_dac(struct i810_state *state)
 {
@@ -758,7 +763,10 @@
 	// wait for the card to acknowledge shutdown
 	while( inb(card->iobase + PO_CR) != 0 ) ;
 	// now clear any latent interrupt bits (like the halt bit)
-	outb( inb(card->iobase + PO_SR), card->iobase + PO_SR );
+	if(card->pci_id == PCI_DEVICE_ID_SI_7012)
+		outb( inb(card->iobase + PO_PICB), card->iobase + PO_PICB );
+	else
+		outb( inb(card->iobase + PO_SR), card->iobase + PO_SR );
 	outl( inl(card->iobase + GLOB_STA) & INT_PO, card->iobase + GLOB_STA);
 }
 
@@ -772,20 +780,25 @@
 	spin_unlock_irqrestore(&card->lock, flags);
 }	
 
-static void start_dac(struct i810_state *state)
+static inline void __start_dac(struct i810_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	struct i810_card *card = state->card;
-	unsigned long flags;
 
 	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
 	    (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
-		spin_lock_irqsave(&card->lock, flags);
 		dmabuf->enable |= DAC_RUNNING;
-		outb((1<<4) | (1<<2) | 1, card->iobase + PO_CR);
-		spin_unlock_irqrestore(&card->lock, flags);
+		outb((1<<4) | (1<<2) | 1, state->card->iobase + PO_CR);
 	}
 }
+static void start_dac(struct i810_state *state)
+{
+	struct i810_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	__start_dac(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
 
 #define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
 #define DMABUF_MINORDER 1
@@ -805,6 +818,8 @@
 		dmabuf->ossfragsize = (PAGE_SIZE<<DMABUF_DEFAULTORDER)/dmabuf->ossmaxfrags;
 	size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
 
+	if(dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)
+		return 0;
 	/* alloc enough to satisfy the oss params */
 	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
 		if ( (PAGE_SIZE<<order) > size )
@@ -873,14 +888,19 @@
 	dmabuf->swptr = dmabuf->hwptr = 0;
 	spin_unlock_irqrestore(&state->card->lock, flags);
 
-	/* allocate DMA buffer if not allocated yet */
-	if (dmabuf->rawbuf)
-		dealloc_dmabuf(state);
+	/* allocate DMA buffer, let alloc_dmabuf determine if we are already
+	 * allocated well enough or if we should replace the current buffer
+	 * (assuming one is already allocated, if it isn't, then allocate it).
+	 */
 	if ((ret = alloc_dmabuf(state)))
 		return ret;
 
 	/* FIXME: figure out all this OSS fragment stuff */
 	/* I did, it now does what it should according to the OSS API.  DL */
+	/* We may not have realloced our dmabuf, but the fragment size to
+	 * fragment number ratio may have changed, so go ahead and reprogram
+	 * things
+	 */
 	dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
 	dmabuf->numfrag = SG_LEN;
 	dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag;
@@ -922,6 +942,8 @@
 			sg->busaddr=virt_to_bus(dmabuf->rawbuf+dmabuf->fragsize*i);
 			// the card will always be doing 16bit stereo
 			sg->control=dmabuf->fragsamples;
+			if(state->card->pci_id == PCI_DEVICE_ID_SI_7012)
+				sg->control <<= 1;
 			sg->control|=CON_BUFPAD;
 			// set us up to get IOC interrupts as often as needed to
 			// satisfy numfrag requirements, no more
@@ -935,7 +957,6 @@
 		outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
 		outb(0, state->card->iobase+c->port+OFF_CIV);
 		outb(0, state->card->iobase+c->port+OFF_LVI);
-		dmabuf->count = 0;
 
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
@@ -969,31 +990,34 @@
 	else
 		port += dmabuf->write_channel->port;
 
-	if(dmabuf->mapped) {
-		if(rec)
-			dmabuf->swptr = (dmabuf->hwptr + dmabuf->dmasize
-				       	- dmabuf->count) % dmabuf->dmasize;
-		else
-			dmabuf->swptr = (dmabuf->hwptr + dmabuf->count)
-			       		% dmabuf->dmasize;
-	}
-	/*
-	 * two special cases, count == 0 on write
-	 * means no data, and count == dmasize
-	 * means no data on read, handle appropriately
+	/* if we are currently stopped, then our CIV is actually set to our
+	 * *last* sg segment and we are ready to wrap to the next.  However,
+	 * if we set our LVI to the last sg segment, then it won't wrap to
+	 * the next sg segment, it won't even get a start.  So, instead, when
+	 * we are stopped, we set both the LVI value and also we increment
+	 * the CIV value to the next sg segment to be played so that when
+	 * we call start_{dac,adc}, things will operate properly
 	 */
-	if(!rec && dmabuf->count == 0) {
-		outb(inb(port+OFF_CIV),port+OFF_LVI);
-		return;
-	}
-	if(rec && dmabuf->count == dmabuf->dmasize) {
-		outb(inb(port+OFF_CIV),port+OFF_LVI);
-		return;
+	if (!dmabuf->enable && dmabuf->ready) {
+		if(rec && dmabuf->count < dmabuf->dmasize &&
+		   (dmabuf->trigger & PCM_ENABLE_INPUT))
+		{
+			outb((inb(port+OFF_CIV)+1)&31, port+OFF_LVI);
+			__start_adc(state);
+			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
+		} else if (!rec && dmabuf->count &&
+			   (dmabuf->trigger & PCM_ENABLE_OUTPUT))
+		{
+			outb((inb(port+OFF_CIV)+1)&31, port+OFF_LVI);
+			__start_dac(state);
+			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
+		}
 	}
+
 	/* swptr - 1 is the tail of our transfer */
 	x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize;
 	x /= dmabuf->fragsize;
-	outb(x&31, port+OFF_LVI);
+	outb(x, port+OFF_LVI);
 }
 
 static void i810_update_lvi(struct i810_state *state, int rec)
@@ -1020,7 +1044,9 @@
 		/* update hardware pointer */
 		hwptr = i810_get_dma_addr(state, 1);
 		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-//		printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
+		printk("ADC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#endif
 		dmabuf->hwptr = hwptr;
 		dmabuf->total_bytes += diff;
 		dmabuf->count += diff;
@@ -1029,8 +1055,8 @@
 			/* this is normal for the end of a read */
 			/* only give an error if we went past the */
 			/* last valid sg entry */
-			if(inb(state->card->iobase + PI_CIV) !=
-			   inb(state->card->iobase + PI_LVI)) {
+			if((inb(state->card->iobase + PI_CIV) & 31) !=
+			   (inb(state->card->iobase + PI_LVI) & 31)) {
 				printk(KERN_WARNING "i810_audio: DMA overrun on read\n");
 				dmabuf->error++;
 			}
@@ -1043,7 +1069,9 @@
 		/* update hardware pointer */
 		hwptr = i810_get_dma_addr(state, 0);
 		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-//		printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
+		printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#endif
 		dmabuf->hwptr = hwptr;
 		dmabuf->total_bytes += diff;
 		dmabuf->count -= diff;
@@ -1052,13 +1080,13 @@
 			/* this is normal for the end of a write */
 			/* only give an error if we went past the */
 			/* last valid sg entry */
-			if(inb(state->card->iobase + PO_CIV) !=
-			   inb(state->card->iobase + PO_LVI)) {
+			if((inb(state->card->iobase + PO_CIV) & 31) !=
+			   (inb(state->card->iobase + PO_LVI) & 31)) {
 				printk(KERN_WARNING "i810_audio: DMA overrun on write\n");
 				printk("i810_audio: CIV %d, LVI %d, hwptr %x, "
 					"count %d\n",
-					inb(state->card->iobase + PO_CIV),
-					inb(state->card->iobase + PO_LVI),
+					inb(state->card->iobase + PO_CIV) & 31,
+					inb(state->card->iobase + PO_LVI) & 31,
 					dmabuf->hwptr, dmabuf->count);
 				dmabuf->error++;
 			}
@@ -1068,7 +1096,43 @@
 	}
 }
 
-static int drain_dac(struct i810_state *state, int nonblock)
+static inline int i810_get_free_write_space(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int free;
+
+	i810_update_ptr(state);
+	// catch underruns during playback
+	if (dmabuf->count < 0) {
+		dmabuf->count = 0;
+		dmabuf->swptr = dmabuf->hwptr;
+	}
+	free = dmabuf->dmasize - dmabuf->count;
+	free -= (dmabuf->hwptr % dmabuf->fragsize);
+	if(free < 0)
+		return(0);
+	return(free);
+}
+
+static inline int i810_get_available_read_data(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int avail;
+
+	i810_update_ptr(state);
+	// catch overruns during record
+	if (dmabuf->count > dmabuf->dmasize) {
+		dmabuf->count = dmabuf->dmasize;
+		dmabuf->swptr = dmabuf->hwptr;
+	}
+	avail = dmabuf->count;
+	avail -= (dmabuf->hwptr % dmabuf->fragsize);
+	if(avail < 0)
+		return(0);
+	return(avail);
+}
+
+static int drain_dac(struct i810_state *state, int signals_allowed)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct dmabuf *dmabuf = &state->dmabuf;
@@ -1078,12 +1142,12 @@
 
 	if (!dmabuf->ready)
 		return 0;
-
+	if(dmabuf->mapped) {
+		stop_dac(state);
+		return 0;
+	}
 	add_wait_queue(&dmabuf->wait, &wait);
 	for (;;) {
-		/* It seems that we have to set the current state to TASK_INTERRUPTIBLE
-		   every time to make the process really go to sleep */
-		set_current_state(TASK_INTERRUPTIBLE);
 
 		spin_lock_irqsave(&state->card->lock, flags);
 		i810_update_ptr(state);
@@ -1093,33 +1157,46 @@
 		if (count <= 0)
 			break;
 
-		if (signal_pending(current))
-			break;
-
-		i810_update_lvi(state,0);
-		if (dmabuf->enable != DAC_RUNNING)
-			start_dac(state);
-
-		if (nonblock) {
-			remove_wait_queue(&dmabuf->wait, &wait);
-			set_current_state(TASK_RUNNING);
-			return -EBUSY;
+		/* 
+		 * This will make sure that our LVI is correct, that our
+		 * pointer is updated, and that the DAC is running.  We
+		 * have to force the setting of dmabuf->trigger to avoid
+		 * any possible deadlocks.
+		 */
+		if(!dmabuf->enable) {
+			dmabuf->trigger = PCM_ENABLE_OUTPUT;
+			i810_update_lvi(state,0);
 		}
+                if (signal_pending(current) && signals_allowed) {
+                        break;
+                }
 
-		tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
-		tmo >>= 1;
-		if (!schedule_timeout(tmo ? tmo : 1) && tmo){
+		/* It seems that we have to set the current state to
+		 * TASK_INTERRUPTIBLE every time to make the process
+		 * really go to sleep.  This also has to be *after* the
+		 * update_ptr() call because update_ptr is likely to
+		 * do a wake_up() which will unset this before we ever
+		 * try to sleep, resuling in a tight loop in this code
+		 * instead of actually sleeping and waiting for an
+		 * interrupt to wake us up!
+		 */
+		set_current_state(TASK_INTERRUPTIBLE);
+		/*
+		 * set the timeout to significantly longer than it *should*
+		 * take for the DAC to drain the DMA buffer
+		 */
+		tmo = (count * HZ) / (dmabuf->rate);
+		if (!schedule_timeout(tmo >= 2 ? tmo : 2)){
 			printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n");
+			count = 0;
 			break;
 		}
 	}
-	stop_dac(state);
-	synchronize_irq();
-	remove_wait_queue(&dmabuf->wait, &wait);
 	set_current_state(TASK_RUNNING);
-	if (signal_pending(current))
+	remove_wait_queue(&dmabuf->wait, &wait);
+	if(count > 0 && signal_pending(current) && signals_allowed)
 		return -ERESTARTSYS;
-
+	stop_dac(state);
 	return 0;
 }
 
@@ -1143,52 +1220,72 @@
 		if(!state->dmabuf.ready)
 			continue;
 		dmabuf = &state->dmabuf;
-		if(dmabuf->enable & DAC_RUNNING)
+		if(dmabuf->enable & DAC_RUNNING) {
 			c=dmabuf->write_channel;
-		else if(dmabuf->enable & ADC_RUNNING)
+		} else if(dmabuf->enable & ADC_RUNNING) {
 			c=dmabuf->read_channel;
-		else	/* This can occur going from R/W to close */
+		} else	/* This can occur going from R/W to close */
 			continue;
 		
 		port+=c->port;
-		
-		status = inw(port + OFF_SR);
+
+		if(card->pci_id == PCI_DEVICE_ID_SI_7012)
+			status = inw(port + OFF_PICB);
+		else
+			status = inw(port + OFF_SR);
+
 #ifdef DEBUG_INTERRUPTS
 		printk("NUM %d PORT %X IRQ ( ST%d ", c->num, c->port, status);
 #endif
 		if(status & DMA_INT_COMPLETE)
 		{
+			/* only wake_up() waiters if this interrupt signals
+			 * us being beyond a userfragsize of data open or
+			 * available, and i810_update_ptr() does that for
+			 * us
+			 */
 			i810_update_ptr(state);
 #ifdef DEBUG_INTERRUPTS
 			printk("COMP %d ", dmabuf->hwptr /
 					dmabuf->fragsize);
 #endif
 		}
-		if(status & DMA_INT_LVI)
+		if(status & (DMA_INT_LVI | DMA_INT_DCH))
 		{
+			/* wake_up() unconditionally on LVI and DCH */
 			i810_update_ptr(state);
 			wake_up(&dmabuf->wait);
 #ifdef DEBUG_INTERRUPTS
-			printk("LVI ");
+			if(status & DMA_INT_LVI)
+				printk("LVI ");
+			if(status & DMA_INT_DCH)
+				printk("DCH -");
 #endif
-		}
-		if(status & DMA_INT_DCH)
-		{
-			i810_update_ptr(state);
 			if(dmabuf->enable & DAC_RUNNING)
 				count = dmabuf->count;
 			else
 				count = dmabuf->dmasize - dmabuf->count;
 			if(count > 0) {
 				outb(inb(port+OFF_CR) | 1, port+OFF_CR);
+#ifdef DEBUG_INTERRUPTS
+				printk(" CONTINUE ");
+#endif
 			} else {
+				if (dmabuf->enable & DAC_RUNNING)
+					__stop_dac(state);
+				if (dmabuf->enable & ADC_RUNNING)
+					__stop_adc(state);
+				dmabuf->enable = 0;
 				wake_up(&dmabuf->wait);
 #ifdef DEBUG_INTERRUPTS
-				printk("DCH - STOP ");
+				printk(" STOP ");
 #endif
 			}
 		}
-		outw(status & DMA_INT_MASK, port + OFF_SR);
+		if(card->pci_id == PCI_DEVICE_ID_SI_7012)
+			outw(status & DMA_INT_MASK, port + OFF_PICB);
+		else
+			outw(status & DMA_INT_MASK, port + OFF_SR);
 	}
 #ifdef DEBUG_INTERRUPTS
 	printk(")\n");
@@ -1254,15 +1351,14 @@
 		return ret;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
-	dmabuf->trigger &= ~PCM_ENABLE_OUTPUT;
 	ret = 0;
 
         add_wait_queue(&dmabuf->wait, &waita);
 	while (count > 0) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		spin_lock_irqsave(&card->lock, flags);
                 if (PM_SUSPENDED(card)) {
                         spin_unlock_irqrestore(&card->lock, flags);
-                        set_current_state(TASK_INTERRUPTIBLE);
                         schedule();
                         if (signal_pending(current)) {
                                 if (!ret) ret = -EAGAIN;
@@ -1271,10 +1367,7 @@
                         continue;
                 }
 		swptr = dmabuf->swptr;
-		if (dmabuf->count > dmabuf->dmasize) {
-			dmabuf->count = dmabuf->dmasize;
-		}
-		cnt = dmabuf->count - dmabuf->fragsize;
+		cnt = i810_get_available_read_data(state);
 		// this is to make the copy_to_user simpler below
 		if(cnt > (dmabuf->dmasize - swptr))
 			cnt = dmabuf->dmasize - swptr;
@@ -1282,20 +1375,39 @@
 
 		if (cnt > count)
 			cnt = count;
+		/* Lop off the last two bits to force the code to always
+		 * write in full samples.  This keeps software that sets
+		 * O_NONBLOCK but doesn't check the return value of the
+		 * write call from getting things out of state where they
+		 * think a full 4 byte sample was written when really only
+		 * a portion was, resulting in odd sound and stereo
+		 * hysteresis.
+		 */
+		cnt &= ~0x3;
 		if (cnt <= 0) {
 			unsigned long tmo;
-			if(!dmabuf->enable) {
-				dmabuf->trigger |= PCM_ENABLE_INPUT;
-				start_adc(state);
-			}
+			/*
+			 * Don't let us deadlock.  The ADC won't start if
+			 * dmabuf->trigger isn't set.  A call to SETTRIGGER
+			 * could have turned it off after we set it to on
+			 * previously.
+			 */
+			dmabuf->trigger = PCM_ENABLE_INPUT;
+			/*
+			 * This does three things.  Updates LVI to be correct,
+			 * makes sure the ADC is running, and updates the
+			 * hwptr.
+			 */
 			i810_update_lvi(state,1);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
-				return ret;
+				goto done;
 			}
-			/* This isnt strictly right for the 810  but it'll do */
-			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
-			tmo >>= 1;
+			/* Set the timeout to how long it would take to fill
+			 * two of our buffers.  If we haven't been woke up
+			 * by then, then we know something is wrong.
+			 */
+			tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
 			/* There are two situations when sleep_on_timeout returns, one is when
 			   the interrupt is serviced correctly and the process is waked up by
 			   ISR ON TIME. Another is when timeout is expired, which means that
@@ -1303,7 +1415,7 @@
 			   is TOO LATE for the process to be scheduled to run (scheduler latency)
 			   which results in a (potential) buffer overrun. And worse, there is
 			   NOTHING we can do to prevent it. */
-			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
+			if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
 #ifdef DEBUG
 				printk(KERN_ERR "i810_audio: recording schedule timeout, "
 				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
@@ -1315,7 +1427,7 @@
 			}
 			if (signal_pending(current)) {
 				ret = ret ? ret : -ERESTARTSYS;
-				return ret;
+				goto done;
 			}
 			continue;
 		}
@@ -1341,10 +1453,8 @@
 		buffer += cnt;
 		ret += cnt;
 	}
-	i810_update_lvi(state,1);
-	if(!(dmabuf->enable & ADC_RUNNING))
-		start_adc(state);
  done:
+	i810_update_lvi(state,1);
         set_current_state(TASK_RUNNING);
         remove_wait_queue(&dmabuf->wait, &waita);
 
@@ -1384,15 +1494,14 @@
 		return ret;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
-	dmabuf->trigger &= ~PCM_ENABLE_INPUT;
 	ret = 0;
 
         add_wait_queue(&dmabuf->wait, &waita);
 	while (count > 0) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		spin_lock_irqsave(&state->card->lock, flags);
                 if (PM_SUSPENDED(card)) {
                         spin_unlock_irqrestore(&card->lock, flags);
-                        set_current_state(TASK_INTERRUPTIBLE);
                         schedule();
                         if (signal_pending(current)) {
                                 if (!ret) ret = -EAGAIN;
@@ -1402,11 +1511,12 @@
                 }
 
 		swptr = dmabuf->swptr;
-		if (dmabuf->count < 0) {
-			dmabuf->count = 0;
-		}
-		cnt = dmabuf->dmasize - dmabuf->fragsize - dmabuf->count;
-		// this is to make the copy_from_user simpler below
+		cnt = i810_get_free_write_space(state);
+		/* Bound the maximum size to how much we can copy to the
+		 * dma buffer before we hit the end.  If we have more to
+		 * copy then it will get done in a second pass of this
+		 * loop starting from the beginning of the buffer.
+		 */
 		if(cnt > (dmabuf->dmasize - swptr))
 			cnt = dmabuf->dmasize - swptr;
 		spin_unlock_irqrestore(&state->card->lock, flags);
@@ -1416,25 +1526,30 @@
 #endif
 		if (cnt > count)
 			cnt = count;
+		/* Lop off the last two bits to force the code to always
+		 * write in full samples.  This keeps software that sets
+		 * O_NONBLOCK but doesn't check the return value of the
+		 * write call from getting things out of state where they
+		 * think a full 4 byte sample was written when really only
+		 * a portion was, resulting in odd sound and stereo
+		 * hysteresis.
+		 */
+		cnt &= ~0x3;
 		if (cnt <= 0) {
 			unsigned long tmo;
 			// There is data waiting to be played
-			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
+			/*
+			 * Force the trigger setting since we would
+			 * deadlock with it set any other way
+			 */
+			dmabuf->trigger = PCM_ENABLE_OUTPUT;
 			i810_update_lvi(state,0);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
 				goto ret;
 			}
 			/* Not strictly correct but works */
-			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 4);
+			tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
 			/* There are two situations when sleep_on_timeout returns, one is when
 			   the interrupt is serviced correctly and the process is waked up by
 			   ISR ON TIME. Another is when timeout is expired, which means that
@@ -1442,7 +1557,7 @@
 			   is TOO LATE for the process to be scheduled to run (scheduler latency)
 			   which results in a (potential) buffer underrun. And worse, there is
 			   NOTHING we can do to prevent it. */
-			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
+			if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
 #ifdef DEBUG
 				printk(KERN_ERR "i810_audio: playback schedule timeout, "
 				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
@@ -1484,10 +1599,8 @@
 		x = dmabuf->fragsize - (swptr % dmabuf->fragsize);
 		memset(dmabuf->rawbuf + swptr, '\0', x);
 	}
+ret:
 	i810_update_lvi(state,0);
-	if (!dmabuf->enable && dmabuf->count >= dmabuf->userfragsize)
-		start_dac(state);
- ret:
         set_current_state(TASK_RUNNING);
         remove_wait_queue(&dmabuf->wait, &waita);
 
@@ -1506,22 +1619,19 @@
 		return 0;
 	poll_wait(file, &dmabuf->wait, wait);
 	spin_lock_irqsave(&state->card->lock, flags);
-	i810_update_ptr(state);
-	if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) {
-		if (dmabuf->count >= (signed)dmabuf->fragsize)
+	if (dmabuf->enable & ADC_RUNNING ||
+	    dmabuf->trigger & PCM_ENABLE_INPUT) {
+		if (i810_get_available_read_data(state) >= 
+		    (signed)dmabuf->userfragsize)
 			mask |= POLLIN | POLLRDNORM;
 	}
-	if (file->f_mode & FMODE_WRITE && dmabuf->enable & DAC_RUNNING) {
-		if (dmabuf->mapped) {
-			if (dmabuf->count >= (signed)dmabuf->fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		}
+	if (dmabuf->enable & DAC_RUNNING ||
+	    dmabuf->trigger & PCM_ENABLE_OUTPUT) {
+		if (i810_get_free_write_space(state) >=
+		    (signed)dmabuf->userfragsize)
+			mask |= POLLOUT | POLLWRNORM;
 	}
 	spin_unlock_irqrestore(&state->card->lock, flags);
-
 	return mask;
 }
 
@@ -1563,12 +1673,9 @@
 			     size, vma->vm_page_prot))
 		goto out;
 	dmabuf->mapped = 1;
-	if(vma->vm_flags & VM_WRITE)
-		dmabuf->count = dmabuf->dmasize;
-	else
-		dmabuf->count = 0;
+	dmabuf->trigger = 0;
 	ret = 0;
-#ifdef DEBUG
+#ifdef DEBUG_MMAP
 	printk("i810_audio: mmap'ed %ld bytes of data space\n", size);
 #endif
 out:
@@ -1579,16 +1686,15 @@
 static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct i810_state *state = (struct i810_state *)file->private_data;
+	struct i810_channel *c = NULL;
 	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned long flags;
 	audio_buf_info abinfo;
 	count_info cinfo;
 	unsigned int i_glob_cnt;
-	int val = 0, mapped, ret;
+	int val = 0, ret;
 	struct ac97_codec *codec = state->card->ac97_codec[0];
 
-	mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||
-		((file->f_mode & FMODE_READ) && dmabuf->mapped);
 #ifdef DEBUG
 	printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *(int *)arg : 0);
 #endif
@@ -1605,13 +1711,23 @@
 #ifdef DEBUG
 		printk("SNDCTL_DSP_RESET\n");
 #endif
-		/* FIXME: spin_lock ? */
+		spin_lock_irqsave(&state->card->lock, flags);
 		if (dmabuf->enable == DAC_RUNNING) {
-			stop_dac(state);
+			c = dmabuf->write_channel;
+			__stop_dac(state);
 		}
 		if (dmabuf->enable == ADC_RUNNING) {
-			stop_adc(state);
+			c = dmabuf->read_channel;
+			__stop_adc(state);
+		}
+		if (c != NULL) {
+			outb(2, state->card->iobase+c->port+OFF_CR);   /* reset DMA machine */
+			outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
+			outb(0, state->card->iobase+c->port+OFF_CIV);
+			outb(0, state->card->iobase+c->port+OFF_LVI);
 		}
+
+		spin_unlock_irqrestore(&state->card->lock, flags);
 		synchronize_irq();
 		dmabuf->ready = 0;
 		dmabuf->swptr = dmabuf->hwptr = 0;
@@ -1624,10 +1740,9 @@
 #endif
 		if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK)
 			return 0;
-		drain_dac(state, 0);
-		dmabuf->ready = 0;
-		dmabuf->swptr = dmabuf->hwptr = 0;
-		dmabuf->count = dmabuf->total_bytes = 0;
+		if((val = drain_dac(state, 1)))
+			return val;
+		dmabuf->total_bytes = 0;
 		return 0;
 
 	case SNDCTL_DSP_SPEED: /* set smaple rate */
@@ -1678,9 +1793,6 @@
 #ifdef DEBUG
 		printk("SNDCTL_DSP_STEREO\n");
 #endif
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-
 		if (dmabuf->enable & DAC_RUNNING) {
 			stop_dac(state);
 		}
@@ -1713,18 +1825,7 @@
 #ifdef DEBUG
 		printk("SNDCTL_DSP_SETFMT\n");
 #endif
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-
-		switch ( val ) {
-			case AFMT_S16_LE:
-				break;
-			case AFMT_QUERY:
-			default:
-				val = AFMT_S16_LE;
-				break;
-		}
-		return put_user(val, (int *)arg);
+		return put_user(AFMT_S16_LE, (int *)arg);
 
 	case SNDCTL_DSP_CHANNELS:
 #ifdef DEBUG
@@ -1824,22 +1925,47 @@
 
 		dmabuf->ossfragsize = 1<<(val & 0xffff);
 		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
-		if (dmabuf->ossmaxfrags <= 4)
-			dmabuf->ossmaxfrags = 4;
-		else if (dmabuf->ossmaxfrags <= 8)
-			dmabuf->ossmaxfrags = 8;
-		else if (dmabuf->ossmaxfrags <= 16)
-			dmabuf->ossmaxfrags = 16;
-		else
-			dmabuf->ossmaxfrags = 32;
+		if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
+			return -EINVAL;
+		/*
+		 * Bound the frag size into our allowed range of 256 - 4096
+		 */
+		if (dmabuf->ossfragsize < 256)
+			dmabuf->ossfragsize = 256;
+		else if (dmabuf->ossfragsize > 4096)
+			dmabuf->ossfragsize = 4096;
+		/*
+		 * The numfrags could be something reasonable, or it could
+		 * be 0xffff meaning "Give me as much as possible".  So,
+		 * we check the numfrags * fragsize doesn't exceed our
+		 * 64k buffer limit, nor is it less than our 8k minimum.
+		 * If it fails either one of these checks, then adjust the
+		 * number of fragments, not the size of them.  It's OK if
+		 * our number of fragments doesn't equal 32 or anything
+		 * like our hardware based number now since we are using
+		 * a different frag count for the hardware.  Before we get
+		 * into this though, bound the maxfrags to avoid overflow
+		 * issues.  A reasonable bound would be 64k / 256 since our
+		 * maximum buffer size is 64k and our minimum frag size is
+		 * 256.  On the other end, our minimum buffer size is 8k and
+		 * our maximum frag size is 4k, so the lower bound should
+		 * be 2.
+		 */
+
+		if(dmabuf->ossmaxfrags > 256)
+			dmabuf->ossmaxfrags = 256;
+		else if (dmabuf->ossmaxfrags < 2)
+			dmabuf->ossmaxfrags = 2;
+
 		val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
-		if (val < 16384)
-			val = 16384;
-		if (val > 65536)
-			val = 65536;
-		dmabuf->ossmaxfrags = val/dmabuf->ossfragsize;
-		if(dmabuf->ossmaxfrags<4)
-			dmabuf->ossfragsize = val/4;
+		while (val < 8192) {
+		    val <<= 1;
+		    dmabuf->ossmaxfrags <<= 1;
+		}
+		while (val > 65536) {
+		    val >>= 1;
+		    dmabuf->ossmaxfrags >>= 1;
+		}
 		dmabuf->ready = 0;
 #ifdef DEBUG
 		printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
@@ -1857,13 +1983,13 @@
 		i810_update_ptr(state);
 		abinfo.fragsize = dmabuf->userfragsize;
 		abinfo.fragstotal = dmabuf->userfrags;
-		if(dmabuf->mapped)
-			abinfo.bytes = dmabuf->count;
-		else
-			abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+		if (dmabuf->mapped)
+ 			abinfo.bytes = dmabuf->dmasize;
+  		else
+ 			abinfo.bytes = i810_get_free_write_space(state);
 		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
 		spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes,
 			abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
 #endif
@@ -1875,17 +2001,17 @@
 		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
 			return val;
 		spin_lock_irqsave(&state->card->lock, flags);
-		i810_update_ptr(state);
+		val = i810_get_free_write_space(state);
 		cinfo.bytes = dmabuf->total_bytes;
 		cinfo.ptr = dmabuf->hwptr;
-		cinfo.blocks = (dmabuf->dmasize - dmabuf->count)/dmabuf->userfragsize;
-		if (dmabuf->mapped) {
-			dmabuf->count = (dmabuf->dmasize - 
-					 (dmabuf->count & (dmabuf->userfragsize-1)));
+		cinfo.blocks = val/dmabuf->userfragsize;
+		if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
+			dmabuf->count += val;
+			dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
 			__i810_update_lvi(state, 0);
 		}
 		spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
 			cinfo.blocks, cinfo.ptr, dmabuf->count);
 #endif
@@ -1897,13 +2023,12 @@
 		if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
 			return val;
 		spin_lock_irqsave(&state->card->lock, flags);
-		i810_update_ptr(state);
+		abinfo.bytes = i810_get_available_read_data(state);
 		abinfo.fragsize = dmabuf->userfragsize;
 		abinfo.fragstotal = dmabuf->userfrags;
-		abinfo.bytes = dmabuf->dmasize - dmabuf->count;
 		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
 		spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes,
 			abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
 #endif
@@ -1915,16 +2040,17 @@
 		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
 			return val;
 		spin_lock_irqsave(&state->card->lock, flags);
-		i810_update_ptr(state);
+		val = i810_get_available_read_data(state);
 		cinfo.bytes = dmabuf->total_bytes;
-		cinfo.blocks = dmabuf->count/dmabuf->userfragsize;
+		cinfo.blocks = val/dmabuf->userfragsize;
 		cinfo.ptr = dmabuf->hwptr;
-		if (dmabuf->mapped) {
-			dmabuf->count &= (dmabuf->userfragsize-1);
+		if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
+			dmabuf->count -= val;
+			dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
 			__i810_update_lvi(state, 1);
 		}
 		spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
 			cinfo.blocks, cinfo.ptr, dmabuf->count);
 #endif
@@ -1954,7 +2080,7 @@
 	case SNDCTL_DSP_SETTRIGGER:
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
-#ifdef DEBUG
+#if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
 #endif
 		if( !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
@@ -1964,7 +2090,7 @@
 			stop_dac(state);
 		}
 		dmabuf->trigger = val;
-		if(val & PCM_ENABLE_OUTPUT) {
+		if(val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) {
 			if (!dmabuf->write_channel) {
 				dmabuf->ready = 0;
 				dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
@@ -1974,13 +2100,18 @@
 			if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
 				return ret;
 			if (dmabuf->mapped) {
-				dmabuf->count = dmabuf->dmasize;
-				i810_update_lvi(state,0);
-			}
-			if (!dmabuf->enable && dmabuf->count > dmabuf->userfragsize)
+				spin_lock_irqsave(&state->card->lock, flags);
+				i810_update_ptr(state);
+				dmabuf->count = 0;
+				dmabuf->swptr = dmabuf->hwptr;
+				dmabuf->count = i810_get_free_write_space(state);
+				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
+				__i810_update_lvi(state, 0);
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			} else
 				start_dac(state);
 		}
-		if(val & PCM_ENABLE_INPUT) {
+		if(val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) {
 			if (!dmabuf->read_channel) {
 				dmabuf->ready = 0;
 				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
@@ -1990,12 +2121,14 @@
 			if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
 				return ret;
 			if (dmabuf->mapped) {
+				spin_lock_irqsave(&state->card->lock, flags);
+				i810_update_ptr(state);
+				dmabuf->swptr = dmabuf->hwptr;
 				dmabuf->count = 0;
-				i810_update_lvi(state,1);
+				spin_unlock_irqrestore(&state->card->lock, flags);
 			}
-			if (!dmabuf->enable && dmabuf->count <
-			    (dmabuf->dmasize - dmabuf->userfragsize))
-				start_adc(state);
+			i810_update_lvi(state, 1);
+			start_adc(state);
 		}
 		return 0;
 
@@ -2199,7 +2332,19 @@
 
 	/* find an avaiable virtual channel (instance of /dev/dsp) */
 	while (card != NULL) {
-		for (i = 0; i < NR_HW_CH; i++) {
+		/*
+		 * If we are initializing and then fail, card could go
+		 * away unuexpectedly while we are in the for() loop.
+		 * So, check for card on each iteration before we check
+		 * for card->initializing to avoid a possible oops.
+		 * This usually only matters for times when the driver is
+		 * autoloaded by kmod.
+		 */
+		for (i = 0; i < 50 && card && card->initializing; i++) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ/20);
+		}
+		for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) {
 			if (card->states[i] == NULL) {
 				state = card->states[i] = (struct i810_state *)
 					kmalloc(sizeof(struct i810_state), GFP_KERNEL);
@@ -2233,8 +2378,8 @@
 			card->states[i] = NULL;;
 			return -EBUSY;
 		}
-		i810_set_adc_rate(state, 8000);
 		dmabuf->trigger |= PCM_ENABLE_INPUT;
+		i810_set_adc_rate(state, 8000);
 	}
 	if(file->f_mode & FMODE_WRITE) {
 		if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
@@ -2245,13 +2390,13 @@
 		/* Initialize to 8kHz?  What if we don't support 8kHz? */
 		/*  Let's change this to check for S/PDIF stuff */
 	
+		dmabuf->trigger |= PCM_ENABLE_OUTPUT;
 		if ( spdif_locked ) {
 			i810_set_dac_rate(state, spdif_locked);
 			i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked);
 		} else {
 			i810_set_dac_rate(state, 8000);
 		}
-		dmabuf->trigger |= PCM_ENABLE_OUTPUT;
 	}
 		
 	/* set default sample format. According to OSS Programmer's Guide  /dev/dsp
@@ -2278,11 +2423,10 @@
 	lock_kernel();
 
 	/* stop DMA state machine and free DMA buffers/channels */
-	if(dmabuf->enable & DAC_RUNNING ||
-	   (dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
-		drain_dac(state,0);
+	if(dmabuf->trigger & PCM_ENABLE_OUTPUT) {
+		drain_dac(state, 0);
 	}
-	if(dmabuf->enable & ADC_RUNNING) {
+	if(dmabuf->trigger & PCM_ENABLE_INPUT) {
 		stop_adc(state);
 	}
 	spin_lock_irqsave(&card->lock, flags);
@@ -2348,13 +2492,26 @@
 	unsigned int minor = minor(inode->i_rdev);
 	struct i810_card *card = devs;
 
-	for (card = devs; card != NULL; card = card->next)
-		for (i = 0; i < NR_AC97; i++)
+	for (card = devs; card != NULL; card = card->next) {
+		/*
+		 * If we are initializing and then fail, card could go
+		 * away unuexpectedly while we are in the for() loop.
+		 * So, check for card on each iteration before we check
+		 * for card->initializing to avoid a possible oops.
+		 * This usually only matters for times when the driver is
+		 * autoloaded by kmod.
+		 */
+		for (i = 0; i < 50 && card && card->initializing; i++) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ/20);
+		}
+		for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
 			if (card->ac97_codec[i] != NULL &&
 			    card->ac97_codec[i]->dev_mixer == minor) {
 				file->private_data = card->ac97_codec[i];
 				return 0;
 			}
+	}
 	return -ENODEV;
 }
 
@@ -2700,6 +2857,7 @@
 	}
 	memset(card, 0, sizeof(*card));
 
+	card->initializing = 1;
 	card->iobase = pci_resource_start (pci_dev, 1);
 	card->ac97base = pci_resource_start (pci_dev, 0);
 	card->pci_dev = pci_dev;
@@ -2756,7 +2914,8 @@
 	}
 	pci_set_drvdata(pci_dev, card);
 
-	if(clocking == 48000) {
+	if(clocking == 0) {
+		clocking = 48000;
 		i810_configure_clocking();
 	}
 
@@ -2775,7 +2934,7 @@
 		kfree(card);
 		return -ENODEV;
 	}
-
+ 	card->initializing = 0;
 	return 0;
 }
 
@@ -2793,6 +2952,7 @@
 		if (card->ac97_codec[i] != NULL) {
 			unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
 			kfree (card->ac97_codec[i]);
+			card->ac97_codec[i] = NULL;
 		}
 	unregister_sound_dsp(card->dev_audio);
 	kfree(card);
@@ -2961,14 +3121,11 @@
 	if(ftsodell != 0) {
 		printk("i810_audio: ftsodell is now a deprecated option.\n");
 	}
-	if(clocking == 48000) {
-		i810_configure_clocking();
-	}
 	if(spdif_locked > 0 ) {
 		if(spdif_locked == 32000 || spdif_locked == 44100 || spdif_locked == 48000) {
 			printk("i810_audio: Enabling S/PDIF at sample rate %dHz.\n", spdif_locked);
 		} else {
-			printk("i810_audio: S/PDIF can only be locked to 32000, 441000, or 48000Hz.\n");
+			printk("i810_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
 			spdif_locked = 0;
 		}
 	}
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/ite8172.c linux/drivers/sound/ite8172.c
--- v2.5.2/linux/drivers/sound/ite8172.c	Thu Oct 25 13:53:52 2001
+++ linux/drivers/sound/ite8172.c	Tue Jan 15 10:56:35 2002
@@ -1106,7 +1106,7 @@
 	unlock_kernel();
 	return -EINVAL;
     }
-    if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf),
+    if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf),
 			 size, vma->vm_page_prot)) {
 	unlock_kernel();
 	return -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c
--- v2.5.2/linux/drivers/sound/maestro.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/maestro.c	Tue Jan 15 10:56:35 2002
@@ -2510,7 +2510,7 @@
 	if (size > (PAGE_SIZE << db->buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
 		goto out;
 	db->mapped = 1;
 	ret = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/maestro3.c linux/drivers/sound/maestro3.c
--- v2.5.2/linux/drivers/sound/maestro3.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/maestro3.c	Tue Jan 15 10:56:35 2002
@@ -1555,7 +1555,7 @@
      * ask Jeff what the hell I'm doing wrong.
      */
     ret = -EAGAIN;
-    if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+    if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
         goto out;
 
     db->mapped = 1;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/rme96xx.c linux/drivers/sound/rme96xx.c
--- v2.5.2/linux/drivers/sound/rme96xx.c	Thu Oct 25 13:53:52 2001
+++ linux/drivers/sound/rme96xx.c	Tue Jan 15 10:56:35 2002
@@ -1411,14 +1411,14 @@
 	if (vma->vm_flags & VM_WRITE) {
 		if (!s->started) rme96xx_startcard(s,1);
 
-		if (remap_page_range(vma->vm_start, virt_to_phys(s->playbuf + dma->outoffset*RME96xx_DMA_MAX_SIZE), size, vma->vm_page_prot)) {
+		if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->outoffset*RME96xx_DMA_MAX_SIZE), size, vma->vm_page_prot)) {
 			unlock_kernel();
 			return -EAGAIN;
 		}
 	} 
 	else if (vma->vm_flags & VM_READ) {
 		if (!s->started) rme96xx_startcard(s,1);
-		if (remap_page_range(vma->vm_start, virt_to_phys(s->playbuf + dma->inoffset*RME96xx_DMA_MAX_SIZE), size, vma->vm_page_prot)) {
+		if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->inoffset*RME96xx_DMA_MAX_SIZE), size, vma->vm_page_prot)) {
 			unlock_kernel();
 			return -EAGAIN;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.5.2/linux/drivers/sound/sonicvibes.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/sonicvibes.c	Tue Jan 15 10:56:35 2002
@@ -1549,7 +1549,7 @@
 	if (size > (PAGE_SIZE << db->buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
 		goto out;
 	db->mapped = 1;
 	ret = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.5.2/linux/drivers/sound/soundcard.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/soundcard.c	Tue Jan 15 10:56:35 2002
@@ -473,7 +473,7 @@
 	if (size != dmap->bytes_in_use) {
 		printk(KERN_WARNING "Sound: mmap() size = %ld. Should be %d\n", size, dmap->bytes_in_use);
 	}
-	if (remap_page_range(vma->vm_start, virt_to_phys(dmap->raw_buf),
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmap->raw_buf),
 		vma->vm_end - vma->vm_start,
 		vma->vm_page_prot)) {
 		unlock_kernel();
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
--- v2.5.2/linux/drivers/sound/trident.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/trident.c	Tue Jan 15 10:56:35 2002
@@ -2074,7 +2074,7 @@
 	if (size > (PAGE_SIZE << dmabuf->buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf),
 			     size, vma->vm_page_prot))
 		goto out;
 	dmabuf->mapped = 1;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- v2.5.2/linux/drivers/sound/via82cxxx_audio.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/sound/via82cxxx_audio.c	Thu Jan 24 11:51:11 2002
@@ -1358,7 +1358,7 @@
 
 static int via_mixer_open (struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct via_info *card;
 	struct pci_dev *pdev;
 	struct pci_driver *drvr;
@@ -1995,7 +1995,7 @@
 	/* just to be a nice neighbor */
 	/* Thomas Sailer:
 	 * But also to ourselves, release semaphore if we do so */
-	if (current->need_resched) {
+	if (need_resched()) {
 		up(&card->syscall_sem);
 		schedule ();
 		ret = via_syscall_down (card, nonblock);
@@ -2171,7 +2171,7 @@
 	/* just to be a nice neighbor */
 	/* Thomas Sailer:
 	 * But also to ourselves, release semaphore if we do so */
-	if (current->need_resched) {
+	if (need_resched()) {
 		up(&card->syscall_sem);
 		schedule ();
 		ret = via_syscall_down (card, nonblock);
@@ -2974,7 +2974,7 @@
 
 static int via_dsp_open (struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct via_info *card;
 	struct pci_dev *pdev;
 	struct via_channel *chan;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- v2.5.2/linux/drivers/sound/ymfpci.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/ymfpci.c	Wed Jan 23 15:48:21 2002
@@ -832,7 +832,14 @@
 	u32 lpfK = ymfpci_calc_lpfK(rate);
 	ymfpci_playback_bank_t *bank;
 	int nbank;
-	unsigned le_0x40000000 = cpu_to_le32(0x40000000);
+
+	/*
+	 * The gain is a floating point number. According to the manual,
+	 * bit 31 indicates a sign bit, bit 30 indicates an integer part,
+	 * and bits [29:15] indicate a decimal fraction part. Thus,
+	 * for a gain of 1.0 the constant of 0x40000000 is loaded.
+	 */
+	unsigned default_gain = cpu_to_le32(0x40000000);
 
 	format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
 	if (stereo)
@@ -847,7 +854,7 @@
 		bank->loop_start = 0;
 		bank->loop_end = cpu_to_le32(end);
 		bank->loop_frac = 0;
-		bank->eg_gain_end = le_0x40000000;
+		bank->eg_gain_end = default_gain;
 		bank->lpfQ = cpu_to_le32(lpfQ);
 		bank->status = 0;
 		bank->num_of_frames = 0;
@@ -858,7 +865,7 @@
 		bank->delta_end = cpu_to_le32(delta);
 		bank->lpfK =
 		bank->lpfK_end = cpu_to_le32(lpfK);
-		bank->eg_gain = le_0x40000000;
+		bank->eg_gain = default_gain;
 		bank->lpfD1 =
 		bank->lpfD2 = 0;
 
@@ -878,31 +885,31 @@
 				bank->left_gain = 
 				bank->right_gain =
 				bank->left_gain_end =
-				bank->right_gain_end = le_0x40000000;
+				bank->right_gain_end = default_gain;
 			} else {
 				bank->eff2_gain =
 				bank->eff2_gain_end =
 				bank->eff3_gain =
-				bank->eff3_gain_end = le_0x40000000;
+				bank->eff3_gain_end = default_gain;
 			}
 		} else {
 			if (!spdif) {
 				if ((voice->number & 1) == 0) {
 					bank->left_gain =
-					bank->left_gain_end = le_0x40000000;
+					bank->left_gain_end = default_gain;
 				} else {
 					bank->format |= cpu_to_le32(1);
 					bank->right_gain =
-					bank->right_gain_end = le_0x40000000;
+					bank->right_gain_end = default_gain;
 				}
 			} else {
 				if ((voice->number & 1) == 0) {
 					bank->eff2_gain =
-					bank->eff2_gain_end = le_0x40000000;
+					bank->eff2_gain_end = default_gain;
 				} else {
 					bank->format |= cpu_to_le32(1);
 					bank->eff3_gain =
-					bank->eff3_gain_end = le_0x40000000;
+					bank->eff3_gain_end = default_gain;
 				}
 			}
 		}
@@ -1525,7 +1532,7 @@
 	size = vma->vm_end - vma->vm_start;
 	if (size > (PAGE_SIZE << dmabuf->buforder))
 		return -EINVAL;
-	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf),
 			     size, vma->vm_page_prot))
 		return -EAGAIN;
 	dmabuf->mapped = 1;
diff -u --recursive --new-file v2.5.2/linux/drivers/tc/tc.c linux/drivers/tc/tc.c
--- v2.5.2/linux/drivers/tc/tc.c	Thu Oct 11 09:43:30 2001
+++ linux/drivers/tc/tc.c	Wed Jan 23 10:54:42 2002
@@ -236,6 +236,8 @@
 	}
 }
 
+subsys_initcall(tc_init);
+
 EXPORT_SYMBOL(search_tc_card);
 EXPORT_SYMBOL(claim_tc_card);
 EXPORT_SYMBOL(release_tc_card);
diff -u --recursive --new-file v2.5.2/linux/drivers/telephony/Config.help linux/drivers/telephony/Config.help
--- v2.5.2/linux/drivers/telephony/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/telephony/Config.help	Fri Jan 25 16:03:35 2002
@@ -0,0 +1,28 @@
+CONFIG_PHONE
+  Say Y here if you have a telephony card, which for example allows
+  you to use a regular phone for voice-over-IP applications.
+
+  Note: this has nothing to do with modems.  You do not need to say Y
+  here in order to be able to use a modem under Linux.
+
+  This support is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  phonedev.o.
+
+CONFIG_PHONE_IXJ
+  Say M if you have a telephony card manufactured by Quicknet
+  Technologies, Inc.  These include the Internet PhoneJACK and
+  Internet LineJACK Telephony Cards. You will get a module called
+  ixj.o.
+
+  For the ISA versions of these products, you can configure the
+  cards using the isapnp tools (pnpdump/isapnp) or you can use the
+  isapnp support.  Please read <file:Documentation/telephony/ixj.txt>.
+
+  For more information on these cards, see Quicknet's web site at:
+  <http://www.quicknet.net/>.
+
+  If you do not have any Quicknet telephony cards, you can safely
+  say N here.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/CDCEther.c linux/drivers/usb/CDCEther.c
--- v2.5.2/linux/drivers/usb/CDCEther.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/CDCEther.c	Wed Jan 23 15:33:46 2002
@@ -125,14 +125,14 @@
 
 goon:
 	// Prep the USB to wait for another frame
-	FILL_BULK_URB( &ether_dev->rx_urb, ether_dev->usb,
+	FILL_BULK_URB( ether_dev->rx_urb, ether_dev->usb,
 			usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),
 			ether_dev->rx_buff, ether_dev->wMaxSegmentSize, 
 			read_bulk_callback, ether_dev );
 			
 	// Give this to the USB subsystem so it can tell us 
 	// when more data arrives.
-	if ( (res = usb_submit_urb(&ether_dev->rx_urb)) ) {
+	if ( (res = usb_submit_urb(ether_dev->rx_urb)) ) {
 		warn( __FUNCTION__ " failed submint rx_urb %d", res);
 	}
 	
@@ -259,8 +259,8 @@
 	warn("%s: Tx timed out.", net->name);
 	
 	// Tear the waiting frame off the list
-	ether_dev->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
-	usb_unlink_urb( &ether_dev->tx_urb );
+	ether_dev->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+	usb_unlink_urb( ether_dev->tx_urb );
 	
 	// Update statistics
 	ether_dev->stats.tx_errors++;
@@ -293,16 +293,16 @@
 	memcpy(ether_dev->tx_buff, skb->data, skb->len);
 
 	// Fill in the URB for shipping it out.
-	FILL_BULK_URB( &ether_dev->tx_urb, ether_dev->usb,
+	FILL_BULK_URB( ether_dev->tx_urb, ether_dev->usb,
 			usb_sndbulkpipe(ether_dev->usb, ether_dev->data_ep_out),
 			ether_dev->tx_buff, ether_dev->wMaxSegmentSize, 
 			write_bulk_callback, ether_dev );
 
 	// Tell the URB how much it will be transporting today
-	ether_dev->tx_urb.transfer_buffer_length = count;
+	ether_dev->tx_urb->transfer_buffer_length = count;
 	
 	// Send the URB on its merry way.
-	if ((res = usb_submit_urb(&ether_dev->tx_urb)))  {
+	if ((res = usb_submit_urb(ether_dev->tx_urb)))  {
 		// Hmm...  It didn't go. Tell someone...
 		warn("failed tx_urb %d", res);
 		// update some stats...
@@ -344,13 +344,13 @@
 	}
 
 	// Prep a receive URB
-	FILL_BULK_URB( &ether_dev->rx_urb, ether_dev->usb,
+	FILL_BULK_URB( ether_dev->rx_urb, ether_dev->usb,
 			usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),
 			ether_dev->rx_buff, ether_dev->wMaxSegmentSize, 
 			read_bulk_callback, ether_dev );
 
 	// Put it out there so the device can send us stuff
-	if ( (res = usb_submit_urb(&ether_dev->rx_urb)) )
+	if ( (res = usb_submit_urb(ether_dev->rx_urb)) )
 	{
 		// Hmm...  Okay...
 		warn( __FUNCTION__ " failed rx_urb %d", res );
@@ -383,9 +383,9 @@
 	}
 
 	// We don't need the URBs anymore.
-	usb_unlink_urb( &ether_dev->rx_urb );
-	usb_unlink_urb( &ether_dev->tx_urb );
-	usb_unlink_urb( &ether_dev->intr_urb );
+	usb_unlink_urb( ether_dev->rx_urb );
+	usb_unlink_urb( ether_dev->tx_urb );
+	usb_unlink_urb( ether_dev->intr_urb );
 	
 	// That's it.  I'm done.
 	return 0;
@@ -1144,6 +1144,25 @@
 	// Zero everything out.
 	memset(ether_dev, 0, sizeof(ether_dev_t));
 
+	ether_dev->rx_urb = usb_alloc_urb(0);
+	if (!ether_dev->rx_urb) {
+		kfree(ether_dev);
+		return NULL;
+	}
+	ether_dev->tx_urb = usb_alloc_urb(0);
+	if (!ether_dev->tx_urb) {
+		usb_free_urb(ether_dev->rx_urb);
+		kfree(ether_dev);
+		return NULL;
+	}
+	ether_dev->intr_urb = usb_alloc_urb(0);
+	if (!ether_dev->intr_urb) {
+		usb_free_urb(ether_dev->tx_urb);
+		usb_free_urb(ether_dev->rx_urb);
+		kfree(ether_dev);
+		return NULL;
+	}
+
 	// Let's see if we can find a configuration we can use.
 	rc = find_valid_configuration( usb, ether_dev );
 	if (rc)	{
@@ -1290,6 +1309,9 @@
 	                              &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]) );
 
 	// No more tied up kernel memory
+	usb_free_urb(ether_dev->intr_urb);
+	usb_free_urb(ether_dev->rx_urb);
+	usb_free_urb(ether_dev->rx_urb);
 	kfree( ether_dev );
 	
 	// This does no good, but it looks nice!
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/CDCEther.h linux/drivers/usb/CDCEther.h
--- v2.5.2/linux/drivers/usb/CDCEther.h	Sun Sep 23 09:49:00 2001
+++ linux/drivers/usb/CDCEther.h	Wed Jan 23 15:33:46 2002
@@ -83,7 +83,7 @@
 	__u16			wNumberMCFilters;
 	__u8			bNumberPowerFilters;
 	int			intr_interval;
-	struct urb		rx_urb, tx_urb, intr_urb;
+	struct urb		*rx_urb, *tx_urb, *intr_urb;
 	unsigned char		ALIGN(rx_buff[CDC_ETHER_MAX_MTU]);
 	unsigned char		ALIGN(tx_buff[CDC_ETHER_MAX_MTU]);
 	unsigned char		ALIGN(intr_buff[8]);
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/Config.help linux/drivers/usb/Config.help
--- v2.5.2/linux/drivers/usb/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/Config.help	Fri Jan 25 16:03:54 2002
@@ -0,0 +1,600 @@
+CONFIG_USB
+  Universal Serial Bus (USB) is a specification for a serial bus
+  subsystem which offers higher speeds and more features than the
+  traditional PC serial port.  The bus supplies power to peripherals
+  and allows for hot swapping.  Up to 127 USB peripherals can be
+  connected to a single USB port in a tree structure.  The USB port is
+  the root of the tree, the peripherals are the leaves and the inner
+  nodes are special USB devices called hubs.  Many newer PC's have USB
+  ports and newer peripherals such as scanners, keyboards, mice,
+  modems, and printers support the USB protocol and can be connected
+  to the PC via those ports.
+
+  Say Y here if your computer has a USB port and you want to use USB
+  devices.  You then need to say Y to at least one of "UHCI support"
+  or "OHCI support" below (the type of interface that the USB hardware
+  in your computer provides to the operating system) and then choose
+  from among the drivers for USB peripherals.  You may want to check
+  out the information provided in <file:Documentation/usb/> and
+  especially the links given in <file:Documentation/usb/usb-help.txt>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usbcore.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_DEBUG
+  Say Y here if you want the USB core & hub drivers to produce a bunch
+  of debug messages to the system log. Select this if you are having a
+  problem with USB support and want to see more of what is going on.
+
+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
+  patient.  There should be no harm in selecting this, but it is
+  needed for some MGE Ellipse UPSes.
+
+  If you have an MGE Ellipse UPS, or you see timeouts in HID
+  transactions, say Y; otherwise say N.
+
+CONFIG_USB_UHCI
+  The Universal Host Controller Interface is a standard by Intel for
+  accessing the USB hardware in the PC (which is also called the USB
+  host controller). If your USB host controller conforms to this
+  standard, you may want to say Y, but see below. All recent boards
+  with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
+  i810, i820) conform to this standard. Also all VIA PCI chipsets
+  (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
+  133).
+
+  Currently there exist two drivers for UHCI host controllers: this
+  one and the so-called JE driver, which you can get from
+  "UHCI alternate (JE) support", below. You need only one.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usb-uhci.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_UHCI_ALT
+  The Universal Host Controller Interface is a standard by Intel for
+  accessing the USB hardware in the PC (which is also called the USB
+  host controller). If your USB host controller conforms to this
+  standard, you may want to say Y, but see below. All recent boards
+  with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
+  i810, i820) conform to this standard. Also all VIA PCI chipsets
+  (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
+  133). If unsure, say Y.
+
+  Currently there exist two drivers for UHCI host controllers: this
+  so-called JE driver, and the one you get from "UHCI support", above.
+  You need only one.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called uhci.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_OHCI
+  The Open Host Controller Interface is a standard by
+  Compaq/Microsoft/National for accessing the USB PC hardware (also
+  called USB host controller). If your USB host controller conforms to
+  this standard, say Y. The USB host controllers on most non-Intel
+  architectures and on several x86 compatibles with non-Intel chipsets
+  -- like SiS (aktual 610, 610 and so on) or ALi (ALi IV, ALi V,
+  Aladdin Pro..) -- conform to this standard.
+
+  You may want to read <file:Documentation/usb/ohci.txt>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usb-ohci.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_HID
+  Say Y here if you want full HID support to connect keyboards,
+  mice, joysticks, graphic tablets, or any other HID based devices
+  to your computer via USB. You can't use this driver and the
+  HIDBP (Boot Protocol) keyboard and mouse drivers at the same time.
+  More information is available: <file:Documentation/input/input.txt>.
+
+  If unsure, say Y.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called hid.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_HIDDEV
+  Say Y here if you want to support HID devices (from the USB
+  specification standpoint) that aren't strictly user interface
+  devices, like monitor controls and Uninterruptable Power Supplies.
+
+  This module supports these devices separately using a separate
+  event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
+  This driver requires CONFIG_USB_HID.
+
+  If unsure, say N.
+
+CONFIG_USB_KBD
+  Say Y here if you don't want to use the generic HID driver for your
+  USB keyboard and prefer to use the keyboard in its limited Boot
+  Protocol mode instead. This driver is much smaller than the HID one.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usbkbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+  If unsure, say N.
+
+CONFIG_USB_MOUSE
+  Say Y here if you don't want to use the generic HID driver for your
+  USB mouse and prefer to use the mouse in its limited Boot Protocol
+  mode instead. This driver is much smaller than the HID one.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usbmouse.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+  If unsure, say N.
+
+CONFIG_USB_WACOM
+  Say Y here if you want to use the USB version of the Wacom Intuos
+  or Graphire tablet.  Make sure to say Y to "Mouse support"
+  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+  (CONFIG_INPUT_EVDEV) as well.
+
+  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 wacom.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SCANNER
+  Say Y here if you want to connect a USB scanner to your computer's
+  USB port. Please read <file:Documentation/usb/scanner.txt> and
+  <file:Documentation/usb/scanner-hp-sane.txt> for more information.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called scanner.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_AUDIO
+  Say Y here if you want to connect USB audio equipment such as
+  speakers to your computer's USB port.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called audio.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_ACM
+  This driver supports USB modems and ISDN adapters which support the
+  Communication Device Class Abstract Control Model interface.
+  Please read <file:Documentation/usb/acm.txt> for details.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called acm.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_PRINTER
+  Say Y here if you want to connect a USB printer to your computer's
+  USB port.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called printer.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_IBMCAM
+  Say Y here if you want to connect a IBM "C-It" camera, also known as
+  "Xirlink PC Camera" to your computer's USB port.  For more
+  information, read <file:Documentation/usb/ibmcam.txt>.
+
+  This driver uses the Video For Linux API.  You must enable
+  (Y or M in config) Video For Linux (under Character Devices)
+  to use this driver.  Information on this API and pointers to
+  "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ibmcam.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>. This
+  camera has several configuration options which can be specified when
+  you load the module.  Read <file:Documentation/usb/ibmcam.txt> to
+  learn more.
+
+CONFIG_USB_OV511
+  Say Y here if you want to connect this type of camera to your
+  computer's USB port. See <file:Documentation/usb/ov511.txt> for more
+  information and for a list of supported cameras.
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Character Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ov511.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/>.
+
+  This driver should work with the following devices:
+        * Ericsson PipeRider (all variants)
+        * Motorola (DM100 and SB4100)
+        * Broadcom Cable Modem (reference design)
+        * Toshiba PCX1100U and possibly other cable modems
+
+  The device creates a network device (ethX, where X depends on what
+  other networking devices you have in use), as for a normal PCI
+  or ISA based ethernet network card.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called CDCEther.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_PWC
+  Say Y or M here if you want to use one of these Philips USB webcams:
+  PCA645, PCA646, PCVC675, PCVC680, PCVC690, PCVC730, PCVC740, or
+  the Askey VC010. The PCA635, PCVC665 and PCVC720 are not supported
+  by this driver and never will be.
+
+  This driver has an optional plugin, which is distributed as a binary
+  module only.  It contains code that allow you to use higher
+  resolutions and framerates but may not be distributed as source.
+  But even without this plugin you can these cams for most
+  applications.
+
+  See <file:Documentation/usb/philips.txt> for more information and
+  installation instructions.
+
+  The built-in microphone is enabled by selecting USB Audio support.
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Character Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pwc.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SE401
+  Say Y here if you want to connect this type of camera to your
+  computer's USB port. See <file:Documentation/usb/se401.txt> for more
+  information and for a list of supported cameras.
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Multimedia Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called se401.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_STV680
+  Say Y here if you want to connect this type of camera to your
+  computer's USB port. This includes the Pencam line of cameras.
+  See <file:Documentation/usb/stv680.txt> for more information and for
+  a list of supported cameras.
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Multimedia Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called stv680.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_VICAM
+  Say Y here if you have 3com homeconnect camera (vicam).
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Multimedia Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called vicam.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_PEGASUS
+  Say Y here if you know you have Pegasus or Pegasus II based adapter.
+  If in doubt then look at linux/drivers/usb/pegasus.h for the complete
+  list of supported devices.
+  If your particular adapter is not in the list and you are _sure_ it
+  is Pegasus or Pegasus II based then send me (pmanolov@lnxw.com) vendor
+  and device IDs.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pegasus.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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:
+       3Com 3C19250
+       ADS USB-10BT
+       ATEN USB Ethernet
+       ASANTE USB To Ethernet Adapter
+       AOX Endpoints USB Ethernet
+       Correga K.K.
+       D-Link DSB-650C and DU-E10
+       Entrega / Portgear E45
+       I-O DATA USB-ET/T
+       Jaton USB Ethernet Device Adapter
+       Kingston Technology USB Ethernet Adapter
+       Linksys USB10T
+       Mobility USB-Ethernet Adapter
+       NetGear EA-101
+       Peracom Enet and Enet2
+       Portsmith Express Ethernet Adapter
+       Shark Pocket Adapter
+       SMC 2202USB
+       Sony Vaio port extender
+
+  This driver is likely to work with most 10Mbps only USB Ethernet
+  adapters, including some "no brand" devices. It does NOT work on
+  SmartBridges smartNIC or on Belkin F5U111 devices - you should use
+  the CATC NetMate driver for those. If you are not sure which one
+  you need, select both, and the correct one should be selected for
+  you.
+
+  This driver makes the adapter appear as a normal Ethernet interface,
+  typically on eth0, if it is the only ethernet device, or perhaps on
+  eth1, if you have a PCI or ISA ethernet card installed.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called kaweth.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_CATC
+  Say Y if you want to use one of the following 10Mbps USB Ethernet
+  device based on the EL1210A chip. Supported devices are:
+    Belkin F5U111
+    CATC NetMate
+    CATC NetMate II
+    smartBridges smartNIC
+
+  This driver makes the adapter appear as a normal Ethernet interface,
+  typically on eth0, if it is the only ethernet device, or perhaps on
+  eth1, if you have a PCI or ISA ethernet card installed.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called catc.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_DC2XX
+  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/>).
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called dc2xx.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/>).
+  To use it create a device node with "mknod /dev/mustek c 180 32" and
+  configure it in your software.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called mdc800.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_STORAGE
+  Say Y here if you want to connect USB mass storage devices to your
+  computer's USB port.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usb-storage.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_STORAGE_DEBUG
+  Say Y here in order to have the USB Mass Storage code generate
+  verbose debugging messages.
+
+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.
+
+  Some of the products that use this chip are:
+
+    - Archos Jukebox 6000
+    - ISD SmartCable for Storage
+    - Taiwan Skymaster CD530U/DEL-0241 IDE bridge
+    - Sony CRX10U CD-R/RW drive
+    - CyQ've CQ8060A CDRW drive
+    - Planex eXtreme Drive RX-25HU USB-IDE cable (not model RX-25U)
+
+CONFIG_USB_USS720
+  This driver is for USB parallel port adapters that use the Lucent
+  Technologies USS-720 chip. These cables are plugged into your USB
+  port and provide USB compatibility to peripherals designed with
+  parallel port interfaces.
+
+  The chip has two modes: automatic mode and manual mode. In automatic
+  mode, it looks to the computer like a standard USB printer. Only
+  printers may be connected to the USS-720 in this mode. The generic
+  USB printer driver ("USB Printer support", above) may be used in
+  that mode, and you can say N here if you want to use the chip only
+  in this mode.
+
+  Manual mode is not limited to printers, any parallel port
+  device should work. This driver utilizes manual mode.
+  Note however that some operations are three orders of magnitude
+  slower than on a PCI/ISA Parallel Port, so timing critical
+  applications might not work.
+
+  Say Y here if you own an USS-720 USB->Parport cable and intend to
+  connect anything other than a printer to it.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called uss720.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_DEVICEFS
+  If you say Y here (and to "/proc file system support" in the "File
+  systems section, above), you will get a file /proc/bus/usb/devices
+  which lists the devices currently connected to your USB bus or
+  busses, a file /proc/bus/usb/drivers which lists the USB kernel
+  client drivers currently loaded, and for every connected device a
+  file named  "/proc/bus/usb/xxx/yyy", where xxx is the bus number and
+  yyy the device number; the latter files can be used by user space
+  programs to talk directly to the device. These files are "virtual",
+  meaning they are generated on the fly and not stored on the hard
+  drive.
+
+  You may need to mount the usbdevfs file system to see the files, use
+   mount -t usbdevfs none /proc/bus/usb
+
+  For the format of the various /proc/bus/usb/ files, please read
+  <file:Documentation/usb/proc_usb_info.txt>.
+
+  Please note that this code is completely unrelated to devfs, the
+  "/dev file system support".
+
+  Most users want to say Y here.
+
+CONFIG_USB_BANDWIDTH
+  If you say Y here, the USB subsystem enforces USB bandwidth
+  allocation and will prevent some device opens from succeeding
+  if they would cause USB bandwidth usage to go above 90% of
+  the bus bandwidth.
+
+  If you say N here, these conditions will cause warning messages
+  about USB bandwidth usage to be logged and some devices or
+  drivers may not work correctly.
+
+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
+  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>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called dabusb.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_USBNET
+  This driver supports network links over USB with USB "Network"
+  or "data transfer" cables, often used to network laptops to PCs.
+  Such cables have chips from suppliers such as Belkin/eTEK, GeneSys
+  (GeneLink), NetChip and Prolific. Intelligent USB devices could also
+  use this approach to provide Internet access, using standard USB
+  cabling. You can find these chips also on some motherboards with
+  USB PC2PC support.
+
+  These links will have names like "usb0", "usb1", etc.  They act
+  like two-node Ethernets, so you can use 802.1d Ethernet Bridging
+  (CONFIG_BRIDGE) to simplify your network routing.
+
+  This code is also available as a kernel module (code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usbnet.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_STORAGE_FREECOM
+  Support for the Freecom USB to IDE/ATAPI adaptor.
+  Freecom has a web page at <http://www.freecom.de/>.
+
+CONFIG_USB_STORAGE_DPCM
+  Say Y here to support the Microtech ZiO! CompactFlash/SmartMedia
+  reader, details at <http://www.microtechint.com/zio/index.html>.
+  This driver treats the flash card as a removable storage device.
+
+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.
+
+CONFIG_USB_RIO500
+  Say Y here if you want to connect a USB Rio500 mp3 player to your
+  computer's USB port. Please read <file:Documentation/usb/rio.txt>
+  for more information.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called rio500.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_AUERSWALD
+  Say Y here if you want to connect an Auerswald USB ISDN Device
+  to your computer's USB port.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called auerswald.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_DSBR
+  Say Y here if you want to connect this type of radio to your
+  computer's USB port. Note that the audio is not digital, and
+  you must connect the line out connector to a sound card or a
+  set of speakers.
+
+  This driver uses the Video For Linux API.  You must enable
+  (Y or M in config) Video For Linux (under Character Devices)
+  to use this driver.  Information on this API and pointers to
+  "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called dsbr100.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_MICROTEK
+  Say Y here if you want support for the Microtek X6USB and
+  possibly the Phantom 336CX, Phantom C6 and ScanMaker V6U(S)L.
+  Support for anything but the X6 is experimental.
+  Please report failures and successes.
+  The scanner will appear as a scsi generic device to the rest
+  of the system. Scsi support is required for this driver to compile
+  and work. SANE 1.0.4 or newer is needed to make use of your scanner.
+  This driver can be compiled as a module.
+
+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.
+  The scanner will be accessible as a SCSI device.
+
+CONFIG_USB_BLUETOOTH
+  Say Y here if you want to connect a USB Bluetooth device to your
+  computer's USB port. You will need the Bluetooth stack (available
+  at <http://developer.axis.com/software/index.shtml>) to fully use
+  the device.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called bluetooth.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.5.2/linux/drivers/usb/Makefile	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/Makefile	Mon Jan 21 15:44:21 2002
@@ -46,6 +46,10 @@
 	obj-y += hcd/ehci-hcd.o
 endif
 
+ifeq ($(CONFIG_USB_OHCI_HCD),y)
+	obj-y += hcd/ohci-hcd.o
+endif
+
 obj-$(CONFIG_USB_UHCI)		+= usb-uhci.o
 obj-$(CONFIG_USB_UHCI_ALT)	+= uhci.o
 obj-$(CONFIG_USB_OHCI)		+= usb-ohci.o
@@ -85,6 +89,7 @@
 mod-subdirs	:= serial hcd
 
 subdir-$(CONFIG_USB_EHCI_HCD)	+= hcd
+subdir-$(CONFIG_USB_OHCI_HCD)	+= hcd
 subdir-$(CONFIG_USB_SERIAL)	+= serial
 subdir-$(CONFIG_USB_STORAGE)	+= storage
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.5.2/linux/drivers/usb/audio.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/audio.c	Wed Jan 23 15:33:46 2002
@@ -297,13 +297,13 @@
 #define FLG_CONNECTED    32
 
 struct my_data_urb {
-	urb_t urb;
-	iso_packet_descriptor_t isoframe[DESCFRAMES];
+	struct urb *urb;
+	struct usb_iso_packet_descriptor isoframe[DESCFRAMES];
 };
 
 struct my_sync_urb {
-	urb_t urb;
-	iso_packet_descriptor_t isoframe[SYNCFRAMES];
+	struct urb *urb;
+	struct usb_iso_packet_descriptor isoframe[SYNCFRAMES];
 };
 
 
@@ -510,7 +510,7 @@
 	return 0;
 }
 
-static int dmabuf_mmap(struct dmabuf *db, unsigned long start, unsigned long size, pgprot_t prot)
+static int dmabuf_mmap(struct vm_area_struct *vma, struct dmabuf *db, unsigned long start, unsigned long size, pgprot_t prot)
 {
 	unsigned int nr;
 
@@ -522,7 +522,7 @@
 			return -EINVAL;
 	db->mapped = 1;
 	for(nr = 0; nr < size; nr++) {
-		if (remap_page_range(start, virt_to_phys(db->sgbuf[nr]), PAGE_SIZE, prot))
+		if (remap_page_range(vma, start, virt_to_phys(db->sgbuf[nr]), PAGE_SIZE, prot))
 			return -EAGAIN;
 		start += PAGE_SIZE;
 	}
@@ -648,27 +648,27 @@
 		spin_unlock_irqrestore(&as->lock, flags);
 		if (notkilled && signal_pending(current)) {
 			if (i & FLG_URB0RUNNING)
-				usb_unlink_urb(&u->durb[0].urb);
+				usb_unlink_urb(u->durb[0].urb);
 			if (i & FLG_URB1RUNNING)
-				usb_unlink_urb(&u->durb[1].urb);
+				usb_unlink_urb(u->durb[1].urb);
 			if (i & FLG_SYNC0RUNNING)
-				usb_unlink_urb(&u->surb[0].urb);
+				usb_unlink_urb(u->surb[0].urb);
 			if (i & FLG_SYNC1RUNNING)
-				usb_unlink_urb(&u->surb[1].urb);
+				usb_unlink_urb(u->surb[1].urb);
 			notkilled = 0;
 		}
 	}
 	set_current_state(TASK_RUNNING);
-	if (u->durb[0].urb.transfer_buffer)
-		kfree(u->durb[0].urb.transfer_buffer);
-	if (u->durb[1].urb.transfer_buffer)
-		kfree(u->durb[1].urb.transfer_buffer);
-	if (u->surb[0].urb.transfer_buffer)
-		kfree(u->surb[0].urb.transfer_buffer);
-	if (u->surb[1].urb.transfer_buffer)
-		kfree(u->surb[1].urb.transfer_buffer);
-	u->durb[0].urb.transfer_buffer = u->durb[1].urb.transfer_buffer = 
-		u->surb[0].urb.transfer_buffer = u->surb[1].urb.transfer_buffer = NULL;
+	if (u->durb[0].urb->transfer_buffer)
+		kfree(u->durb[0].urb->transfer_buffer);
+	if (u->durb[1].urb->transfer_buffer)
+		kfree(u->durb[1].urb->transfer_buffer);
+	if (u->surb[0].urb->transfer_buffer)
+		kfree(u->surb[0].urb->transfer_buffer);
+	if (u->surb[1].urb->transfer_buffer)
+		kfree(u->surb[1].urb->transfer_buffer);
+	u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
+		u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
 }
 
 static inline void usbin_release(struct usb_audiodev *as)
@@ -904,9 +904,9 @@
 #if 0
 	printk(KERN_DEBUG "usbin_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
 #endif
-	if (urb == &u->durb[0].urb)
+	if (urb == u->durb[0].urb)
 		mask = FLG_URB0RUNNING;
-	else if (urb == &u->durb[1].urb)
+	else if (urb == u->durb[1].urb)
 		mask = FLG_URB1RUNNING;
 	else {
 		mask = 0;
@@ -969,9 +969,9 @@
 #if 0
 	printk(KERN_DEBUG "usbin_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
 #endif
-	if (urb == &u->surb[0].urb)
+	if (urb == u->surb[0].urb)
 		mask = FLG_SYNC0RUNNING;
-	else if (urb == &u->surb[1].urb)
+	else if (urb == u->surb[1].urb)
 		mask = FLG_SYNC1RUNNING;
 	else {
 		mask = 0;
@@ -1017,26 +1017,26 @@
 		u->phase = 0;
 		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
 		bufsz = DESCFRAMES * maxsze;
-		if (u->durb[0].urb.transfer_buffer)
-			kfree(u->durb[0].urb.transfer_buffer);
-		u->durb[0].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[0].urb.transfer_buffer_length = bufsz;
-		if (u->durb[1].urb.transfer_buffer)
-			kfree(u->durb[1].urb.transfer_buffer);
-		u->durb[1].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[1].urb.transfer_buffer_length = bufsz;
+		if (u->durb[0].urb->transfer_buffer)
+			kfree(u->durb[0].urb->transfer_buffer);
+		u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+		u->durb[0].urb->transfer_buffer_length = bufsz;
+		if (u->durb[1].urb->transfer_buffer)
+			kfree(u->durb[1].urb->transfer_buffer);
+		u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+		u->durb[1].urb->transfer_buffer_length = bufsz;
 		if (u->syncpipe) {
-			if (u->surb[0].urb.transfer_buffer)
-				kfree(u->surb[0].urb.transfer_buffer);
-			u->surb[0].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[0].urb.transfer_buffer_length = 3*SYNCFRAMES;
-			if (u->surb[1].urb.transfer_buffer)
-				kfree(u->surb[1].urb.transfer_buffer);
-			u->surb[1].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[1].urb.transfer_buffer_length = 3*SYNCFRAMES;
+			if (u->surb[0].urb->transfer_buffer)
+				kfree(u->surb[0].urb->transfer_buffer);
+			u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+			u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
+			if (u->surb[1].urb->transfer_buffer)
+				kfree(u->surb[1].urb->transfer_buffer);
+			u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+			u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
 		}
-		if (!u->durb[0].urb.transfer_buffer || !u->durb[1].urb.transfer_buffer || 
-		    (u->syncpipe && (!u->surb[0].urb.transfer_buffer || !u->surb[1].urb.transfer_buffer))) {
+		if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || 
+		    (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
 			printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
 			return 0;
 		}
@@ -1048,7 +1048,7 @@
 	}
 	u->flags |= FLG_RUNNING;
 	if (!(u->flags & FLG_URB0RUNNING)) {
-		urb = &u->durb[0].urb;
+		urb = u->durb[0].urb;
 		urb->dev = dev;
 		urb->pipe = u->datapipe;
 		urb->transfer_flags = USB_ISO_ASAP;
@@ -1061,7 +1061,7 @@
 			u->flags &= ~FLG_RUNNING;
 	}
 	if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
-		urb = &u->durb[1].urb;
+		urb = u->durb[1].urb;
 		urb->dev = dev;
 		urb->pipe = u->datapipe;
 		urb->transfer_flags = USB_ISO_ASAP;
@@ -1075,7 +1075,7 @@
 	}
 	if (u->syncpipe) {
 		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
-			urb = &u->surb[0].urb;
+			urb = u->surb[0].urb;
 			urb->dev = dev;
 			urb->pipe = u->syncpipe;
 			urb->transfer_flags = USB_ISO_ASAP;
@@ -1089,7 +1089,7 @@
 				u->flags &= ~FLG_RUNNING;
 		}
 		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
-			urb = &u->surb[1].urb;
+			urb = u->surb[1].urb;
 			urb->dev = dev;
 			urb->pipe = u->syncpipe;
 			urb->transfer_flags = USB_ISO_ASAP;
@@ -1125,27 +1125,27 @@
 		spin_unlock_irqrestore(&as->lock, flags);
 		if (notkilled && signal_pending(current)) {
 			if (i & FLG_URB0RUNNING)
-				usb_unlink_urb(&u->durb[0].urb);
+				usb_unlink_urb(u->durb[0].urb);
 			if (i & FLG_URB1RUNNING)
-				usb_unlink_urb(&u->durb[1].urb);
+				usb_unlink_urb(u->durb[1].urb);
 			if (i & FLG_SYNC0RUNNING)
-				usb_unlink_urb(&u->surb[0].urb);
+				usb_unlink_urb(u->surb[0].urb);
 			if (i & FLG_SYNC1RUNNING)
-				usb_unlink_urb(&u->surb[1].urb);
+				usb_unlink_urb(u->surb[1].urb);
 			notkilled = 0;
 		}
 	}
 	set_current_state(TASK_RUNNING);
-	if (u->durb[0].urb.transfer_buffer)
-		kfree(u->durb[0].urb.transfer_buffer);
-	if (u->durb[1].urb.transfer_buffer)
-		kfree(u->durb[1].urb.transfer_buffer);
-	if (u->surb[0].urb.transfer_buffer)
-		kfree(u->surb[0].urb.transfer_buffer);
-	if (u->surb[1].urb.transfer_buffer)
-		kfree(u->surb[1].urb.transfer_buffer);
-	u->durb[0].urb.transfer_buffer = u->durb[1].urb.transfer_buffer = 
-		u->surb[0].urb.transfer_buffer = u->surb[1].urb.transfer_buffer = NULL;
+	if (u->durb[0].urb->transfer_buffer)
+		kfree(u->durb[0].urb->transfer_buffer);
+	if (u->durb[1].urb->transfer_buffer)
+		kfree(u->durb[1].urb->transfer_buffer);
+	if (u->surb[0].urb->transfer_buffer)
+		kfree(u->surb[0].urb->transfer_buffer);
+	if (u->surb[1].urb->transfer_buffer)
+		kfree(u->surb[1].urb->transfer_buffer);
+	u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
+		u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
 }
 
 static inline void usbout_release(struct usb_audiodev *as)
@@ -1262,9 +1262,9 @@
 #if 0
 	printk(KERN_DEBUG "usbout_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
 #endif
-	if (urb == &u->durb[0].urb)
+	if (urb == u->durb[0].urb)
 		mask = FLG_URB0RUNNING;
-	else if (urb == &u->durb[1].urb)
+	else if (urb == u->durb[1].urb)
 		mask = FLG_URB1RUNNING;
 	else {
 		mask = 0;
@@ -1334,9 +1334,9 @@
 #if 0
 	printk(KERN_DEBUG "usbout_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
 #endif
-	if (urb == &u->surb[0].urb)
+	if (urb == u->surb[0].urb)
 		mask = FLG_SYNC0RUNNING;
-	else if (urb == &u->surb[1].urb)
+	else if (urb == u->surb[1].urb)
 		mask = FLG_SYNC1RUNNING;
 	else {
 		mask = 0;
@@ -1382,26 +1382,26 @@
 		u->phase = 0;
 		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
 		bufsz = DESCFRAMES * maxsze;
-		if (u->durb[0].urb.transfer_buffer)
-			kfree(u->durb[0].urb.transfer_buffer);
-		u->durb[0].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[0].urb.transfer_buffer_length = bufsz;
-		if (u->durb[1].urb.transfer_buffer)
-			kfree(u->durb[1].urb.transfer_buffer);
-		u->durb[1].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[1].urb.transfer_buffer_length = bufsz;
+		if (u->durb[0].urb->transfer_buffer)
+			kfree(u->durb[0].urb->transfer_buffer);
+		u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+		u->durb[0].urb->transfer_buffer_length = bufsz;
+		if (u->durb[1].urb->transfer_buffer)
+			kfree(u->durb[1].urb->transfer_buffer);
+		u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+		u->durb[1].urb->transfer_buffer_length = bufsz;
 		if (u->syncpipe) {
-			if (u->surb[0].urb.transfer_buffer)
-				kfree(u->surb[0].urb.transfer_buffer);
-			u->surb[0].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[0].urb.transfer_buffer_length = 3*SYNCFRAMES;
-			if (u->surb[1].urb.transfer_buffer)
-				kfree(u->surb[1].urb.transfer_buffer);
-			u->surb[1].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[1].urb.transfer_buffer_length = 3*SYNCFRAMES;
+			if (u->surb[0].urb->transfer_buffer)
+				kfree(u->surb[0].urb->transfer_buffer);
+			u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+			u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
+			if (u->surb[1].urb->transfer_buffer)
+				kfree(u->surb[1].urb->transfer_buffer);
+			u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+			u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
 		}
-		if (!u->durb[0].urb.transfer_buffer || !u->durb[1].urb.transfer_buffer || 
-		    (u->syncpipe && (!u->surb[0].urb.transfer_buffer || !u->surb[1].urb.transfer_buffer))) {
+		if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || 
+		    (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
 			printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
 			return 0;
 		}
@@ -1413,7 +1413,7 @@
 	}
        	u->flags |= FLG_RUNNING;
 	if (!(u->flags & FLG_URB0RUNNING)) {
-		urb = &u->durb[0].urb;
+		urb = u->durb[0].urb;
 		urb->dev = dev;
 		urb->pipe = u->datapipe;
 		urb->transfer_flags = USB_ISO_ASAP;
@@ -1426,7 +1426,7 @@
 			u->flags &= ~FLG_RUNNING;
 	}
 	if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
-		urb = &u->durb[1].urb;
+		urb = u->durb[1].urb;
 		urb->dev = dev;
 		urb->pipe = u->datapipe;
 		urb->transfer_flags = USB_ISO_ASAP;
@@ -1440,7 +1440,7 @@
 	}
 	if (u->syncpipe) {
 		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
-			urb = &u->surb[0].urb;
+			urb = u->surb[0].urb;
 			urb->dev = dev;
 			urb->pipe = u->syncpipe;
 			urb->transfer_flags = USB_ISO_ASAP;
@@ -1454,7 +1454,7 @@
 				u->flags &= ~FLG_RUNNING;
 		}
 		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
-			urb = &u->surb[1].urb;
+			urb = u->surb[1].urb;
 			urb->dev = dev;
 			urb->pipe = u->syncpipe;
 			urb->transfer_flags = USB_ISO_ASAP;
@@ -1921,6 +1921,14 @@
 		usbout_release(as);
 		dmabuf_release(&as->usbin.dma);
 		dmabuf_release(&as->usbout.dma);
+		usb_free_urb(as->usbin.durb[0].urb);
+		usb_free_urb(as->usbin.durb[1].urb);
+		usb_free_urb(as->usbin.surb[0].urb);
+		usb_free_urb(as->usbin.surb[1].urb);
+		usb_free_urb(as->usbout.durb[0].urb);
+		usb_free_urb(as->usbout.durb[1].urb);
+		usb_free_urb(as->usbout.surb[0].urb);
+		usb_free_urb(as->usbout.surb[1].urb);
 		kfree(as);
 	}
 	while (!list_empty(&s->mixerlist)) {
@@ -2341,7 +2349,7 @@
 	if (vma->vm_pgoff != 0)
 		goto out;
 
-	ret = dmabuf_mmap(db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
+	ret = dmabuf_mmap(vma, db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
 out:
 	unlock_kernel();
 	return ret;
@@ -2821,14 +2829,33 @@
 	init_waitqueue_head(&as->usbin.dma.wait);
 	init_waitqueue_head(&as->usbout.dma.wait);
 	spin_lock_init(&as->lock);
-	spin_lock_init(&as->usbin.durb[0].urb.lock);
-	spin_lock_init(&as->usbin.durb[1].urb.lock);
-	spin_lock_init(&as->usbin.surb[0].urb.lock);
-	spin_lock_init(&as->usbin.surb[1].urb.lock);
-	spin_lock_init(&as->usbout.durb[0].urb.lock);
-	spin_lock_init(&as->usbout.durb[1].urb.lock);
-	spin_lock_init(&as->usbout.surb[0].urb.lock);
-	spin_lock_init(&as->usbout.surb[1].urb.lock);
+	as->usbin.durb[0].urb = usb_alloc_urb(0);
+	as->usbin.durb[1].urb = usb_alloc_urb(0);
+	as->usbin.surb[0].urb = usb_alloc_urb(0);
+	as->usbin.surb[1].urb = usb_alloc_urb(0);
+	as->usbout.durb[0].urb = usb_alloc_urb(0);
+	as->usbout.durb[1].urb = usb_alloc_urb(0);
+	as->usbout.surb[0].urb = usb_alloc_urb(0);
+	as->usbout.surb[1].urb = usb_alloc_urb(0);
+	if ((!as->usbin.durb[0].urb) ||
+	    (!as->usbin.durb[1].urb) ||
+	    (!as->usbin.surb[0].urb) ||
+	    (!as->usbin.surb[1].urb) ||
+	    (!as->usbout.durb[0].urb) ||
+	    (!as->usbout.durb[1].urb) ||
+	    (!as->usbout.surb[0].urb) ||
+	    (!as->usbout.surb[1].urb)) {
+		usb_free_urb(as->usbin.durb[0].urb);
+		usb_free_urb(as->usbin.durb[1].urb);
+		usb_free_urb(as->usbin.surb[0].urb);
+		usb_free_urb(as->usbin.surb[1].urb);
+		usb_free_urb(as->usbout.durb[0].urb);
+		usb_free_urb(as->usbout.durb[1].urb);
+		usb_free_urb(as->usbout.surb[0].urb);
+		usb_free_urb(as->usbout.surb[1].urb);
+		kfree(as);
+		return;
+	}
 	as->state = s;
 	as->usbin.interface = asifin;
 	as->usbout.interface = asifout;
@@ -2997,11 +3024,27 @@
 		}
 	}
 	if (as->numfmtin == 0 && as->numfmtout == 0) {
+		usb_free_urb(as->usbin.durb[0].urb);
+		usb_free_urb(as->usbin.durb[1].urb);
+		usb_free_urb(as->usbin.surb[0].urb);
+		usb_free_urb(as->usbin.surb[1].urb);
+		usb_free_urb(as->usbout.durb[0].urb);
+		usb_free_urb(as->usbout.durb[1].urb);
+		usb_free_urb(as->usbout.surb[0].urb);
+		usb_free_urb(as->usbout.surb[1].urb);
 		kfree(as);
 		return;
 	}
 	if ((as->dev_audio = register_sound_dsp(&usb_audio_fops, -1)) < 0) {
 		printk(KERN_ERR "usbaudio: cannot register dsp\n");
+		usb_free_urb(as->usbin.durb[0].urb);
+		usb_free_urb(as->usbin.durb[1].urb);
+		usb_free_urb(as->usbin.surb[0].urb);
+		usb_free_urb(as->usbin.surb[1].urb);
+		usb_free_urb(as->usbout.durb[0].urb);
+		usb_free_urb(as->usbout.durb[1].urb);
+		usb_free_urb(as->usbout.surb[0].urb);
+		usb_free_urb(as->usbout.surb[1].urb);
 		kfree(as);
 		return;
 	}
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/auerswald.c linux/drivers/usb/auerswald.c
--- v2.5.2/linux/drivers/usb/auerswald.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/auerswald.c	Mon Jan 21 15:44:21 2002
@@ -176,7 +176,7 @@
 typedef struct
 {
         struct auerchain *chain;        /* pointer to the chain to which this element belongs */
-        urb_t * urbp;                   /* pointer to attached urb */
+        struct urb * urbp;                   /* pointer to attached urb */
         void *context;                  /* saved URB context */
         usb_complete_t complete;        /* saved URB completion function */
         struct list_head list;          /* to include element into a list */
@@ -200,7 +200,7 @@
         unsigned int len;               /* number of characters in data buffer */
 	unsigned int retries;		/* for urb retries */
         struct usb_ctrlrequest *dr;	/* for setup data in control messages */
-        urb_t * urbp;                   /* USB urb */
+        struct urb * urbp;                   /* USB urb */
         struct auerbufctl *list;        /* pointer to list */
         struct list_head buff_list;     /* reference to next buffer in list */
 } auerbuf_t,*pauerbuf_t;
@@ -237,7 +237,7 @@
 	int			open_count;	    /* count the number of open character channels */
         char 			dev_desc[AUSI_DLEN];/* for storing a textual description */
         unsigned int 		maxControlLength;   /* max. Length of control paket (without header) */
-        urb_t * 		inturbp;            /* interrupt urb */
+        struct urb * 		inturbp;            /* interrupt urb */
         char *			intbufp;            /* data buffer for interrupt urb */
 	unsigned int 		irqsize;	    /* size of interrupt endpoint 1 */
         struct auerchain 	controlchain;  	    /* for chaining of control messages */
@@ -274,7 +274,7 @@
 
 /*-------------------------------------------------------------------*/
 /* Forwards */
-static void auerswald_ctrlread_complete (urb_t * urb);
+static void auerswald_ctrlread_complete (struct urb * urb);
 static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp);
 
 
@@ -283,7 +283,7 @@
 /* --------------------------                                        */
 
 /* completion function for chained urbs */
-static void auerchain_complete (urb_t * urb)
+static void auerchain_complete (struct urb * urb)
 {
 	unsigned long flags;
         int result;
@@ -350,7 +350,7 @@
    this function may be called from completion context or from user space!
    early = 1 -> submit in front of chain
 */
-static int auerchain_submit_urb_list (pauerchain_t acp, urb_t * urb, int early)
+static int auerchain_submit_urb_list (pauerchain_t acp, struct urb * urb, int early)
 {
         int result;
         unsigned long flags;
@@ -424,7 +424,7 @@
 /* submit function for chained urbs
    this function may be called from completion context or from user space!
 */
-static int auerchain_submit_urb (pauerchain_t acp, urb_t * urb)
+static int auerchain_submit_urb (pauerchain_t acp, struct urb * urb)
 {
 	return auerchain_submit_urb_list (acp, urb, 0);
 }
@@ -433,10 +433,10 @@
    the result is 0 if the urb is cancelled, or -EINPROGRESS if
    USB_ASYNC_UNLINK is set and the function is successfully started.
 */
-static int auerchain_unlink_urb (pauerchain_t acp, urb_t * urb)
+static int auerchain_unlink_urb (pauerchain_t acp, struct urb * urb)
 {
 	unsigned long flags;
-        urb_t * urbp;
+        struct urb * urbp;
         pauerchainelement_t acep;
         struct list_head *tmp;
 
@@ -492,7 +492,7 @@
 static void auerchain_unlink_all (pauerchain_t acp)
 {
 	unsigned long flags;
-        urb_t * urbp;
+        struct urb * urbp;
         pauerchainelement_t acep;
 
         dbg ("auerchain_unlink_all called");
@@ -598,7 +598,7 @@
 
 
 /* completion handler for synchronous chained URBs */
-static void auerchain_blocking_completion (urb_t *urb)
+static void auerchain_blocking_completion (struct urb *urb)
 {
 	wait_queue_head_t *wakeup = (wait_queue_head_t *)urb->context;
 	wake_up (wakeup);
@@ -606,7 +606,7 @@
 
 
 /* Starts chained urb and waits for completion or timeout */
-static int auerchain_start_wait_urb (pauerchain_t acp, urb_t *urb, int timeout, int* actual_length)
+static int auerchain_start_wait_urb (pauerchain_t acp, struct urb *urb, int timeout, int* actual_length)
 {
 	DECLARE_WAITQUEUE (wait, current);
 	DECLARE_WAIT_QUEUE_HEAD (wqh);
@@ -675,7 +675,7 @@
 {
 	int ret;
 	struct usb_ctrlrequest *dr;
-	urb_t *urb;
+	struct urb *urb;
         int length;
 
         dbg ("auerchain_control_msg");
@@ -858,7 +858,7 @@
 }
 
 /* Completion of asynchronous write block */
-static void auerchar_ctrlwrite_complete (urb_t * urb)
+static void auerchar_ctrlwrite_complete (struct urb * urb)
 {
 	pauerbuf_t bp = (pauerbuf_t) urb->context;
 	pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
@@ -871,7 +871,7 @@
 }
 
 /* Completion handler for dummy retry packet */
-static void auerswald_ctrlread_wretcomplete (urb_t * urb)
+static void auerswald_ctrlread_wretcomplete (struct urb * urb)
 {
         pauerbuf_t bp = (pauerbuf_t) urb->context;
         pauerswald_t cp;
@@ -910,7 +910,7 @@
 }
 
 /* completion handler for receiving of control messages */
-static void auerswald_ctrlread_complete (urb_t * urb)
+static void auerswald_ctrlread_complete (struct urb * urb)
 {
         unsigned int  serviceid;
         pauerswald_t  cp;
@@ -980,7 +980,7 @@
    messages from the USB device.
 */
 /* int completion handler. */
-static void auerswald_int_complete (urb_t * urb)
+static void auerswald_int_complete (struct urb * urb)
 {
         unsigned long flags;
         unsigned  int channelid;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/catc.c linux/drivers/usb/catc.c
--- v2.5.2/linux/drivers/usb/catc.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/catc.c	Wed Jan 23 15:33:46 2002
@@ -179,7 +179,7 @@
 		void (*callback)(struct catc *catc, struct ctrl_queue *q);
 	} ctrl_queue[CTRL_QUEUE];
 
-	struct urb tx_urb, rx_urb, irq_urb, ctrl_urb;
+	struct urb *tx_urb, *rx_urb, *irq_urb, *ctrl_urb;
 };
 
 /*
@@ -256,8 +256,8 @@
 	}
 
 	if ((data[1] & 0x80) && !test_and_set_bit(RX_RUNNING, &catc->flags)) {
-		catc->rx_urb.dev = catc->usbdev;
-		if ((status = usb_submit_urb(&catc->rx_urb)) < 0) {
+		catc->rx_urb->dev = catc->usbdev;
+		if ((status = usb_submit_urb(catc->rx_urb)) < 0) {
 			err("submit(rx_urb) status %d", status);
 			return;
 		} 
@@ -282,11 +282,11 @@
 {
 	int status;
 
-	catc->tx_urb.transfer_buffer_length = catc->tx_ptr;
-	catc->tx_urb.transfer_buffer = catc->tx_buf[catc->tx_idx];
-	catc->tx_urb.dev = catc->usbdev;
+	catc->tx_urb->transfer_buffer_length = catc->tx_ptr;
+	catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx];
+	catc->tx_urb->dev = catc->usbdev;
 
-	if ((status = usb_submit_urb(&catc->tx_urb)) < 0)
+	if ((status = usb_submit_urb(catc->tx_urb)) < 0)
 		err("submit(tx_urb), status %d", status);
 
 	catc->tx_idx = !catc->tx_idx;
@@ -363,8 +363,8 @@
 	struct catc *catc = netdev->priv;
 
 	warn("Transmit timed out.");
-	catc->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
-	usb_unlink_urb(&catc->tx_urb);
+	catc->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+	usb_unlink_urb(catc->tx_urb);
 }
 
 /*
@@ -383,7 +383,7 @@
 {
 	struct ctrl_queue *q = catc->ctrl_queue + catc->ctrl_tail;
 	struct usb_device *usbdev = catc->usbdev;
-	struct urb *urb = &catc->ctrl_urb;
+	struct urb *urb = catc->ctrl_urb;
 	struct usb_ctrlrequest *dr = &catc->ctrl_dr;
 	int status;
 
@@ -402,7 +402,7 @@
 	if (!q->dir && q->buf && q->len)
 		memcpy(catc->ctrl_buf, q->buf, q->len);
 
-	if ((status = usb_submit_urb(&catc->ctrl_urb)))
+	if ((status = usb_submit_urb(catc->ctrl_urb)))
 		err("submit(ctrl_urb) status %d", status);
 }
 
@@ -624,8 +624,8 @@
 	struct catc *catc = netdev->priv;
 	int status;
 
-	catc->irq_urb.dev = catc->usbdev;
-	if ((status = usb_submit_urb(&catc->irq_urb)) < 0) {
+	catc->irq_urb->dev = catc->usbdev;
+	if ((status = usb_submit_urb(catc->irq_urb)) < 0) {
 		err("submit(irq_urb) status %d", status);
 		return -1;
 	}
@@ -645,10 +645,10 @@
 
 	del_timer_sync(&catc->timer);
 
-	usb_unlink_urb(&catc->rx_urb);
-	usb_unlink_urb(&catc->tx_urb);
-	usb_unlink_urb(&catc->irq_urb);
-	usb_unlink_urb(&catc->ctrl_urb);
+	usb_unlink_urb(catc->rx_urb);
+	usb_unlink_urb(catc->tx_urb);
+	usb_unlink_urb(catc->irq_urb);
+	usb_unlink_urb(catc->ctrl_urb);
 
 	return 0;
 }
@@ -694,16 +694,26 @@
 	catc->timer.data = (long) catc;
 	catc->timer.function = catc_stats_timer;
 
-	FILL_CONTROL_URB(&catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
+	catc->ctrl_urb = usb_alloc_urb(0);
+	catc->tx_urb = usb_alloc_urb(0);
+	catc->rx_urb = usb_alloc_urb(0);
+	catc->irq_urb = usb_alloc_urb(0);
+	if ((!catc->ctrl_urb) || (!catc->tx_urb) || 
+	    (!catc->rx_urb) || (!catc->irq_urb)) {
+		err("No free urbs available.");
+		return NULL;
+	}
+
+	FILL_CONTROL_URB(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
 		NULL, NULL, 0, catc_ctrl_done, catc);
 
-	FILL_BULK_URB(&catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),
+	FILL_BULK_URB(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),
 		NULL, 0, catc_tx_done, catc);
 
-	FILL_BULK_URB(&catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
+	FILL_BULK_URB(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
 		catc->rx_buf, RX_MAX_BURST * (PKT_SZ + 2), catc_rx_done, catc);
 
-	FILL_INT_URB(&catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
+	FILL_INT_URB(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
                 catc->irq_buf, 2, catc_irq_done, catc, 1);
 
 	dbg("Checking memory size\n");
@@ -772,6 +782,10 @@
 {
 	struct catc *catc = dev_ptr;
 	unregister_netdev(catc->netdev);
+	usb_free_urb(catc->ctrl_urb);
+	usb_free_urb(catc->tx_urb);
+	usb_free_urb(catc->rx_urb);
+	usb_free_urb(catc->irq_urb);
 	kfree(catc->netdev);
 	kfree(catc);
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/devio.c linux/drivers/usb/devio.c
--- v2.5.2/linux/drivers/usb/devio.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/devio.c	Wed Jan 23 15:33:46 2002
@@ -53,7 +53,7 @@
 	unsigned int signr;
 	void *userbuffer;
         void *userurb;
-        urb_t urb;
+        struct urb *urb;
 };
 
 static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
@@ -170,22 +170,26 @@
 
 static struct async *alloc_async(unsigned int numisoframes)
 {
-        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(iso_packet_descriptor_t);
+        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor);
         struct async *as = kmalloc(assize, GFP_KERNEL);
         if (!as)
                 return NULL;
         memset(as, 0, assize);
-        as->urb.number_of_packets = numisoframes;
-        spin_lock_init(&as->urb.lock);
+	as->urb = usb_alloc_urb(numisoframes);
+	if (!as->urb) {
+		kfree(as);
+		return NULL;
+	}
         return as;
 }
 
 static void free_async(struct async *as)
 {
-        if (as->urb.transfer_buffer)
-                kfree(as->urb.transfer_buffer);
-        if (as->urb.setup_packet)
-                kfree(as->urb.setup_packet);
+        if (as->urb->transfer_buffer)
+                kfree(as->urb->transfer_buffer);
+        if (as->urb->setup_packet)
+                kfree(as->urb->setup_packet);
+	usb_free_urb(as->urb);
         kfree(as);
 }
 
@@ -259,7 +263,7 @@
         wake_up(&ps->wait);
 	if (as->signr) {
 		sinfo.si_signo = as->signr;
-		sinfo.si_errno = as->urb.status;
+		sinfo.si_errno = as->urb->status;
 		sinfo.si_code = SI_ASYNCIO;
 		sinfo.si_addr = as->userurb;
 		send_sig_info(as->signr, &sinfo, as->task);
@@ -278,7 +282,7 @@
                 INIT_LIST_HEAD(&as->asynclist);
                 spin_unlock_irqrestore(&ps->lock, flags);
                 /* usb_unlink_urb calls the completion handler with status == -ENOENT */
-                usb_unlink_urb(&as->urb);
+                usb_unlink_urb(as->urb);
                 spin_lock_irqsave(&ps->lock, flags);
         }
         spin_unlock_irqrestore(&ps->lock, flags);
@@ -862,7 +866,7 @@
 			kfree(dr);
 		return -ENOMEM;
 	}
-	if (!(as->urb.transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
+	if (!(as->urb->transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
 		if (isopkt)
 			kfree(isopkt);
 		if (dr)
@@ -870,19 +874,19 @@
 		free_async(as);
 		return -ENOMEM;
 	}
-        as->urb.next = NULL;
-        as->urb.dev = ps->dev;
-        as->urb.pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
-        as->urb.transfer_flags = uurb.flags;
-	as->urb.transfer_buffer_length = uurb.buffer_length;
-	as->urb.setup_packet = (unsigned char*)dr;
-	as->urb.start_frame = uurb.start_frame;
-	as->urb.number_of_packets = uurb.number_of_packets;
-        as->urb.context = as;
-        as->urb.complete = async_completed;
+        as->urb->next = NULL;
+        as->urb->dev = ps->dev;
+        as->urb->pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
+        as->urb->transfer_flags = uurb.flags;
+	as->urb->transfer_buffer_length = uurb.buffer_length;
+	as->urb->setup_packet = (unsigned char*)dr;
+	as->urb->start_frame = uurb.start_frame;
+	as->urb->number_of_packets = uurb.number_of_packets;
+        as->urb->context = as;
+        as->urb->complete = async_completed;
 	for (totlen = u = 0; u < uurb.number_of_packets; u++) {
-		as->urb.iso_frame_desc[u].offset = totlen;
-		as->urb.iso_frame_desc[u].length = isopkt[u].length;
+		as->urb->iso_frame_desc[u].offset = totlen;
+		as->urb->iso_frame_desc[u].length = isopkt[u].length;
 		totlen += isopkt[u].length;
 	}
 	if (isopkt)
@@ -896,13 +900,13 @@
 	as->signr = uurb.signr;
 	as->task = current;
 	if (!(uurb.endpoint & USB_DIR_IN)) {
-		if (copy_from_user(as->urb.transfer_buffer, uurb.buffer, as->urb.transfer_buffer_length)) {
+		if (copy_from_user(as->urb->transfer_buffer, uurb.buffer, as->urb->transfer_buffer_length)) {
 			free_async(as);
 			return -EFAULT;
 		}
 	}
         async_newpending(as);
-        if ((ret = usb_submit_urb(&as->urb))) {
+        if ((ret = usb_submit_urb(as->urb))) {
 		printk(KERN_DEBUG "usbdevfs: usb_submit_urb returned %d\n", ret);
                 async_removepending(as);
                 free_async(as);
@@ -918,34 +922,35 @@
 	as = async_getpending(ps, arg);
 	if (!as)
 		return -EINVAL;
-	usb_unlink_urb(&as->urb);
+	usb_unlink_urb(as->urb);
 	return 0;
 }
 
 static int processcompl(struct async *as)
 {
+	struct urb *urb = as->urb;
 	unsigned int i;
 
 	if (as->userbuffer)
-		if (copy_to_user(as->userbuffer, as->urb.transfer_buffer, as->urb.transfer_buffer_length))
+		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
 			return -EFAULT;
-	if (put_user(as->urb.status,
+	if (put_user(urb->status,
 		     &((struct usbdevfs_urb *)as->userurb)->status))
 		return -EFAULT;
-	if (put_user(as->urb.actual_length,
+	if (put_user(urb->actual_length,
 		     &((struct usbdevfs_urb *)as->userurb)->actual_length))
 		return -EFAULT;
-	if (put_user(as->urb.error_count,
+	if (put_user(urb->error_count,
 		     &((struct usbdevfs_urb *)as->userurb)->error_count))
 		return -EFAULT;
 
-	if (!(usb_pipeisoc(as->urb.pipe)))
+	if (!(usb_pipeisoc(urb->pipe)))
 		return 0;
-	for (i = 0; i < as->urb.number_of_packets; i++) {
-		if (put_user(as->urb.iso_frame_desc[i].actual_length, 
+	for (i = 0; i < urb->number_of_packets; i++) {
+		if (put_user(urb->iso_frame_desc[i].actual_length, 
 			     &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length))
 			return -EFAULT;
-		if (put_user(as->urb.iso_frame_desc[i].status, 
+		if (put_user(urb->iso_frame_desc[i].status, 
 			     &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status))
 			return -EFAULT;
 	}
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/dsbr100.c linux/drivers/usb/dsbr100.c
--- v2.5.2/linux/drivers/usb/dsbr100.c	Tue Oct  9 15:15:02 2001
+++ linux/drivers/usb/dsbr100.c	Wed Jan 23 15:33:46 2002
@@ -90,7 +90,7 @@
 MODULE_PARM(radio_nr, "i");
 
 typedef struct
-{	struct urb readurb,writeurb;
+{
 	struct usb_device *dev;
 	unsigned char transfer_buffer[TB_LEN];
 	int curfreq;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/Config.help linux/drivers/usb/hcd/Config.help
--- v2.5.2/linux/drivers/usb/hcd/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/Config.help	Fri Jan 25 16:17:51 2002
@@ -0,0 +1,38 @@
+CONFIG_USB_EHCI_HCD
+  The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
+  "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
+  If your USB host controller supports USB 2.0, you will likely want to
+  configure this Host Controller Driver.  At this writing, the primary
+  implementation of EHCI is a chip from NEC, widely available in add-on
+  PCI cards, but implementations are in the works from other vendors
+  including Intel and Philips.  Motherboard support is appearing.
+
+  EHCI controllers are packaged with "companion" host controllers (OHCI
+  or UHCI) to handle USB 1.1 devices connected to root hub ports.  Ports
+  will connect to EHCI if it the device is high speed, otherwise they
+  connect to a companion controller.  If you configure EHCI, you should
+  probably configure the OHCI (for NEC and some other vendors) USB Host
+  Controller Driver too.
+
+  You may want to read <file:Documentation/usb/ehci.txt>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ehci-hcd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+OHCI (most USB hosts except VIA, Intel PIIX) support
+CONFIG_USB_OHCI_HCD
+  The Open Host Controller Interface (OHCI) is a standard for accessing
+  USB 1.1 host controller hardware.  It does more in hardware than Intel's
+  UHCI specification.  If your USB host controller follows the OHCI spec,
+  say Y.  On most non-x86 systems, and on x86 hardware that's not using a
+  USB controller from Intel or VIA, this is appropriate.  If your host
+  controller doesn't use PCI, this is probably appropriate.  For a PCI
+  based system where you're not sure, the "lspci -v" entry will list the
+  right "prog-if" for your USB controller(s):  EHCI, OHCI, or UHCI.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ohci-hcd.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/Config.in linux/drivers/usb/hcd/Config.in
--- v2.5.2/linux/drivers/usb/hcd/Config.in	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hcd/Config.in	Mon Jan 21 15:44:21 2002
@@ -2,6 +2,6 @@
 # USB Host Controller Drivers
 #
 dep_tristate '  EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-# dep_tristate '  OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+dep_tristate '  OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
 # dep_tristate '  UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/Makefile linux/drivers/usb/hcd/Makefile
--- v2.5.2/linux/drivers/usb/hcd/Makefile	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hcd/Makefile	Mon Jan 21 15:44:21 2002
@@ -6,7 +6,7 @@
 O_TARGET	:=
 
 obj-$(CONFIG_USB_EHCI_HCD)			+= ehci-hcd.o
-# obj-$(CONFIG_USB_OHCI_HCD)			+= ohci-hcd.o
+obj-$(CONFIG_USB_OHCI_HCD)			+= ohci-hcd.o
 # obj-$(CONFIG_USB_UHCI_HCD)			+= uhci-hcd.o
 
 # Extract lists of the multi-part drivers.
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ehci-hcd.c linux/drivers/usb/hcd/ehci-hcd.c
--- v2.5.2/linux/drivers/usb/hcd/ehci-hcd.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hcd/ehci-hcd.c	Fri Jan 25 16:17:51 2002
@@ -70,9 +70,15 @@
  *	Brad Hards
  *	Rory Bolt
  *	...
+ *
+ * HISTORY:
+ * 2002-01-14	Minor cleanup; version synch.
+ * 2002-01-08	Fix roothub handoff of FS/LS to companion controllers.
+ * 2002-01-04	Control/Bulk queuing behaves.
+ * 2001-12-12	Initial patch version for Linux 2.5.1 kernel.
  */
 
-#define DRIVER_VERSION "$Revision: 0.25 $"
+#define DRIVER_VERSION "$Revision: 0.26 $"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
@@ -80,7 +86,7 @@
 // #define EHCI_VERBOSE_DEBUG
 // #define have_iso
 
-#ifdef	DEBUG
+#ifdef	CONFIG_DEBUG_SLAB
 #	define	EHCI_SLAB_FLAGS		(SLAB_POISON)
 #else
 #	define	EHCI_SLAB_FLAGS		0
@@ -97,9 +103,6 @@
 static int log2_irq_thresh = 0;		// 0 to 6
 MODULE_PARM (log2_irq_thresh, "i");
 MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
-
-/* Some A steppings of the NEC controller need soft retries */
-//#define	EHCI_SOFT_RETRIES	5	/* after CERR-induced fault */
 
 #define	INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ehci-hub.c linux/drivers/usb/hcd/ehci-hub.c
--- v2.5.2/linux/drivers/usb/hcd/ehci-hub.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hcd/ehci-hub.c	Thu Jan 17 14:06:53 2002
@@ -82,11 +82,12 @@
 	for (i = 0; i < ports; i++) {
 		temp = readl (&ehci->regs->port_status [i]);
 		if (temp & PORT_OWNER) {
-			// get disconnected ports back if no companion driver
-			if (temp & PORT_CONNECT)
-				continue;
-			temp &= ~(PORT_OWNER|PORT_CSC);
-			writel (temp, &ehci->regs->port_status [i]);
+			/* don't report this in GetPortStatus */
+			if (temp & PORT_CSC) {
+				temp &= ~PORT_CSC;
+				writel (temp, &ehci->regs->port_status [i]);
+			}
+			continue;
 		}
 		if (!(temp & PORT_CONNECT))
 			ehci->reset_done [i] = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ehci-q.c linux/drivers/usb/hcd/ehci-q.c
--- v2.5.2/linux/drivers/usb/hcd/ehci-q.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hcd/ehci-q.c	Thu Jan 17 14:06:53 2002
@@ -883,11 +883,10 @@
 		/* can't get here without STS_ASS set */
 		if (ehci->hcd.state != USB_STATE_HALT) {
 			if (cmd & CMD_PSE)
-				writel (cmd & __constant_cpu_to_le32 (~CMD_ASE),
-					&ehci->regs->command);
+				writel (cmd & ~CMD_ASE, &ehci->regs->command);
 			else {
 				ehci_ready (ehci);
-				while (!(readl (&ehci->regs->status) & STS_ASS))
+				while (readl (&ehci->regs->status) & STS_ASS)
 					udelay (100);
 			}
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ehci-sched.c linux/drivers/usb/hcd/ehci-sched.c
--- v2.5.2/linux/drivers/usb/hcd/ehci-sched.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hcd/ehci-sched.c	Mon Jan 21 15:44:21 2002
@@ -381,7 +381,7 @@
 			vdbg ("qh %p usecs %d period %d starting frame %d.%d",
 				qh, qh->usecs, period, frame, uframe);
 			do {
-				if (unlikely ((long)ehci->pshadow [frame].ptr)) {
+				if (unlikely (ehci->pshadow [frame].ptr != 0)) {
 // FIXME -- just link to the end, before any qh with a shorter period,
 // AND handle it already being (implicitly) linked into this frame
 					BUG ();
@@ -630,7 +630,7 @@
 	if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
 			&& ehci->hcd.state != USB_STATE_HALT) {
 		int			i;
-		iso_packet_descriptor_t	*desc;
+		struct usb_iso_packet_descriptor	*desc;
 		struct ehci_itd		*first_itd = urb->hcpriv;
 
 		/* update status for this frame's transfers */
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ohci-dbg.c linux/drivers/usb/hcd/ohci-dbg.c
--- v2.5.2/linux/drivers/usb/hcd/ohci-dbg.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ohci-dbg.c	Mon Jan 21 15:44:21 2002
@@ -0,0 +1,236 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under GPL
+ * $Id: ohci-dbg.c,v 1.2 2002/01/19 00:15:45 dbrownell Exp $
+ */
+ 
+/*-------------------------------------------------------------------------*/
+ 
+#ifdef DEBUG
+
+#define pipestring(pipe) ({ char *temp; \
+	switch (usb_pipetype (pipe)) { \
+	case PIPE_CONTROL:	temp = "CTRL"; break; \
+	case PIPE_BULK:		temp = "BULK"; break; \
+	case PIPE_INTERRUPT:	temp = "INTR"; break; \
+	default: 		temp = "ISOC"; break; \
+	}; temp;})
+
+/* debug| print the main components of an URB     
+ * small: 0) header + data packets 1) just header
+ */
+static void urb_print (struct urb * urb, char * str, int small)
+{
+	unsigned int pipe= urb->pipe;
+	
+	if (!urb->dev || !urb->dev->bus) {
+		dbg("%s URB: no dev", str);
+		return;
+	}
+	
+#ifndef	OHCI_VERBOSE_DEBUG
+	if (urb->status != 0)
+#endif
+	dbg("%s:[%4x] dev:%d,ep=%d-%c,%s,flags:%4x,len:%d/%d,stat:%d", 
+		    str,
+		    usb_get_current_frame_number (urb->dev), 
+		    usb_pipedevice (pipe),
+		    usb_pipeendpoint (pipe), 
+		    usb_pipeout (pipe)? 'O': 'I',
+		    pipestring (pipe),
+		    urb->transfer_flags, 
+		    urb->actual_length, 
+		    urb->transfer_buffer_length,
+		    urb->status);
+
+#ifdef	OHCI_VERBOSE_DEBUG
+	if (!small) {
+		int i, len;
+
+		if (usb_pipecontrol (pipe)) {
+			printk (KERN_DEBUG __FILE__ ": cmd(8):");
+			for (i = 0; i < 8 ; i++) 
+				printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
+			printk ("\n");
+		}
+		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+			printk (KERN_DEBUG __FILE__ ": data(%d/%d):", 
+				urb->actual_length, 
+				urb->transfer_buffer_length);
+			len = usb_pipeout (pipe)? 
+						urb->transfer_buffer_length: urb->actual_length;
+			for (i = 0; i < 16 && i < len; i++) 
+				printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
+			printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+		}
+	} 
+#endif
+}
+
+static inline struct ed *
+dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma);
+
+/* print non-empty branches of the periodic ed tree */
+void ep_print_int_eds (struct ohci_hcd *ohci, char * str)
+{
+	int i, j;
+	 __u32 * ed_p;
+	for (i= 0; i < 32; i++) {
+		j = 5;
+		ed_p = &(ohci->hcca->int_table [i]);
+		if (*ed_p == 0)
+		    continue;
+		printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):",
+				str, i, i);
+		while (*ed_p != 0 && j--) {
+			struct ed *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
+			printk (" ed: %4x;", ed->hwINFO);
+			ed_p = &ed->hwNextED;
+		}
+		printk ("\n");
+	}
+}
+
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+	dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+		label,
+		mask,
+		(mask & OHCI_INTR_MIE) ? " MIE" : "",
+		(mask & OHCI_INTR_OC) ? " OC" : "",
+		(mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+		(mask & OHCI_INTR_FNO) ? " FNO" : "",
+		(mask & OHCI_INTR_UE) ? " UE" : "",
+		(mask & OHCI_INTR_RD) ? " RD" : "",
+		(mask & OHCI_INTR_SF) ? " SF" : "",
+		(mask & OHCI_INTR_WDH) ? " WDH" : "",
+		(mask & OHCI_INTR_SO) ? " SO" : ""
+		);
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+	if (value)
+		dbg ("%s %08x", label, value);
+}
+
+static char *hcfs2string (int state)
+{
+	switch (state) {
+		case OHCI_USB_RESET:	return "reset";
+		case OHCI_USB_RESUME:	return "resume";
+		case OHCI_USB_OPER:	return "operational";
+		case OHCI_USB_SUSPEND:	return "suspend";
+	}
+	return "?";
+}
+
+// dump control and status registers
+static void ohci_dump_status (struct ohci_hcd *controller)
+{
+	struct ohci_regs	*regs = controller->regs;
+	__u32			temp;
+
+	temp = readl (&regs->revision) & 0xff;
+	if (temp != 0x10)
+		dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+	temp = readl (&regs->control);
+	dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+		(temp & OHCI_CTRL_RWE) ? " RWE" : "",
+		(temp & OHCI_CTRL_RWC) ? " RWC" : "",
+		(temp & OHCI_CTRL_IR) ? " IR" : "",
+		hcfs2string (temp & OHCI_CTRL_HCFS),
+		(temp & OHCI_CTRL_BLE) ? " BLE" : "",
+		(temp & OHCI_CTRL_CLE) ? " CLE" : "",
+		(temp & OHCI_CTRL_IE) ? " IE" : "",
+		(temp & OHCI_CTRL_PLE) ? " PLE" : "",
+		temp & OHCI_CTRL_CBSR
+		);
+
+	temp = readl (&regs->cmdstatus);
+	dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+		(temp & OHCI_SOC) >> 16,
+		(temp & OHCI_OCR) ? " OCR" : "",
+		(temp & OHCI_BLF) ? " BLF" : "",
+		(temp & OHCI_CLF) ? " CLF" : "",
+		(temp & OHCI_HCR) ? " HCR" : ""
+		);
+
+	ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+	ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+	// intrdisable always same as intrenable
+	// ohci_dump_intr_mask ("intrdisable", readl (&regs->intrdisable));
+
+	maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+	maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+	maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+	maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+	maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+	maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (struct ohci_hcd *controller, int verbose)
+{
+	__u32			temp, ndp, i;
+
+	temp = roothub_a (controller);
+	ndp = (temp & RH_A_NDP);
+
+	if (verbose) {
+		dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+			((temp & RH_A_POTPGT) >> 24) & 0xff,
+			(temp & RH_A_NOCP) ? " NOCP" : "",
+			(temp & RH_A_OCPM) ? " OCPM" : "",
+			(temp & RH_A_DT) ? " DT" : "",
+			(temp & RH_A_NPS) ? " NPS" : "",
+			(temp & RH_A_PSM) ? " PSM" : "",
+			ndp
+			);
+		temp = roothub_b (controller);
+		dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+			temp,
+			(temp & RH_B_PPCM) >> 16,
+			(temp & RH_B_DR)
+			);
+		temp = roothub_status (controller);
+		dbg ("roothub.status: %08x%s%s%s%s%s%s",
+			temp,
+			(temp & RH_HS_CRWE) ? " CRWE" : "",
+			(temp & RH_HS_OCIC) ? " OCIC" : "",
+			(temp & RH_HS_LPSC) ? " LPSC" : "",
+			(temp & RH_HS_DRWE) ? " DRWE" : "",
+			(temp & RH_HS_OCI) ? " OCI" : "",
+			(temp & RH_HS_LPS) ? " LPS" : ""
+			);
+	}
+	
+	for (i = 0; i < ndp; i++) {
+		temp = roothub_portstatus (controller, i);
+		dbg_port (controller, "", i, temp);
+	}
+}
+
+static void ohci_dump (struct ohci_hcd *controller, int verbose)
+{
+	dbg ("OHCI controller %s state", controller->hcd.bus_name);
+
+	// dumps some of the state we know about
+	ohci_dump_status (controller);
+	if (verbose)
+		ep_print_int_eds (controller, "hcca");
+	dbg ("hcca frame #%04x", controller->hcca->frame_no);
+	ohci_dump_roothub (controller, 1);
+}
+
+
+#endif
+
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ohci-hcd.c linux/drivers/usb/hcd/ohci-hcd.c
--- v2.5.2/linux/drivers/usb/hcd/ohci-hcd.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ohci-hcd.c	Mon Jan 21 15:44:21 2002
@@ -0,0 +1,973 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * [ Initialisation is based on Linus'  ]
+ * [ uhci code and gregs ohci fragments ]
+ * [ (C) Copyright 1999 Linus Torvalds  ]
+ * [ (C) Copyright 1999 Gregory P. Smith]
+ * 
+ * 
+ * History:
+ * 
+ * 2002/01/18 package as a patch for 2.5.3; this should match the
+ *	2.4.17 kernel modulo some bugs being fixed.
+ *
+ * 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes
+ *	from post-2.4.5 patches.
+ * 2001/09/20 USB_ZERO_PACKET support; hcca_dma portability, OPTi warning
+ * 2001/09/07 match PCI PM changes, errnos from Linus' tree
+ * 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify;
+ *	pbook pci quirks gone (please fix pbook pci sw!) (db)
+ *
+ * 2001/04/08 Identify version on module load (gb)
+ * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
+ 	pci_map_single (db)
+ * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
+ * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
+ *
+ * 2000/09/26 fixed races in removing the private portion of the urb
+ * 2000/09/07 disable bulk and control lists when unlinking the last
+ *	endpoint descriptor in order to avoid unrecoverable errors on
+ *	the Lucent chips. (rwc@sgi)
+ * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
+ *	urb unlink probs, indentation fixes
+ * 2000/08/11 various oops fixes mostly affecting iso and cleanup from
+ *	device unplugs.
+ * 2000/06/28 use PCI hotplug framework, for better power management
+ *	and for Cardbus support (David Brownell)
+ * 2000/earlier:  fixes for NEC/Lucent chips; suspend/resume handling
+ *	when the controller loses power; handle UE; cleanup; ...
+ *
+ * v5.2 1999/12/07 URB 3rd preview, 
+ * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
+ * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume 
+ * 	i386: HUB, Keyboard, Mouse, Printer 
+ *
+ * v4.3 1999/10/27 multiple HCs, bulk_request
+ * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
+ * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
+ * v4.0 1999/08/18 
+ * v3.0 1999/06/25 
+ * v2.1 1999/05/09  code clean up
+ * v2.0 1999/05/04 
+ * v1.0 1999/04/27 initial release
+ *
+ * This file is licenced under GPL
+ * $Id: ohci-hcd.c,v 1.7 2002/01/19 00:20:56 dbrownell Exp $
+ */
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>  /* for in_interrupt () */
+
+#ifndef CONFIG_USB_DEBUG
+	#define CONFIG_USB_DEBUG	/* this is still experimental! */
+#endif
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "../hcd.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/pci-bridge.h>
+#ifndef CONFIG_PM
+#	define CONFIG_PM
+#endif
+#endif
+
+/*
+ * TO DO:
+ *
+ *	- "disabled" should be the hcd state
+ *	- bandwidth alloc to generic code
+ *	- lots more testing!!
+ */
+
+#define DRIVER_VERSION "$Revision: 1.7 $"
+#define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
+#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
+
+/*-------------------------------------------------------------------------*/
+
+#define OHCI_USE_NPS		// force NoPowerSwitching mode
+// #define OHCI_VERBOSE_DEBUG	/* not always helpful */
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define	OHCI_CONTROL_INIT \
+	 (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+#define OHCI_UNLINK_TIMEOUT	 (HZ / 10)
+
+/*-------------------------------------------------------------------------*/
+
+#include "ohci.h"
+
+#include "ohci-hub.c"
+#include "ohci-dbg.c"
+#include "ohci-mem.c"
+#include "ohci-q.c"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * queue up an urb for anything except the root hub
+ */
+static int ohci_urb_enqueue (
+	struct usb_hcd	*hcd,
+	struct urb	*urb,
+	int		mem_flags
+) {
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	struct ed	*ed;
+	urb_priv_t	*urb_priv;
+	unsigned int	pipe = urb->pipe;
+	int		i, size = 0;
+	unsigned long	flags;
+	int		bustime = 0;
+	
+#ifdef OHCI_VERBOSE_DEBUG
+	urb_print (urb, "SUB", usb_pipein (pipe));
+#endif
+	
+	/* every endpoint has a ed, locate and fill it */
+	if (! (ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) {
+		usb_dec_dev_use (urb->dev);	
+		return -ENOMEM;
+	}
+
+	/* for the private part of the URB we need the number of TDs (size) */
+	switch (usb_pipetype (pipe)) {
+		case PIPE_CONTROL:
+			/* 1 TD for setup, 1 for ACK, plus ... */
+			size = 2;
+			/* FALLTHROUGH */
+		case PIPE_BULK:
+			/* one TD for every 4096 Bytes (can be upto 8K) */
+			size += urb->transfer_buffer_length / 4096;
+			/* ... and for any remaining bytes ... */
+			if ((urb->transfer_buffer_length % 4096) != 0)
+				size++;
+			/* ... and maybe a zero length packet to wrap it up */
+			if (size == 0)
+				size++;
+			else if ((urb->transfer_flags & USB_ZERO_PACKET) != 0
+				&& (urb->transfer_buffer_length
+					% usb_maxpacket (urb->dev, pipe,
+						usb_pipeout (pipe))) != 0)
+				size++;
+			break;
+		case PIPE_ISOCHRONOUS: /* number of packets from URB */
+			size = urb->number_of_packets;
+			if (size <= 0) {
+				usb_dec_dev_use (urb->dev);	
+				return -EINVAL;
+			}
+			for (i = 0; i < urb->number_of_packets; i++) {
+  				urb->iso_frame_desc [i].actual_length = 0;
+  				urb->iso_frame_desc [i].status = -EXDEV;
+  			}
+			break;
+		case PIPE_INTERRUPT: /* one TD */
+			size = 1;
+			break;
+	}
+
+	/* allocate the private part of the URB */
+	urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
+			mem_flags);
+	if (!urb_priv) {
+		usb_dec_dev_use (urb->dev);	
+		return -ENOMEM;
+	}
+	memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
+	
+	/* fill the private part of the URB */
+	urb_priv->length = size;
+	urb_priv->ed = ed;	
+
+	/* allocate the TDs (updating hash chains) */
+	spin_lock_irqsave (&ohci->lock, flags);
+	for (i = 0; i < size; i++) { 
+		urb_priv->td [i] = td_alloc (ohci, SLAB_ATOMIC);
+		if (!urb_priv->td [i]) {
+			urb_priv->length = i;
+			urb_free_priv (ohci, urb_priv);
+			spin_unlock_irqrestore (&ohci->lock, flags);
+			usb_dec_dev_use (urb->dev);	
+			return -ENOMEM;
+		}
+	}	
+
+// FIXME:  much of this switch should be generic, move to hcd code ...
+
+	/* allocate and claim bandwidth if needed; ISO
+	 * needs start frame index if it was't provided.
+	 */
+	switch (usb_pipetype (pipe)) {
+		case PIPE_ISOCHRONOUS:
+			if (urb->transfer_flags & USB_ISO_ASAP) { 
+				urb->start_frame = ( (ed->state == ED_OPER)
+					? (ed->last_iso + 1)
+					: (le16_to_cpu (ohci->hcca->frame_no)
+						+ 10)) & 0xffff;
+			}	
+			/* FALLTHROUGH */
+		case PIPE_INTERRUPT:
+			if (urb->bandwidth == 0) {
+				bustime = usb_check_bandwidth (urb->dev, urb);
+			}
+			if (bustime < 0) {
+				urb_free_priv (ohci, urb_priv);
+				spin_unlock_irqrestore (&ohci->lock, flags);
+				usb_dec_dev_use (urb->dev);	
+				return bustime;
+			}
+			usb_claim_bandwidth (urb->dev, urb,
+				bustime, usb_pipeisoc (urb->pipe));
+	}
+
+	urb->hcpriv = urb_priv;
+
+	/* link the ed into a chain if is not already */
+	if (ed->state != ED_OPER)
+		ep_link (ohci, ed);
+
+	/* fill the TDs and link it to the ed */
+	td_submit_urb (urb);
+
+	spin_unlock_irqrestore (&ohci->lock, flags);
+
+	return 0;	
+}
+
+/*
+ * decouple the URB from the HC queues (TDs, urb_priv); it's
+ * already marked for deletion.  reporting is always done
+ * asynchronously, and we might be dealing with an urb that's
+ * almost completed anyway...
+ */
+static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	unsigned long		flags;
+	
+#ifdef DEBUG
+	urb_print (urb, "UNLINK", 1);
+#endif		  
+
+	if (!ohci->disabled) {
+		urb_priv_t  *urb_priv;
+
+		/* flag the urb's data for deletion in some upcoming
+		 * SF interrupt's delete list processing
+		 */
+		spin_lock_irqsave (&ohci->lock, flags);
+		urb_priv = urb->hcpriv;
+
+		if (!urb_priv || (urb_priv->state == URB_DEL)) {
+			spin_unlock_irqrestore (&ohci->lock, flags);
+			return 0;
+		}
+			
+		urb_priv->state = URB_DEL; 
+		ed_unlink (urb->dev, urb_priv->ed);
+		spin_unlock_irqrestore (&ohci->lock, flags);
+	} else {
+		/*
+		 * with HC dead, we won't respect hc queue pointers
+		 * any more ... just clean up every urb's memory.
+		 */
+		finish_urb (ohci, urb);
+	}	
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	struct hcd_dev		*dev = (struct hcd_dev *) udev->hcpriv;
+	int			i;
+	unsigned long		flags;
+
+	/* free any eds, and dummy tds, still hanging around */
+	spin_lock_irqsave (&ohci->lock, flags);
+	for (i = 0; i < 32; i++) {
+		struct ed	*ed = dev->ep [i];
+		struct td	*tdTailP;
+
+		if (!ed)
+			continue;
+
+		ed->state &= ~ED_URB_DEL;
+		if (ohci->disabled && ed->state == ED_OPER)
+			ed->state = ED_UNLINK;
+		switch (ed->state) {
+		case ED_NEW:
+			break;
+		case ED_UNLINK:
+			tdTailP = dma_to_td (ohci,
+				le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
+			td_free (ohci, tdTailP); /* free dummy td */
+			hash_free_ed (ohci, ed);
+			break;
+
+		case ED_OPER:
+		default:
+			err ("illegal ED %d state in free_config, %d",
+				i, ed->state);
+#ifdef DEBUG
+			BUG ();
+#endif
+		}
+		ed_free (ohci, ed);
+	}
+	spin_unlock_irqrestore (&ohci->lock, flags);
+}
+
+static int ohci_get_frame (struct usb_hcd *hcd)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+
+	dbg ("%s: ohci_get_frame", hcd->bus_name);
+	return le16_to_cpu (ohci->hcca->frame_no);
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (struct ohci_hcd *ohci)
+{
+	int timeout = 30;
+	int smm_timeout = 50; /* 0,5 sec */
+	 	
+	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+		writel (OHCI_INTR_OC, &ohci->regs->intrenable);
+		writel (OHCI_OCR, &ohci->regs->cmdstatus);
+		dbg ("USB HC TakeOver from SMM");
+		while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+			wait_ms (10);
+			if (--smm_timeout == 0) {
+				err ("USB HC TakeOver failed!");
+				return -1;
+			}
+		}
+	}	
+		
+	/* Disable HC interrupts */
+	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+	dbg ("USB HC reset_hc %s: ctrl = 0x%x ;",
+		ohci->hcd.bus_name,
+		readl (&ohci->regs->control));
+
+  	/* Reset USB (needed by some controllers) */
+	writel (0, &ohci->regs->control);
+      	
+	/* HC Reset requires max 10 ms delay */
+	writel (OHCI_HCR,  &ohci->regs->cmdstatus);
+	while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+		if (--timeout == 0) {
+			err ("USB HC reset timed out!");
+			return -1;
+		}	
+		udelay (1);
+	}	 
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts 
+ * connect the virtual root hub
+ */
+static int hc_start (struct ohci_hcd *ohci)
+{
+  	__u32			mask;
+  	unsigned int		fminterval;
+  	struct usb_device	*udev;
+	
+	spin_lock_init (&ohci->lock);
+	ohci->disabled = 1;
+	ohci->sleeping = 0;
+
+	/* Tell the controller where the control and bulk lists are
+	 * The lists are empty now. */
+	 
+	writel (0, &ohci->regs->ed_controlhead);
+	writel (0, &ohci->regs->ed_bulkhead);
+	
+	/* a reset clears this */
+	writel ((u32) ohci->hcca_dma, &ohci->regs->hcca);
+   
+  	fminterval = 0x2edf;
+	writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+	fminterval |= ((((fminterval - 210) * 6) / 7) << 16); 
+	writel (fminterval, &ohci->regs->fminterval);	
+	writel (0x628, &ohci->regs->lsthresh);
+
+ 	/* start controller operations */
+ 	ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+	ohci->disabled = 0;
+ 	writel (ohci->hc_control, &ohci->regs->control);
+ 
+	/* Choose the interrupts we care about now, others later on demand */
+	mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+	writel (mask, &ohci->regs->intrstatus);
+	writel (mask, &ohci->regs->intrenable);
+
+#ifdef	OHCI_USE_NPS
+	/* required for AMD-756 and some Mac platforms */
+	writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+		&ohci->regs->roothub.a);
+	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif	/* OHCI_USE_NPS */
+
+	// POTPGT delay is bits 24-31, in 2 ms units.
+	mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+ 
+	/* connect the virtual root hub */
+	ohci->hcd.bus->root_hub = udev = usb_alloc_dev (NULL, ohci->hcd.bus);
+	ohci->hcd.state = USB_STATE_READY;
+	if (!udev) {
+	    ohci->disabled = 1;
+// FIXME cleanup
+	    return -ENOMEM;
+	}
+
+	usb_connect (udev);
+	udev->speed = USB_SPEED_FULL;
+	if (usb_new_device (udev) != 0) {
+		usb_free_dev (udev); 
+		ohci->disabled = 1;
+// FIXME cleanup
+		return -ENODEV;
+	}
+	
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static void ohci_irq (struct usb_hcd *hcd)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	struct ohci_regs	*regs = ohci->regs;
+ 	int			ints; 
+
+	if ((ohci->hcca->done_head != 0)
+			&& ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
+		ints =  OHCI_INTR_WDH;
+	} else if ((ints = (readl (&regs->intrstatus)
+			& readl (&regs->intrenable))) == 0) {
+		return;
+	} 
+
+	// dbg ("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
+
+	if (ints & OHCI_INTR_UE) {
+		ohci->disabled++;
+		err ("OHCI Unrecoverable Error, %s disabled", hcd->bus_name);
+		// e.g. due to PCI Master/Target Abort
+
+#ifdef	DEBUG
+		ohci_dump (ohci, 1);
+#endif
+		hc_reset (ohci);
+	}
+  
+	if (ints & OHCI_INTR_WDH) {
+		writel (OHCI_INTR_WDH, &regs->intrdisable);	
+		dl_done_list (ohci, dl_reverse_done_list (ohci));
+		writel (OHCI_INTR_WDH, &regs->intrenable); 
+	}
+  
+	if (ints & OHCI_INTR_SO) {
+		dbg ("USB Schedule overrun");
+		writel (OHCI_INTR_SO, &regs->intrenable); 	 
+	}
+
+	// FIXME:  this assumes SOF (1/ms) interrupts don't get lost...
+	if (ints & OHCI_INTR_SF) { 
+		unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1;
+		writel (OHCI_INTR_SF, &regs->intrdisable);	
+		if (ohci->ed_rm_list [!frame] != NULL) {
+			dl_del_list (ohci, !frame);
+		}
+		if (ohci->ed_rm_list [frame] != NULL)
+			writel (OHCI_INTR_SF, &regs->intrenable);	
+	}
+
+	writel (ints, &regs->intrstatus);
+	writel (OHCI_INTR_MIE, &regs->intrenable);	
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void ohci_stop (struct usb_hcd *hcd)
+{	
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+
+	dbg ("%s: stop %s controller%s",
+		hcd->bus_name,
+		hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
+		ohci->disabled ? " (disabled)" : ""
+		);
+#ifdef	DEBUG
+	ohci_dump (ohci, 1);
+#endif
+
+	if (!ohci->disabled)
+		hc_reset (ohci);
+	
+	ohci_mem_cleanup (ohci);
+
+#ifdef CONFIG_PCI
+	pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca,
+		ohci->hcca, ohci->hcca_dma);
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ret;
+
+#ifdef CONFIG_PCI
+	if (hcd->pdev) {
+		ohci->hcca = pci_alloc_consistent (hcd->pdev,
+				sizeof *ohci->hcca, &ohci->hcca_dma);
+		if (!ohci->hcca)
+			return -ENOMEM;
+
+		/* AMD 756, for most chips (early revs), corrupts register
+		 * values on read ... so enable the vendor workaround.
+		 */
+		if (hcd->pdev->vendor == 0x1022
+				&& hcd->pdev->device == 0x740c) {
+			ohci->flags = OHCI_QUIRK_AMD756;
+			info ("%s: AMD756 erratum 4 workaround",
+				hcd->bus_name);
+		}
+
+		/* Apple's OHCI driver has a lot of bizarre workarounds
+		 * for this chip.  Evidently control and bulk lists
+		 * can get confused.  (B&W G3 models, and ...)
+		 */
+		else if (hcd->pdev->vendor == 0x1045
+				&& hcd->pdev->device == 0xc861) {
+			info ("%s: WARNING: OPTi workarounds unavailable",
+				hcd->bus_name);
+		}
+	}
+#else
+#	error "where's hcca coming from?"
+#endif /* CONFIG_PCI */
+
+        memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+	if ((ret = ohci_mem_init (ohci)) < 0) {
+		ohci_stop (hcd);
+		return ret;
+	}
+	ohci->regs = hcd->regs;
+
+	if (hc_reset (ohci) < 0) {
+		ohci_stop (hcd);
+		return -ENODEV;
+	}
+
+	if (hc_start (ohci) < 0) {
+		err ("can't start %s", ohci->hcd.bus_name);
+		ohci_stop (hcd);
+		return -EBUSY;
+	}
+
+#ifdef	DEBUG
+	ohci_dump (ohci, 1);
+#endif
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_PM
+
+static int ohci_suspend (struct usb_hcd *hcd, u32 state)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	unsigned long		flags;
+	u16			cmd;
+
+	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
+		dbg ("can't suspend %s (state is %s)", hcd->bus_name,
+			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
+		return -EIO;
+	}
+
+	/* act as if usb suspend can always be used */
+	dbg ("%s: suspend to %d", hcd->bus_name, state);
+	ohci->sleeping = 1;
+
+	/* First stop processing */
+  	spin_lock_irqsave (&ohci->lock, flags);
+	ohci->hc_control &=
+		~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
+	writel (ohci->hc_control, &ohci->regs->control);
+	writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+	(void) readl (&ohci->regs->intrstatus);
+  	spin_unlock_irqrestore (&ohci->lock, flags);
+
+	/* Wait a frame or two */
+	mdelay (1);
+	if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
+		mdelay (1);
+		
+ #ifdef CONFIG_PMAC_PBOOK
+	if (_machine == _MACH_Pmac)
+		disable_irq (ohci->irq);
+ 	/* else, 2.4 assumes shared irqs -- don't disable */
+ #endif
+
+	/* Enable remote wakeup */
+	writel (readl (&ohci->regs->intrenable) | OHCI_INTR_RD,
+		&ohci->regs->intrenable);
+
+	/* Suspend chip and let things settle down a bit */
+ 	ohci->hc_control = OHCI_USB_SUSPEND;
+ 	writel (ohci->hc_control, &ohci->regs->control);
+	(void) readl (&ohci->regs->control);
+	mdelay (500); /* No schedule here ! */
+
+	switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
+		case OHCI_USB_RESET:
+			dbg ("%s suspend->reset ?", hcd->bus_name);
+			break;
+		case OHCI_USB_RESUME:
+			dbg ("%s suspend->resume ?", hcd->bus_name);
+			break;
+		case OHCI_USB_OPER:
+			dbg ("%s suspend->operational ?", hcd->bus_name);
+			break;
+		case OHCI_USB_SUSPEND:
+			dbg ("%s suspended", hcd->bus_name);
+			break;
+	}
+
+	/* In some rare situations, Apple's OHCI have happily trashed
+	 * memory during sleep. We disable its bus master bit during
+	 * suspend
+	 */
+	pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd);
+	cmd &= ~PCI_COMMAND_MASTER;
+	pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd);
+#ifdef CONFIG_PMAC_PBOOK
+	{
+	   	struct device_node	*of_node;
+ 
+		/* Disable USB PAD & cell clock */
+		of_node = pci_device_to_OF_node (hcd->pdev);
+		if (of_node)
+			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
+	}
+#endif
+	return 0;
+}
+
+
+// FIXME:  this restart logic should be generic,
+// and handle full hcd state cleanup
+
+/* controller died; cleanup debris, then restart */
+/* must not be called from interrupt context */
+
+static int hc_restart (struct ohci_hcd *ohci)
+{
+	int temp;
+	int i;
+
+	ohci->disabled = 1;
+	ohci->sleeping = 0;
+	if (ohci->hcd.bus->root_hub)
+		usb_disconnect (&ohci->hcd.bus->root_hub);
+	
+	/* empty the interrupt branches */
+	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load [i] = 0;
+	for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0;
+	
+	/* no EDs to remove */
+	ohci->ed_rm_list [0] = NULL;
+	ohci->ed_rm_list [1] = NULL;
+
+	/* empty control and bulk lists */	 
+	ohci->ed_isotail     = NULL;
+	ohci->ed_controltail = NULL;
+	ohci->ed_bulktail    = NULL;
+
+	if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
+		err ("can't restart %s, %d", ohci->hcd.bus_name, temp);
+		return temp;
+	} else
+		dbg ("restart %s completed", ohci->hcd.bus_name);
+	return 0;
+}
+
+static int ohci_resume (struct usb_hcd *hcd)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	int			temp;
+	int			retval = 0;
+	unsigned long		flags;
+
+#ifdef CONFIG_PMAC_PBOOK
+	{
+		struct device_node *of_node;
+
+		/* Re-enable USB PAD & cell clock */
+		of_node = pci_device_to_OF_node (hcd->pdev);
+		if (of_node)
+			pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
+	}
+#endif
+	/* did we suspend, or were we powered off? */
+	ohci->hc_control = readl (&ohci->regs->control);
+	temp = ohci->hc_control & OHCI_CTRL_HCFS;
+
+#ifdef DEBUG
+	/* the registers may look crazy here */
+	ohci_dump_status (ohci);
+#endif
+
+	/* Re-enable bus mastering */
+	pci_set_master (ohci->hcd.pdev);
+	
+	switch (temp) {
+
+	case OHCI_USB_RESET:	// lost power
+		info ("USB restart: %s", hcd->bus_name);
+		retval = hc_restart (ohci);
+		break;
+
+	case OHCI_USB_SUSPEND:	// host wakeup
+	case OHCI_USB_RESUME:	// remote wakeup
+		info ("USB continue: %s from %s wakeup", hcd->bus_name,
+			 (temp == OHCI_USB_SUSPEND)
+				? "host" : "remote");
+		ohci->hc_control = OHCI_USB_RESUME;
+		writel (ohci->hc_control, &ohci->regs->control);
+		(void) readl (&ohci->regs->control);
+		mdelay (20); /* no schedule here ! */
+		/* Some controllers (lucent) need a longer delay here */
+		mdelay (15);
+
+		temp = readl (&ohci->regs->control);
+		temp = ohci->hc_control & OHCI_CTRL_HCFS;
+		if (temp != OHCI_USB_RESUME) {
+			err ("controller %s won't resume", hcd->bus_name);
+			ohci->disabled = 1;
+			retval = -EIO;
+			break;
+		}
+
+		/* Some chips likes being resumed first */
+		writel (OHCI_USB_OPER, &ohci->regs->control);
+		(void) readl (&ohci->regs->control);
+		mdelay (3);
+
+		/* Then re-enable operations */
+		spin_lock_irqsave (&ohci->lock, flags);
+		ohci->disabled = 0;
+		ohci->sleeping = 0;
+		ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+		if (!ohci->ed_rm_list [0] && !ohci->ed_rm_list [1]) {
+			if (ohci->ed_controltail)
+				ohci->hc_control |= OHCI_CTRL_CLE;
+			if (ohci->ed_bulktail)
+				ohci->hc_control |= OHCI_CTRL_BLE;
+		}
+		hcd->state = USB_STATE_READY;
+		writel (ohci->hc_control, &ohci->regs->control);
+
+		/* trigger a start-frame interrupt (why?) */
+		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+
+		/* Check for a pending done list */
+		writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);	
+		(void) readl (&ohci->regs->intrdisable);
+		spin_unlock_irqrestore (&ohci->lock, flags);
+
+ #ifdef CONFIG_PMAC_PBOOK
+		if (_machine == _MACH_Pmac)
+			enable_irq (ohci->irq);
+ #endif
+		if (ohci->hcca->done_head)
+			dl_done_list (ohci, dl_reverse_done_list (ohci));
+		writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
+
+//		writel (OHCI_BLF, &ohci->regs->cmdstatus);
+//		writel (OHCI_CLF, &ohci->regs->cmdstatus);
+ohci_dump_status (ohci);
+dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled);
+		break;
+
+	default:
+		warn ("odd PCI resume for %s", hcd->bus_name);
+	}
+	return retval;
+}
+
+#endif	/* CONFIG_PM */
+
+
+/*-------------------------------------------------------------------------*/
+
+static const char	hcd_name [] = "ohci-hcd";
+
+static const struct hc_driver ohci_driver = {
+	description:		hcd_name,
+
+	/*
+	 * generic hardware linkage
+	 */
+	irq:			ohci_irq,
+	flags:			HCD_MEMORY | HCD_USB11,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	start:			ohci_start,
+#ifdef	CONFIG_PM
+	suspend:		ohci_suspend,
+	resume:			ohci_resume,
+#endif
+	stop:			ohci_stop,
+
+	/*
+	 * memory lifecycle (except per-request)
+	 */
+	hcd_alloc:		ohci_hcd_alloc,
+	hcd_free:		ohci_hcd_free,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	urb_enqueue:		ohci_urb_enqueue,
+	urb_dequeue:		ohci_urb_dequeue,
+	free_config:		ohci_free_config,
+
+	/*
+	 * scheduling support
+	 */
+	get_frame_number:	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	hub_status_data:	ohci_hub_status_data,
+	hub_control:		ohci_hub_control,
+};
+
+#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_LICENSE ("GPL");
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PCI
+
+/* There do exist non-PCI implementations of OHCI ...
+ * Examples include the SA-1111 (ARM) and some MIPS
+ * and related hardware.
+ */
+
+static const struct pci_device_id __devinitdata pci_ids [] = { {
+
+	/* handle any USB OHCI controller */
+	class:		(PCI_CLASS_SERIAL_USB << 8) | 0x10,
+	class_mask:	~0,
+	driver_data:	(unsigned long) &ohci_driver,
+
+	/* no matter who makes it */
+	vendor:		PCI_ANY_ID,
+	device:		PCI_ANY_ID,
+	subvendor:	PCI_ANY_ID,
+	subdevice:	PCI_ANY_ID,
+
+	}, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver ohci_pci_driver = {
+	name:		(char *) hcd_name,
+	id_table:	pci_ids,
+
+	probe:		usb_hcd_pci_probe,
+	remove:		usb_hcd_pci_remove,
+
+#ifdef	CONFIG_PM
+	suspend:	usb_hcd_pci_suspend,
+	resume:		usb_hcd_pci_resume,
+#endif
+};
+
+ 
+static int __init ohci_hcd_init (void) 
+{
+	dbg (DRIVER_INFO);
+	dbg ("block sizes: ed %d td %d",
+		sizeof (struct ed), sizeof (struct td));
+	return pci_module_init (&ohci_pci_driver);
+}
+module_init (ohci_hcd_init);
+
+/*-------------------------------------------------------------------------*/
+
+static void __exit ohci_hcd_cleanup (void) 
+{	
+	pci_unregister_driver (&ohci_pci_driver);
+}
+module_exit (ohci_hcd_cleanup);
+
+#endif /* CONFIG_PCI */
+
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ohci-hub.c linux/drivers/usb/hcd/ohci-hub.c
--- v2.5.2/linux/drivers/usb/hcd/ohci-hub.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ohci-hub.c	Mon Jan 21 15:44:21 2002
@@ -0,0 +1,267 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under GPL
+ * $Id: ohci-hub.c,v 1.2 2002/01/19 00:21:49 dbrownell Exp $
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * OHCI Root Hub ... the nonsharable stuff
+ *
+ * Registers don't need cpu_to_le32, that happens transparently
+ */
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect.  AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define read_roothub(hc, register, mask) ({ \
+	u32 temp = readl (&hc->regs->roothub.register); \
+	if (hc->flags & OHCI_QUIRK_AMD756) \
+		while (temp & mask) \
+			temp = readl (&hc->regs->roothub.register); \
+	temp; })
+
+static u32 roothub_a (struct ohci_hcd *hc)
+	{ return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci_hcd *hc)
+	{ return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci_hcd *hc)
+	{ return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
+	{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+/*-------------------------------------------------------------------------*/
+
+#define dbg_port(hc,label,num,value) \
+	dbg ("%s: %s roothub.portstatus [%d] " \
+		"= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s", \
+		hc->hcd.bus_name, label, num, temp, \
+		(temp & RH_PS_PRSC) ? " PRSC" : "", \
+		(temp & RH_PS_OCIC) ? " OCIC" : "", \
+		(temp & RH_PS_PSSC) ? " PSSC" : "", \
+		(temp & RH_PS_PESC) ? " PESC" : "", \
+		(temp & RH_PS_CSC) ? " CSC" : "", \
+ 		\
+		(temp & RH_PS_LSDA) ? " LSDA" : "", \
+		(temp & RH_PS_PPS) ? " PPS" : "", \
+		(temp & RH_PS_PRS) ? " PRS" : "", \
+		(temp & RH_PS_POCI) ? " POCI" : "", \
+		(temp & RH_PS_PSS) ? " PSS" : "", \
+ 		\
+		(temp & RH_PS_PES) ? " PES" : "", \
+		(temp & RH_PS_CCS) ? " CCS" : "" \
+		);
+
+
+/*-------------------------------------------------------------------------*/
+
+/* build "status change" packet (one or two bytes) from HC registers */
+
+static int
+ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ports, i, changed = 0, length = 1;
+
+	ports = roothub_a (ohci) & RH_A_NDP; 
+	if (ports > MAX_ROOT_PORTS) {
+		err ("%s: bogus NDP=%d", hcd->bus_name, ports);
+		err ("rereads as NDP=%d",
+			readl (&ohci->regs->roothub.a) & RH_A_NDP);
+		/* retry later; "should not happen" */
+		return 0;
+	}
+
+	/* init status */
+	if (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC))
+		buf [0] = changed = 1;
+	else
+		buf [0] = 0;
+	if (ports > 7) {
+		buf [1] = 0;
+		length++;
+	}
+
+	/* look at each port */
+	for (i = 0; i < ports; i++) {
+		u32	status = roothub_portstatus (ohci, i);
+
+		status &= RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
+				| RH_PS_OCIC | RH_PS_PRSC;
+		if (status) {
+			changed = 1;
+			set_bit (i + 1, buf);
+		}
+	}
+	return changed ? length : 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+ohci_hub_descriptor (
+	struct ohci_hcd			*ohci,
+	struct usb_hub_descriptor	*desc
+) {
+	u32		rh = roothub_a (ohci);
+	int		ports = rh & RH_A_NDP; 
+	u16		temp;
+
+	desc->bDescriptorType = 0x29;
+	desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24;
+	desc->bHubContrCurrent = 0;
+
+	desc->bNbrPorts = ports;
+	temp = 1 + (ports / 8);
+	desc->bDescLength = 7 + 2 * temp;
+
+	temp = 0;
+	if (rh & RH_A_PSM) 		/* per-port power switching? */
+	    temp |= 0x0001;
+	if (rh & RH_A_NOCP)		/* no overcurrent reporting? */
+	    temp |= 0x0010;
+	else if (rh & RH_A_OCPM)	/* per-port overcurrent reporting? */
+	    temp |= 0x0008;
+	desc->wHubCharacteristics = cpu_to_le16 (temp);
+
+	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+	rh = roothub_b (ohci);
+	desc->bitmap [0] = rh & RH_B_DR;
+	if (ports > 7) {
+		desc->bitmap [1] = (rh & RH_B_DR) >> 8;
+		desc->bitmap [2] = desc->bitmap [3] = 0xff;
+	} else
+		desc->bitmap [1] = 0xff;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hub_control (
+	struct usb_hcd	*hcd,
+	u16		typeReq,
+	u16		wValue,
+	u16		wIndex,
+	char		*buf,
+	u16		wLength
+) {
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ports;
+	u32		temp;
+	int		retval = 0;
+
+	// if (port request)
+		ports = roothub_a (ohci) & RH_A_NDP; 
+	switch (typeReq) {
+	case ClearHubFeature:
+		switch (wValue) {
+		case C_HUB_OVER_CURRENT:
+			writel (RH_HS_OCIC, &ohci->regs->roothub.status);
+		case C_HUB_LOCAL_POWER:
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case ClearPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			temp = RH_PS_CCS;
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			temp = RH_PS_PESC;
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+			temp = RH_PS_POCI;
+			break;
+		case USB_PORT_FEAT_C_SUSPEND:
+			temp = RH_PS_PSSC;
+			break;
+		case USB_PORT_FEAT_POWER:
+			temp = RH_PS_LSDA;
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			temp = RH_PS_CSC;
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			temp = RH_PS_OCIC;
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			temp = RH_PS_PRSC;
+			break;
+		default:
+			goto error;
+		}
+		writel (temp, &ohci->regs->roothub.portstatus [wIndex]);
+		// readl (&ohci->regs->roothub.portstatus [wIndex]);
+		break;
+	case GetHubDescriptor:
+		ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf);
+		break;
+	case GetHubStatus:
+		temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE);
+		*(u32 *) buf = cpu_to_le32 (temp);
+		break;
+	case GetPortStatus:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = roothub_portstatus (ohci, wIndex);
+		*(u32 *) buf = cpu_to_le32 (temp);
+
+#ifndef	OHCI_VERBOSE_DEBUG
+	if (*(u16*)(buf+2))	/* only if wPortChange is interesting */
+#endif
+		dbg_port (ohci, "GetStatus", wIndex + 1, temp);
+		break;
+	case SetHubFeature:
+		switch (wValue) {
+		case C_HUB_OVER_CURRENT:
+			// FIXME:  this can be cleared, yes?
+		case C_HUB_LOCAL_POWER:
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case SetPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			writel (RH_PS_PSS,
+				&ohci->regs->roothub.portstatus [wIndex]);
+			break;
+		case USB_PORT_FEAT_POWER:
+			writel (RH_PS_PPS,
+				&ohci->regs->roothub.portstatus [wIndex]);
+			break;
+		case USB_PORT_FEAT_RESET:
+			temp = readl (&ohci->regs->roothub.portstatus [wIndex]);
+			if (temp & RH_PS_CCS)
+				writel (RH_PS_PRS,
+				    &ohci->regs->roothub.portstatus [wIndex]);
+			break;
+		default:
+			goto error;
+		}
+		break;
+
+	default:
+error:
+		/* "protocol stall" on error */
+		retval = -EPIPE;
+	}
+	return retval;
+}
+
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ohci-mem.c linux/drivers/usb/hcd/ohci-mem.c
--- v2.5.2/linux/drivers/usb/hcd/ohci-mem.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ohci-mem.c	Mon Jan 21 15:44:21 2002
@@ -0,0 +1,251 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under GPL
+ * $Id: ohci-mem.c,v 1.2 2002/01/19 00:22:13 dbrownell Exp $
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * There's basically three types of memory:
+ *	- data used only by the HCD ... kmalloc is fine
+ *	- async and periodic schedules, shared by HC and HCD ... these
+ *	  need to use pci_pool or pci_alloc_consistent
+ *	- driver buffers, read/written by HC ... single shot DMA mapped 
+ *
+ * There's also PCI "register" data, which is memory mapped.
+ * No memory seen by this driver is pagable.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_hcd *ohci_hcd_alloc (void)
+{
+	struct ohci_hcd *ohci;
+
+	ohci = (struct ohci_hcd *) kmalloc (sizeof *ohci, GFP_KERNEL);
+	if (ohci != 0) {
+		memset (ohci, 0, sizeof (struct ohci_hcd));
+		return &ohci->hcd;
+	}
+	return 0;
+}
+
+static void ohci_hcd_free (struct usb_hcd *hcd)
+{
+	kfree (hcd_to_ohci (hcd));
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#	define OHCI_MEM_FLAGS	SLAB_POISON
+#else
+#	define OHCI_MEM_FLAGS	0
+#endif
+ 
+#ifndef CONFIG_PCI
+#	error "usb-ohci currently requires PCI-based controllers"
+	/* to support non-PCI OHCIs, you need custom bus/mem/... glue */
+#endif
+
+
+/* Recover a TD/ED using its collision chain */
+static inline void *
+dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
+{
+	struct hash_t * scan = entry->head;
+	while (scan && scan->dma != dma)
+		scan = scan->next;
+	return scan->virt;
+}
+
+static inline struct ed *
+dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma)
+{
+	return (struct ed *) dma_to_ed_td(&(hc->ed_hash [ED_HASH_FUNC(ed_dma)]),
+				      ed_dma);
+}
+
+static inline struct td *
+dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
+{
+	return (struct td *) dma_to_ed_td(&(hc->td_hash [TD_HASH_FUNC(td_dma)]),
+				      td_dma);
+}
+
+// FIXME:  when updating the hashtables this way, mem_flags is unusable...
+
+/* Add a hash entry for a TD/ED; return true on success */
+static int
+hash_add_ed_td (
+	struct hash_list_t *entry,
+	void *virt,
+	dma_addr_t dma,
+	int mem_flags
+)
+{
+	struct hash_t * scan;
+	
+	scan = (struct hash_t *) kmalloc (sizeof *scan, mem_flags);
+	if (!scan)
+		return 0;
+	
+	if (!entry->tail) {
+		entry->head = entry->tail = scan;
+	} else {
+		entry->tail->next = scan;
+		entry->tail = scan;
+	}
+	
+	scan->virt = virt;
+	scan->dma = dma;
+	scan->next = NULL;
+	return 1;
+}
+
+static inline int
+hash_add_ed (struct ohci_hcd *hc, struct ed *ed, int mem_flags)
+{
+	return hash_add_ed_td (&(hc->ed_hash [ED_HASH_FUNC (ed->dma)]),
+			ed, ed->dma, mem_flags);
+}
+
+static inline int
+hash_add_td (struct ohci_hcd *hc, struct td *td, int mem_flags)
+{
+	return hash_add_ed_td (&(hc->td_hash [TD_HASH_FUNC (td->td_dma)]),
+			td, td->td_dma, mem_flags);
+}
+
+
+static void
+hash_free_ed_td (struct hash_list_t *entry, void *virt)
+{
+	struct hash_t *scan, *prev;
+	scan = prev = entry->head;
+
+	// Find and unlink hash entry
+	while (scan && scan->virt != virt) {
+		prev = scan;
+		scan = scan->next;
+	}
+	if (scan) {
+		if (scan == entry->head) {
+			if (entry->head == entry->tail)
+				entry->head = entry->tail = NULL;
+			else
+				entry->head = scan->next;
+		} else if (scan == entry->tail) {
+			entry->tail = prev;
+			prev->next = NULL;
+		} else
+			prev->next = scan->next;
+		kfree(scan);
+	}
+}
+
+static inline void
+hash_free_ed (struct ohci_hcd *hc, struct ed * ed)
+{
+	hash_free_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]), ed);
+}
+
+static inline void
+hash_free_td (struct ohci_hcd *hc, struct td * td)
+{
+	hash_free_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]), td);
+}
+
+
+static int ohci_mem_init (struct ohci_hcd *ohci)
+{
+	ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev,
+		sizeof (struct td),
+		32 /* byte alignment */,
+		0 /* no page-crossing issues */,
+		GFP_KERNEL | OHCI_MEM_FLAGS);
+	if (!ohci->td_cache)
+		return -ENOMEM;
+	ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev,
+		sizeof (struct ed),
+		16 /* byte alignment */,
+		0 /* no page-crossing issues */,
+		GFP_KERNEL | OHCI_MEM_FLAGS);
+	if (!ohci->ed_cache) {
+		pci_pool_destroy (ohci->td_cache);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void ohci_mem_cleanup (struct ohci_hcd *ohci)
+{
+	if (ohci->td_cache) {
+		pci_pool_destroy (ohci->td_cache);
+		ohci->td_cache = 0;
+	}
+	if (ohci->ed_cache) {
+		pci_pool_destroy (ohci->ed_cache);
+		ohci->ed_cache = 0;
+	}
+}
+
+/* TDs ... */
+static struct td *
+td_alloc (struct ohci_hcd *hc, int mem_flags)
+{
+	dma_addr_t	dma;
+	struct td	*td;
+
+	td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
+	if (td) {
+		td->td_dma = dma;
+		/* hash it for later reverse mapping */
+		if (!hash_add_td (hc, td, mem_flags)) {
+			pci_pool_free (hc->td_cache, td, dma);
+			return NULL;
+		}
+	}
+	return td;
+}
+
+static inline void
+td_free (struct ohci_hcd *hc, struct td *td)
+{
+	hash_free_td (hc, td);
+	pci_pool_free (hc->td_cache, td, td->td_dma);
+}
+
+
+/* EDs ... */
+static struct ed *
+ed_alloc (struct ohci_hcd *hc, int mem_flags)
+{
+	dma_addr_t	dma;
+	struct ed	*ed;
+
+	ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma);
+	if (ed) {
+		memset (ed, 0, sizeof (*ed));
+		ed->dma = dma;
+		/* hash it for later reverse mapping */
+		if (!hash_add_ed (hc, ed, mem_flags)) {
+			pci_pool_free (hc->ed_cache, ed, dma);
+			return NULL;
+		}
+	}
+	return ed;
+}
+
+static inline void
+ed_free (struct ohci_hcd *hc, struct ed *ed)
+{
+	hash_free_ed (hc, ed);
+	pci_pool_free (hc->ed_cache, ed, ed->dma);
+}
+
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ohci-q.c linux/drivers/usb/hcd/ohci-q.c
--- v2.5.2/linux/drivers/usb/hcd/ohci-q.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ohci-q.c	Mon Jan 21 15:44:21 2002
@@ -0,0 +1,1000 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under GPL
+ * $Id: ohci-q.c,v 1.6 2002/01/19 00:23:15 dbrownell Exp $
+ */
+ 
+static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
+{
+	int		last = urb_priv->length - 1;
+
+	if (last >= 0) {
+		int		i;
+		struct td	*td = urb_priv->td [0];
+#ifdef CONFIG_PCI
+		int		len = td->urb->transfer_buffer_length;
+		int		dir = usb_pipeout (td->urb->pipe)
+					? PCI_DMA_TODEVICE
+					: PCI_DMA_FROMDEVICE;
+
+		/* unmap CTRL URB setup buffer (always td 0) */
+		if (usb_pipecontrol (td->urb->pipe)) {
+			pci_unmap_single (hc->hcd.pdev, 
+					td->data_dma, 8, PCI_DMA_TODEVICE);
+			
+			/* CTRL data buffer starts at td 1 if len > 0 */
+			if (len && last > 0)
+				td = urb_priv->td [1]; 		
+		}
+		/* else:  ISOC, BULK, INTR data buffer starts at td 0 */
+
+		/* unmap data buffer */
+		if (len && td->data_dma)
+			pci_unmap_single (hc->hcd.pdev,
+					td->data_dma, len, dir);
+#else
+#	warning "assuming no buffer unmapping is needed"
+#endif
+
+		for (i = 0; i <= last; i++) {
+			td = urb_priv->td [i];
+			if (td)
+				td_free (hc, td);
+		}
+	}
+
+	kfree (urb_priv);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * URB goes back to driver, and isn't reissued.
+ * It's completely gone from HC data structures, so no locking
+ * is needed ... or desired! (Giveback can call back to hcd.)
+ */
+static inline void finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+{
+	if (urb->hcpriv) {
+		urb_free_priv (ohci, urb->hcpriv);
+		urb->hcpriv = NULL;
+	}
+	usb_hcd_giveback_urb (&ohci->hcd, urb);
+}
+
+static void td_submit_urb (struct urb *urb);
+
+/*
+ * URB is reported to driver, is reissued if it's periodic.
+ */
+static int return_urb (struct ohci_hcd *hc, struct urb *urb)
+{
+	urb_priv_t	*urb_priv = urb->hcpriv;
+	struct urb	*urbt;
+	unsigned long	flags;
+	int		i;
+
+#ifdef DEBUG
+	if (!urb_priv) {
+		err ("already unlinked!");
+		BUG ();
+	}
+
+	/* just to be sure */
+	if (!urb->complete) {
+		err ("no completion!");
+		BUG ();
+	}
+#endif
+
+#ifdef OHCI_VERBOSE_DEBUG
+	urb_print (urb, "RET", usb_pipeout (urb->pipe));
+#endif
+
+// FIXME:  but if urb->status says it was was unlinked ...
+
+	switch (usb_pipetype (urb->pipe)) {
+  		case PIPE_INTERRUPT:
+#ifdef CONFIG_PCI
+			pci_unmap_single (hc->hcd.pdev,
+				urb_priv->td [0]->data_dma,
+				urb->transfer_buffer_length,
+				usb_pipeout (urb->pipe)
+					? PCI_DMA_TODEVICE
+					: PCI_DMA_FROMDEVICE);
+#endif
+			urb->complete (urb);
+
+			/* implicitly requeued */
+  			urb->actual_length = 0;
+  			urb->status = -EINPROGRESS;
+  			if (urb_priv->state != URB_DEL) {
+				spin_lock_irqsave (&hc->lock, flags);
+  				td_submit_urb (urb);
+  				spin_unlock_irqrestore (&hc->lock, flags);
+			}
+  			break;
+
+		case PIPE_ISOCHRONOUS:
+			for (urbt = urb->next;
+					urbt && (urbt != urb);
+					urbt = urbt->next)
+				continue;
+			if (urbt) { /* send the reply and requeue URB */	
+#ifdef CONFIG_PCI
+// FIXME this style unmap is only done on this route ...
+				pci_unmap_single (hc->hcd.pdev,
+					urb_priv->td [0]->data_dma,
+					urb->transfer_buffer_length,
+					usb_pipeout (urb->pipe)
+						? PCI_DMA_TODEVICE
+						: PCI_DMA_FROMDEVICE);
+#endif
+				urb->complete (urb);
+				spin_lock_irqsave (&hc->lock, flags);
+				urb->actual_length = 0;
+  				urb->status = -EINPROGRESS;
+  				urb->start_frame = urb_priv->ed->last_iso + 1;
+  				if (urb_priv->state != URB_DEL) {
+  					for (i = 0; i < urb->number_of_packets;
+							i++) {
+  						urb->iso_frame_desc [i]
+							.actual_length = 0;
+  						urb->iso_frame_desc [i]
+							.status = -EXDEV;
+  					}
+  					td_submit_urb (urb);
+  				}
+// FIXME if not deleted, should have been "finished"
+  				spin_unlock_irqrestore (&hc->lock, flags);
+
+  			} else { /* not reissued */
+				finish_urb (hc, urb);
+			}		
+			break;
+
+		/*
+		 * C/B requests that get here are never reissued.
+		 */
+		case PIPE_BULK:
+		case PIPE_CONTROL:
+			finish_urb (hc, urb);
+			break;
+	}
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/  
+
+/* search for the right branch to insert an interrupt ed into the int tree 
+ * do some load balancing;
+ * returns the branch and 
+ * sets the interval to interval = 2^integer (ld (interval))
+ */
+static int ep_int_balance (struct ohci_hcd *ohci, int interval, int load)
+{
+	int	i, branch = 0;
+
+	/* search for the least loaded interrupt endpoint branch */
+	for (i = 0; i < NUM_INTS ; i++) 
+		if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i])
+			branch = i; 
+
+	branch = branch % interval;
+	for (i = branch; i < NUM_INTS; i += interval)
+		ohci->ohci_int_load [i] += load;
+
+	return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*  2^int ( ld (inter)) */
+
+static int ep_2_n_interval (int inter)
+{	
+	int	i;
+
+	for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++)
+		continue;
+	return 1 << i;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the int tree is a binary tree 
+ * in order to process it sequentially the indexes of the branches have
+ * to be mapped the mapping reverses the bits of a word of num_bits length
+ */
+static int ep_rev (int num_bits, int word)
+{
+	int			i, wout = 0;
+
+	for (i = 0; i < num_bits; i++)
+		wout |= (( (word >> i) & 1) << (num_bits - i - 1));
+	return wout;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (struct ohci_hcd *ohci, struct ed *edi)
+{	 
+	int			int_branch, i;
+	int			inter, interval, load;
+	__u32			*ed_p;
+	volatile struct ed	*ed = edi;
+
+	ed->state = ED_OPER;
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		ed->hwNextED = 0;
+		if (ohci->ed_controltail == NULL) {
+			writel (ed->dma, &ohci->regs->ed_controlhead);
+		} else {
+			ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma);
+		}
+		ed->ed_prev = ohci->ed_controltail;
+		if (!ohci->ed_controltail
+				&& !ohci->ed_rm_list [0]
+				&& !ohci->ed_rm_list [1]
+				&& !ohci->sleeping
+				) {
+			ohci->hc_control |= OHCI_CTRL_CLE;
+			writel (ohci->hc_control, &ohci->regs->control);
+		}
+		ohci->ed_controltail = edi;	  
+		break;
+
+	case PIPE_BULK:
+		ed->hwNextED = 0;
+		if (ohci->ed_bulktail == NULL) {
+			writel (ed->dma, &ohci->regs->ed_bulkhead);
+		} else {
+			ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma);
+		}
+		ed->ed_prev = ohci->ed_bulktail;
+		if (!ohci->ed_bulktail
+				&& !ohci->ed_rm_list [0]
+				&& !ohci->ed_rm_list [1]
+				&& !ohci->sleeping
+				) {
+			ohci->hc_control |= OHCI_CTRL_BLE;
+			writel (ohci->hc_control, &ohci->regs->control);
+		}
+		ohci->ed_bulktail = edi;	  
+		break;
+
+	case PIPE_INTERRUPT:
+		load = ed->int_load;
+		interval = ep_2_n_interval (ed->int_period);
+		ed->int_interval = interval;
+		int_branch = ep_int_balance (ohci, interval, load);
+		ed->int_branch = int_branch;
+
+		for (i = 0; i < ep_rev (6, interval); i += inter) {
+			inter = 1;
+			for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i) + int_branch]); 
+				 (*ed_p != 0) && ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval >= interval); 
+				ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) 
+					inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
+			ed->hwNextED = *ed_p; 
+			*ed_p = cpu_to_le32 (ed->dma);
+		}
+#ifdef DEBUG
+		ep_print_int_eds (ohci, "LINK_INT");
+#endif
+		break;
+
+	case PIPE_ISOCHRONOUS:
+		ed->hwNextED = 0;
+		ed->int_interval = 1;
+		if (ohci->ed_isotail != NULL) {
+			ohci->ed_isotail->hwNextED = cpu_to_le32 (ed->dma);
+			ed->ed_prev = ohci->ed_isotail;
+		} else {
+			for ( i = 0; i < NUM_INTS; i += inter) {
+				inter = 1;
+				for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i)]); 
+					*ed_p != 0; 
+					ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) 
+						inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
+				*ed_p = cpu_to_le32 (ed->dma);	
+			}	
+			ed->ed_prev = NULL;
+		}	
+		ohci->ed_isotail = edi;  
+#ifdef DEBUG
+		ep_print_int_eds (ohci, "LINK_ISO");
+#endif
+		break;
+	}	 	
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* unlink an ed from one of the HC chains. 
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed
+ */
+static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed) 
+{
+	int	int_branch;
+	int	i;
+	int	inter;
+	int	interval;
+	__u32	*ed_p;
+
+	ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP);
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_CLE;
+				writel (ohci->hc_control, &ohci->regs->control);
+			}
+			writel (le32_to_cpup (&ed->hwNextED),
+				&ohci->regs->ed_controlhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		if (ohci->ed_controltail == ed) {
+			ohci->ed_controltail = ed->ed_prev;
+		} else {
+			 (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
+			 	->ed_prev = ed->ed_prev;
+		}
+		break;
+
+	case PIPE_BULK:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_BLE;
+				writel (ohci->hc_control, &ohci->regs->control);
+			}
+			writel (le32_to_cpup (&ed->hwNextED),
+				&ohci->regs->ed_bulkhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		if (ohci->ed_bulktail == ed) {
+			ohci->ed_bulktail = ed->ed_prev;
+		} else {
+			 (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
+			 	->ed_prev = ed->ed_prev;
+		}
+		break;
+
+	case PIPE_INTERRUPT:
+		int_branch = ed->int_branch;
+		interval = ed->int_interval;
+
+		for (i = 0; i < ep_rev (6, interval); i += inter) {
+			for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i) + int_branch]), inter = 1; 
+				 (*ed_p != 0) && (*ed_p != ed->hwNextED); 
+				ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED), 
+				inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval)) {				
+					if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
+			  			*ed_p = ed->hwNextED;		
+			  			break;
+			  		}
+			  }
+		}
+		for (i = int_branch; i < NUM_INTS; i += interval)
+		    ohci->ohci_int_load [i] -= ed->int_load;
+#ifdef DEBUG
+		ep_print_int_eds (ohci, "UNLINK_INT");
+#endif
+		break;
+
+	case PIPE_ISOCHRONOUS:
+		if (ohci->ed_isotail == ed)
+			ohci->ed_isotail = ed->ed_prev;
+		if (ed->hwNextED != 0) 
+			(dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
+		    		->ed_prev = ed->ed_prev;
+
+		if (ed->ed_prev != NULL) {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		} else {
+			for (i = 0; i < NUM_INTS; i++) {
+				for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i)]); 
+						*ed_p != 0; 
+						ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) {
+					// inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
+					if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
+						*ed_p = ed->hwNextED;		
+						break;
+					}
+				}
+			}	
+		}	
+#ifdef DEBUG
+		ep_print_int_eds (ohci, "UNLINK_ISO");
+#endif
+		break;
+	}
+	ed->state = ED_UNLINK;
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* (re)init an endpoint; this _should_ be done once at the
+ * usb_set_configuration command, but the USB stack is a bit stateless
+ * so we do it at every transaction.
+ * if the state of the ed is ED_NEW then a dummy td is added and the
+ * state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are set even though most of them should
+ * not change
+ */
+static struct ed *ep_add_ed (
+	struct usb_device	*udev,
+	unsigned int		pipe,
+	int			interval,
+	int			load,
+	int			mem_flags
+) {
+   	struct ohci_hcd		*ohci = hcd_to_ohci (udev->bus->hcpriv);
+	struct hcd_dev		*dev = (struct hcd_dev *) udev->hcpriv;
+	struct td		*td;
+	struct ed		*ed; 
+	unsigned		ep;
+	unsigned long		flags;
+
+	spin_lock_irqsave (&ohci->lock, flags);
+
+	ep = usb_pipeendpoint (pipe) << 1;
+	if (!usb_pipecontrol (pipe) && usb_pipeout (pipe))
+		ep |= 1;
+	if (!(ed = dev->ep [ep])) {
+		ed = ed_alloc (ohci, SLAB_ATOMIC);
+		if (!ed) {
+			/* out of memory */
+			spin_unlock_irqrestore (&ohci->lock, flags);
+			return NULL;
+		}
+		dev->ep [ep] = ed;
+	}
+
+	if (ed->state & ED_URB_DEL) {
+		/* pending unlink request */
+		spin_unlock_irqrestore (&ohci->lock, flags);
+		return NULL;
+	}
+
+	if (ed->state == ED_NEW) {
+		ed->hwINFO = __constant_cpu_to_le32 (OHCI_ED_SKIP);
+  		/* dummy td; end of td list for ed */
+		td = td_alloc (ohci, SLAB_ATOMIC);
+ 		if (!td) {
+			/* out of memory */
+			spin_unlock_irqrestore (&ohci->lock, flags);
+			return NULL;
+		}
+		ed->hwTailP = cpu_to_le32 (td->td_dma);
+		ed->hwHeadP = ed->hwTailP;	
+		ed->state = ED_UNLINK;
+		ed->type = usb_pipetype (pipe);
+	}
+
+	ohci->dev [usb_pipedevice (pipe)] = udev;
+
+// FIXME:  don't do this if it's linked to the HC,
+// we might clobber data toggle or other state ...
+
+	ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe)
+			| usb_pipeendpoint (pipe) << 7
+			| (usb_pipeisoc (pipe)? 0x8000: 0)
+			| (usb_pipecontrol (pipe)
+				? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) 
+			| (udev->speed == USB_SPEED_LOW) << 13
+			| usb_maxpacket (udev, pipe, usb_pipeout (pipe))
+				<< 16);
+
+  	if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
+  		ed->int_period = interval;
+  		ed->int_load = load;
+  	}
+
+	spin_unlock_irqrestore (&ohci->lock, flags);
+	return ed; 
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* request unlinking of an endpoint from an operational HC.
+ * put the ep on the rm_list and stop the bulk or ctrl list 
+ * real work is done at the next start frame (SF) hardware interrupt
+ */
+static void ed_unlink (struct usb_device *usb_dev, struct ed *ed)
+{    
+	unsigned int		frame;
+   	struct ohci_hcd		*ohci = hcd_to_ohci (usb_dev->bus->hcpriv);
+
+	/* already pending? */
+	if (ed->state & ED_URB_DEL)
+		return;
+	ed->state |= ED_URB_DEL;
+
+	ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP);
+
+	switch (ed->type) {
+		case PIPE_CONTROL: /* stop control list */
+			ohci->hc_control &= ~OHCI_CTRL_CLE;
+			writel (ohci->hc_control,
+				&ohci->regs->control); 
+			break;
+		case PIPE_BULK: /* stop bulk list */
+			ohci->hc_control &= ~OHCI_CTRL_BLE;
+			writel (ohci->hc_control,
+				&ohci->regs->control); 
+			break;
+	}
+
+	frame = le16_to_cpu (ohci->hcca->frame_no) & 0x1;
+	ed->ed_rm_list = ohci->ed_rm_list [frame];
+	ohci->ed_rm_list [frame] = ed;
+
+	/* enable SOF interrupt */
+	if (!ohci->sleeping) {
+		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+	}
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void
+td_fill (struct ohci_hcd *ohci, unsigned int info,
+	dma_addr_t data, int len,
+	struct urb *urb, int index)
+{
+	volatile struct td	*td, *td_pt;
+	urb_priv_t		*urb_priv = urb->hcpriv;
+
+	if (index >= urb_priv->length) {
+		err ("internal OHCI error: TD index > length");
+		return;
+	}
+
+	/* use this td as the next dummy */
+	td_pt = urb_priv->td [index];
+	td_pt->hwNextTD = 0;
+
+	/* fill the old dummy TD */
+	td = urb_priv->td [index] = dma_to_td (ohci,
+			le32_to_cpup (&urb_priv->ed->hwTailP) & ~0xf);
+
+	td->ed = urb_priv->ed;
+	td->next_dl_td = NULL;
+	td->index = index;
+	td->urb = urb; 
+	td->data_dma = data;
+	if (!len)
+		data = 0;
+
+	td->hwINFO = cpu_to_le32 (info);
+	if ((td->ed->type) == PIPE_ISOCHRONOUS) {
+		td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
+		td->ed->last_iso = info & 0xffff;
+	} else {
+		td->hwCBP = cpu_to_le32 (data); 
+	}			
+	if (data)
+		td->hwBE = cpu_to_le32 (data + len - 1);
+	else
+		td->hwBE = 0;
+	td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
+	td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
+
+	/* append to queue */
+	td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare all TDs of a transfer */
+
+static void td_submit_urb (struct urb *urb)
+{ 
+	urb_priv_t	*urb_priv = urb->hcpriv;
+	struct ohci_hcd *ohci = hcd_to_ohci (urb->dev->bus->hcpriv);
+	dma_addr_t	data;
+	int		data_len = urb->transfer_buffer_length;
+	int		cnt = 0; 
+	__u32		info = 0;
+  	unsigned int	toggle = 0;
+
+	/* OHCI handles the DATA-toggles itself, we just use the
+	 * USB-toggle bits for resetting
+	 */
+  	if (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+			usb_pipeout (urb->pipe))) {
+  		toggle = TD_T_TOGGLE;
+	} else {
+  		toggle = TD_T_DATA0;
+		usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+			usb_pipeout (urb->pipe), 1);
+	}
+
+	urb_priv->td_cnt = 0;
+
+	if (data_len) {
+#ifdef CONFIG_PCI
+		data = pci_map_single (ohci->hcd.pdev,
+			urb->transfer_buffer, data_len,
+			usb_pipeout (urb->pipe)
+				? PCI_DMA_TODEVICE
+				: PCI_DMA_FROMDEVICE
+			);
+#else
+#	error "what dma addr to use"
+#endif
+	} else
+		data = 0;
+
+	switch (usb_pipetype (urb->pipe)) {
+		case PIPE_BULK:
+			info = usb_pipeout (urb->pipe)
+				? TD_CC | TD_DP_OUT
+				: TD_CC | TD_DP_IN ;
+			while (data_len > 4096) {		
+				td_fill (ohci,
+					info | (cnt? TD_T_TOGGLE:toggle),
+					data, 4096, urb, cnt);
+				data += 4096; data_len -= 4096; cnt++;
+			}
+			info = usb_pipeout (urb->pipe)?
+				TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+			td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle),
+				data, data_len, urb, cnt);
+			cnt++;
+			if ((urb->transfer_flags & USB_ZERO_PACKET)
+					&& cnt < urb_priv->length) {
+				td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle),
+					0, 0, urb, cnt);
+				cnt++;
+			}
+			/* start bulk list */
+			if (!ohci->sleeping)
+				writel (OHCI_BLF, &ohci->regs->cmdstatus);
+			break;
+
+		case PIPE_INTERRUPT:
+			info = TD_CC | toggle;
+			info |= usb_pipeout (urb->pipe) 
+				?  TD_DP_OUT
+				:  TD_R | TD_DP_IN;
+			td_fill (ohci, info, data, data_len, urb, cnt++);
+			break;
+
+		case PIPE_CONTROL:
+			info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+			td_fill (ohci, info,
+#ifdef CONFIG_PCI
+				pci_map_single (ohci->hcd.pdev,
+					urb->setup_packet, 8,
+					PCI_DMA_TODEVICE),
+#else
+#	error "what dma addr to use"				
+#endif
+				8, urb, cnt++); 
+			if (data_len > 0) {  
+				info = TD_CC | TD_R | TD_T_DATA1;
+				info |= usb_pipeout (urb->pipe)
+				    ? TD_DP_OUT
+				    : TD_DP_IN;
+				/* NOTE:  mishandles transfers >8K, some >4K */
+				td_fill (ohci, info, data, data_len,
+						urb, cnt++);  
+			} 
+			info = usb_pipeout (urb->pipe)
+				? TD_CC | TD_DP_IN | TD_T_DATA1
+				: TD_CC | TD_DP_OUT | TD_T_DATA1;
+			td_fill (ohci, info, data, 0, urb, cnt++);
+			/* start control list */
+			if (!ohci->sleeping)
+				writel (OHCI_CLF, &ohci->regs->cmdstatus);
+			break;
+
+		case PIPE_ISOCHRONOUS:
+			for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
+				td_fill (ohci, TD_CC | TD_ISO
+					| ((urb->start_frame + cnt) & 0xffff), 
+				    data + urb->iso_frame_desc [cnt].offset, 
+				    urb->iso_frame_desc [cnt].length, urb, cnt); 
+			}
+			break;
+	} 
+	if (urb_priv->length != cnt) 
+		dbg ("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length (struct td *td)
+{
+	__u32		tdINFO, tdBE, tdCBP;
+ 	__u16		tdPSW;
+ 	struct urb	*urb = td->urb;
+ 	urb_priv_t	*urb_priv = urb->hcpriv;
+	int		dlen = 0;
+	int		cc = 0;
+
+	tdINFO = le32_to_cpup (&td->hwINFO);
+  	tdBE   = le32_to_cpup (&td->hwBE);
+  	tdCBP  = le32_to_cpup (&td->hwCBP);
+
+
+  	if (tdINFO & TD_ISO) {
+ 		tdPSW = le16_to_cpu (td->hwPSW [0]);
+ 		cc = (tdPSW >> 12) & 0xF;
+		if (cc < 0xE)  {
+			if (usb_pipeout (urb->pipe)) {
+				dlen = urb->iso_frame_desc [td->index].length;
+			} else {
+				dlen = tdPSW & 0x3ff;
+			}
+			urb->actual_length += dlen;
+			urb->iso_frame_desc [td->index].actual_length = dlen;
+			if (! (urb->transfer_flags & USB_DISABLE_SPD)
+					&& (cc == TD_DATAUNDERRUN))
+				cc = TD_CC_NOERROR;
+
+			urb->iso_frame_desc [td->index].status
+				= cc_to_error [cc];
+		}
+	} else { /* BULK, INT, CONTROL DATA */
+		if (! (usb_pipetype (urb->pipe) == PIPE_CONTROL && 
+				 ((td->index == 0)
+				 || (td->index == urb_priv->length - 1)))) {
+ 			if (tdBE != 0) {
+				urb->actual_length += (td->hwCBP == 0)
+					? (tdBE - td->data_dma + 1)
+					: (tdCBP - td->data_dma);
+			}
+  		}
+  	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we unreverse the hc-reversed done-list
+ */
+static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
+{
+	__u32		td_list_hc;
+	struct td	*td_rev = NULL;
+	struct td	*td_list = NULL;
+  	urb_priv_t	*urb_priv = NULL;
+  	unsigned long	flags;
+
+  	spin_lock_irqsave (&ohci->lock, flags);
+
+	td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
+	ohci->hcca->done_head = 0;
+
+	while (td_list_hc) {		
+		td_list = dma_to_td (ohci, td_list_hc);
+
+		if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
+			urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
+			dbg (" USB-error/status: %x : %p", 
+				TD_CC_GET (le32_to_cpup (&td_list->hwINFO)),
+				td_list);
+			if (td_list->ed->hwHeadP
+					& __constant_cpu_to_le32 (0x1)) {
+				if (urb_priv && ((td_list->index + 1)
+						< urb_priv->length)) {
+					td_list->ed->hwHeadP = 
+			    (urb_priv->td [urb_priv->length - 1]->hwNextTD
+				    & __constant_cpu_to_le32 (0xfffffff0))
+			    | (td_list->ed->hwHeadP
+				    & __constant_cpu_to_le32 (0x2));
+					urb_priv->td_cnt += urb_priv->length
+						- td_list->index - 1;
+				} else 
+					td_list->ed->hwHeadP &=
+					__constant_cpu_to_le32 (0xfffffff2);
+			}
+		}
+
+		td_list->next_dl_td = td_rev;	
+		td_rev = td_list;
+		td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;	
+	}	
+	spin_unlock_irqrestore (&ohci->lock, flags);
+	return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* there are some pending requests to unlink 
+ * - some URBs/TDs if urb_priv->state == URB_DEL
+ */
+static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
+{
+	unsigned long	flags;
+	struct ed	*ed;
+	__u32		edINFO;
+	__u32		tdINFO;
+	struct td	*td = NULL, *td_next = NULL,
+			*tdHeadP = NULL, *tdTailP;
+	__u32		*td_p;
+	int		ctrl = 0, bulk = 0;
+
+	spin_lock_irqsave (&ohci->lock, flags);
+
+	for (ed = ohci->ed_rm_list [frame]; ed != NULL; ed = ed->ed_rm_list) {
+
+		tdTailP = dma_to_td (ohci,
+			le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
+		tdHeadP = dma_to_td (ohci,
+			le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+		edINFO = le32_to_cpup (&ed->hwINFO);
+		td_p = &ed->hwHeadP;
+
+		for (td = tdHeadP; td != tdTailP; td = td_next) {
+			struct urb *urb = td->urb;
+			urb_priv_t *urb_priv = td->urb->hcpriv;
+
+			td_next = dma_to_td (ohci,
+				le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
+			if ((urb_priv->state == URB_DEL)) {
+				tdINFO = le32_to_cpup (&td->hwINFO);
+				if (TD_CC_GET (tdINFO) < 0xE)
+					dl_transfer_length (td);
+				*td_p = td->hwNextTD | (*td_p
+					& __constant_cpu_to_le32 (0x3));
+
+				/* URB is done; clean up */
+				if (++ (urb_priv->td_cnt) == urb_priv->length)
+// FIXME:  we shouldn't hold ohci->lock here, else the
+// completion function can't talk to this hcd ...
+					finish_urb (ohci, urb);
+			} else {
+				td_p = &td->hwNextTD;
+			}
+		}
+
+		ed->state &= ~ED_URB_DEL;
+		tdHeadP = dma_to_td (ohci,
+			le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+
+		if (tdHeadP == tdTailP) {
+			if (ed->state == ED_OPER)
+				ep_unlink (ohci, ed);
+			td_free (ohci, tdTailP);
+			ed->hwINFO = __constant_cpu_to_le32 (OHCI_ED_SKIP);
+			ed->state = ED_NEW;
+		} else
+			ed->hwINFO &= ~__constant_cpu_to_le32 (OHCI_ED_SKIP);
+
+		switch (ed->type) {
+			case PIPE_CONTROL:
+				ctrl = 1;
+				break;
+			case PIPE_BULK:
+				bulk = 1;
+				break;
+		}
+   	}
+
+	/* maybe reenable control and bulk lists */ 
+	if (!ohci->disabled) {
+		if (ctrl) 	/* reset control list */
+			writel (0, &ohci->regs->ed_controlcurrent);
+		if (bulk)	/* reset bulk list */
+			writel (0, &ohci->regs->ed_bulkcurrent);
+		if (!ohci->ed_rm_list [!frame]) {
+			if (ohci->ed_controltail)
+				ohci->hc_control |= OHCI_CTRL_CLE;
+			if (ohci->ed_bulktail)
+				ohci->hc_control |= OHCI_CTRL_BLE;
+			writel (ohci->hc_control, &ohci->regs->control);   
+		}
+	}
+
+   	ohci->ed_rm_list [frame] = NULL;
+   	spin_unlock_irqrestore (&ohci->lock, flags);
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * process normal completions (error or success) and some unlinked eds
+ * this is the main path for handing urbs back to drivers
+ */
+static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
+{
+  	struct td	*td_list_next = NULL;
+	struct ed	*ed;
+	int		cc = 0;
+	struct urb	*urb;
+	urb_priv_t	*urb_priv;
+ 	__u32		tdINFO, edHeadP, edTailP;
+
+ 	unsigned long flags;
+
+  	while (td_list) {
+   		td_list_next = td_list->next_dl_td;
+
+  		urb = td_list->urb;
+  		urb_priv = urb->hcpriv;
+  		tdINFO = le32_to_cpup (&td_list->hwINFO);
+
+   		ed = td_list->ed;
+
+   		dl_transfer_length (td_list);
+
+  		/* error code of transfer */
+  		cc = TD_CC_GET (tdINFO);
+  		if (cc == TD_CC_STALL)
+			usb_endpoint_halt (urb->dev,
+				usb_pipeendpoint (urb->pipe),
+				usb_pipeout (urb->pipe));
+
+  		if (! (urb->transfer_flags & USB_DISABLE_SPD)
+				&& (cc == TD_DATAUNDERRUN))
+			cc = TD_CC_NOERROR;
+
+  		if (++ (urb_priv->td_cnt) == urb_priv->length) {
+			/*
+			 * Except for periodic transfers, both branches do
+			 * the same thing.  Periodic urbs get reissued until
+			 * they're "deleted" with usb_unlink_urb.
+			 */
+			if ((ed->state & (ED_OPER | ED_UNLINK))
+					&& (urb_priv->state != URB_DEL)) {
+				spin_lock (&urb->lock);
+				if (urb->status == -EINPROGRESS)
+  					urb->status = cc_to_error [cc];
+				spin_unlock (&urb->lock);
+  				return_urb (ohci, urb);
+  			} else
+  				finish_urb (ohci, urb);
+  		}
+
+  		spin_lock_irqsave (&ohci->lock, flags);
+  		if (ed->state != ED_NEW) { 
+  			edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
+  			edTailP = le32_to_cpup (&ed->hwTailP);
+
+// FIXME:  ED_UNLINK is very fuzzy w.r.t. what the hc knows...
+
+			/* unlink eds if they are not busy */
+     			if ((edHeadP == edTailP) && (ed->state == ED_OPER)) 
+     				ep_unlink (ohci, ed);
+     		}	
+     		spin_unlock_irqrestore (&ohci->lock, flags);
+
+    		td_list = td_list_next;
+  	}  
+}
+
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ohci.h linux/drivers/usb/hcd/ohci.h
--- v2.5.2/linux/drivers/usb/hcd/ohci.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ohci.h	Mon Jan 21 15:44:21 2002
@@ -0,0 +1,360 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under GPL
+ * $Id: ohci.h,v 1.5 2002/01/19 00:24:01 dbrownell Exp $
+ */
+ 
+static const int cc_to_error [16] = { 
+
+/* map OHCI status to errno values */ 
+	/* No  Error  */               0,
+	/* CRC Error  */               -EILSEQ,
+	/* Bit Stuff  */               -EPROTO,
+	/* Data Togg  */               -EILSEQ,
+	/* Stall      */               -EPIPE,
+	/* DevNotResp */               -ETIMEDOUT,
+	/* PIDCheck   */               -EPROTO,
+	/* UnExpPID   */               -EPROTO,
+	/* DataOver   */               -EOVERFLOW,
+	/* DataUnder  */               -EREMOTEIO,
+	/* (for hw)   */               -EIO,
+	/* (for hw)   */               -EIO,
+	/* BufferOver */               -ECOMM,
+	/* BuffUnder  */               -ENOSR,
+	/* (for HCD)  */               -EALREADY,
+	/* (for HCD)  */               -EALREADY 
+};
+
+
+/* ED States */
+
+#define ED_NEW 		0x00		/* unused, no dummy td */
+#define ED_UNLINK 	0x01		/* dummy td, maybe linked to hc */
+#define ED_OPER		0x02		/* dummy td, _is_ linked to hc */
+
+#define ED_URB_DEL  	0x08		/* masked in */
+
+/* usb_ohci_ed */
+struct ed {
+	/* first fields are hardware-specified */
+	__u32 hwINFO;       
+	__u32 hwTailP;
+	__u32 hwHeadP;
+	__u32 hwNextED;
+
+	struct ed * ed_prev;  
+	__u8 int_period;
+	__u8 int_branch;
+	__u8 int_load; 
+	__u8 int_interval;
+	__u8 state;			// ED_{NEW,UNLINK,OPER}
+	__u8 type; 
+	__u16 last_iso;
+	struct ed * ed_rm_list;
+
+	dma_addr_t dma;
+	__u32 unused [3];
+} __attribute((aligned(16)));
+
+ 
+/* TD info field */
+#define TD_CC       0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC       0x0C000000
+#define TD_T        0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R        0x00040000
+#define TD_DI       0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP       0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+#define TD_ISO	    0x00010000
+#define TD_DEL      0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR      0x00
+#define TD_CC_CRC          0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL        0x04
+#define TD_DEVNOTRESP      0x05
+#define TD_PIDCHECKFAIL    0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN     0x08
+#define TD_DATAUNDERRUN    0x09
+    /* 0x0A, 0x0B reserved for hardware */
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+    /* 0x0E, 0x0F reserved for HCD */
+#define TD_NOTACCESSED     0x0F
+
+
+#define MAXPSW 1
+
+struct td {
+	/* first hardware fields are in all tds */
+	__u32		hwINFO;
+  	__u32		hwCBP;		/* Current Buffer Pointer */
+  	__u32		hwNextTD;	/* Next TD Pointer */
+  	__u32		hwBE;		/* Memory Buffer End Pointer */
+
+  	__u16		hwPSW [MAXPSW];	/* PSW is only for ISO */
+
+  	__u8		unused;
+  	__u8		index;
+  	struct ed	*ed;
+  	struct td	*next_dl_td;
+  	struct urb	*urb;
+
+	dma_addr_t	td_dma;
+	dma_addr_t	data_dma;
+	__u32		unused2 [2];
+} __attribute((aligned(32)));		/* iso needs 32 */
+
+#define OHCI_ED_SKIP	(1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. The host controller is
+ * told the base address of it.  It must be 256-byte aligned.
+ */
+#define NUM_INTS 32	/* part of the OHCI standard */
+struct ohci_hcca {
+	__u32	int_table [NUM_INTS];	/* Interrupt ED table */
+	__u16	frame_no;		/* current frame number */
+	__u16	pad1;			/* set to 0 on each frame_no change */
+	__u32	done_head;		/* info returned for an interrupt */
+	u8	reserved_for_hc [116];
+} __attribute((aligned(256)));
+
+  
+/*
+ * Maximum number of root hub ports.  
+ */
+#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.  You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+	/* control and status registers */
+	__u32	revision;
+	__u32	control;
+	__u32	cmdstatus;
+	__u32	intrstatus;
+	__u32	intrenable;
+	__u32	intrdisable;
+
+	/* memory pointers */
+	__u32	hcca;
+	__u32	ed_periodcurrent;
+	__u32	ed_controlhead;
+	__u32	ed_controlcurrent;
+	__u32	ed_bulkhead;
+	__u32	ed_bulkcurrent;
+	__u32	donehead;
+
+	/* frame counters */
+	__u32	fminterval;
+	__u32	fmremaining;
+	__u32	fmnumber;
+	__u32	periodicstart;
+	__u32	lsthresh;
+
+	/* Root hub ports */
+	struct	ohci_roothub_regs {
+		__u32	a;
+		__u32	b;
+		__u32	status;
+		__u32	portstatus [MAX_ROOT_PORTS];
+	} roothub;
+
+	/* and some optional registers for legacy compatibility */
+} __attribute((aligned(32)));
+
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR	(3 << 0)	/* control/bulk service ratio */
+#define OHCI_CTRL_PLE	(1 << 2)	/* periodic list enable */
+#define OHCI_CTRL_IE	(1 << 3)	/* isochronous enable */
+#define OHCI_CTRL_CLE	(1 << 4)	/* control list enable */
+#define OHCI_CTRL_BLE	(1 << 5)	/* bulk list enable */
+#define OHCI_CTRL_HCFS	(3 << 6)	/* host controller functional state */
+#define OHCI_CTRL_IR	(1 << 8)	/* interrupt routing */
+#define OHCI_CTRL_RWC	(1 << 9)	/* remote wakeup connected */
+#define OHCI_CTRL_RWE	(1 << 10)	/* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#	define OHCI_USB_RESET	(0 << 6)
+#	define OHCI_USB_RESUME	(1 << 6)
+#	define OHCI_USB_OPER	(2 << 6)
+#	define OHCI_USB_SUSPEND	(3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR	(1 << 0)	/* host controller reset */
+#define OHCI_CLF  	(1 << 1)	/* control list filled */
+#define OHCI_BLF  	(1 << 2)	/* bulk list filled */
+#define OHCI_OCR  	(1 << 3)	/* ownership change request */
+#define OHCI_SOC  	(3 << 16)	/* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
+#define OHCI_INTR_WDH	(1 << 1)	/* writeback of done_head */
+#define OHCI_INTR_SF	(1 << 2)	/* start frame */
+#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
+#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
+#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
+#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
+#define OHCI_INTR_OC	(1 << 30)	/* ownership change */
+#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+ 
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS            0x00000001   	/* current connect status */
+#define RH_PS_PES            0x00000002   	/* port enable status*/
+#define RH_PS_PSS            0x00000004   	/* port suspend status */
+#define RH_PS_POCI           0x00000008   	/* port over current indicator */
+#define RH_PS_PRS            0x00000010  	/* port reset status */
+#define RH_PS_PPS            0x00000100   	/* port power status */
+#define RH_PS_LSDA           0x00000200    	/* low speed device attached */
+#define RH_PS_CSC            0x00010000 	/* connect status change */
+#define RH_PS_PESC           0x00020000   	/* port enable status change */
+#define RH_PS_PSSC           0x00040000    	/* port suspend status change */
+#define RH_PS_OCIC           0x00080000    	/* over current indicator change */
+#define RH_PS_PRSC           0x00100000   	/* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS	     0x00000001		/* local power status */
+#define RH_HS_OCI	     0x00000002		/* over current indicator */
+#define RH_HS_DRWE	     0x00008000		/* device remote wakeup enable */
+#define RH_HS_LPSC	     0x00010000		/* local power status change */
+#define RH_HS_OCIC	     0x00020000		/* over current indicator change */
+#define RH_HS_CRWE	     0x80000000		/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR		0x0000ffff		/* device removable flags */
+#define RH_B_PPCM	0xffff0000		/* port power control mask */
+
+/* roothub.a masks */
+#define	RH_A_NDP	(0xff << 0)		/* number of downstream ports */
+#define	RH_A_PSM	(1 << 8)		/* power switching mode */
+#define	RH_A_NPS	(1 << 9)		/* no power switching */
+#define	RH_A_DT		(1 << 10)		/* device type (mbz) */
+#define	RH_A_OCPM	(1 << 11)		/* over current protection mode */
+#define	RH_A_NOCP	(1 << 12)		/* no over current protection */
+#define	RH_A_POTPGT	(0xff << 24)		/* power on to power good time */
+
+
+/* urb */
+typedef struct urb_priv
+{
+	struct ed		*ed;
+	__u16			length;		// # tds in this request
+	__u16			td_cnt;		// tds already serviced
+	int   			state;
+	struct td		*td [0];	// all TDs in this request
+
+} urb_priv_t;
+
+#define URB_DEL 1
+
+
+/* Hash struct used for TD/ED hashing */
+struct hash_t {
+	void		*virt;
+	dma_addr_t	dma;
+	struct hash_t	*next; // chaining for collision cases
+};
+
+/* List of TD/ED hash entries */
+struct hash_list_t {
+	struct hash_t	*head;
+	struct hash_t	*tail;
+};
+
+#define TD_HASH_SIZE    64    /* power'o'two */
+#define ED_HASH_SIZE    64    /* power'o'two */
+
+#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 5)) % TD_HASH_SIZE)
+#define ED_HASH_FUNC(ed_dma) ((ed_dma ^ (ed_dma >> 5)) % ED_HASH_SIZE)
+
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+struct ohci_hcd {
+	spinlock_t		lock;
+
+	/*
+	 * I/O memory used to communicate with the HC (uncached);
+	 */
+	struct ohci_regs	*regs;
+
+	/*
+	 * main memory used to communicate with the HC (uncached)
+	 */
+	struct ohci_hcca	*hcca;
+	dma_addr_t		hcca_dma;
+
+	struct ed		*ed_rm_list [2];	/* to be removed */
+
+	struct ed		*ed_bulktail;		/* last in bulk list */
+	struct ed		*ed_controltail;	/* last in ctrl list */
+ 	struct ed		*ed_isotail;		/* last in iso list */
+
+#ifdef CONFIG_PCI
+	struct pci_pool		*td_cache;
+	struct pci_pool		*ed_cache;
+	struct hash_list_t	td_hash [TD_HASH_SIZE];
+	struct hash_list_t	ed_hash [ED_HASH_SIZE];
+#endif
+
+	/*
+	 * driver state
+	 */
+	int			disabled;	/* e.g. got a UE, we're hung */
+	int			sleeping;
+	int			ohci_int_load [NUM_INTS];
+	u32 			hc_control;	/* copy of hc control reg */
+	struct usb_device	*dev [128];
+
+	unsigned long		flags;		/* for HC bugs */
+#define	OHCI_QUIRK_AMD756	0x01			/* erratum #4 */
+
+	/*
+	 * framework state
+	 */
+	struct usb_hcd		hcd;
+};
+
+#define hcd_to_ohci(hcd_ptr) list_entry(hcd_ptr, struct ohci_hcd, hcd)
+
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd.c linux/drivers/usb/hcd.c
--- v2.5.2/linux/drivers/usb/hcd.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hcd.c	Tue Jan 29 13:52:28 2002
@@ -606,7 +606,7 @@
 			return retval;
 		}
 	}
-	dev->driver_data = hcd;
+	pci_set_drvdata(dev, hcd);
 	hcd->driver = driver;
 	hcd->description = driver->description;
 	hcd->pdev = dev;
@@ -689,7 +689,7 @@
 	struct usb_hcd		*hcd;
 	struct usb_device	*hub;
 
-	hcd = (struct usb_hcd *) dev->driver_data;
+	hcd = pci_get_drvdata(dev);
 	if (!hcd)
 		return;
 	info ("remove: %s, state %x", hcd->bus_name, hcd->state);
@@ -769,7 +769,7 @@
 	struct usb_hcd		*hcd;
 	int			retval;
 
-	hcd = (struct usb_hcd *) dev->driver_data;
+	hcd = pci_get_drvdata(dev);
 	info ("suspend %s to state %d", hcd->bus_name, state);
 
 	pci_save_state (dev, hcd->pci_state);
@@ -798,7 +798,7 @@
 	struct usb_hcd		*hcd;
 	int			retval;
 
-	hcd = (struct usb_hcd *) dev->driver_data;
+	hcd = pci_get_drvdata(dev);
 	info ("resume %s", hcd->bus_name);
 
 	/* guard against multiple resumes (APM bug?) */
@@ -996,6 +996,9 @@
 	// hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)
 	// It would catch submission paths for all urbs.
 
+	/* increment the reference count of the urb, as we now also control it. */
+	urb = usb_get_urb(urb);
+
 	/*
 	 * Atomically queue the urb,  first to our records, then to the HCD.
 	 * Access to urb->status is controlled by urb->lock ... changes on
@@ -1081,20 +1084,20 @@
 	if (!urb)
 		return -EINVAL;
 
-	// FIXME:  add some explicit records to flag the
-	// state where the URB is "in periodic completion".
-	// Workaround is for driver to set the urb status
-	// to "-EINPROGRESS", so it can get through here
-	// and unlink from the completion handler.
-
 	/*
 	 * we contend for urb->status with the hcd core,
 	 * which changes it while returning the urb.
+	 *
+	 * Caller guaranteed that the urb pointer hasn't been freed, and
+	 * that it was submitted.  But as a rule it can't know whether or
+	 * not it's already been unlinked ... so we respect the reversed
+	 * lock sequence needed for the usb_hcd_giveback_urb() code paths
+	 * (urb lock, then hcd_data_lock) in case some other CPU is now
+	 * unlinking it.
 	 */
 	spin_lock_irqsave (&urb->lock, flags);
-	if (!urb->hcpriv
-			|| urb->status != -EINPROGRESS
-			|| urb->transfer_flags & USB_TIMEOUT_KILLED) {
+	spin_lock (&hcd_data_lock);
+	if (!urb->hcpriv || urb->transfer_flags & USB_TIMEOUT_KILLED) {
 		retval = -EINVAL;
 		goto done;
 	}
@@ -1103,6 +1106,8 @@
 		retval = -ENODEV;
 		goto done;
 	}
+
+	/* giveback clears dev; non-null means it's linked at this level */
 	dev = urb->dev->hcpriv;
 	hcd = urb->dev->bus->hcpriv;
 	if (!dev || !hcd) {
@@ -1110,6 +1115,27 @@
 		goto done;
 	}
 
+	/* For non-periodic transfers, any status except -EINPROGRESS means
+	 * the HCD has already started to unlink this URB from the hardware.
+	 * In that case, there's no more work to do.
+	 *
+	 * For periodic transfers, this is the only way to trigger unlinking
+	 * from the hardware.  Since we (currently) overload urb->status to
+	 * tell the driver to unlink, error status might get clobbered ...
+	 * unless that transfer hasn't yet restarted.  One such case is when
+	 * the URB gets unlinked from its completion handler.
+	 *
+	 * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
+	 */
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		if (urb->status != -EINPROGRESS) {
+			retval = 0;
+			goto done;
+		}
+	}
+
 	/* maybe set up to block on completion notification */
 	if ((urb->transfer_flags & USB_TIMEOUT_KILLED))
 		urb->status = -ETIMEDOUT;
@@ -1130,6 +1156,7 @@
 		/* asynchronous unlink */
 		urb->status = -ECONNRESET;
 	}
+	spin_unlock (&hcd_data_lock);
 	spin_unlock_irqrestore (&urb->lock, flags);
 
 	if (urb == (struct urb *) hcd->rh_timer.data) {
@@ -1151,9 +1178,12 @@
 			dbg ("%s: wait for giveback urb %p",
 				hcd->bus_name, urb);
 		}
+	} else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
+		return -EINPROGRESS;
 	}
 	goto bye;
 done:
+	spin_unlock (&hcd_data_lock);
 	spin_unlock_irqrestore (&urb->lock, flags);
 bye:
 	if (retval)
@@ -1301,5 +1331,6 @@
 	/* pass ownership to the completion handler */
 	usb_dec_dev_use (dev);
 	urb->complete (urb);
+	usb_put_urb (urb);
 }
 EXPORT_SYMBOL (usb_hcd_giveback_urb);
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hpusbscsi.c linux/drivers/usb/hpusbscsi.c
--- v2.5.2/linux/drivers/usb/hpusbscsi.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hpusbscsi.c	Wed Jan 23 15:33:46 2002
@@ -56,8 +56,17 @@
 		return NULL;
 	DEBUG ("Allocated memory\n");
 	memset (new, 0, sizeof (struct hpusbscsi));
-	spin_lock_init (&new->dataurb.lock);
-	spin_lock_init (&new->controlurb.lock);
+	new->dataurb = usb_alloc_urb(0);
+	if (!new->dataurb) {
+		kfree (new);
+		return NULL;
+	}
+	new->controlurb = usb_alloc_urb(0);
+	if (!new->controlurb) {
+		usb_free_urb (new->dataurb);
+		kfree (new);
+		return NULL;
+	}
 	new->dev = dev;
 	init_waitqueue_head (&new->pending);
 	init_waitqueue_head (&new->deathrow);
@@ -126,6 +135,8 @@
 	return new;
 
       err_out:
+	usb_free_urb (new->controlurb);
+	usb_free_urb (new->dataurb);
 	kfree (new);
 	return NULL;
 }
@@ -133,7 +144,7 @@
 static void
 hpusbscsi_usb_disconnect (struct usb_device *dev, void *ptr)
 {
-                 usb_unlink_urb(&(((struct hpusbscsi *) ptr)->controlurb));
+                 usb_unlink_urb((((struct hpusbscsi *) ptr)->controlurb));
 	((struct hpusbscsi *) ptr)->dev = NULL;
 }
 
@@ -184,8 +195,10 @@
 		old = tmp;
 		tmp = tmp->next;
 		o = (struct hpusbscsi *)old;
-		usb_unlink_urb(&o->controlurb);
+		usb_unlink_urb(o->controlurb);
 		scsi_unregister_host(&o->ctempl);
+		usb_free_urb(o->controlurb);
+		usb_free_urb(o->dataurb);
 		kfree(old);
 	}
 
@@ -222,7 +235,7 @@
 	sht->proc_dir = NULL;
 
 	/* build and submit an interrupt URB for status byte handling */
- 	FILL_INT_URB(&desc->controlurb,
+ 	FILL_INT_URB(desc->controlurb,
 			desc->dev,
 			usb_rcvintpipe(desc->dev,desc->ep_int),
 			&desc->scsi_state_byte,
@@ -232,7 +245,7 @@
 			desc->interrupt_interval
 	);
 
-	if ( 0  >  usb_submit_urb(&desc->controlurb)) {
+	if ( 0  >  usb_submit_urb(desc->controlurb)) {
 		kfree(sht->proc_name);
 		return 0;
 	}
@@ -241,7 +254,7 @@
 	desc->host = scsi_register (sht, sizeof (desc));
 	if (desc->host == NULL) {
 		kfree (sht->proc_name);
-		usb_unlink_urb(&desc->controlurb);
+		usb_unlink_urb(desc->controlurb);
 		return 0;
 	}
 	desc->host->hostdata[0] = (unsigned long) desc;
@@ -272,7 +285,7 @@
 	if (!srb->bufflen) {
 		usb_callback = simple_command_callback;
 	} else {
-        	if (srb->use_sg) {
+        	if (likely(srb->use_sg)) {
 			usb_callback = scatter_gather_callback;
 			hpusbscsi->fragment = 0;
 		} else {
@@ -288,10 +301,6 @@
 
 
 	TRACE_STATE;
-	if (hpusbscsi->state != HP_STATE_FREE) {
-		printk(KERN_CRIT"hpusbscsi - Ouch: queueing violation!\n");
-		return 1; /* This must not happen */
-	}
 
         /* We zero the sense buffer to avoid confusing user space */
         memset(srb->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
@@ -301,7 +310,7 @@
 
 	/* We prepare the urb for writing out the scsi command */
 	FILL_BULK_URB(
-		&hpusbscsi->dataurb,
+		hpusbscsi->dataurb,
 		hpusbscsi->dev,
 		usb_sndbulkpipe(hpusbscsi->dev,hpusbscsi->ep_out),
 		srb->cmnd,
@@ -312,11 +321,11 @@
 	hpusbscsi->scallback = callback;
 	hpusbscsi->srb = srb;
 
-	res = usb_submit_urb(&hpusbscsi->dataurb);
-	if (res) {
+	res = usb_submit_urb(hpusbscsi->dataurb);
+	if (unlikely(res)) {
 		hpusbscsi->state = HP_STATE_FREE;
 		TRACE_STATE;
-		if (callback) {
+		if (likely(callback != NULL)) {
 			srb->result = DID_ERROR;
 			callback(srb);
 		}
@@ -344,8 +353,8 @@
 	struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
 	printk(KERN_DEBUG"Requested is canceled.\n");
 
-	usb_unlink_urb(&hpusbscsi->dataurb);
-	usb_unlink_urb(&hpusbscsi->controlurb);
+	usb_unlink_urb(hpusbscsi->dataurb);
+	usb_unlink_urb(hpusbscsi->controlurb);
 	hpusbscsi->state = HP_STATE_FREE;
 
 	return SCSI_ABORT_PENDING;
@@ -355,7 +364,7 @@
 
 static void handle_usb_error (struct hpusbscsi *hpusbscsi)
 {
-	if (hpusbscsi->scallback != NULL) {
+	if (likely(hpusbscsi->scallback != NULL)) {
 		hpusbscsi->srb->result = DID_ERROR;
 		hpusbscsi->scallback(hpusbscsi->srb);
 	}
@@ -367,8 +376,8 @@
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
 
 DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
-	if(u->status < 0) {
-                if (hpusbscsi->state != HP_STATE_FREE)
+	if(unlikely(u->status < 0)) {
+                if (likely(hpusbscsi->state != HP_STATE_FREE))
                         handle_usb_error(hpusbscsi);
 		return;
 	}
@@ -402,7 +411,7 @@
 static void simple_command_callback(struct urb *u)
 {
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-	if (u->status<0) {
+	if (unlikely(u->status<0)) {
 		handle_usb_error(hpusbscsi);
 		return;
         }
@@ -411,7 +420,7 @@
 	        TRACE_STATE;
 		hpusbscsi->state = HP_STATE_WAIT;
 	} else {
-		if (hpusbscsi->scallback != NULL)
+		if (likely(hpusbscsi->scallback != NULL))
 			hpusbscsi->scallback(hpusbscsi->srb);
 		hpusbscsi->state = HP_STATE_FREE;
 	TRACE_STATE;
@@ -426,7 +435,7 @@
         int res;
 
         DEBUG("Going through scatter/gather\n");
-        if (u->status < 0) {
+        if (unlikely(u->status < 0)) {
                 handle_usb_error(hpusbscsi);
                 return;
         }
@@ -452,7 +461,7 @@
         );
 
         res = usb_submit_urb(u);
-        if (res)
+        if (unlikely(res))
                 hpusbscsi->state = HP_STATE_ERROR;
 	TRACE_STATE;
 }
@@ -461,20 +470,20 @@
 {
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
 
-        if (u->status < 0) {
+        if (unlikely(u->status < 0)) {
                 handle_usb_error(hpusbscsi);
                 return;
         }
         DEBUG("Data transfer done\n");
 	TRACE_STATE;
 	if (hpusbscsi->state != HP_STATE_PREMATURE) {
-		if (u->status < 0)
+		if (unlikely(u->status < 0))
 			hpusbscsi->state = HP_STATE_ERROR;
 		else
 			hpusbscsi->state = HP_STATE_WAIT;
 		TRACE_STATE;
 	} else {
-		if (hpusbscsi->scallback != NULL)
+		if (likely(hpusbscsi->scallback != NULL))
 			hpusbscsi->scallback(hpusbscsi->srb);
 		hpusbscsi->state = HP_STATE_FREE;
 	}
@@ -485,7 +494,7 @@
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
 	int res;
 
-	if (u->status<0) {
+	if (unlikely(u->status<0)) {
                 handle_usb_error(hpusbscsi);
 		return;
         }
@@ -501,7 +510,7 @@
 	);
 
 	res = usb_submit_urb(u);
-	if (res) {
+	if (unlikely(res)) {
                 handle_usb_error(hpusbscsi);
 		return;
         }
@@ -510,10 +519,11 @@
 		hpusbscsi->state = HP_STATE_WORKING;
 	TRACE_STATE;
 	} else {
-		if (hpusbscsi->scallback != NULL)
+		if (likely(hpusbscsi->scallback != NULL))
 			hpusbscsi->scallback(hpusbscsi->srb);
 		hpusbscsi->state = HP_STATE_FREE;
 	TRACE_STATE;
 	}
 }
+
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hpusbscsi.h linux/drivers/usb/hpusbscsi.h
--- v2.5.2/linux/drivers/usb/hpusbscsi.h	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/hpusbscsi.h	Wed Jan 23 15:33:46 2002
@@ -26,8 +26,8 @@
         wait_queue_head_t pending;
         wait_queue_head_t deathrow;
 
-        struct urb dataurb;
-        struct urb controlurb;
+        struct urb *dataurb;
+        struct urb *controlurb;
         int fragment;
 
         int state;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.5.2/linux/drivers/usb/hub.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hub.c	Thu Jan 17 14:06:53 2002
@@ -557,6 +557,10 @@
 		dbg("port %d, portstatus %x, change %x, %s", port + 1,
 			portstatus, portchange, portspeed (portstatus));
 
+		/* Device went away? */
+		if (!(portstatus & USB_PORT_STAT_CONNECTION))
+			return 1;
+
 		/* bomb out completely if something weird happened */
 		if ((portchange & USB_PORT_STAT_C_CONNECTION))
 			return -1;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/ibmcam.h linux/drivers/usb/ibmcam.h
--- v2.5.2/linux/drivers/usb/ibmcam.h	Mon Dec 11 13:17:55 2000
+++ linux/drivers/usb/ibmcam.h	Mon Jan 21 15:44:21 2002
@@ -147,7 +147,7 @@
 
 struct ibmcam_sbuf {
 	char *data;
-	urb_t *urb;
+	struct urb *urb;
 };
 
 struct ibmcam_frame {
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/inode.c linux/drivers/usb/inode.c
--- v2.5.2/linux/drivers/usb/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/inode.c	Wed Jan 23 15:33:46 2002
@@ -678,6 +678,8 @@
 void usbfs_add_device(struct usb_device *dev)
 {
 	char name[8];
+	int i;
+	int i_size;
 
 	sprintf (name, "%03d", dev->devnum);
 	dev->dentry = fs_create_file (name,
@@ -687,6 +689,17 @@
 				      devuid, devgid);
 	if (dev->dentry == NULL)
 		return;
+
+	/* Set the size of the device's file to be
+	 * equal to the size of the device descriptors. */
+	i_size = sizeof (struct usb_device_descriptor);
+	for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) {
+		struct usb_config_descriptor *config =
+			(struct usb_config_descriptor *)dev->rawdescriptors[i];
+		i_size += le16_to_cpu (config->wTotalLength);
+	}
+	if (dev->dentry->d_inode)
+		dev->dentry->d_inode->i_size = i_size;
 
 	usbfs_update_special();
 	usbdevfs_conn_disc_event();
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/kaweth.c linux/drivers/usb/kaweth.c
--- v2.5.2/linux/drivers/usb/kaweth.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/kaweth.c	Mon Jan 21 15:44:21 2002
@@ -953,7 +953,7 @@
 /*-------------------------------------------------------------------*
  * completion handler for compatibility wrappers (sync control/bulk) *
  *-------------------------------------------------------------------*/
-static void usb_api_blocking_completion(urb_t *urb)
+static void usb_api_blocking_completion(struct urb *urb)
 {
         struct usb_api_data *awd = (struct usb_api_data *)urb->context;
 
@@ -966,7 +966,7 @@
  *-------------------------------------------------------------------*/
 
 // Starts urb and waits for completion or timeout
-static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
+static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
 {
         DECLARE_WAITQUEUE(wait, current);
 	struct usb_api_data awd;
@@ -1017,7 +1017,7 @@
                             struct usb_ctrlrequest *cmd, void *data, int len,
 			    int timeout)
 {
-        urb_t *urb;
+        struct urb *urb;
         int retv;
         int length;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/microtek.c linux/drivers/usb/microtek.c
--- v2.5.2/linux/drivers/usb/microtek.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/microtek.c	Wed Jan 23 15:33:46 2002
@@ -320,16 +320,11 @@
 
 #endif
 
-
-/* static inline int mts_is_aborting(struct mts_desc* desc) {
-	return (atomic_read(&desc->context.do_abort));
-}  */
-
 static inline void mts_urb_abort(struct mts_desc* desc) {
 	MTS_DEBUG_GOT_HERE();
 	mts_debug_dump(desc);
 
-	usb_unlink_urb( &desc->urb );
+	usb_unlink_urb( desc->urb );
 }
 
 static struct mts_desc * mts_list; /* list of active scanners */
@@ -370,6 +365,7 @@
 	scsi_unregister_host(&to_remove->ctempl);
 	unlock_kernel();
 
+	usb_free_urb(to_remove->urb);
 	kfree( to_remove );
 }
 
@@ -504,7 +500,7 @@
 	transfer->status = 0;
 
 	res = usb_submit_urb( transfer );
-	if ( res ) {
+	if ( unlikely(res) ) {
 		MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
 		context->srb->result = DID_ERROR << 16;
 		mts_transfer_cleanup(transfer);
@@ -518,7 +514,7 @@
 {
 	MTS_INT_INIT();
 
-	if ( context->final_callback )
+	if ( likely(context->final_callback != NULL) )
 		context->final_callback(context->srb);
 
 }
@@ -556,7 +552,7 @@
 
 	if ( context->data_length != transfer->actual_length ) {
 		context->srb->resid = context->data_length - transfer->actual_length;
-	} else if ( transfer->status ) {
+	} else if ( unlikely(transfer->status) ) {
 		context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
 	}
 
@@ -571,7 +567,7 @@
 {
 	MTS_INT_INIT();
 
-	if ( transfer->status ) {
+	if ( unlikely(transfer->status) ) {
 	        if (transfer->status == -ENOENT) {
 		        /* We are being killed */
 			MTS_DEBUG_GOT_HERE();
@@ -605,7 +601,7 @@
 	
 	MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
 
-	if (transfer->status) {
+	if (unlikely(transfer->status)) {
                 context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
 		mts_transfer_cleanup(transfer);
         }
@@ -703,14 +699,14 @@
 
 		srb->result = DID_BAD_TARGET << 16;
 
-		if(callback)
+		if(likely(callback != NULL))
 			callback(srb);
 
 		goto out;
 	}
 
 	
-	FILL_BULK_URB(&desc->urb,
+	FILL_BULK_URB(desc->urb,
 		      desc->usb_dev,
 		      usb_sndbulkpipe(desc->usb_dev,desc->ep_out),
 		      srb->cmnd,
@@ -723,13 +719,13 @@
 	mts_build_transfer_context( srb, desc );
 	desc->context.final_callback = callback;
 	
-	res=usb_submit_urb(&desc->urb);
+	res=usb_submit_urb(desc->urb);
 
-	if(res){
+	if(unlikely(res)){
 		MTS_ERROR("error %d submitting URB\n",(int)res);
 		srb->result = DID_ERROR << 16;
 
-		if(callback)
+		if(likely(callback != NULL))
 			callback(srb);
 
 	}
@@ -937,10 +933,12 @@
 		return NULL;
 	}
 
-	/* As done by usb_alloc_urb */
 	memset( new_desc, 0, sizeof(*new_desc) );
-	spin_lock_init(&new_desc->urb.lock);
-	
+	new_desc->urb = usb_alloc_urb(0);
+	if (!new_desc->urb) {
+		kfree(new_desc);
+		return NULL;
+	}
 		
 	/* initialising that descriptor */
 	new_desc->usb_dev = dev;
@@ -1061,4 +1059,5 @@
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL");
+
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/microtek.h linux/drivers/usb/microtek.h
--- v2.5.2/linux/drivers/usb/microtek.h	Fri Mar 23 11:50:01 2001
+++ linux/drivers/usb/microtek.h	Wed Jan 23 15:33:46 2002
@@ -46,7 +46,7 @@
 
 	struct semaphore lock;
 
-	struct urb urb;
+	struct urb *urb;
 	struct mts_transfer_context context;
 };
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- v2.5.2/linux/drivers/usb/ov511.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/ov511.c	Tue Jan 29 13:52:28 2002
@@ -57,7 +57,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.48 for Linux 2.4"
+#define DRIVER_VERSION "v1.48a for Linux 2.4"
 #define EMAIL "mmcclell@bigfoot.com"
 #define DRIVER_AUTHOR "Mark McClelland <mmcclell@bigfoot.com> & Bret Wallach \
 	& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
@@ -492,6 +492,10 @@
 static struct proc_dir_entry *ov511_proc_entry = NULL;
 extern struct proc_dir_entry *video_proc_entry;
 
+static struct file_operations ov511_control_fops = {
+	ioctl:		ov511_control_ioctl,
+};
+
 #define YES_NO(x) ((x) ? "yes" : "no")
 
 /* /proc/video/ov511/<minor#>/info */
@@ -673,8 +677,8 @@
 		unlock_kernel();
 		return;
 	}
-	ov511->proc_control->proc_fops->ioctl = ov511_control_ioctl;
 	ov511->proc_control->data = ov511;
+	ov511->proc_control->proc_fops = &ov511_control_fops;
 	unlock_kernel();
 }
 
@@ -3875,7 +3879,7 @@
  **********************************************************************/
 
 static int 
-ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
+ov511_move_data(struct usb_ov511 *ov511, struct urb *urb)
 {
 	unsigned char *cdata;
 	int data_size, num, offset, i, totlen = 0;
@@ -4108,7 +4112,7 @@
 }
 
 static int 
-ov518_move_data(struct usb_ov511 *ov511, urb_t *urb)
+ov518_move_data(struct usb_ov511 *ov511, struct urb *urb)
 {
 	unsigned char *cdata;
 	int i, data_size, totlen = 0;
@@ -4369,7 +4373,7 @@
 static int 
 ov511_init_isoc(struct usb_ov511 *ov511)
 {
-	urb_t *urb;
+	struct urb *urb;
 	int fx, err, n, size;
 
 	PDEBUG(3, "*** Initializing capture ***");
@@ -5552,7 +5556,7 @@
 }
 
 static int 
-ov511_mmap(struct video_device *vdev, const char *adr, unsigned long size)
+ov511_mmap(struct vm_area_struct *vma, struct video_device *vdev, const char *adr, unsigned long size)
 {
 	struct usb_ov511 *ov511 = vdev->priv;
 	unsigned long start = (unsigned long)adr;
@@ -5574,7 +5578,7 @@
 	pos = (unsigned long)ov511->fbuf;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up(&ov511->lock);
 			return -EAGAIN;
 		}
@@ -6893,13 +6897,13 @@
 		}
 	}
 
-	usb_driver_release_interface(&ov511_driver,
-		&ov511->dev->actconfig->interface[ov511->iface]);
-	ov511->dev = NULL;
-
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
         destroy_proc_ov511_cam(ov511);
 #endif
+
+	usb_driver_release_interface(&ov511_driver,
+		&ov511->dev->actconfig->interface[ov511->iface]);
+	ov511->dev = NULL;
 
 	/* Free the memory */
 	if (ov511 && !ov511->user) {
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/ov511.h linux/drivers/usb/ov511.h
--- v2.5.2/linux/drivers/usb/ov511.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/ov511.h	Mon Jan 21 15:44:21 2002
@@ -366,7 +366,7 @@
 
 struct ov511_sbuf {
 	char *data;
-	urb_t *urb;
+	struct urb *urb;
 };
 
 enum {
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c
--- v2.5.2/linux/drivers/usb/pegasus.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/pegasus.c	Wed Jan 23 15:33:46 2002
@@ -94,7 +94,7 @@
 
 static int update_eth_regs_async( pegasus_t * );
 /* Aargh!!! I _really_ hate such tweaks */
-static void ctrl_callback( urb_t *urb )
+static void ctrl_callback( struct urb *urb )
 {
 	pegasus_t	*pegasus = urb->context;
 
@@ -147,9 +147,9 @@
 	pegasus->dr.wValue = cpu_to_le16 (0);
 	pegasus->dr.wIndex = cpu_to_le16p(&indx);
 	pegasus->dr.wLength = cpu_to_le16p(&size);
-	pegasus->ctrl_urb.transfer_buffer_length = size;
+	pegasus->ctrl_urb->transfer_buffer_length = size;
 
-	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
 			  usb_rcvctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
 			  buffer, size, ctrl_callback, pegasus );
@@ -157,7 +157,7 @@
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_UNINTERRUPTIBLE );
 
-	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
+	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRLs %d", ret);
 		goto out;
 	}
@@ -197,9 +197,9 @@
 	pegasus->dr.wValue = cpu_to_le16 (0);
 	pegasus->dr.wIndex = cpu_to_le16p( &indx );
 	pegasus->dr.wLength = cpu_to_le16p( &size );
-	pegasus->ctrl_urb.transfer_buffer_length = size;
+	pegasus->ctrl_urb->transfer_buffer_length = size;
 
-	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
 			  usb_sndctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
 			  buffer, size, ctrl_callback, pegasus );
@@ -207,7 +207,7 @@
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_UNINTERRUPTIBLE );
 
-	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
+	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRL %d", ret);
 		goto out;
 	}
@@ -247,9 +247,9 @@
 	pegasus->dr.wValue = cpu_to_le16p( &dat);
 	pegasus->dr.wIndex = cpu_to_le16p( &indx );
 	pegasus->dr.wLength = cpu_to_le16( 1 );
-	pegasus->ctrl_urb.transfer_buffer_length = 1;
+	pegasus->ctrl_urb->transfer_buffer_length = 1;
 
-	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
 			  usb_sndctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
 			  buffer, 1, ctrl_callback, pegasus );
@@ -257,7 +257,7 @@
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_UNINTERRUPTIBLE );
 
-	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
+	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRL %d", ret);
 		goto out;
 	}
@@ -280,14 +280,14 @@
 	pegasus->dr.wValue = 0;
 	pegasus->dr.wIndex =  cpu_to_le16(EthCtrl0);
 	pegasus->dr.wLength = cpu_to_le16(3);
-	pegasus->ctrl_urb.transfer_buffer_length = 3;
+	pegasus->ctrl_urb->transfer_buffer_length = 3;
 
-	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
 			  usb_sndctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
 			  pegasus->eth_regs, 3, ctrl_callback, pegasus );
 
-	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) )
+	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) )
 		err( __FUNCTION__ " BAD CTRL %d, flags %x",ret,pegasus->flags );
 
 	return	ret;
@@ -569,11 +569,11 @@
 	pegasus->stats.rx_bytes += pkt_len;
 
 goon:
-	FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,
+	FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
 			usb_rcvbulkpipe(pegasus->usb, 1),
 			pegasus->rx_buff, PEGASUS_MAX_MTU, 
 			read_bulk_callback, pegasus );
-	if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
+	if ( (res = usb_submit_urb(pegasus->rx_urb)) )
 		warn( __FUNCTION__ " failed submint rx_urb %d", res);
 	pegasus->flags &= ~PEGASUS_RX_BUSY;
 }
@@ -639,8 +639,8 @@
 		return;
 		
 	warn("%s: Tx timed out.", net->name);
-	pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
-	usb_unlink_urb( &pegasus->tx_urb );
+	pegasus->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+	usb_unlink_urb( pegasus->tx_urb );
 	pegasus->stats.tx_errors++;
 }
 
@@ -656,12 +656,12 @@
 		
 	((__u16 *)pegasus->tx_buff)[0] = cpu_to_le16( l16 );
 	memcpy(pegasus->tx_buff+2, skb->data, skb->len);
-	FILL_BULK_URB( &pegasus->tx_urb, pegasus->usb,
+	FILL_BULK_URB( pegasus->tx_urb, pegasus->usb,
 			usb_sndbulkpipe(pegasus->usb, 2),
 			pegasus->tx_buff, PEGASUS_MAX_MTU, 
 			write_bulk_callback, pegasus );
-	pegasus->tx_urb.transfer_buffer_length = count;
-	if ((res = usb_submit_urb(&pegasus->tx_urb))) {
+	pegasus->tx_urb->transfer_buffer_length = count;
+	if ((res = usb_submit_urb(pegasus->tx_urb))) {
 		warn("failed tx_urb %d", res);
 		pegasus->stats.tx_errors++;
 		netif_start_queue( net );
@@ -717,18 +717,18 @@
 		err("can't enable_net_traffic() - %d", res);
 		return -EIO;
 	}
-	FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,
+	FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
 			usb_rcvbulkpipe(pegasus->usb, 1),
 			pegasus->rx_buff, PEGASUS_MAX_MTU, 
 			read_bulk_callback, pegasus );
-	if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
+	if ( (res = usb_submit_urb(pegasus->rx_urb)) )
 		warn( __FUNCTION__ " failed rx_urb %d", res );
 #ifdef	PEGASUS_USE_INTR
-	FILL_INT_URB( &pegasus->intr_urb, pegasus->usb,
+	FILL_INT_URB( pegasus->intr_urb, pegasus->usb,
 			usb_rcvintpipe(pegasus->usb, 3),
 			pegasus->intr_buff, sizeof(pegasus->intr_buff),
 			intr_callback, pegasus, pegasus->intr_interval );
-	if ( (res = usb_submit_urb(&pegasus->intr_urb)) )
+	if ( (res = usb_submit_urb(pegasus->intr_urb)) )
 		warn( __FUNCTION__ " failed intr_urb %d", res);
 #endif
 	netif_start_queue( net );
@@ -747,11 +747,11 @@
 	if ( !(pegasus->flags & PEGASUS_UNPLUG) )
 		disable_net_traffic( pegasus );
 
-	usb_unlink_urb( &pegasus->rx_urb );
-	usb_unlink_urb( &pegasus->tx_urb );
-	usb_unlink_urb( &pegasus->ctrl_urb );
+	usb_unlink_urb( pegasus->rx_urb );
+	usb_unlink_urb( pegasus->tx_urb );
+	usb_unlink_urb( pegasus->ctrl_urb );
 #ifdef	PEGASUS_USE_INTR
-	usb_unlink_urb( &pegasus->intr_urb );
+	usb_unlink_urb( pegasus->intr_urb );
 #endif
 
 	return 0;
@@ -800,7 +800,7 @@
 	}
 
 	pegasus->flags |= ETH_REGS_CHANGE;
-	ctrl_callback( &pegasus->ctrl_urb );
+	ctrl_callback( pegasus->ctrl_urb );
 
 	netif_wake_queue(net);
 }
@@ -856,6 +856,33 @@
 	pegasus->dev_index = dev_index;
 	init_waitqueue_head( &pegasus->ctrl_wait );
 
+	pegasus->ctrl_urb = usb_alloc_urb(0);
+	if (!pegasus->ctrl_urb) {
+		kfree (pegasus);
+		return NULL;
+	}
+	pegasus->rx_urb = usb_alloc_urb(0);
+	if (!pegasus->rx_urb) {
+		usb_free_urb (pegasus->ctrl_urb);
+		kfree (pegasus);
+		return NULL;
+	}
+	pegasus->tx_urb = usb_alloc_urb(0);
+	if (!pegasus->tx_urb) {
+		usb_free_urb (pegasus->rx_urb);
+		usb_free_urb (pegasus->ctrl_urb);
+		kfree (pegasus);
+		return NULL;
+	}
+	pegasus->intr_urb = usb_alloc_urb(0);
+	if (!pegasus->intr_urb) {
+		usb_free_urb (pegasus->tx_urb);
+		usb_free_urb (pegasus->rx_urb);
+		usb_free_urb (pegasus->ctrl_urb);
+		kfree (pegasus);
+		return NULL;
+	}
+
 	net = init_etherdev( NULL, 0 );
 	if ( !net ) {
 		kfree( pegasus );
@@ -883,6 +910,7 @@
 	if ( reset_mac(pegasus) ) {
 		err("can't reset MAC");
 		unregister_netdev( pegasus->net );
+		kfree(pegasus->net);
 		kfree(pegasus);
 		pegasus = NULL;
 		return NULL;
@@ -919,6 +947,11 @@
 	pegasus->flags |= PEGASUS_UNPLUG;
 	unregister_netdev( pegasus->net );
 	usb_dec_dev_use( dev );
+	usb_free_urb (pegasus->intr_urb);
+	usb_free_urb (pegasus->tx_urb);
+	usb_free_urb (pegasus->rx_urb);
+	usb_free_urb (pegasus->ctrl_urb);
+	kfree( pegasus->net );
 	kfree( pegasus );
 	pegasus = NULL;
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/pegasus.h linux/drivers/usb/pegasus.h
--- v2.5.2/linux/drivers/usb/pegasus.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/pegasus.h	Wed Jan 23 15:33:46 2002
@@ -107,7 +107,7 @@
 	unsigned		features;
 	int			dev_index;
 	int			intr_interval;
-	struct urb		ctrl_urb, rx_urb, tx_urb, intr_urb;
+	struct urb		*ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
 	struct usb_ctrlrequest	dr;
 	wait_queue_head_t	ctrl_wait;
 	struct semaphore	ctrl_sem;
@@ -145,6 +145,7 @@
 #define	VENDOR_SMARTBRIDGES	0x08d1
 #define	VENDOR_SMC		0x0707
 #define	VENDOR_SOHOWARE		0x15e8
+#define	VENDOR_SIEMENS		0x067c
 
 
 #else	/* PEGASUS_DEV */
@@ -173,6 +174,8 @@
 		DEFAULT_GPIO_RESET | PEGASUS_II ) 	
 PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
+		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8511,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
@@ -244,6 +247,8 @@
 PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
+		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
 		DEFAULT_GPIO_RESET )
 
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/pwc-if.c linux/drivers/usb/pwc-if.c
--- v2.5.2/linux/drivers/usb/pwc-if.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/pwc-if.c	Tue Jan 15 10:56:35 2002
@@ -125,7 +125,7 @@
 static long pwc_video_write(struct video_device *vdev, const char *buf, unsigned long count, int noblock);
 static unsigned int pwc_video_poll(struct video_device *vdev, struct file *file, poll_table *wait);
 static int  pwc_video_ioctl(struct video_device *vdev, unsigned int cmd, void *arg);
-static int  pwc_video_mmap(struct video_device *dev, const char *adr, unsigned long size);
+static int  pwc_video_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size);
 
 static struct video_device pwc_template = {
 	owner:		THIS_MODULE,
@@ -1580,7 +1580,7 @@
 	return 0;
 }	
 
-static int pwc_video_mmap(struct video_device *vdev, const char *adr, unsigned long size)
+static int pwc_video_mmap(struct vm_area_struct *vma, struct video_device *vdev, const char *adr, unsigned long size)
 {
 	struct pwc_device *pdev;
 	unsigned long start = (unsigned long)adr;
@@ -1593,7 +1593,7 @@
 	pos = (unsigned long)pdev->image_data;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
 			return -EAGAIN;
 
 		start += PAGE_SIZE;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- v2.5.2/linux/drivers/usb/scanner.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/scanner.c	Wed Jan 23 15:33:46 2002
@@ -972,6 +972,13 @@
 	}
 	memset (scn, 0, sizeof(struct scn_usb_data));
 
+	scn->scn_irq = usb_alloc_urb(0);
+	if (!scn->scn_irq) {
+		kfree(scn);
+		up(&scn_mutex);
+		return NULL;
+	}
+
 	init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
 
 	dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
@@ -979,13 +986,13 @@
 /* Ok, if we detected an interrupt EP, setup a handler for it */
 	if (have_intr) {
 		dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr);
-		FILL_INT_URB(&scn->scn_irq, dev,
+		FILL_INT_URB(scn->scn_irq, dev,
 			     usb_rcvintpipe(dev, have_intr),
 			     &scn->button, 1, irq_scanner, scn,
 			     // endpoint[(int)have_intr].bInterval);
 			     250);
 
-	        if (usb_submit_urb(&scn->scn_irq)) {
+	        if (usb_submit_urb(scn->scn_irq)) {
 			err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
                 	kfree(scn);
 			up(&scn_mutex);
@@ -1067,7 +1074,7 @@
 
 	if(scn->intr_ep) {
 		dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor);
-		usb_unlink_urb(&scn->scn_irq);
+		usb_unlink_urb(scn->scn_irq);
 	}
         usb_driver_release_interface(&scanner_driver,
                 &scn->scn_dev->actconfig->interface[scn->ifnum]);
@@ -1078,6 +1085,7 @@
 	dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
 	devfs_unregister(scn->devfs);
 	p_scn_table[scn->scn_minor] = NULL;
+	usb_free_urb(scn->scn_irq);
 	up (&(scn->sem));
 	kfree (scn);
 	up (&scn_mutex);
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/scanner.h linux/drivers/usb/scanner.h
--- v2.5.2/linux/drivers/usb/scanner.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/scanner.h	Wed Jan 23 15:33:46 2002
@@ -241,7 +241,7 @@
 struct scn_usb_data {
 	struct usb_device *scn_dev;
 	devfs_handle_t devfs;	/* devfs device */
-	struct urb scn_irq;
+	struct urb *scn_irq;
 	unsigned int ifnum;	/* Interface number of the USB device */
 	int scn_minor;		/* Scanner minor - used in disconnect() */
 	unsigned char button;	/* Front panel buffer */
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/se401.c linux/drivers/usb/se401.c
--- v2.5.2/linux/drivers/usb/se401.c	Fri Sep 14 14:27:10 2001
+++ linux/drivers/usb/se401.c	Mon Jan 21 15:44:21 2002
@@ -610,7 +610,7 @@
 */
 static int se401_start_stream(struct usb_se401 *se401)
 {
-	urb_t *urb;
+	struct urb *urb;
 	int err=0, i;
 	se401->streaming=1;
 
@@ -1354,7 +1354,7 @@
 	return realcount;
 }
 
-static int se401_mmap(struct video_device *dev, const char *adr,
+static int se401_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr,
         unsigned long size)
 {
 	struct usb_se401 *se401 = (struct usb_se401 *)dev;
@@ -1374,7 +1374,7 @@
 	pos = (unsigned long)se401->fbuf;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up(&se401->lock);
 			return -EAGAIN;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/se401.h linux/drivers/usb/se401.h
--- v2.5.2/linux/drivers/usb/se401.h	Fri Sep  7 10:59:04 2001
+++ linux/drivers/usb/se401.h	Mon Jan 21 15:44:21 2002
@@ -197,8 +197,8 @@
 
 	char *fbuf;		/* Videodev buffer area */
 
-	urb_t *urb[SE401_NUMSBUF];
-	urb_t *inturb;
+	struct urb *urb[SE401_NUMSBUF];
+	struct urb *inturb;
 	
 	int button;
 	int buttonpressed;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/serial/Config.help linux/drivers/usb/serial/Config.help
--- v2.5.2/linux/drivers/usb/serial/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/Config.help	Fri Jan 25 16:03:53 2002
@@ -0,0 +1,268 @@
+CONFIG_USB_SERIAL
+  Say Y here if you have a USB device that provides normal serial
+  ports, or acts like a serial device, and you want to connect it to
+  your USB bus.
+
+  Please read <file:Documentation/usb/usb-serial.txt> for more
+  information on the specifics of the different devices that are
+  supported, and on how to use them.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usbserial.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_GENERIC
+  Say Y here if you want to use the generic USB serial driver.  Please
+  read <file:Documentation/usb/usb-serial.txt> for more information on
+  using this driver.  It is recommended that the "USB Serial converter
+  support" be compiled as a module for this driver to be used
+  properly.
+
+CONFIG_USB_SERIAL_WHITEHEAT
+  Say Y here if you want to use a ConnectTech WhiteHEAT 4 port
+  USB to serial converter device.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called whiteheat.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+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
+  driver.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called visor.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_IPAQ
+  Say Y here if you want to connect to your Compaq iPAQ running
+  Windows CE 3.0 using a USB autosync cable. For information on using
+  the driver, read <file:Documentation/usb/usb-serial.txt>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ipaq.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_IR
+  Say Y here if you want to enable simple serial support for USB IrDA
+  devices.  This is useful if you do not want to use the full IrDA
+  stack.
+  
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ir-usb.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_IR
+  Say Y here if you want to enable simple serial support for USB IrDA
+  devices.  This is useful if you do not want to use the full IrDA
+  stack.
+  
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ir-usb.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_BELKIN
+  Say Y here if you want to use a Belkin USB Serial single port
+  adaptor (F5U103 is one of the model numbers) or the Peracom single
+  port USB to serial adapter.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called belkin_sa.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_FTDI_SIO
+  Say Y here if you want to use a FTDI SIO single port USB to serial
+  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
+  information on this driver and the device.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ftdi_sio.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_KEYSPAN_PDA
+  Say Y here if you want to use a Keyspan PDA single port USB to
+  serial converter device.  This driver makes use of firmware
+  developed from scratch by Brian Warner.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called keyspan_pda.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_XIRCOM
+  Say Y here if you want to use a Xircom or Entregra single port USB to
+  serial converter device.  This driver makes use of firmware
+  developed from scratch by Brian Warner.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called keyspan_pda.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_KEYSPAN
+  Say Y here if you want to use Keyspan USB to serial converter
+  devices.  This driver makes use of Keyspan's official firmware
+  and was developed with their support.  You must also include
+  firmware to support your particular device(s).
+
+  See <http://misc.nu/hugh/keyspan.html> for more information.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called keyspan.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_KEYSPAN_USA28
+  Say Y here to include firmware for the USA-28 converter.
+
+CONFIG_USB_SERIAL_KEYSPAN_USA28X
+  Say Y here to include firmware for the USA-28X converter.
+  Be sure you have a USA-28X, there are also 28XA and 28XB
+  models, the label underneath has the actual part number.
+
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA
+  Say Y here to include firmware for the USA-28XA converter.
+  Be sure you have a USA-28XA, there are also 28X and 28XB
+  models, the label underneath has the actual part number.
+
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB
+  Say Y here to include firmware for the USA-28XB converter.
+  Be sure you have a USA-28XB, there are also 28X and 28XA
+  models, the label underneath has the actual part number.
+
+CONFIG_USB_SERIAL_KEYSPAN_USA19
+  Say Y here to include firmware for the USA-19 converter.
+
+CONFIG_USB_SERIAL_KEYSPAN_USA18X
+  Say Y here to include firmware for the USA-18X converter.
+
+CONFIG_USB_SERIAL_KEYSPAN_USA19W
+  Say Y here to include firmware for the USA-19W converter.
+
+CONFIG_USB_SERIAL_KEYSPAN_USA49W
+  Say Y here to include firmware for the USA-49W converter.
+
+CONFIG_USB_SERIAL_OMNINET
+  Say Y here if you want to use a ZyXEL omni.net LCD ISDN TA.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called omninet.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT
+  Say Y here if you want to use Digi AccelePort USB 2 or 4 devices,
+  2 port (plus parallel port) and 4 port USB serial converters.  The
+  parallel port on the USB 2 appears as a third serial port on Linux.
+  The Digi Acceleport USB 8 is not yet supported by this driver.
+
+  This driver works under SMP with the usb-uhci driver.  It does not
+  work under SMP with the uhci driver.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called digi_acceleport.o.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_EMPEG
+  Say Y here if you want to connect to your Empeg empeg-car Mark I/II
+  mp3 player via USB.  The driver uses a single ttyUSB{0,1,2,...}
+  device node.  See <file:Documentation/usb/usb-serial.txt> for more
+  tidbits of information.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called empeg.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_MCT_U232
+  Say Y here if you want to use a USB Serial single port adapter from
+  Magic Control Technology Corp. (U232 is one of the model numbers).
+
+  This driver also works with Sitecom U232-P25 and D-Link DU-H3SP USB
+  BAY devices.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called mct_u232.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_PL2303
+  Say Y here if you want to use the PL2303 USB Serial single port
+  adapter from Prolific.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pl2303.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_CYBERJACK
+  Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard
+  reader. This is an interface to ISO 7816 compatible contactbased
+  chipcards, e.g. GSM SIMs.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cyberjack.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+  If unsure, say N.
+
+CONFIG_USB_SERIAL_EDGEPORT
+  Say Y here if you want to use any of the following devices from
+  Inside Out Networks (Digi):
+       Edgeport/4
+       Rapidport/4
+       Edgeport/4t
+       Edgeport/2
+       Edgeport/4i
+       Edgeport/2i
+       Edgeport/421
+       Edgeport/21
+       Edgeport/8
+       Edgeport/8 Dual
+       Edgeport/2D8
+       Edgeport/4D8
+       Edgeport/8i
+       Edgeport/2 DIN
+       Edgeport/4 DIN
+       Edgeport/16 Dual
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called io_edgeport.o.  If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_KLSI
+  Say Y here if you want to use a KL5KUSB105 - based single port
+  serial adapter. The most widely known -- and currently the only
+  tested -- device in this category is the PalmConnect USB Serial
+  adapter sold by Palm Inc. for use with their Palm III and Palm V
+  series PDAs.
+
+  Please read <file:Documentation/usb/usb-serial.txt> for more
+  information.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called kl5kusb105.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SERIAL_DEBUG
+  Say Y here if you want verbose debug messages from the USB Serial
+  Drivers sent to the kernel debug log.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- v2.5.2/linux/drivers/usb/serial/ftdi_sio.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/serial/ftdi_sio.c	Mon Jan 21 15:44:21 2002
@@ -138,6 +138,7 @@
    
 static __devinitdata struct usb_device_id id_table_8U232AM [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
+	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
 	{ }						/* Terminating entry */
 };
 
@@ -145,6 +146,7 @@
 static __devinitdata struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
+	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
 	{ }						/* Terminating entry */
 };
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/serial/ftdi_sio.h linux/drivers/usb/serial/ftdi_sio.h
--- v2.5.2/linux/drivers/usb/serial/ftdi_sio.h	Thu May 24 14:55:51 2001
+++ linux/drivers/usb/serial/ftdi_sio.h	Mon Jan 21 15:44:21 2002
@@ -22,6 +22,8 @@
 #define FTDI_VID	0x0403	/* Vendor Id */
 #define FTDI_SIO_PID	0x8372	/* Product Id SIO application of 8U100AX  */
 #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
+#define FTDI_NF_RIC_VID	0x0DCD	/* Vendor Id */
+#define FTDI_NF_RIC_PID	0x0001	/* Product Id */
 
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c
--- v2.5.2/linux/drivers/usb/serial/io_edgeport.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/serial/io_edgeport.c	Mon Jan 21 15:44:21 2002
@@ -2456,7 +2456,7 @@
 {
 	struct edgeport_serial *edge_serial = (struct edgeport_serial *)edge_port->port->serial->private;
 	int status = 0;
-	urb_t *urb;
+	struct urb *urb;
 	int timeout;
 
 	usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer);
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/serial/ir-usb.c linux/drivers/usb/serial/ir-usb.c
--- v2.5.2/linux/drivers/usb/serial/ir-usb.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/serial/ir-usb.c	Thu Jan 17 14:06:53 2002
@@ -2,6 +2,7 @@
  * USB IR Dongle driver
  *
  *	Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *	Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.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
@@ -20,6 +21,12 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * 2002_Jan_14  gb
+ *	Added module parameter to force specific number of XBOFs.
+ *	Added ir_xbof_change().
+ *	Reorganized read_bulk_callback error handling.
+ *	Switched from FILL_BULK_URB() to usb_fill_bulk_urb().
+ *
  * 2001_Nov_08  greg kh
  *	Changed the irda_usb_find_class_desc() function based on comments and
  *	code from Martin Diehl.
@@ -62,13 +69,15 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.3"
+#define DRIVER_VERSION "v0.4"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC "USB IR Dongle driver"
 
 /* if overridden by the user, then use their value for the size of the read and
  * write urbs */
 static int buffer_size = 0;
+/* if overridden by the user, then use the specified number of XBOFs */
+static int xbof = -1;
 
 static int  ir_startup (struct usb_serial *serial);
 static int  ir_open (struct usb_serial_port *port, struct file *filep);
@@ -78,6 +87,9 @@
 static void ir_read_bulk_callback (struct urb *urb);
 static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios);
 
+static u8 ir_baud = 0;
+static u8 ir_xbof = 0;
+static u8 ir_add_bof = 0;
 
 static __devinitdata struct usb_device_id id_table [] = {
 	{ USB_DEVICE(0x050f, 0x0180) },		/* KC Technology, KC-180 */
@@ -148,14 +160,16 @@
 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 			0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500));
 	
-	dbg(__FUNCTION__ " -  ret=%d", ret);
+	dbg("%s -  ret=%d", __FUNCTION__, ret);
 	if (ret < sizeof(*desc)) {
-		dbg(__FUNCTION__ " - class descriptor read %s (%d)",
-				(ret<0) ? "failed" : "too short", ret);
+		dbg("%s - class descriptor read %s (%d)",
+				__FUNCTION__, 
+				(ret<0) ? "failed" : "too short",
+				ret);
 		goto error;
 	}
 	if (desc->bDescriptorType != USB_DT_IRDA) {
-		dbg(__FUNCTION__ " - bad class descriptor type");
+		dbg("%s - bad class descriptor type", __FUNCTION__);
 		goto error;
 	}
 	
@@ -166,6 +180,28 @@
 	return NULL;
 }
 
+
+static u8 ir_xbof_change(u8 xbof)
+{
+	u8 result;
+	/* reference irda-usb.c */
+	switch(xbof) {
+		case 48: result = 0x10; break;
+		case 28:
+		case 24: result = 0x20; break;
+		default:
+		case 12: result = 0x30; break;
+		case  5:
+		case  6: result = 0x40; break;
+		case  3: result = 0x50; break;
+		case  2: result = 0x60; break;
+		case  1: result = 0x70; break;
+		case  0: result = 0x80; break;
+	}
+	return(result);
+}
+
+
 static int ir_startup (struct usb_serial *serial)
 {
 	struct irda_class_desc *irda_desc;
@@ -175,16 +211,30 @@
 		err ("IRDA class descriptor not found, device not bound");
 		return -ENODEV;
 	}
-	dbg (__FUNCTION__" - Baud rates supported: %s%s%s%s%s%s%s%s%s",
-	     (irda_desc->wBaudRate & 0x0001) ? "2400 " : "",
-	     irda_desc->wBaudRate & 0x0002 ? "9600 " : "",
-	     irda_desc->wBaudRate & 0x0004 ? "19200 " : "",
-	     irda_desc->wBaudRate & 0x0008 ? "38400 " : "",
-	     irda_desc->wBaudRate & 0x0010 ? "57600 " : "",
-	     irda_desc->wBaudRate & 0x0020 ? "115200 " : "",
-	     irda_desc->wBaudRate & 0x0040 ? "576000 " : "",
-	     irda_desc->wBaudRate & 0x0080 ? "1152000 " : "",
-	     irda_desc->wBaudRate & 0x0100 ? "4000000 " : "");
+
+	dbg ("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s",
+		__FUNCTION__,
+		(irda_desc->wBaudRate & 0x0001) ? " 2400"    : "",
+		(irda_desc->wBaudRate & 0x0002) ? " 9600"    : "",
+		(irda_desc->wBaudRate & 0x0004) ? " 19200"   : "",
+		(irda_desc->wBaudRate & 0x0008) ? " 38400"   : "",
+		(irda_desc->wBaudRate & 0x0010) ? " 57600"   : "",
+		(irda_desc->wBaudRate & 0x0020) ? " 115200"  : "",
+		(irda_desc->wBaudRate & 0x0040) ? " 576000"  : "",
+		(irda_desc->wBaudRate & 0x0080) ? " 1152000" : "",
+		(irda_desc->wBaudRate & 0x0100) ? " 4000000" : "");
+
+	switch( irda_desc->bmAdditionalBOFs ) {
+		case 0x01: ir_add_bof = 48; break;
+		case 0x02: ir_add_bof = 24; break;
+		case 0x04: ir_add_bof = 12; break;
+		case 0x08: ir_add_bof =  6; break;
+		case 0x10: ir_add_bof =  3; break;
+		case 0x20: ir_add_bof =  2; break;
+		case 0x40: ir_add_bof =  1; break;
+		case 0x80: ir_add_bof =  0; break;
+		default:
+	}
 
 	kfree (irda_desc);
 
@@ -200,7 +250,7 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	down (&port->sem);
 	
@@ -211,7 +261,7 @@
 			/* override the default buffer sizes */
 			buffer = kmalloc (buffer_size, GFP_KERNEL);
 			if (!buffer) {
-				err (__FUNCTION__ " - out of memory.");
+				err ("%s - out of memory.", __FUNCTION__);
 				return -ENOMEM;
 			}
 			kfree (port->read_urb->transfer_buffer);
@@ -220,7 +270,7 @@
 
 			buffer = kmalloc (buffer_size, GFP_KERNEL);
 			if (!buffer) {
-				err (__FUNCTION__ " - out of memory.");
+				err ("%s - out of memory.", __FUNCTION__);
 				return -ENOMEM;
 			}
 			kfree (port->write_urb->transfer_buffer);
@@ -230,13 +280,18 @@
 		}
 
 		/* Start reading from the device */
-		FILL_BULK_URB(port->read_urb, serial->dev, 
-			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-			      ir_read_bulk_callback, port);
+		usb_fill_bulk_urb (
+			port->read_urb,
+			serial->dev, 
+			usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+			port->read_urb->transfer_buffer,
+			port->read_urb->transfer_buffer_length,
+			ir_read_bulk_callback,
+			port);
+		port->read_urb->transfer_flags = USB_QUEUE_BULK;
 		result = usb_submit_urb(port->read_urb);
 		if (result)
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+			err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
 	}
 	
 	up (&port->sem);
@@ -251,7 +306,7 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 			 
 	serial = get_usb_serial (port, __FUNCTION__);
 	if (!serial)
@@ -276,11 +331,12 @@
 {
 	unsigned char *transfer_buffer;
 	int result;
+	int transfer_size;
 
-	dbg(__FUNCTION__ " - port = %d, count = %d", port->number, count);
+	dbg("%s - port = %d, count = %d", __FUNCTION__, port->number, count);
 
 	if (!port->tty) {
-		err (__FUNCTION__ " - no tty???");
+		err ("%s - no tty???", __FUNCTION__);
 		return 0;
 	}
 
@@ -288,37 +344,49 @@
 		return 0;
 
 	if (port->write_urb->status == -EINPROGRESS) {
-		dbg (__FUNCTION__ " - already writing");
+		dbg ("%s - already writing", __FUNCTION__);
 		return 0;
 	}
 
+	transfer_buffer = port->write_urb->transfer_buffer;
+	transfer_size = min(count, port->bulk_out_size - 1);
+
 	/*
-	 * The first byte of the packet we send to the device contains a BOD
-	 * and baud rate change.  So we set it to 0.
+	 * The first byte of the packet we send to the device contains an
+	 * inband header which indicates an additional number of BOFs and
+	 * a baud rate change.
+	 *
 	 * See section 5.4.2.2 of the USB IrDA spec.
 	 */
-	transfer_buffer = port->write_urb->transfer_buffer;
-	count = min (port->bulk_out_size-1, count);
+	*transfer_buffer = ir_xbof | ir_baud;
+	++transfer_buffer;
+
 	if (from_user) {
-		if (copy_from_user (&transfer_buffer[1], buf, count))
+		if (copy_from_user (transfer_buffer, buf, transfer_size))
 			return -EFAULT;
 	} else {
-		memcpy (&transfer_buffer[1], buf, count);
+		memcpy (transfer_buffer, buf, transfer_size);
 	}
 
-	/* use 12 XBOF's as default */
-	transfer_buffer[0] = 0x30;
-
-	usb_serial_debug_data (__FILE__, __FUNCTION__, count+1, transfer_buffer);
+	usb_fill_bulk_urb (
+		port->write_urb,
+		port->serial->dev,
+		usb_sndbulkpipe(port->serial->dev,
+			port->bulk_out_endpointAddress),
+		port->write_urb->transfer_buffer,
+		transfer_size + 1,
+		ir_write_bulk_callback,
+		port);
+
+	port->write_urb->transfer_flags
+		= USB_QUEUE_BULK
+		| USB_ZERO_PACKET;
 
-	port->write_urb->transfer_buffer_length = count + 1;
-	port->write_urb->dev = port->serial->dev;
-	port->write_urb->transfer_flags |= USB_ZERO_PACKET;
 	result = usb_submit_urb (port->write_urb);
 	if (result)
-		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+		err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 	else
-		result = count;
+		result = transfer_size;
 
 	return result;
 }
@@ -330,13 +398,19 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
+	usb_serial_debug_data (
+		__FILE__,
+		__FUNCTION__,
+		urb->actual_length,
+		urb->transfer_buffer);
+
 	queue_task(&port->tqueue, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
 	
@@ -354,34 +428,87 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
-	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+	if (!port->open_count) {
+		dbg("%s - port closed.", __FUNCTION__);
 		return;
 	}
 
-	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+	switch (urb->status) {
+
+		case 0: /* Successful */
+
+			/*
+			 * The first byte of the packet we get from the device
+			 * contains a busy indicator and baud rate change.
+			 * See section 5.4.1.2 of the USB IrDA spec.
+			 */
+			if((*data & 0x0f) > 0) ir_baud = *data & 0x0f;
+
+			usb_serial_debug_data (
+				__FILE__,
+				__FUNCTION__,
+				urb->actual_length,
+				data);
+
+			/*
+			 * Bypass flip-buffers, and feed the ldisc directly
+			 * due to our potentally large buffer size.  Since we
+			 * used to set low_latency, this is exactly what the
+			 * tty layer did anyway :)
+			 */
+			tty = port->tty;
+
+			tty->ldisc.receive_buf(
+				tty,
+				data+1,
+				NULL,
+				urb->actual_length-1);
+
+			/*
+			 * No break here.
+			 * We want to resubmit the urb so we can read
+			 * again.
+			 */
+
+		case -EPROTO: /* taking inspiration from pl2303.c */
+
+			/* Continue trying to always read */
+			usb_fill_bulk_urb (
+				port->read_urb,
+				serial->dev, 
+				usb_rcvbulkpipe(serial->dev,
+					port->bulk_in_endpointAddress),
+				port->read_urb->transfer_buffer,
+				port->read_urb->transfer_buffer_length,
+				ir_read_bulk_callback,
+				port);
+
+			port->read_urb->transfer_flags = USB_QUEUE_BULK;
+
+			result = usb_submit_urb(port->read_urb);
+
+			if (result)
+				err("%s - failed resubmitting read urb, error %d",
+					__FUNCTION__, 
+					result);
+
+			break ;
+
+		default:
+			dbg("%s - nonzero read bulk status received: %d",
+				__FUNCTION__, 
+				urb->status);
+			break ;
+
+	}
 
-	/* Bypass flip-buffers, and feed the ldisc directly due to our 
-	 * potentally large buffer size.  Since we used to set low_latency,
-	 * this is exactly what the tty layer did anyway :) */
-	tty = port->tty;
-	tty->ldisc.receive_buf(tty, data+1, NULL, urb->actual_length-1);
-
-	/* Continue trying to always read  */
-	FILL_BULK_URB(port->read_urb, serial->dev, 
-		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-		      ir_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb);
-	if (result)
-		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 	return;
 }
 
@@ -390,12 +517,11 @@
 	unsigned char *transfer_buffer;
 	unsigned int cflag;
 	int result;
-	u8 baud;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if ((!port->tty) || (!port->tty->termios)) {
-		dbg(__FUNCTION__" - no tty structures");
+		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 	}
 
@@ -404,44 +530,70 @@
 	if (old_termios) {
 		if ((cflag == old_termios->c_cflag) &&
 		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-			dbg(__FUNCTION__ " - nothing to change...");
+			dbg("%s - nothing to change...", __FUNCTION__);
 			return;
 		}
 	}
 
 	/* All we can change is the baud rate */
 	if (cflag & CBAUD) {
-		dbg (__FUNCTION__ " - asking for baud %d", tty_get_baud_rate(port->tty));
+
+		dbg ("%s - asking for baud %d",
+			__FUNCTION__,
+			tty_get_baud_rate(port->tty));
+
 		/* 
 		 * FIXME, we should compare the baud request against the
 		 * capability stated in the IR header that we got in the
 		 * startup funtion.
 		 */
 		switch (cflag & CBAUD) {
-			case B2400:	baud = SPEED_2400;	break;
-			case B9600:	baud = SPEED_9600;	break;
-			case B19200:	baud = SPEED_19200;	break;
-			case B38400:	baud = SPEED_38400;	break;
-			case B57600:	baud = SPEED_57600;	break;
-			case B115200:	baud = SPEED_115200;	break;
-			case B576000:	baud = SPEED_576000;	break;
-			case B1152000:	baud = SPEED_1152000;	break;
-			case B4000000:	baud = SPEED_4000000;	break;
+			case B2400:    ir_baud = SPEED_2400;    break;
 			default:
-				err ("ir-usb driver does not support the baudrate (%d) requested", tty_get_baud_rate(port->tty));
-				return;
+			case B9600:    ir_baud = SPEED_9600;    break;
+			case B19200:   ir_baud = SPEED_19200;   break;
+			case B38400:   ir_baud = SPEED_38400;   break;
+			case B57600:   ir_baud = SPEED_57600;   break;
+			case B115200:  ir_baud = SPEED_115200;  break;
+			case B576000:  ir_baud = SPEED_576000;  break;
+			case B1152000: ir_baud = SPEED_1152000; break;
+			case B4000000: ir_baud = SPEED_4000000; break;
 		}
-		
+
+		if (xbof == -1) {
+			ir_xbof = ir_xbof_change(ir_add_bof);
+		} else {
+			ir_xbof = ir_xbof_change(xbof) ;
+		}
+
+		/* Notify the tty driver that the termios have changed. */
+		port->tty->ldisc.set_termios(port->tty, NULL);
+
 		/* FIXME need to check to see if our write urb is busy right
-		 * now, or use a urb pool. */
-		/* send the baud change out on an "empty" data packet */
+		 * now, or use a urb pool.
+		 *
+		 * send the baud change out on an "empty" data packet
+		 */
 		transfer_buffer = port->write_urb->transfer_buffer;
-		transfer_buffer[0] = baud;
-		port->write_urb->transfer_buffer_length = 1;
-		port->write_urb->dev = port->serial->dev;
+		*transfer_buffer = ir_xbof | ir_baud;
+
+		usb_fill_bulk_urb (
+			port->write_urb,
+			port->serial->dev,
+			usb_sndbulkpipe(port->serial->dev,
+				port->bulk_out_endpointAddress),
+			port->write_urb->transfer_buffer,
+			1,
+			ir_write_bulk_callback,
+			port);
+
+		port->write_urb->transfer_flags
+			= USB_QUEUE_BULK
+			| USB_ZERO_PACKET;
+
 		result = usb_submit_urb (port->write_urb);
 		if (result)
-			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+			err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 	}
 	return;
 }
@@ -470,6 +622,8 @@
 
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug enabled or not");
+MODULE_PARM(xbof, "i");
+MODULE_PARM_DESC(xbof, "Force specific number of XBOFs");
 MODULE_PARM(buffer_size, "i");
 MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers");
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c
--- v2.5.2/linux/drivers/usb/serial/keyspan.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/serial/keyspan.c	Mon Jan 21 15:44:21 2002
@@ -109,11 +109,11 @@
 
 	const keyspan_device_details	*device_details;
 
-	urb_t		*instat_urb;
+	struct urb	*instat_urb;
 	char		instat_buf[INSTAT_BUFLEN];
 
 	/* XXX this one probably will need a lock */
-	urb_t		*glocont_urb;
+	struct urb	*glocont_urb;
 	char		glocont_buf[GLOCONT_BUFLEN];
 };
 
@@ -128,18 +128,18 @@
 	const keyspan_device_details	*device_details;
 
 	/* Input endpoints and buffer for this port */
-	urb_t		*in_urbs[2];
+	struct urb	*in_urbs[2];
 	char		in_buffer[2][64];
 	/* Output endpoints and buffer for this port */
-	urb_t		*out_urbs[2];
+	struct urb	*out_urbs[2];
 	char		out_buffer[2][64];
 
 	/* Input ack endpoint */
-	urb_t		*inack_urb;
+	struct urb	*inack_urb;
 	char		inack_buffer[1];
 
 	/* Output control endpoint */
-	urb_t		*outcont_urb;
+	struct urb	*outcont_urb;
 	char		outcont_buffer[64];
 
 	/* Settings for the port */
@@ -178,15 +178,7 @@
 /* Functions used by new usb-serial code. */
 static int __init keyspan_init (void)
 {
-	usb_serial_register (&keyspan_usa18x_pre_device);
-	usb_serial_register (&keyspan_usa19_pre_device);
-	usb_serial_register (&keyspan_usa19w_pre_device);
-	usb_serial_register (&keyspan_usa28_pre_device);
-	usb_serial_register (&keyspan_usa28x_pre_device);
-	usb_serial_register (&keyspan_usa28xa_pre_device);
-	usb_serial_register (&keyspan_usa28xb_pre_device);
-	usb_serial_register (&keyspan_usa49w_pre_device);
-
+	usb_serial_register (&keyspan_pre_device);
 	usb_serial_register (&keyspan_usa18x_device);
 	usb_serial_register (&keyspan_usa19_device);
 	usb_serial_register (&keyspan_usa19w_device);
@@ -203,15 +195,7 @@
 
 static void __exit keyspan_exit (void)
 {
-	usb_serial_deregister (&keyspan_usa18x_pre_device);
-	usb_serial_deregister (&keyspan_usa19_pre_device);
-	usb_serial_deregister (&keyspan_usa19w_pre_device);
-	usb_serial_deregister (&keyspan_usa28_pre_device);
-	usb_serial_deregister (&keyspan_usa28x_pre_device);
-	usb_serial_deregister (&keyspan_usa28xa_pre_device);
-	usb_serial_deregister (&keyspan_usa28xb_pre_device);
-	usb_serial_deregister (&keyspan_usa49w_pre_device);
-
+	usb_serial_deregister (&keyspan_pre_device);
 	usb_serial_deregister (&keyspan_usa18x_device);
 	usb_serial_deregister (&keyspan_usa19_device);
 	usb_serial_deregister (&keyspan_usa19w_device);
@@ -340,7 +324,7 @@
 	const keyspan_device_details	*d_details;
 	int				flip;
 	int 				left, todo;
-	urb_t 				*this_urb;
+	struct urb			*this_urb;
 	int 				err;
 
 	p_priv = (struct keyspan_port_private *)(port->private);
@@ -869,7 +853,7 @@
 	struct usb_serial 		*serial = port->serial;
 	const keyspan_device_details	*d_details;
 	int				i, already_active, err;
-	urb_t *urb;
+	struct urb			*urb;
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 	p_priv = (struct keyspan_port_private *)(port->private);
@@ -906,7 +890,7 @@
 	return (0);
 }
 
-static inline void stop_urb(urb_t *urb)
+static inline void stop_urb(struct urb *urb)
 {
 	if (urb && urb->status == -EINPROGRESS) {
 		urb->transfer_flags &= ~USB_ASYNC_UNLINK;
@@ -1057,11 +1041,11 @@
 }
 
 /* Helper functions used by keyspan_setup_urbs */
-static urb_t *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
-				int dir, void *ctx, char *buf, int len,
-				void (*callback)(urb_t *))
+static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
+				     int dir, void *ctx, char *buf, int len,
+				     void (*callback)(struct urb *))
 {
-	urb_t *urb;
+	struct urb *urb;
 
 	if (endpoint == -1)
 		return NULL;		/* endpoint not needed */
@@ -1082,12 +1066,12 @@
 }
 
 static struct callbacks {
-	void	(*instat_callback)(urb_t *);
-	void	(*glocont_callback)(urb_t *);
-	void	(*indat_callback)(urb_t *);
-	void	(*outdat_callback)(urb_t *);
-	void	(*inack_callback)(urb_t *);
-	void	(*outcont_callback)(urb_t *);
+	void	(*instat_callback)(struct urb *);
+	void	(*glocont_callback)(struct urb *);
+	void	(*indat_callback)(struct urb *);
+	void	(*outdat_callback)(struct urb *);
+	void	(*inack_callback)(struct urb *);
+	void	(*outcont_callback)(struct urb *);
 } keyspan_callbacks[] = {
 	{
 		/* msg_usa26 callbacks */
@@ -1311,7 +1295,7 @@
 	struct keyspan_port_private 		*p_priv;
 	const  keyspan_device_details		*d_details;
 	int 					outcont_urb;
-	urb_t *this_urb;
+	struct urb				*this_urb;
 	int err;
 
 	dbg ("%s reset=%d\n", __FUNCTION__, reset_port); 
@@ -1446,7 +1430,7 @@
 	struct keyspan_serial_private	 	*s_priv;
 	struct keyspan_port_private 		*p_priv;
 	const  keyspan_device_details		*d_details;
-	urb_t *this_urb;
+	struct urb				*this_urb;
 	int err;
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
@@ -1532,7 +1516,7 @@
 	struct keyspan_port_private 		*p_priv;
 	const  keyspan_device_details		*d_details;
 	int 					glocont_urb;
-	urb_t 					*this_urb;
+	struct urb				*this_urb;
 	int 					err;
 	int					device_port;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/serial/keyspan.h linux/drivers/usb/serial/keyspan.h
--- v2.5.2/linux/drivers/usb/serial/keyspan.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/serial/keyspan.h	Thu Jan 17 14:06:53 2002
@@ -372,42 +372,15 @@
    ID pattern.  But, for now, it looks like we need slightly different
    behavior for each match. */
 
-static __devinitdata struct usb_device_id keyspan_usa18x_pre_ids[] = {
+/* usb_device_id table for the pre-firmware download keyspan devices */
+static __devinitdata struct usb_device_id keyspan_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
-	{ }	/* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19w_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28x_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xa_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xb_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa49w_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
 	{ } /* Terminating entry */
 };
@@ -448,10 +421,10 @@
 };
 
     /* Structs for the devices, pre and post renumeration. */
-static struct usb_serial_device_type keyspan_usa18x_pre_device = {
+static struct usb_serial_device_type keyspan_pre_device = {
 	owner:			THIS_MODULE,
-	name:			"Keyspan USA18X - (without firmware)",
-	id_table:		keyspan_usa18x_pre_ids,
+	name:			"Keyspan - (without firmware)",
+	id_table:		keyspan_pre_ids,
 	num_interrupt_in:	NUM_DONT_CARE,
 	num_bulk_in:		NUM_DONT_CARE,
 	num_bulk_out:		NUM_DONT_CARE,
@@ -459,84 +432,6 @@
 	startup:		keyspan_fake_startup	
 };
 
-static struct usb_serial_device_type keyspan_usa19_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA19 - (without firmware)",
-	id_table:		keyspan_usa19_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		keyspan_fake_startup	
-};
-
-
-static struct usb_serial_device_type keyspan_usa19w_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA19W - (without firmware)",
-	id_table:		keyspan_usa19w_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		keyspan_fake_startup	
-};
-
-
-static struct usb_serial_device_type keyspan_usa28_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA28 - (without firmware)",
-	id_table:		keyspan_usa28_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa28x_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA28X - (without firmware)",
-	id_table:		keyspan_usa28x_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa28xa_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA28XA - (without firmware)",
-	id_table:		keyspan_usa28xa_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa28xb_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA28XB - (without firmware)",
-	id_table:		keyspan_usa28xb_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa49w_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA49W - (without firmware)",
-	id_table:		keyspan_usa49w_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		4,
-	startup:		keyspan_fake_startup	
-};
 
 static struct usb_serial_device_type keyspan_usa18x_device = {
 	owner:			THIS_MODULE,
@@ -550,8 +445,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-	//write_bulk_callback: 	Not used - we define our own herbs
-	//read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -574,8 +467,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-//	write_bulk_callback: 	keyspan_write_bulk_callback,
-//	read_int_callback:	keyspan_usa28_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -599,8 +490,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-	//write_bulk_callback: 	Not used - we define our own herbs
-	//read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -640,8 +529,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-//	write_bulk_callback: 	keyspan_write_bulk_callback,
-//	read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -665,8 +552,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-//	write_bulk_callback: 	keyspan_write_bulk_callback,
-//	read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -690,8 +575,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-	//write_bulk_callback: 	Not used - we define our own herbs
-	//read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/storage/protocol.c linux/drivers/usb/storage/protocol.c
--- v2.5.2/linux/drivers/usb/storage/protocol.c	Sun Jul 29 21:11:50 2001
+++ linux/drivers/usb/storage/protocol.c	Thu Jan 17 14:06:53 2002
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: protocol.c,v 1.10 2001/07/30 00:27:59 mdharm Exp $
+ * $Id: protocol.c,v 1.11 2002/01/13 06:40:25 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -76,7 +76,7 @@
 		data_ptr = (unsigned char *)srb->request_buffer;
 
 	/* Change the SCSI revision number */
-	data_ptr[2] |= 0x2;
+	data_ptr[2] = (data_ptr[2] & ~7) | 2;
 }
 
 /***********************************************************************
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/storage/transport.c linux/drivers/usb/storage/transport.c
--- v2.5.2/linux/drivers/usb/storage/transport.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/storage/transport.c	Mon Jan 21 15:44:21 2002
@@ -369,7 +369,7 @@
 /* This is the completion handler which will wake us up when an URB
  * completes.
  */
-static void usb_stor_blocking_completion(urb_t *urb)
+static void usb_stor_blocking_completion(struct urb *urb)
 {
 	struct completion *urb_done_ptr = (struct completion *)urb->context;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/storage/unusual_devs.h linux/drivers/usb/storage/unusual_devs.h
--- v2.5.2/linux/drivers/usb/storage/unusual_devs.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/storage/unusual_devs.h	Tue Jan 29 21:44:41 2002
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * Ununsual Devices File
  *
- * $Id: unusual_devs.h,v 1.24 2001/12/29 03:12:45 mdharm Exp $
+ * $Id: unusual_devs.h,v 1.25 2002/01/13 06:39:17 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -458,6 +458,14 @@
                 US_SC_ISD200, US_PR_BULK, isd200_Initialization,
                 0 ),
 #endif
+
+/* Submitted by Brian Hall <brihall@bigfoot.com>
+ * Needed for START_STOP flag */
+UNUSUAL_DEV(  0x0c76, 0x0003, 0x0100, 0x0100,
+		"JMTek",
+		"USBDrive",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_START_STOP ),
 
 /* Reported by Dan Pilone <pilone@slac.com>
  * The device needs the flags only.
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/storage/usb.c linux/drivers/usb/storage/usb.c
--- v2.5.2/linux/drivers/usb/storage/usb.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/storage/usb.c	Thu Jan 17 14:06:53 2002
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: usb.c,v 1.69 2001/11/11 03:33:03 mdharm Exp $
+ * $Id: usb.c,v 1.70 2002/01/06 07:14:12 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -314,10 +314,14 @@
 	 * This thread doesn't need any user-level access,
 	 * so get rid of all our resources..
 	 */
-	exit_files(current);
-	current->files = init_task.files;
-	atomic_inc(&current->files->count);
 	daemonize();
+
+	/* avoid getting signals */
+	spin_lock_irq(&current->sigmask_lock);
+	flush_signals(current);
+	sigfillset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
 
 	/* set our name for identification purposes */
 	sprintf(current->comm, "usb-storage-%d", us->host_number);
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/stv680.c linux/drivers/usb/stv680.c
--- v2.5.2/linux/drivers/usb/stv680.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/stv680.c	Mon Jan 21 15:44:21 2002
@@ -43,6 +43,13 @@
  * 			   Took out sharpen function, ran code through
  * 			   Lindent, and did other minor tweaks to get
  * 			   things to work properly with 2.5.1
+ *
+ * ver 0.24 Jan, 2002 (kjs) 
+ *                         Fixed the problem with webcam crashing after
+ *                         two pictures. Changed the way pic is halved to 
+ *                         improve quality. Got rid of green line around 
+ *                         frame. Fix brightness reset when changing size 
+ *                         bug. Adjusted gamma filters slightly.
  */
 
 #include <linux/config.h>
@@ -65,7 +72,8 @@
 #include "stv680.h"
 
 static int video_nr = -1;
-static int swapRGB = 0;
+static int swapRGB = 0;   /* default for auto sleect */
+static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
 
 static unsigned int debug = 0;
 
@@ -79,7 +87,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.23"
+#define DRIVER_VERSION "v0.24"
 #define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
 #define DRIVER_DESC "STV0680 USB Camera Driver"
 
@@ -88,8 +96,8 @@
 MODULE_LICENSE ("GPL");
 MODULE_PARM (debug, "i");
 MODULE_PARM_DESC (debug, "Debug enabled or not");
-MODULE_PARM (swapRGB, "i");
-MODULE_PARM_DESC (swapRGB, "Swap red and blue, e.g., for xawtv");
+MODULE_PARM (swapRGB_on, "i");
+MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
 MODULE_PARM (video_nr, "i");
 EXPORT_NO_SYMBOLS;
 
@@ -521,8 +529,15 @@
 	stv680->palette = STV_VIDEO_PALETTE;
 	stv680->depth = 24;	/* rgb24 bits */
 	swapRGB = 0;
-	PDEBUG (1, "STV(i): swapRGB is OFF");
-
+	if ((swapRGB_on == 0) && (swapRGB == 0))
+		PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
+	else if ((swapRGB_on == 1) && (swapRGB == 1))
+		PDEBUG (1, "STV(i): swapRGB is (auto) ON");
+	else if (swapRGB_on == 1)
+		PDEBUG (1, "STV(i): swapRGB is (forced) ON");
+	else if (swapRGB_on == -1)
+		PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
+	
 	if (stv_set_video_mode (stv680) < 0) {
 		PDEBUG (0, "STV(e): Could not set video mode in stv_init");
 		return -1;
@@ -543,6 +558,7 @@
 extern struct proc_dir_entry *video_proc_entry;
 
 #define YES_NO(x) ((x) ? "yes" : "no")
+#define ON_OFF(x) ((x) ? "(auto) on" : "(auto) off")
 
 static int stv680_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -559,7 +575,13 @@
 	out += sprintf (out, "num_frames      : %d\n", STV680_NUMFRAMES);
 
 	out += sprintf (out, "Current size    : %ix%i\n", stv680->vwidth, stv680->vheight);
-	out += sprintf (out, "swapRGB         : %s\n", YES_NO (swapRGB));
+	if (swapRGB_on == 0)
+		out += sprintf (out, "swapRGB         : %s\n", ON_OFF (swapRGB));
+	else if (swapRGB_on == 1)
+		out += sprintf (out, "swapRGB         : (forced) on\n");
+	else if (swapRGB_on == -1)
+		out += sprintf (out, "swapRGB         : (forced) off\n");
+
 	out += sprintf (out, "Palette         : %i", stv680->palette);
 
 	out += sprintf (out, "\n");
@@ -671,9 +693,7 @@
 	if (stv680->brightness != p->brightness) {
 		stv680->chgbright = 1;
 		stv680->brightness = p->brightness;
-	} else {
-		stv680->chgbright = 0;
-	}
+	} 
 
 	stv680->whiteness = p->whiteness;	/* greyscale */
 	stv680->colour = p->colour;
@@ -746,7 +766,7 @@
 
 static int stv680_start_stream (struct usb_stv *stv680)
 {
-	urb_t *urb;
+	struct urb *urb;
 	int err = 0, i;
 
 	stv680->streaming = 1;
@@ -888,7 +908,7 @@
 {
 	int x, y, i;
 	int w = stv680->cwidth;
-	int vw = stv680->cwidth, vh = stv680->cheight, vstep = 1;
+	int vw = stv680->cwidth, vh = stv680->cheight;
 	unsigned int p = 0;
 	int colour = 0, bayer = 0;
 	unsigned char *raw = buffer->data;
@@ -908,46 +928,23 @@
 		return;
 	}
 
-	if ((stv680->vwidth == 322) || (stv680->vwidth == 320)) {
+	if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
 		vw = 320;
 		vh = 240;
-		vstep = 1;
 	}
-	if ((stv680->vwidth == 352)) {
+	if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
 		vw = 352;
 		vh = 288;
-		vstep = 1;
 	}
-	if ((stv680->vwidth == 160)) {
-		vw = 160;
-		vh = 120;
-		vstep = 2;
-	}
-	if ((stv680->vwidth == 176)) {
-		vw = 176;
-		vh = 144;
-		vstep = 2;
-	}
-	memset (output, 0, 3 * vw * vh);	/* clear output matrix. Maybe not necessary. */
+
+	memset (output, 0, 3 * vw * vh);	/* clear output matrix. */
 
 	for (y = 0; y < vh; y++) {
 		for (x = 0; x < vw; x++) {
-
-			switch (vstep) {
-			case 1:
-				if (x & 1)
-					p = *(raw + y * w + (x >> 1));
-				else
-					p = *(raw + y * w + (x >> 1) + (w >> 1));
-				break;
-
-			case 2:
-				if (x & 1)
-					p = *(raw + ((y * w) << 1) + x);
-				else
-					p = *(raw + ((y * w) << 1) + x + (w >> 1));
-				break;
-			}
+			if (x & 1)
+				p = *(raw + y * w + (x >> 1));
+			else
+				p = *(raw + y * w + (x >> 1) + (w >> 1));
 
 			if (y & 1)
 				bayer = 2;
@@ -968,9 +965,10 @@
 				colour = 2;
 				break;
 			}
-			i = (y * vw + x) * 3;	/* output already zeroed out with memset */
+			i = (y * vw + x) * 3;	
 			*(output + i + colour) = (unsigned char) p;
 		}		/* for x */
+
 	}			/* for y */
 
 	/****** gamma correction plus hardcoded white balance */
@@ -979,6 +977,7 @@
 	   (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. 
 	   White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and 
 	   converted to unsigned char. Values are in stv680.h  */
+
 	for (y = 0; y < vh; y++) {
 		for (x = 0; x < vw; x++) {
 			i = (y * vw + x) * 3;
@@ -1022,8 +1021,47 @@
 		}		/* for x */
 	}			/* for y  - end demosaic  */
 
+	/* fix top and bottom row, left and right side */
+	i = vw * 3;
+	memcpy (output, (output + i), i);
+	memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
+	for (y = 0; y < vh; y++) {
+		i = y * vw * 3;
+		memcpy ((output + i), (output + i + 3), 3);
+		memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
+	}
+
+	/*  process all raw data, then trim to size if necessary */
+	if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
+		i = 0;
+		for (y = 0; y < vh; y++) {
+			if (!(y & 1)) {
+				for (x = 0; x < vw; x++) {
+					p = (y * vw + x) * 3;
+					if (!(x & 1)) {
+						*(output + i) = *(output + p);
+						*(output + i + 1) = *(output + p + 1);
+						*(output + i + 2) = *(output + p + 2);
+						i += 3;
+					}
+				}  /* for x */
+			}
+		}  /* for y */
+	}
+	/* reset to proper width */
+	if ((stv680->vwidth == 160)) {
+		vw = 160;
+		vh = 120;
+	}
+	if ((stv680->vwidth == 176)) {
+		vw = 176;
+		vh = 144;
+	}
+
 	/* output is RGB; some programs want BGR  */
-	if (swapRGB == 1) {
+	/* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
+	/* swapRGB_on=-1, never swap */
+	if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
 		for (y = 0; y < vh; y++) {
 			for (x = 0; x < vw; x++) {
 				i = (y * vw + x) * 3;
@@ -1242,7 +1280,7 @@
 				return -EFAULT;
 			}
 			copy_from_user (&p, arg, sizeof (p));
-			PDEBUG (2, "STV(i): palette set to RGB in VIDIOSPICT");
+			PDEBUG (2, "STV(i): palette set to %i in VIDIOSPICT", p.palette);
 
 			if (stv680_set_pict (stv680, &p))
 				return -EINVAL;
@@ -1309,8 +1347,8 @@
 			if (vm.format != STV_VIDEO_PALETTE) {
 				PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
 					vm.format, STV_VIDEO_PALETTE);
-				if (vm.format == 3) {
-					PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is ON");
+				if ((vm.format == 3) && (swapRGB_on == 0))  {
+					PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
 					/* this may fix those apps (e.g., xawtv) that want BGR */
 					swapRGB = 1;
 				}
@@ -1320,8 +1358,10 @@
 				PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
 				return -EINVAL;
 			}
-			if (stv680->frame[vm.frame].grabstate != FRAME_UNUSED) {
-				PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate != FRAME_UNUSED");
+			if ((stv680->frame[vm.frame].grabstate == FRAME_ERROR)
+			    || (stv680->frame[vm.frame].grabstate == FRAME_GRABBING)) {
+				PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
+					stv680->frame[vm.frame].grabstate);
 				return -EBUSY;
 			}
 			/* Is this according to the v4l spec??? */
@@ -1390,7 +1430,7 @@
 	return 0;
 }
 
-static int stv680_mmap (struct video_device *dev, const char *adr, unsigned long size)
+static int stv680_mmap (struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
 {
 	struct usb_stv *stv680 = (struct usb_stv *) dev;
 	unsigned long start = (unsigned long) adr;
@@ -1410,7 +1450,7 @@
 	pos = (unsigned long) stv680->fbuf;
 	while (size > 0) {
 		page = kvirt_to_pa (pos);
-		if (remap_page_range (start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range (vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up (&stv680->lock);
 			return -EAGAIN;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/stv680.h linux/drivers/usb/stv680.h
--- v2.5.2/linux/drivers/usb/stv680.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/stv680.h	Mon Jan 21 15:44:21 2002
@@ -43,7 +43,7 @@
 #define USB_PENCAM_PRODUCT_ID	0x0202
 #define PENCAM_TIMEOUT          1000
 /* fmt 4 */
-#define STV_VIDEO_PALETTE    VIDEO_PALETTE_RGB24
+#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
 
 static __devinitdata struct usb_device_id device_table[] = {
 	{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
@@ -118,7 +118,7 @@
 	int removed;		/* device disconnected */
 	int streaming;		/* Are we streaming video? */
 	char *fbuf;		/* Videodev buffer area */
-	urb_t *urb[STV680_NUMSBUF];	/* # of queued bulk transfers */
+	struct urb *urb[STV680_NUMSBUF];	/* # of queued bulk transfers */
 	int curframe;		/* Current receiving frame */
 	struct stv680_frame frame[STV680_NUMFRAMES];	/* # frames supported by v4l part */
 	int readcount;
@@ -146,77 +146,78 @@
 	int nullpackets;
 };
 
-unsigned char red[256] = {
-	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
-	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
-	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
-	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
-	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
-	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
-	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
-	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
-	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
-	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
-	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
-	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
-	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
-	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
-	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
-	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
-	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
-	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
-	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
-	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
-	245, 245, 246, 246
-};
+
+unsigned char red[256] = { 
+	0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
+	18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
+	44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
+	71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
+	88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
+	102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+	114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+	125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
+	134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
+	143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
+	152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
+	159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
+	167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
+	173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
+	180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
+	187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
+	192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
+	198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
+	204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
+	209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
+	215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
+	220, 220, 221, 221 
+}; 
 
 unsigned char green[256] = {
-	0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-	24, 24, 24, 24, 24, 24, 24, 32, 39, 45, 50, 54,
-	58, 62, 65, 69, 71, 74, 77, 79, 83, 85, 87, 90,
-	92, 93, 95, 98, 100, 101, 104, 106, 107, 109, 111, 113,
-	114, 116, 118, 119, 121, 122, 124, 126, 127, 128, 129, 132,
-	133, 134, 135, 136, 138, 140, 141, 142, 143, 145, 146, 147,
-	148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161,
-	162, 163, 164, 166, 167, 168, 168, 169, 170, 171, 173, 174,
-	175, 176, 176, 177, 179, 180, 181, 182, 182, 183, 184, 186,
-	187, 187, 188, 189, 190, 191, 191, 193, 194, 195, 195, 196,
-	197, 198, 198, 200, 201, 201, 202, 203, 204, 204, 205, 207,
-	207, 208, 209, 209, 210, 211, 212, 212, 214, 215, 215, 216,
-	217, 217, 218, 218, 219, 221, 221, 222, 223, 223, 224, 225,
-	225, 226, 226, 228, 229, 229, 230, 231, 231, 232, 232, 233,
-	235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242,
-	243, 243, 244, 244, 245, 245, 246, 248, 248, 249, 249, 250,
-	250, 251, 251, 252, 253, 253, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255
-};
+	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
+	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
+	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
+	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
+	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
+	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
+	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
+	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
+	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
+	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
+	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
+	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
+	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
+	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
+	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
+	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
+	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
+	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
+	245, 245, 246, 246 
+}; 
 
 unsigned char blue[256] = {
-	0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
-	31, 31, 31, 31, 31, 31, 31, 41, 50, 57, 63, 69,
-	74, 78, 82, 87, 90, 94, 97, 100, 105, 108, 111, 113,
-	116, 118, 121, 124, 127, 128, 131, 134, 136, 139, 140, 143,
-	145, 148, 149, 150, 153, 155, 156, 159, 161, 162, 164, 167,
-	168, 170, 171, 173, 174, 177, 179, 180, 182, 183, 185, 186,
-	187, 189, 190, 192, 193, 195, 196, 198, 199, 201, 202, 204,
-	205, 207, 208, 210, 211, 213, 213, 214, 216, 217, 219, 220,
-	222, 223, 223, 224, 226, 227, 229, 230, 230, 232, 233, 235,
-	236, 236, 238, 239, 241, 242, 242, 244, 245, 247, 247, 248,
-	250, 251, 251, 253, 254, 254, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255
-};
+	0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
+	23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
+	55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
+	86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
+	107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
+	125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+	152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
+	165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
+	176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
+	185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
+	194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
+	204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
+	212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
+	235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
+	243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
+	249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255 
+}; 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.5.2/linux/drivers/usb/uhci.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/uhci.c	Fri Jan 25 16:17:51 2002
@@ -520,7 +520,8 @@
 
 	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
 
-	uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1);
+	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe),
+		uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1));
 
 	/* All qh's in the queue need to link to the next queue */
 	urbp->qh->link = eurbp->qh->link;
@@ -556,6 +557,7 @@
 
 	/* Fix up the toggle for the next URB's */
 	if (!urbp->queued)
+		/* We set the toggle when we unlink */
 		toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
 	else {
 		/* If we're in the middle of the queue, grab the toggle */
@@ -811,7 +813,9 @@
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
 
 	/* 3 errors */
-	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+	status = TD_CTRL_ACTIVE | (3 << 27);
+	if (urb->dev->speed == USB_SPEED_LOW)
+		status |= TD_CTRL_LS;
 
 	/*
 	 * Build the TD for the control request
@@ -890,7 +894,7 @@
 	qh->urbp = urbp;
 
 	/* Low speed or small transfers gets a different queue and treatment */
-	if (urb->pipe & TD_CTRL_LS) {
+	if (urb->dev->speed == USB_SPEED_LOW) {
 		uhci_insert_tds_in_qh(qh, urb, 0);
 		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
 	} else {
@@ -1057,7 +1061,7 @@
 	uhci_insert_tds_in_qh(urbp->qh, urb, 0);
 
 	/* Low speed or small transfers gets a different queue and treatment */
-	if (urb->pipe & TD_CTRL_LS)
+	if (urb->dev->speed == USB_SPEED_LOW)
 		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
 	else
 		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
@@ -1081,7 +1085,9 @@
 	/* The "pipe" thing contains the destination in bits 8--18 */
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
 
-	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+	status = TD_CTRL_ACTIVE | TD_CTRL_IOC;
+	if (urb->dev->speed == USB_SPEED_LOW)
+		status |= TD_CTRL_LS;
 
 	td = uhci_alloc_td(uhci, urb->dev);
 	if (!td)
@@ -1216,7 +1222,7 @@
 		return -EINVAL;
 
 	/* Can't have low speed bulk transfers */
-	if (urb->pipe & TD_CTRL_LS)
+	if (urb->dev->speed == USB_SPEED_LOW)
 		return -EINVAL;
 
 	/* The "pipe" thing contains the destination in bits 8--18 */
@@ -1683,8 +1689,8 @@
 
 		/* Control and Isochronous ignore the toggle, so this */
 		/* is safe for all types */
-		if (!(td->status & TD_CTRL_ACTIVE) &&
-		    (uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
+		if ((!(td->status & TD_CTRL_ACTIVE) &&
+		    (uhci_actual_length(td->status) < uhci_expected_length(td->info)) ||
 		    tmp == head)) {
 			usb_settoggle(urb->dev, uhci_endpoint(td->info),
 				uhci_packetout(td->info),
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- v2.5.2/linux/drivers/usb/usb-ohci.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/usb-ohci.c	Fri Jan 25 16:17:51 2002
@@ -173,7 +173,7 @@
 	kfree (urb_priv);
 }
  
-static void urb_rm_priv_locked (urb_t * urb) 
+static void urb_rm_priv_locked (struct urb * urb) 
 {
 	urb_priv_t * urb_priv = urb->hcpriv;
 	
@@ -207,7 +207,7 @@
 	}
 }
 
-static void urb_rm_priv (urb_t * urb)
+static void urb_rm_priv (struct urb * urb)
 {
 	unsigned long flags;
 
@@ -224,7 +224,7 @@
 /* debug| print the main components of an URB     
  * small: 0) header + data packets 1) just header */
  
-static void urb_print (urb_t * urb, char * str, int small)
+static void urb_print (struct urb * urb, char * str, int small)
 {
 	unsigned int pipe= urb->pipe;
 	
@@ -453,10 +453,10 @@
 
 /* return a request to the completion handler */
  
-static int sohci_return_urb (struct ohci *hc, urb_t * urb)
+static int sohci_return_urb (struct ohci *hc, struct urb * urb)
 {
 	urb_priv_t * urb_priv = urb->hcpriv;
-	urb_t * urbt;
+	struct urb * urbt;
 	unsigned long flags;
 	int i;
 	
@@ -532,7 +532,7 @@
 
 /* get a transfer request */
  
-static int sohci_submit_urb (urb_t * urb)
+static int sohci_submit_urb (struct urb * urb)
 {
 	ohci_t * ohci;
 	ed_t * ed;
@@ -716,7 +716,7 @@
 /* deactivate all TDs and remove the private part of the URB */
 /* interrupt callers must use async unlink mode */
 
-static int sohci_unlink_urb (urb_t * urb)
+static int sohci_unlink_urb (struct urb * urb)
 {
 	unsigned long flags;
 	ohci_t * ohci;
@@ -1234,7 +1234,7 @@
 			| usb_pipeendpoint (pipe) << 7
 			| (usb_pipeisoc (pipe)? 0x8000: 0)
 			| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) 
-			| usb_pipeslow (pipe) << 13
+			| (usb_dev->speed == USB_SPEED_LOW) << 13
 			| usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
   
   	if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
@@ -1295,7 +1295,7 @@
 static void
 td_fill (ohci_t * ohci, unsigned int info,
 	dma_addr_t data, int len,
-	urb_t * urb, int index)
+	struct urb * urb, int index)
 {
 	volatile td_t  * td, * td_pt;
 	urb_priv_t * urb_priv = urb->hcpriv;
@@ -1343,7 +1343,7 @@
  
 /* prepare all TDs of a transfer */
 
-static void td_submit_urb (urb_t * urb)
+static void td_submit_urb (struct urb * urb)
 { 
 	urb_priv_t * urb_priv = urb->hcpriv;
 	ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
@@ -1452,7 +1452,7 @@
 {
 	__u32 tdINFO, tdBE, tdCBP;
  	__u16 tdPSW;
- 	urb_t * urb = td->urb;
+ 	struct urb * urb = td->urb;
  	urb_priv_t * urb_priv = urb->hcpriv;
 	int dlen = 0;
 	int cc = 0;
@@ -1493,7 +1493,7 @@
 
 /* handle an urb that is being unlinked */
 
-static void dl_del_urb (urb_t * urb)
+static void dl_del_urb (struct urb * urb)
 {
 	wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;
 
@@ -1582,7 +1582,7 @@
 		td_p = &ed->hwHeadP;
 
 		for (td = tdHeadP; td != tdTailP; td = td_next) { 
-			urb_t * urb = td->urb;
+			struct urb * urb = td->urb;
 			urb_priv_t * urb_priv = td->urb->hcpriv;
 			
 			td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
@@ -1670,7 +1670,7 @@
   	td_t * td_list_next = NULL;
 	ed_t * ed;
 	int cc = 0;
-	urb_t * urb;
+	struct urb * urb;
 	urb_priv_t * urb_priv;
  	__u32 tdINFO, edHeadP, edTailP;
  	
@@ -1846,7 +1846,7 @@
 {
 	int len; 
 
-	urb_t * urb = (urb_t *) ptr;
+	struct urb * urb = (struct urb *) ptr;
 	ohci_t * ohci = urb->dev->bus->hcpriv;
 
 	if (ohci->disabled)
@@ -1875,7 +1875,7 @@
 
 /* Root Hub INTs are polled by this timer */
 
-static int rh_init_int_timer (urb_t * urb) 
+static int rh_init_int_timer (struct urb * urb) 
 {
 	ohci_t * ohci = urb->dev->bus->hcpriv;
 
@@ -1900,7 +1900,7 @@
 
 /* request to virtual root hub */
 
-static int rh_submit_urb (urb_t * urb)
+static int rh_submit_urb (struct urb * urb)
 {
 	struct usb_device * usb_dev = urb->dev;
 	ohci_t * ohci = usb_dev->bus->hcpriv;
@@ -2106,7 +2106,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int rh_unlink_urb (urb_t * urb)
+static int rh_unlink_urb (struct urb * urb)
 {
 	ohci_t * ohci = urb->dev->bus->hcpriv;
  
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/usb-ohci.h linux/drivers/usb/usb-ohci.h
--- v2.5.2/linux/drivers/usb/usb-ohci.h	Tue Dec 18 14:56:39 2001
+++ linux/drivers/usb/usb-ohci.h	Mon Jan 21 15:44:21 2002
@@ -111,7 +111,7 @@
   	__u8 index;
   	struct ed * ed;
   	struct td * next_dl_td;
-  	urb_t * urb;
+  	struct urb * urb;
 
 	dma_addr_t td_dma;
 	dma_addr_t data_dma;
@@ -430,12 +430,12 @@
 static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load, int mem_flags);
 static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
 /* td */
-static void td_fill(ohci_t * ohci, unsigned int info, dma_addr_t data, int len, urb_t * urb, int index);
-static void td_submit_urb(urb_t * urb);
+static void td_fill(ohci_t * ohci, unsigned int info, dma_addr_t data, int len, struct urb * urb, int index);
+static void td_submit_urb(struct urb * urb);
 /* root hub */
-static int rh_submit_urb(urb_t * urb);
-static int rh_unlink_urb(urb_t * urb);
-static int rh_init_int_timer(urb_t * urb);
+static int rh_submit_urb(struct urb * urb);
+static int rh_unlink_urb(struct urb * urb);
+static int rh_init_int_timer(struct urb * urb);
 
 /*-------------------------------------------------------------------------*/
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- v2.5.2/linux/drivers/usb/usb-uhci.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/usb-uhci.c	Fri Jan 25 16:17:51 2002
@@ -16,7 +16,7 @@
  * (C) Copyright 1999 Randy Dunlap
  * (C) Copyright 1999 Gregory P. Smith
  *
- * $Id: usb-uhci.c,v 1.268 2001/08/29 14:08:43 acher Exp $
+ * $Id: usb-uhci.c,v 1.275 2002/01/19 20:57:33 acher Exp $
  */
 
 #include <linux/config.h>
@@ -34,6 +34,7 @@
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/pm.h>
+#include <linux/timer.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -52,7 +53,7 @@
 /* This enables an extra UHCI slab for memory debugging */
 #define DEBUG_SLAB
 
-#define VERSTR "$Revision: 1.268 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__
 
 #include <linux/usb.h>
 #include "usb-uhci.h"
@@ -61,7 +62,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.268"
+#define DRIVER_VERSION "v1.275"
 #define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
 #define DRIVER_DESC "USB Universal Host Controller Interface driver"
 
@@ -71,6 +72,9 @@
 #define DEBUG_SYMBOLS
 #ifdef DEBUG_SYMBOLS
 	#define _static
+	#ifndef EXPORT_SYMTAB
+		#define EXPORT_SYMTAB
+	#endif
 #else
 	#define _static static
 #endif
@@ -113,12 +117,12 @@
 // Suppress HC interrupt error messages for 5s
 #define ERROR_SUPPRESSION_TIME (HZ*5)
 
-_static int rh_submit_urb (urb_t *urb);
-_static int rh_unlink_urb (urb_t *urb);
+_static int rh_submit_urb (struct urb *urb);
+_static int rh_unlink_urb (struct urb *urb);
 _static int delete_qh (uhci_t *s, uhci_desc_t *qh);
-_static int process_transfer (uhci_t *s, urb_t *urb, int mode);
-_static int process_interrupt (uhci_t *s, urb_t *urb);
-_static int process_iso (uhci_t *s, urb_t *urb, int force);
+_static int process_transfer (uhci_t *s, struct urb *urb, int mode);
+_static int process_interrupt (uhci_t *s, struct urb *urb);
+_static int process_iso (uhci_t *s, struct urb *urb, int force);
 
 // How much URBs with ->next are walked
 #define MAX_NEXT_COUNT 2048
@@ -164,7 +168,7 @@
 }
 /*-------------------------------------------------------------------*/
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-_static void enable_desc_loop(uhci_t *s, urb_t *urb)
+_static void enable_desc_loop(uhci_t *s, struct urb *urb)
 {
 	int flags;
 
@@ -179,7 +183,7 @@
 	spin_unlock_irqrestore (&s->qh_lock, flags);
 }
 /*-------------------------------------------------------------------*/
-_static void disable_desc_loop(uhci_t *s, urb_t *urb)
+_static void disable_desc_loop(uhci_t *s, struct urb *urb)
 {
 	int flags;
 
@@ -200,7 +204,7 @@
 }
 #endif
 /*-------------------------------------------------------------------*/
-_static void queue_urb_unlocked (uhci_t *s, urb_t *urb)
+_static void queue_urb_unlocked (uhci_t *s, struct urb *urb)
 {
 	struct list_head *p=&urb->urb_list;
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
@@ -220,7 +224,7 @@
 	uhci_switch_timer_int(s);
 }
 /*-------------------------------------------------------------------*/
-_static void queue_urb (uhci_t *s, urb_t *urb)
+_static void queue_urb (uhci_t *s, struct urb *urb)
 {
 	unsigned long flags=0;
 
@@ -229,7 +233,7 @@
 	spin_unlock_irqrestore (&s->urb_list_lock, flags);
 }
 /*-------------------------------------------------------------------*/
-_static void dequeue_urb (uhci_t *s, urb_t *urb)
+_static void dequeue_urb (uhci_t *s, struct urb *urb)
 {
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
 	int type;
@@ -694,7 +698,7 @@
 //                         LOW LEVEL STUFF
 //          assembles QHs und TDs for control, bulk and iso
 /*-------------------------------------------------------------------*/
-_static int uhci_submit_control_urb (urb_t *urb)
+_static int uhci_submit_control_urb (struct urb *urb)
 {
 	uhci_desc_t *qh, *td;
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
@@ -719,8 +723,11 @@
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
 
 	/* 3 errors */
-	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
-		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+	status = TD_CTRL_ACTIVE
+		| (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD)
+		| (3 << 27);
+	if (urb->dev->speed == USB_SPEED_LOW)
+		status |= TD_CTRL_LS;
 
 	/*  Build the TD for the control request, try forever, 8 bytes of data */
 	fill_td (td, status, destination | (7 << 21), urb_priv->setup_packet_dma);
@@ -795,7 +802,7 @@
 
 	//uhci_show_queue(qh);
 	/* Start it up... put low speed first */
-	if (urb->pipe & TD_CTRL_LS)
+	if (urb->dev->speed == USB_SPEED_LOW)
 		insert_qh (s, s->control_chain, qh, 0);
 	else
 		insert_qh (s, s->bulk_chain, qh, 0);
@@ -811,7 +818,7 @@
 // For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh)
 // Due to the linking with other bulk urbs, it has to be locked with urb_list_lock!
 
-_static int uhci_submit_bulk_urb (urb_t *urb, urb_t *bulk_urb)
+_static int uhci_submit_bulk_urb (struct urb *urb, struct urb *bulk_urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	urb_priv_t *urb_priv = urb->hcpriv, *upriv, *bpriv=NULL;
@@ -872,8 +879,11 @@
 	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
 
 	/* 3 errors */
-	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
-		((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27);
+	status = TD_CTRL_ACTIVE
+		| ((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD)
+		| (3 << 27);
+	if (urb->dev->speed == USB_SPEED_LOW)
+		status |= TD_CTRL_LS;
 
 	/* Build the TDs for the bulk request */
 	len = urb->transfer_buffer_length;
@@ -973,7 +983,7 @@
  looks a bit complicated because of all the bulk queueing goodies
 */
 
-_static void uhci_clean_transfer (uhci_t *s, urb_t *urb, uhci_desc_t *qh, int mode)
+_static void uhci_clean_transfer (uhci_t *s, struct urb *urb, uhci_desc_t *qh, int mode)
 {
 	uhci_desc_t *bqh, *nqh, *prevqh, *prevtd;
 	int now;
@@ -1027,7 +1037,7 @@
 		       urb, priv->prev_queued_urb,  priv->next_queued_urb, qh, bqh, priv->next_qh);	
        	
 		if (mode != CLEAN_TRANSFER_DELETION_MARK) {	// no work for cleanup at unlink-completion
-			urb_t *nurb;
+			struct urb *nurb;
 			unsigned long flags;
 
 			nurb = priv->next_queued_urb;
@@ -1065,7 +1075,7 @@
 }
 /*-------------------------------------------------------------------*/
 // Release bandwidth for Interrupt or Isoc. transfers 
-_static void uhci_release_bandwidth(urb_t *urb)
+_static void uhci_release_bandwidth(struct urb *urb)
 {       
 	if (urb->bandwidth) {
 		switch (usb_pipetype(urb->pipe)) {
@@ -1081,7 +1091,7 @@
 	}	
 }
 
-_static void uhci_urb_dma_sync(uhci_t *s, urb_t *urb, urb_priv_t *urb_priv)
+_static void uhci_urb_dma_sync(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
 {
 	if (urb_priv->setup_packet_dma)
 		pci_dma_sync_single(s->uhci_pci, urb_priv->setup_packet_dma,
@@ -1095,7 +1105,7 @@
 				    PCI_DMA_TODEVICE);
 }
 
-_static void uhci_urb_dma_unmap(uhci_t *s, urb_t *urb, urb_priv_t *urb_priv)
+_static void uhci_urb_dma_unmap(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
 {
 	if (urb_priv->setup_packet_dma) {
 		pci_unmap_single(s->uhci_pci, urb_priv->setup_packet_dma,
@@ -1116,7 +1126,7 @@
    mode: UNLINK_ASYNC_STORE_URB: unlink and move URB into unlinked list
          UNLINK_ASYNC_DONT_STORE: unlink, don't move URB into unlinked list
 */
-_static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb, int mode)
+_static int uhci_unlink_urb_async (uhci_t *s, struct urb *urb, int mode)
 {
 	uhci_desc_t *qh;
 	urb_priv_t *urb_priv;
@@ -1161,7 +1171,7 @@
 }
 /*-------------------------------------------------------------------*/
 // kills an urb by unlinking descriptors and waiting for at least one frame
-_static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
+_static int uhci_unlink_urb_sync (uhci_t *s, struct urb *urb)
 {
 	uhci_desc_t *qh;
 	urb_priv_t *urb_priv;
@@ -1182,6 +1192,7 @@
 		// cleanup the rest
 		switch (usb_pipetype (urb->pipe)) {
 
+		case PIPE_INTERRUPT:
 		case PIPE_ISOCHRONOUS:
 			uhci_wait_ms(1);
 			uhci_clean_iso_step2(s, urb_priv);
@@ -1224,7 +1235,7 @@
 _static void uhci_cleanup_unlink(uhci_t *s, int force)
 {
 	struct list_head *q;
-	urb_t *urb;
+	struct urb *urb;
 	struct usb_device *dev;
 	int now, type;
 	urb_priv_t *urb_priv;
@@ -1234,7 +1245,7 @@
 
 	while (q != &s->urb_unlinked) {
 
-		urb = list_entry (q, urb_t, urb_list);
+		urb = list_entry (q, struct urb, urb_list);
 
 		urb_priv = (urb_priv_t*)urb->hcpriv;
 		q = urb->urb_list.next;
@@ -1303,7 +1314,7 @@
 }
  
 /*-------------------------------------------------------------------*/
-_static int uhci_unlink_urb (urb_t *urb)
+_static int uhci_unlink_urb (struct urb *urb)
 {
 	uhci_t *s;
 	unsigned long flags=0;
@@ -1336,9 +1347,9 @@
 // In case of ASAP iso transfer, search the URB-list for already queued URBs
 // for this EP and calculate the earliest start frame for the new
 // URB (easy seamless URB continuation!)
-_static int find_iso_limits (urb_t *urb, unsigned int *start, unsigned int *end)
+_static int find_iso_limits (struct urb *urb, unsigned int *start, unsigned int *end)
 {
-	urb_t *u, *last_urb = NULL;
+	struct urb *u, *last_urb = NULL;
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	struct list_head *p;
 	int ret=-1;
@@ -1348,7 +1359,7 @@
 	p=s->urb_list.prev;
 
 	for (; p != &s->urb_list; p = p->prev) {
-		u = list_entry (p, urb_t, urb_list);
+		u = list_entry (p, struct urb, urb_list);
 		// look for pending URBs with identical pipe handle
 		// works only because iso doesn't toggle the data bit!
 		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS)) {
@@ -1370,7 +1381,7 @@
 /*-------------------------------------------------------------------*/
 // adjust start_frame according to scheduling constraints (ASAP etc)
 
-_static int iso_find_start (urb_t *urb)
+_static int iso_find_start (struct urb *urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	unsigned int now;
@@ -1428,7 +1439,7 @@
 // ASAP-flag set implicitely
 // if period==0, the transfer is only done once
 
-_static int uhci_submit_int_urb (urb_t *urb)
+_static int uhci_submit_int_urb (struct urb *urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -1467,8 +1478,11 @@
 	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
 		return -ENOMEM;
 
-	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
-		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+	status = TD_CTRL_ACTIVE | TD_CTRL_IOC
+		| (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD)
+		| (3 << 27);
+	if (urb->dev->speed == USB_SPEED_LOW)
+		status |= TD_CTRL_LS;
 
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe) |
 		(((urb->transfer_buffer_length - 1) & 0x7ff) << 21);
@@ -1488,7 +1502,7 @@
 	return 0;
 }
 /*-------------------------------------------------------------------*/
-_static int uhci_submit_iso_urb (urb_t *urb)
+_static int uhci_submit_iso_urb (struct urb *urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -1581,10 +1595,10 @@
 /*-------------------------------------------------------------------*/
 // returns: 0 (no transfer queued), urb* (this urb already queued)
  
-_static urb_t* search_dev_ep (uhci_t *s, urb_t *urb)
+_static struct urb* search_dev_ep (uhci_t *s, struct urb *urb)
 {
 	struct list_head *p;
-	urb_t *tmp;
+	struct urb *tmp;
 	unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0);
 
 	dbg("search_dev_ep:");
@@ -1592,7 +1606,7 @@
 	p=s->urb_list.next;
 
 	for (; p != &s->urb_list; p = p->next) {
-		tmp = list_entry (p, urb_t, urb_list);
+		tmp = list_entry (p, struct urb, urb_list);
 		dbg("urb: %p", tmp);
 		// we can accept this urb if it is not queued at this time 
 		// or if non-iso transfer requests should be scheduled for the same device and pipe
@@ -1605,13 +1619,13 @@
 	return 0;
 }
 /*-------------------------------------------------------------------*/
-_static int uhci_submit_urb (urb_t *urb)
+_static int uhci_submit_urb (struct urb *urb)
 {
 	uhci_t *s;
 	urb_priv_t *urb_priv;
 	int ret = 0, type;
 	unsigned long flags;
-	urb_t *queued_urb=NULL;
+	struct urb *queued_urb=NULL;
 	int bustime;
 		
 	if (!urb->dev || !urb->dev->bus)
@@ -1765,7 +1779,7 @@
 _static void uhci_check_timeouts(uhci_t *s)
 {
 	struct list_head *p,*p2;
-	urb_t *urb;
+	struct urb *urb;
 	int type;	
 
 	p = s->urb_list.prev;	
@@ -1775,21 +1789,19 @@
 
 		p2 = p;
 		p = p->prev;
-		urb = list_entry (p2, urb_t, urb_list);
+		urb = list_entry (p2, struct urb, urb_list);
 		type = usb_pipetype (urb->pipe);
 
 		hcpriv = (urb_priv_t*)urb->hcpriv;
-				
-		if ( urb->timeout && 
-			((hcpriv->started + urb->timeout) < jiffies)) {
+		
+		if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
 			urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
 			async_dbg("uhci_check_timeout: timeout for %p",urb);
 			uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
 		}
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
 		else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
-		     (hcpriv->use_loop) &&
-		     ((hcpriv->started + IDLE_TIMEOUT) < jiffies))
+			 (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))
 			disable_desc_loop(s, urb);
 #endif
 
@@ -1875,7 +1887,7 @@
 
 /*-------------------------------------------------------------------------*/
 /* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
-_static int rh_send_irq (urb_t *urb)
+_static int rh_send_irq (struct urb *urb)
 {
 	int len = 1;
 	int i;
@@ -1902,12 +1914,12 @@
 
 /*-------------------------------------------------------------------------*/
 /* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
-_static int rh_init_int_timer (urb_t *urb);
+_static int rh_init_int_timer (struct urb *urb);
 
 _static void rh_int_timer_do (unsigned long ptr)
 {
 	int len;
-	urb_t *urb = (urb_t*) ptr;
+	struct urb *urb = (struct urb *) ptr;
 	uhci_t *uhci = urb->dev->bus->hcpriv;
 
 	if (uhci->rh.send) {
@@ -1924,7 +1936,7 @@
 /*-------------------------------------------------------------------------*/
 /* Root Hub INTs are polled by this timer, polling interval 20ms */
 
-_static int rh_init_int_timer (urb_t *urb)
+_static int rh_init_int_timer (struct urb *urb)
 {
 	uhci_t *uhci = urb->dev->bus->hcpriv;
 
@@ -1958,7 +1970,7 @@
  *************************/
 
 
-_static int rh_submit_urb (urb_t *urb)
+_static int rh_submit_urb (struct urb *urb)
 {
 	struct usb_device *usb_dev = urb->dev;
 	uhci_t *uhci = usb_dev->bus->hcpriv;
@@ -2159,7 +2171,7 @@
 }
 /*-------------------------------------------------------------------------*/
 
-_static int rh_unlink_urb (urb_t *urb)
+_static int rh_unlink_urb (struct urb *urb)
 {
 	uhci_t *uhci = urb->dev->bus->hcpriv;
 
@@ -2217,14 +2229,14 @@
 	unsigned long flags;
 	struct list_head *p;
 	struct list_head *p2;
-	urb_t *urb;
+	struct urb *urb;
 
 	spin_lock_irqsave (&s->urb_list_lock, flags);
 	p = s->urb_list.prev;	
 	while (p != &s->urb_list) {
 		p2 = p;
 		p = p->prev ;
-		urb = list_entry (p2, urb_t, urb_list);
+		urb = list_entry (p2, struct urb, urb_list);
 		dbg("urb: %p, dev %p, %p", urb, usb_dev,urb->dev);
 		
 		//urb->transfer_flags |=USB_ASYNC_UNLINK; 
@@ -2274,7 +2286,7 @@
 	uhci_unlink_urb
 };
 
-_static void correct_data_toggles(urb_t *urb)
+_static void correct_data_toggles(struct urb *urb)
 {
 	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), 
 		       !usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)));
@@ -2304,7 +2316,7 @@
  *       PROCESS_TRANSFER_DONT_UNLINK: QHs already unlinked (for async unlink_urb)
  */
 
-_static int process_transfer (uhci_t *s, urb_t *urb, int mode)
+_static int process_transfer (uhci_t *s, struct urb *urb, int mode)
 {
 	int ret = 0;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -2392,7 +2404,7 @@
 	if (usb_pipetype (urb->pipe) == PIPE_BULK ) {  /* toggle correction for short bulk transfers (nonqueued/queued) */
 
 		urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-		urb_t *next_queued_urb=priv->next_queued_urb;
+		struct urb *next_queued_urb=priv->next_queued_urb;
 
 		if (next_queued_urb) {
 			urb_priv_t *next_priv=(urb_priv_t*)next_queued_urb->hcpriv;
@@ -2423,7 +2435,7 @@
 	return ret;
 }
 
-_static int process_interrupt (uhci_t *s, urb_t *urb)
+_static int process_interrupt (uhci_t *s, struct urb *urb)
 {
 	int i, ret = -EINPROGRESS;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -2445,7 +2457,7 @@
 			break;
 		}
 
-		if (!desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC)) {
+		if (!(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) {
 			// do not process one-shot TDs, no recycling
 			break;
 		}
@@ -2503,12 +2515,17 @@
 					desc->hw.td.info |= cpu_to_le32((!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
 									     usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE));
 				}
-				desc->hw.td.status= cpu_to_le32((urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
+				desc->hw.td.status= cpu_to_le32(TD_CTRL_ACTIVE | TD_CTRL_IOC |
 					(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27));
+				if (urb->dev->speed == USB_SPEED_LOW)
+					desc->hw.td.status |=
+					    __constant_cpu_to_le32 (TD_CTRL_LS);
 				mb();
 			}
 			else {
 				uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+				// correct toggle after unlink
+				usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
 				clr_td_ioc(desc); // inactivate TD
 			}
 		}
@@ -2520,7 +2537,7 @@
 // mode: PROCESS_ISO_REGULAR: processing only for done TDs, unlink TDs
 // mode: PROCESS_ISO_FORCE: force processing, don't unlink TDs (already unlinked)
 
-_static int process_iso (uhci_t *s, urb_t *urb, int mode)
+_static int process_iso (uhci_t *s, struct urb *urb, int mode)
 {
 	int i;
 	int ret = 0;
@@ -2589,9 +2606,9 @@
 _static int process_urb (uhci_t *s, struct list_head *p)
 {
 	int ret = 0;
-	urb_t *urb;
+	struct urb *urb;
 
-	urb=list_entry (p, urb_t, urb_list);
+	urb=list_entry (p, struct urb, urb_list);
 	//dbg("process_urb: found queued urb: %p", urb);
 
 	switch (usb_pipetype (urb->pipe)) {
@@ -2640,7 +2657,7 @@
 #endif
 
 		if ((usb_pipetype (urb->pipe) != PIPE_INTERRUPT)) {  // process_interrupt does completion on its own		
-			urb_t *next_urb = urb->next;
+			struct urb *next_urb = urb->next;
 			int is_ring = 0;
 			int contains_killed = 0;
 			int loop_count=0;
@@ -2738,7 +2755,7 @@
 
 	if (status != 1) {
 		// Avoid too much error messages at a time
-		if ((jiffies - s->last_error_time > ERROR_SUPPRESSION_TIME)) {
+		if (time_after(jiffies, s->last_error_time + ERROR_SUPPRESSION_TIME)) {
 			warn("interrupt, status %x, frame# %i", status, 
 			     UHCI_GET_CURRENT_FRAME(s));
 			s->last_error_time = jiffies;
@@ -2786,7 +2803,7 @@
 				break;
 		}
 	}
-	if ((jiffies - s->timeout_check) > (HZ/30)) 
+	if (time_after(jiffies, s->timeout_check + (HZ/30)))
 		uhci_check_timeouts(s);
 
 	clean_descs(s, CLEAN_NOT_FORCED);
@@ -2815,7 +2832,7 @@
 _static void start_hc (uhci_t *s)
 {
 	unsigned int io_addr = s->io_addr;
-	int timeout = 1000;
+	int timeout = 10;
 
 	/*
 	 * Reset the HC - this will force us to get a
@@ -2830,6 +2847,7 @@
 			err("USBCMD_HCRESET timed out!");
 			break;
 		}
+		udelay(1);
 	}
 
 	/* Turn on all interrupts */
@@ -2845,7 +2863,8 @@
 	s->running = 1;
 }
 
-_static void __devexit
+/* No  __devexit, since it maybe called from alloc_uhci() */
+_static void
 uhci_pci_remove (struct pci_dev *dev)
 {
 	uhci_t *s = pci_get_drvdata(dev);
@@ -3130,4 +3149,3 @@
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL");
-
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/usb-uhci.h linux/drivers/usb/usb-uhci.h
--- v2.5.2/linux/drivers/usb/usb-uhci.h	Tue Aug 28 11:21:02 2001
+++ linux/drivers/usb/usb-uhci.h	Mon Jan 21 15:44:21 2002
@@ -158,8 +158,8 @@
 	dma_addr_t setup_packet_dma;
 	dma_addr_t transfer_buffer_dma;
 	unsigned long started;
-	urb_t *next_queued_urb;         // next queued urb for this EP
-	urb_t *prev_queued_urb;
+	struct urb *next_queued_urb;	// next queued urb for this EP
+	struct urb *prev_queued_urb;
 	uhci_desc_t *bottom_qh;
 	uhci_desc_t *next_qh;       	// next helper QH
 	char use_loop;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.5.2/linux/drivers/usb/usb.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/usb.c	Tue Jan 29 13:52:28 2002
@@ -324,8 +324,9 @@
 	unsigned int	pipe = urb->pipe;
 	long		bustime;
 
-	bustime = usb_calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe),
-			usb_pipeisoc(pipe), usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
+	bustime = usb_calc_bus_time (dev->speed == USB_SPEED_LOW,
+			usb_pipein(pipe), usb_pipeisoc(pipe),
+			usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
 	if (usb_pipeisoc(pipe))
 		bustime = NS_TO_US(bustime) / urb->number_of_packets;
 	else
@@ -1073,48 +1074,75 @@
  * ----------------------------------------------------------------------*/
 
 /**
- *	usb_alloc_urb - creates a new urb for a USB driver to use
- *	@iso_packets: number of iso packets for this urb
+ * usb_alloc_urb - creates a new urb for a USB driver to use
+ * @iso_packets: number of iso packets for this urb
  *
- *	Creates an urb for the USB driver to use and returns a pointer to it.
- *	If no memory is available, NULL is returned.
+ * Creates an urb for the USB driver to use, initializes a few internal
+ * structures, incrementes the usage counter, and returns a pointer to it.
+ *
+ * If no memory is available, NULL is returned.
  *
- *	If the driver want to use this urb for interrupt, control, or bulk
- *	endpoints, pass '0' as the number of iso packets.
+ * If the driver want to use this urb for interrupt, control, or bulk
+ * endpoints, pass '0' as the number of iso packets.
  *
- *	The driver should call usb_free_urb() when it is finished with the urb.
+ * The driver must call usb_free_urb() when it is finished with the urb.
  */
-urb_t *usb_alloc_urb(int iso_packets)
+struct urb *usb_alloc_urb(int iso_packets)
 {
-	urb_t *urb;
+	struct urb *urb;
 
-	urb = (urb_t *)kmalloc(sizeof(urb_t) + iso_packets * sizeof(iso_packet_descriptor_t),
-	      in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	urb = (struct urb *)kmalloc(sizeof(struct urb) + 
+		iso_packets * sizeof(struct usb_iso_packet_descriptor),
+		in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
 	if (!urb) {
 		err("alloc_urb: kmalloc failed");
 		return NULL;
 	}
 
 	memset(urb, 0, sizeof(*urb));
-
+	atomic_inc(&urb->count);
 	spin_lock_init(&urb->lock);
 
 	return urb;
 }
 
 /**
- *	usb_free_urb - frees the memory used by a urb
- *	@urb: pointer to the urb to free
+ * usb_free_urb - frees the memory used by a urb when all users of it are finished
+ * @urb: pointer to the urb to free
  *
- *	If an urb is created with a call to usb_create_urb() it should be
- *	cleaned up with a call to usb_free_urb() when the driver is finished
- *	with it.
+ * Must be called when a user of a urb is finished with it.  When the last user
+ * of the urb calls this function, the memory of the urb is freed.
+ *
+ * Note: The transfer buffer associated with the urb is not freed, that must be
+ * done elsewhere.
  */
-void usb_free_urb(urb_t* urb)
+void usb_free_urb(struct urb *urb)
 {
 	if (urb)
-		kfree(urb);
+		if (atomic_dec_and_test(&urb->count))
+			kfree(urb);
+}
+
+/**
+ * usb_get_urb - incrementes the reference count of the urb
+ * @urb: pointer to the urb to modify
+ *
+ * This must be  called whenever a urb is transfered from a device driver to a
+ * host controller driver.  This allows proper reference counting to happen
+ * for urbs.
+ *
+ * A pointer to the urb with the incremented reference counter is returned.
+ */
+struct urb * usb_get_urb(struct urb *urb)
+{
+	if (urb) {
+		atomic_inc(&urb->count);
+		return urb;
+	} else
+		return NULL;
 }
+		
+		
 /*-------------------------------------------------------------------*/
 
 /**
@@ -1127,7 +1155,7 @@
  * This call may be issued in interrupt context.
  *
  * The caller must have correctly initialized the URB before submitting
- * it.  Macros such as FILL_BULK_URB() and FILL_CONTROL_URB() are
+ * it.  Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are
  * available to ensure that most fields are correctly initialized, for
  * the particular kind of transfer, although they will not initialize
  * any transfer flags.
@@ -1171,7 +1199,7 @@
  * the periodic request, and bandwidth reservation is being done for
  * this controller, submitting such a periodic request will fail. 
  */
-int usb_submit_urb(urb_t *urb)
+int usb_submit_urb(struct urb *urb)
 {
 	if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
 		return urb->dev->bus->op->submit_urb(urb);
@@ -1205,7 +1233,7 @@
  * and the completion function will see status -ECONNRESET.  Failure is
  * indicated by any other return value.
  */
-int usb_unlink_urb(urb_t *urb)
+int usb_unlink_urb(struct urb *urb)
 {
 	if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
 		return urb->dev->bus->op->unlink_urb(urb);
@@ -1221,7 +1249,7 @@
 	int done;
 };
 
-static void usb_api_blocking_completion(urb_t *urb)
+static void usb_api_blocking_completion(struct urb *urb)
 {
 	struct usb_api_data *awd = (struct usb_api_data *)urb->context;
 
@@ -1231,7 +1259,7 @@
 }
 
 // Starts urb and waits for completion or timeout
-static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
+static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
 { 
 	DECLARE_WAITQUEUE(wait, current);
 	struct usb_api_data awd;
@@ -1289,7 +1317,7 @@
 int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, 
 			    struct usb_ctrlrequest *cmd,  void *data, int len, int timeout)
 {
-	urb_t *urb;
+	struct urb *urb;
 	int retv;
 	int length;
 
@@ -1376,7 +1404,7 @@
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 
 			void *data, int len, int *actual_length, int timeout)
 {
-	urb_t *urb;
+	struct urb *urb;
 
 	if (len < 0)
 		return -EINVAL;
@@ -2252,6 +2280,14 @@
 		return -EINVAL;
 	}
 
+	/* 9.4.10 says devices don't need this, if the interface
+	   only has one alternate setting */
+	if (iface->num_altsetting == 1) {
+		warn("ignoring set_interface for dev %d, iface %d, alt %d",
+			dev->devnum, interface, alternate);
+		return 0;
+	}
+
 	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 	    USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate,
 	    interface, NULL, 0, HZ * 5)) < 0)
@@ -2504,6 +2540,53 @@
 	return err;
 }
 
+/**
+ * usb_make_path - returns device path in the hub tree
+ * @dev: the device whose path is being constructed
+ * @buf: where to put the string
+ * @size: how big is "buf"?
+ *
+ * Returns length of the string (>= 0) or out of memory status (< 0).
+ */
+int usb_make_path(struct usb_device *dev, char *buf, size_t size)
+{
+	struct usb_device *pdev = dev->parent;
+	char *tmp;
+	char *port;
+	int i;
+
+	if (!(port = kmalloc(size, GFP_KERNEL)))
+		return -ENOMEM;
+	if (!(tmp = kmalloc(size, GFP_KERNEL))) {
+		kfree(port);
+		return -ENOMEM;
+	}
+
+	*port = 0;
+	while (pdev) {
+		for (i = 0; i < pdev->maxchild; i++)
+			if (pdev->children[i] == dev)
+				break;
+
+		if (pdev->children[i] != dev) {
+			kfree(port);
+			kfree(tmp);
+			return -ENODEV;
+		}
+
+		strcpy(tmp, port);
+		snprintf(port, size, strlen(port) ? "%d.%s" : "%d", i + 1, tmp);
+
+		dev = pdev;
+		pdev = dev->parent;
+	}
+
+	snprintf(buf, size, "usb%d:%s", dev->bus->busnum, port);
+	kfree(port);
+	kfree(tmp);
+	return strlen(buf);
+}
+
 /*
  * By the time we get here, the device has gotten a new device ID
  * and is in the default state. We need to identify the thing and
@@ -2737,6 +2820,7 @@
 // asynchronous request completion model
 EXPORT_SYMBOL(usb_alloc_urb);
 EXPORT_SYMBOL(usb_free_urb);
+EXPORT_SYMBOL(usb_get_urb);
 EXPORT_SYMBOL(usb_submit_urb);
 EXPORT_SYMBOL(usb_unlink_urb);
 
@@ -2753,5 +2837,6 @@
 EXPORT_SYMBOL(usb_set_configuration);
 EXPORT_SYMBOL(usb_set_interface);
 
+EXPORT_SYMBOL(usb_make_path);
 EXPORT_SYMBOL(usb_devfs_handle);
 MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/usbkbd.c linux/drivers/usb/usbkbd.c
--- v2.5.2/linux/drivers/usb/usbkbd.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/usbkbd.c	Wed Jan 23 15:33:46 2002
@@ -73,7 +73,7 @@
 	struct usb_device *usbdev;
 	unsigned char new[8];
 	unsigned char old[8];
-	struct urb irq, led;
+	struct urb *irq, *led;
 	struct usb_ctrlrequest dr;
 	unsigned char leds, newleds;
 	char name[128];
@@ -121,15 +121,15 @@
 		       (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
 		       (!!test_bit(LED_NUML,    dev->led));
 
-	if (kbd->led.status == -EINPROGRESS)
+	if (kbd->led->status == -EINPROGRESS)
 		return 0;
 
 	if (kbd->leds == kbd->newleds)
 		return 0;
 
 	kbd->leds = kbd->newleds;
-	kbd->led.dev = kbd->usbdev;
-	if (usb_submit_urb(&kbd->led))
+	kbd->led->dev = kbd->usbdev;
+	if (usb_submit_urb(kbd->led))
 		err("usb_submit_urb(leds) failed");
 
 	return 0;
@@ -146,8 +146,8 @@
 		return;
 
 	kbd->leds = kbd->newleds;
-	kbd->led.dev = kbd->usbdev;
-	if (usb_submit_urb(&kbd->led))
+	kbd->led->dev = kbd->usbdev;
+	if (usb_submit_urb(kbd->led))
 		err("usb_submit_urb(leds) failed");
 }
 
@@ -158,8 +158,8 @@
 	if (kbd->open++)
 		return 0;
 
-	kbd->irq.dev = kbd->usbdev;
-	if (usb_submit_urb(&kbd->irq))
+	kbd->irq->dev = kbd->usbdev;
+	if (usb_submit_urb(kbd->irq))
 		return -EIO;
 
 	return 0;
@@ -170,7 +170,7 @@
 	struct usb_kbd *kbd = dev->private;
 
 	if (!--kbd->open)
-		usb_unlink_urb(&kbd->irq);
+		usb_unlink_urb(kbd->irq);
 }
 
 static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
@@ -201,6 +201,18 @@
 	if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL;
 	memset(kbd, 0, sizeof(struct usb_kbd));
 
+	kbd->irq = usb_alloc_urb(0);
+	if (!kbd->irq) {
+		kfree(kbd);
+		return NULL;
+	}
+	kbd->led = usb_alloc_urb(0);
+	if (!kbd->led) {
+		usb_free_urb(kbd->irq);
+		kfree(kbd);
+		return NULL;
+	}
+
 	kbd->usbdev = dev;
 
 	kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
@@ -215,7 +227,7 @@
 	kbd->dev.open = usb_kbd_open;
 	kbd->dev.close = usb_kbd_close;
 
-	FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
+	FILL_INT_URB(kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
 		usb_kbd_irq, kbd, endpoint->bInterval);
 
 	kbd->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
@@ -248,7 +260,7 @@
 
 	kfree(buf);
 
-	FILL_CONTROL_URB(&kbd->led, dev, usb_sndctrlpipe(dev, 0),
+	FILL_CONTROL_URB(kbd->led, dev, usb_sndctrlpipe(dev, 0),
 		(void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd);
 			
 	input_register_device(&kbd->dev);
@@ -262,8 +274,10 @@
 static void usb_kbd_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct usb_kbd *kbd = ptr;
-	usb_unlink_urb(&kbd->irq);
+	usb_unlink_urb(kbd->irq);
 	input_unregister_device(&kbd->dev);
+	usb_free_urb(kbd->irq);
+	usb_free_urb(kbd->led);
 	kfree(kbd);
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/usbmouse.c linux/drivers/usb/usbmouse.c
--- v2.5.2/linux/drivers/usb/usbmouse.c	Tue Dec 18 14:56:39 2001
+++ linux/drivers/usb/usbmouse.c	Wed Jan 23 15:33:46 2002
@@ -54,7 +54,7 @@
 	char name[128];
 	struct usb_device *usbdev;
 	struct input_dev dev;
-	struct urb irq;
+	struct urb *irq;
 	int open;
 };
 
@@ -84,8 +84,8 @@
 	if (mouse->open++)
 		return 0;
 
-	mouse->irq.dev = mouse->usbdev;
-	if (usb_submit_urb(&mouse->irq))
+	mouse->irq->dev = mouse->usbdev;
+	if (usb_submit_urb(mouse->irq))
 		return -EIO;
 
 	return 0;
@@ -96,7 +96,7 @@
 	struct usb_mouse *mouse = dev->private;
 
 	if (!--mouse->open)
-		usb_unlink_urb(&mouse->irq);
+		usb_unlink_urb(mouse->irq);
 }
 
 static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum,
@@ -126,6 +126,12 @@
 	if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL;
 	memset(mouse, 0, sizeof(struct usb_mouse));
 
+	mouse->irq = usb_alloc_urb(0);
+	if (!mouse->irq) {
+		kfree(mouse);
+		return NULL;
+	}
+
 	mouse->usbdev = dev;
 
 	mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
@@ -162,7 +168,7 @@
 
 	kfree(buf);
 
-	FILL_INT_URB(&mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp,
+	FILL_INT_URB(mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp,
 		usb_mouse_irq, mouse, endpoint->bInterval);
 
 	input_register_device(&mouse->dev);
@@ -176,8 +182,9 @@
 static void usb_mouse_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct usb_mouse *mouse = ptr;
-	usb_unlink_urb(&mouse->irq);
+	usb_unlink_urb(mouse->irq);
 	input_unregister_device(&mouse->dev);
+	usb_free_urb(mouse->irq);
 	kfree(mouse);
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/usbvideo.c linux/drivers/usb/usbvideo.c
--- v2.5.2/linux/drivers/usb/usbvideo.c	Wed Oct 10 23:42:46 2001
+++ linux/drivers/usb/usbvideo.c	Mon Jan 21 15:44:21 2002
@@ -1184,7 +1184,7 @@
 	return -EINVAL;
 }
 
-int usbvideo_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size)
+int usbvideo_v4l_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
 {
 	uvd_t *uvd = (uvd_t *) dev;
 	unsigned long start = (unsigned long) adr;
@@ -1199,7 +1199,7 @@
 	pos = (unsigned long) uvd->fbuf;
 	while (size > 0) {
 		page = usbvideo_kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
 			return -EAGAIN;
 
 		start += PAGE_SIZE;
@@ -1776,7 +1776,7 @@
 /*
  * Make all of the blocks of data contiguous
  */
-static int usbvideo_CompressIsochronous(uvd_t *uvd, urb_t *urb)
+static int usbvideo_CompressIsochronous(uvd_t *uvd, struct urb *urb)
 {
 	char *cdata;
 	int i, totlen = 0;
@@ -1891,7 +1891,7 @@
 	/* We double buffer the Iso lists */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		int j, k;
-		urb_t *urb = uvd->sbuf[i].urb;
+		struct urb *urb = uvd->sbuf[i].urb;
 		urb->dev = dev;
 		urb->context = uvd;
 		urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/usbvideo.h linux/drivers/usb/usbvideo.h
--- v2.5.2/linux/drivers/usb/usbvideo.h	Wed Oct 10 23:42:46 2001
+++ linux/drivers/usb/usbvideo.h	Mon Jan 21 15:44:21 2002
@@ -165,7 +165,7 @@
 /* This structure represents one Isoc request - URB and buffer */
 typedef struct {
 	char *data;
-	urb_t *urb;
+	struct urb *urb;
 } usbvideo_sbuf_t;
 
 typedef struct {
@@ -349,7 +349,7 @@
 void usbvideo_v4l_close(struct video_device *dev);
 int usbvideo_v4l_initialize(struct video_device *dev);
 int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg);
-int usbvideo_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size);
+int usbvideo_v4l_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size);
 int usbvideo_v4l_open(struct video_device *dev, int flags);
 long usbvideo_v4l_read(struct video_device *dev, char *buf,
 			unsigned long count, int noblock);
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/vicam.c linux/drivers/usb/vicam.c
--- v2.5.2/linux/drivers/usb/vicam.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/vicam.c	Wed Jan 23 15:33:46 2002
@@ -344,7 +344,7 @@
 	synchronize(vicam);
 	mdelay(10);
 	vicam_parameters(vicam);
-	printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+	printk("Submiting urb: %d\n", usb_submit_urb(vicam->readurb));
 #endif
 }
 
@@ -468,29 +468,23 @@
 	int err = 0;
 	
 	dbg("vicam_v4l_open");
-
-	MOD_INC_USE_COUNT; 
+ 
 	down(&vicam->sem);
 
-	if (vicam->open_count)		/* Maybe not needed? */
-		err = -EBUSY;
+	vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES);
+	if (!vicam->fbuf)
+		err=-ENOMEM;
 	else {
-		vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES);
-		if (!vicam->fbuf)
-			err=-ENOMEM;
-		else {
-			vicam->open_count = 1;
-		}
+		vicam->open_count = 1;
+	}
 #ifdef BLINKING
-		vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
-		info ("led on");
-		vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
+	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
+	info ("led on");
+	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
 #endif
-	}
 
 	up(&vicam->sem);
-	if (err)
-		MOD_DEC_USE_COUNT;
+	
 	return err;
 }
 
@@ -515,7 +509,6 @@
 	up(&vicam->sem);
 	/* Why does se401.c have a usbdevice check here? */
 	/* If device is unplugged while open, I guess we only may unregister now */
-	MOD_DEC_USE_COUNT;
 }
 
 static long vicam_v4l_read(struct video_device *vdev, char *user_buf, unsigned long buflen, int noblock)
@@ -670,7 +663,7 @@
         return ret;
 }
 
-static int vicam_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size)
+static int vicam_v4l_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
 {
 	struct usb_vicam *vicam = (struct usb_vicam *)dev;
 	unsigned long start = (unsigned long)adr;
@@ -691,7 +684,7 @@
 	pos = (unsigned long)vicam->fbuf;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up(&vicam->sem);
 			return -EAGAIN;
 		}
@@ -717,6 +710,7 @@
 
 /* FIXME - vicam_template - important */
 static struct video_device vicam_template = {
+	owner:		THIS_MODULE,
 	name:		"vicam USB camera",
 	type:		VID_TYPE_CAPTURE,
 	hardware:	VID_HARDWARE_SE401, /* need to ask for own id */
@@ -847,9 +841,9 @@
 
 	vicam_parameters(vicam);
 
-	FILL_BULK_URB(&vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
+	FILL_BULK_URB(vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
 		      buf, 0x1e480, vicam_bulk, vicam);
-	printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+	printk("Submiting urb: %d\n", usb_submit_urb(vicam->readurb));
 
 	return 0;
 error:
@@ -883,7 +877,13 @@
 		return NULL;
 	}
 	memset(vicam, 0, sizeof(*vicam));
-	
+
+	vicam->readurb = usb_alloc_urb(0);
+	if (!vicam->readurb) {
+		kfree(vicam);
+		return NULL;
+	}
+
 	vicam->udev = udev;
 	vicam->camera_name = camera_name;
 	vicam->win.brightness = 128;
@@ -931,6 +931,7 @@
 
 	if (!vicam->open_count) {
 		/* Other random junk */
+		usb_free_urb(vicam->readurb);
 		kfree(vicam);
 		vicam = NULL;
 	}
@@ -938,6 +939,7 @@
 
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver vicam_driver = {
+	owner:		THIS_MODULE,
 	name:		"vicam",
 	probe:		vicam_probe,
 	disconnect:	vicam_disconnect,
@@ -984,3 +986,4 @@
 
 module_init(usb_vicam_init);
 module_exit(usb_vicam_exit);
+
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/vicam.h linux/drivers/usb/vicam.h
--- v2.5.2/linux/drivers/usb/vicam.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/vicam.h	Wed Jan 23 15:33:46 2002
@@ -68,14 +68,14 @@
 	/* v4l stuff */
 	char *camera_name;
 	char *fbuf;
-	urb_t *urb[VICAM_NUMSBUF];
+	struct urb *urb[VICAM_NUMSBUF];
 	int sizes;
 	int *width;
 	int *height;
 	int maxframesize;
 	struct picture_parm win;
 	struct proc_dir_entry *proc_entry;      /* /proc/se401/videoX */
-	struct urb readurb;
+	struct urb *readurb;
 };
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/wacom.c linux/drivers/usb/wacom.c
--- v2.5.2/linux/drivers/usb/wacom.c	Mon Sep 17 22:52:35 2001
+++ linux/drivers/usb/wacom.c	Wed Jan 23 15:33:46 2002
@@ -100,7 +100,7 @@
 	signed char data[10];
 	struct input_dev dev;
 	struct usb_device *usbdev;
-	struct urb irq;
+	struct urb *irq;
 	struct wacom_features *features;
 	int tool[2];
 	int open;
@@ -335,8 +335,8 @@
 	if (wacom->open++)
 		return 0;
 
-	wacom->irq.dev = wacom->usbdev;
-	if (usb_submit_urb(&wacom->irq))
+	wacom->irq->dev = wacom->usbdev;
+	if (usb_submit_urb(wacom->irq))
 		return -EIO;
 
 	return 0;
@@ -347,7 +347,7 @@
 	struct wacom *wacom = dev->private;
 
 	if (!--wacom->open)
-		usb_unlink_urb(&wacom->irq);
+		usb_unlink_urb(wacom->irq);
 }
 
 static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
@@ -358,6 +358,12 @@
 	if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL;
 	memset(wacom, 0, sizeof(struct wacom));
 
+	wacom->irq = usb_alloc_urb(0);
+	if (!wacom->irq) {
+		kfree(wacom);
+		return NULL;
+	}
+
 	wacom->features = wacom_features + id->driver_info;
 
 	wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC) | wacom->features->evbit;
@@ -397,7 +403,7 @@
 
 	endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
 
-	FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+	FILL_INT_URB(wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
 		     wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval);
 
 	input_register_device(&wacom->dev);
@@ -411,8 +417,9 @@
 static void wacom_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct wacom *wacom = ptr;
-	usb_unlink_urb(&wacom->irq);
+	usb_unlink_urb(wacom->irq);
 	input_unregister_device(&wacom->dev);
+	usb_free_urb(wacom->irq);
 	kfree(wacom);
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/video/Config.help linux/drivers/video/Config.help
--- v2.5.2/linux/drivers/video/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/Config.help	Fri Jan 25 16:03:31 2002
@@ -0,0 +1,702 @@
+CONFIG_FB_SGIVW
+  SGI Visual Workstation support for framebuffer graphics.
+
+CONFIG_VIDEO_SELECT
+  This enables support for text mode selection on kernel startup. If
+  you want to take advantage of some high-resolution text mode your
+  card's BIOS offers, but the traditional Linux utilities like
+  SVGATextMode don't, you can say Y here and set the mode using the
+  "vga=" option from your boot loader (lilo or loadlin) or set
+  "vga=ask" which brings up a video mode menu on kernel startup. (Try
+  "man bootparam" or see the documentation of your boot loader about
+  how to pass options to the kernel.)
+
+  Read the file <file:Documentation/svga.txt> for more information
+  about the Video mode selection support. If unsure, say N.
+
+CONFIG_FB
+  The frame buffer device provides an abstraction for the graphics
+  hardware. It represents the frame buffer of some video hardware and
+  allows application software to access the graphics hardware through
+  a well-defined interface, so the software doesn't need to know
+  anything about the low-level (hardware register) stuff.
+
+  Frame buffer devices work identically across the different
+  architectures supported by Linux and make the implementation of
+  application programs easier and more portable; at this point, an X
+  server exists which uses the frame buffer device exclusively.
+  On several non-X86 architectures, the frame buffer device is the
+  only way to use the graphics hardware.
+
+  The device is accessed through special device nodes, usually located
+  in the /dev directory, i.e. /dev/fb*.
+
+  You need an utility program called fbset to make full use of frame
+  buffer devices. Please read <file:Documentation/fb/framebuffer.txt>
+  and the Framebuffer-HOWTO at
+  <http://www.tahallah.demon.co.uk/programming/prog.html> for more
+  information.
+
+  Say Y here and to the driver for your graphics board below if you
+  are compiling a kernel for a non-x86 architecture.
+
+  If you are compiling for the x86 architecture, you can say Y if you
+  want to play with it, but it is not essential. Please note that
+  running graphical applications that directly touch the hardware
+  (e.g. an accelerated X server) and that are not frame buffer
+  device-aware may cause unexpected results. If unsure, say N.
+
+CONFIG_FB_ACORN
+  This is the frame buffer device driver for the Acorn VIDC graphics
+  hardware found in Acorn RISC PCs and other ARM-based machines.  If
+  unsure, say N.
+
+CONFIG_FB_PM2
+  This is the frame buffer device driver for the Permedia2 AGP frame
+  buffer card from ASK, aka `Graphic Blaster Exxtreme'.  There is a
+  product page at
+  <http://www.ask.com.hk/product/Permedia%202/permedia2.htm>.
+
+CONFIG_FB_PM2_FIFO_DISCONNECT
+  Support the Permedia2 FIFOI disconnect feature (see CONFIG_FB_PM2).
+
+CONFIG_FB_PM2_PCI
+  Say Y to enable support for Permedia2 AGP frame buffer card from
+  3Dlabs (aka `Graphic Blaster Exxtreme') on the PCI bus.
+
+CONFIG_FB_PM2_CVPPC
+  Say Y to enable support for the Amiga Phase 5 CVisionPPC BVisionPPC
+  framebuffer cards.  Phase 5 is no longer with us, alas.
+
+CONFIG_FB_AMIGA
+  This is the frame buffer device driver for the builtin graphics
+  chipset found in Amigas.
+
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called amifb.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_FB_AMIGA_OCS
+  This enables support for the original Agnus and Denise video chips,
+  found in the Amiga 1000 and most A500's and A2000's. If you intend
+  to run Linux on any of these systems, say Y; otherwise say N.
+
+CONFIG_FB_AMIGA_ECS
+  This enables support for the Enhanced Chip Set, found in later
+  A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If
+  you intend to run Linux on any of these systems, say Y; otherwise
+  say N.
+
+CONFIG_FB_AMIGA_AGA
+  This enables support for the Advanced Graphics Architecture (also
+  known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T
+  and CD32. If you intend to run Linux on any of these systems, say Y;
+  otherwise say N.
+
+CONFIG_FB_CYBER
+  This enables support for the Cybervision 64 graphics card from
+  Phase5. Please note that its use is not all that intuitive (i.e. if
+  you have any questions, be sure to ask!). Say N unless you have a
+  Cybervision 64 or plan to get one before you next recompile the
+  kernel. Please note that this driver DOES NOT support the
+  Cybervision 64 3D card, as they use incompatible video chips.
+
+CONFIG_FB_CYBER2000
+  This enables support for the Integraphics CyberPro 20x0 and 5000
+  VGA chips used in the Rebel.com Netwinder and other machines.
+  Say Y if you have a NetWinder or a graphics card containing this
+  device, otherwise say N.
+
+CONFIG_FB_VIRGE
+  This enables support for the Cybervision 64/3D graphics card from
+  Phase5. Please note that its use is not all that intuitive (i.e. if
+  you have any questions, be sure to ask!). Say N unless you have a
+  Cybervision 64/3D or plan to get one before you next recompile the
+  kernel. Please note that this driver DOES NOT support the older
+  Cybervision 64 card, as they use incompatible video chips.
+
+CONFIG_FB_RETINAZ3
+  This enables support for the Retina Z3 graphics card. Say N unless
+  you have a Retina Z3 or plan to get one before you next recompile
+  the kernel.
+
+CONFIG_FB_CLGEN
+  This enables support for Cirrus Logic GD542x/543x based boards on
+  Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum.
+
+  If you have a PCI-based system, this enables support for these
+  chips: GD-543x, GD-544x, GD-5480.
+
+  Please read the file <file:Documentation/fb/clgenfb.txt>.
+
+  Say N unless you have such a graphics board or plan to get one
+  before you next recompile the kernel.
+
+CONFIG_FB_ATARI
+  This is the frame buffer device driver for the builtin graphics
+  chipset found in Ataris.
+
+CONFIG_FB_FM2
+  This is the frame buffer device driver for the Amiga FrameMaster
+  card from BSC (exhibited 1992 but not shipped as a CBM product).
+
+CONFIG_FB_OF
+  Say Y if you want support with Open Firmware for your graphics
+  board.
+
+CONFIG_FB_S3TRIO
+  If you have a S3 Trio say Y. Say N for S3 Virge.
+
+CONFIG_FB_3DFX
+  This driver supports graphics boards with the 3Dfx Banshee/Voodoo3
+  chips. Say Y if you have such a graphics board.
+
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called tdfxfb.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_FB_RIVA
+  This driver supports graphics boards with the nVidia Riva/Geforce
+  chips.
+  Say Y if you have such a graphics board.
+
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called rivafb.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_FB_ATY
+  This driver supports graphics boards with the ATI Mach64 chips.
+  Say Y if you have such a graphics board.
+
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called atyfb.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_FB_ATY128
+  This driver supports graphics boards with the ATI Rage128 chips.
+  Say Y if you have such a graphics board and read
+  <file:Documentation/fb/aty128fb.txt>.
+
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called aty128fb.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+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/>.
+
+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/>.
+
+CONFIG_FB_PMAGB_B
+  Say Y here to directly support the on-board PMAGB-B framebuffer in
+  the 5000/1xx versions of the DECstation.  There is a page dedicated
+  to Linux on DECstations at <http://decstation.unix-ag.org/>.
+
+CONFIG_FB_NEOMAGIC
+  This driver supports notebooks with NeoMagic PCI chips.
+  Say Y if you have such a graphics card. 
+
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called neofb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+CONFIG_FB_CONTROL
+  This driver supports a frame buffer for the graphics adapter in the
+  Power Macintosh 7300 and others.
+
+CONFIG_FB_PLATINUM
+  This driver supports a frame buffer for the "platinum" graphics
+  adapter in some Power Macintoshes.
+
+CONFIG_FB_VALKYRIE
+  This driver supports a frame buffer for the "valkyrie" graphics
+  adapter in some Power Macintoshes.
+
+CONFIG_FB_CT65550
+  This is the frame buffer device driver for the Chips & Technologies
+  65550 graphics chip in PowerBooks.
+
+CONFIG_FB_TGA
+  This is the frame buffer device driver for generic TGA graphic
+  cards. Say Y if you have one of those.
+
+CONFIG_FB_VESA
+  This is the frame buffer device driver for generic VESA 2.0
+  compliant graphic cards. The older VESA 1.2 cards are not supported.
+  You will get a boot time penguin logo at no additional cost. Please
+  read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
+
+CONFIG_FBCON_VGA_PLANES
+  This low level frame buffer console driver enable the kernel to use
+  the 16-color planar modes of the old VGA cards where the bits of
+  each pixel are separated into 4 planes.
+
+  Only answer Y here if you have a (very old) VGA card that isn't VESA
+  2 compatible.
+
+CONFIG_FB_VGA16
+  This is the frame buffer device driver for VGA 16 color graphic
+  cards. Say Y if you have such a card.
+
+  This code is also available as a module. If you want to compile it
+  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
+  vga16fb.o.
+
+CONFIG_FB_STI
+  STI refers to the HP "Standard Text Interface" which is a set of
+  BIOS routines contained in a ROM chip in HP PA-RISC based machines.
+  Enabling this option will implement the linux framebuffer device and
+  an fbcon color text console using calls to the STI BIOS routines.
+  The HP framebuffer device is usually planar, uses a strange memory
+  layout, and changing the plane mask to create colored pixels
+  requires a call to the STI routines, so do not expect /dev/fb to
+  actually be useful.  However, it is the best we have as far as
+  graphics on the HP chipsets due to lack of hardware level
+  documentation for the various on-board HP chipsets used in these
+  systems.  It is sufficient for basic text console functions,
+  including fonts.
+
+  You should probably enable this option, unless you are having
+  trouble getting video when booting the kernel (make sure it isn't
+  just that you are running the console on the serial port, though).
+  Really old HP boxes may not have STI, and must use the PDC BIOS
+  console or the IODC BIOS.
+
+CONFIG_FBCON_FONTS
+  Say Y here if you would like to use fonts other than the default
+  your frame buffer console usually use.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about foreign fonts.
+
+  If unsure, say N (the default choices are safe).
+
+CONFIG_FONT_8x16
+  This is the "high resolution" font for the VGA frame buffer (the one
+  provided by the VGA text console 80x25 mode.
+
+  If unsure, say Y.
+
+CONFIG_FBCON_FONTWIDTH8_ONLY
+  Answer Y here will make the kernel provide only the 8x8 fonts (these
+  are the less readable).
+
+  If unsure, say N.
+
+CONFIG_FONT_SUN8x16
+  This is the high resolution console font for Sun machines. Say Y.
+
+CONFIG_FONT_SUN12x22
+  This is the high resolution console font for Sun machines with very
+  big letters (like the letters used in the SPARC PROM). If the
+  standard font is unreadable for you, say Y, otherwise say N.
+
+CONFIG_FONT_8x8
+  This is the "high resolution" font for the VGA frame buffer (the one
+  provided by the text console 80x50 (and higher) modes).
+
+  Note that this is a poor quality font. The VGA 8x16 font is quite a
+  lot more readable.
+
+  Given the resolution provided by the frame buffer device, answer N
+  here is safe.
+
+CONFIG_FONT_6x11
+  Small console font with Macintosh-style high-half glyphs.  Some Mac
+  framebuffer drivers don't support this one at all.
+
+CONFIG_FONT_PEARL_8x8
+  Small console font with PC-style control-character and high-half
+  glyphs.
+
+CONFIG_FONT_ACORN_8x8
+  Small console font with PC-style control characters and high-half
+  glyphs.
+
+CONFIG_FB_HGA
+  Say Y here if you have a Hercules mono graphics card.
+
+  This driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want).
+  The module will be called hgafb.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+  As this card technology is 15 years old, most people will answer N
+  here.
+
+CONFIG_FB_E1355
+  Build in support for the SED1355 Epson Research Embedded RAMDAC
+  LCD/CRT Controller (since redesignated as the S1D13505) as a
+  framebuffer.  Product specs at
+  <http://www.erd.epson.com/vdc/html/products.htm>.
+
+CONFIG_E1355_REG_BASE
+  Epson SED1355/S1D13505 LCD/CRT controller register base address.
+  See the manuals at
+  <http://www.erd.epson.com/vdc/html/contents/S1D13505.htm> for
+  discussion.
+
+CONFIG_E1355_FB_BASE
+  Epson SED1355/S1D13505 LCD/CRT controller memory base address.  See
+  the manuals at
+  <http://www.erd.epson.com/vdc/html/contents/S1D13505.htm> for
+  discussion.
+
+CONFIG_FB_PVR2
+  Say Y here if you have a PowerVR 2 card in your box.  If you plan to
+  run linux on your Dreamcast, you will have to say Y here.
+  This driver may or may not work on other PowerVR 2 cards, but is
+  totally untested.  Use at your own risk.  If unsure, say N.
+
+  This driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want).
+  The module will be called pvr2fb.o.  If you want to compile it as
+  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=pvr2:XXX", where
+  the meaning of XXX can be found at the end of the main source file
+  (<file:drivers/video/pvr2fb.c>). Please see the file
+  <file:Documentation/fb/pvr2fb.txt>.
+
+CONFIG_FB_PVR2_DEBUG
+  Say Y here if you wish for the pvr2fb driver to print out debugging
+  messages. Most people will want to say N here. If unsure, you will
+  also want to say N.
+
+CONFIG_FB_MATROX
+  Say Y here if you have a Matrox Millennium, Matrox Millennium II,
+  Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox
+  Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video,
+  Matrox G400 or G450 card in your box. At this time, support for the
+  G100 is untested and support for G450 is highly experimental.
+
+  This driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want).
+  The module will be called matroxfb.o. If you want to compile it as
+  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", and
+  are described in <file:Documentation/fb/matroxfb.txt>.
+
+CONFIG_FB_MATROX_MILLENIUM
+  Say Y here if you have a Matrox Millennium or Matrox Millennium II
+  video card. If you select "Advanced lowlevel driver options" below,
+  you should check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp
+  packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can
+  also use font widths different from 8.
+
+CONFIG_FB_MATROX_MYSTIQUE
+  Say Y here if you have a Matrox Mystique or Matrox Mystique 220
+  video card. If you select "Advanced lowlevel driver options" below,
+  you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp
+  packed pixel and 32 bpp packed pixel. You can also use font widths
+  different from 8.
+
+CONFIG_FB_MATROX_G100
+  Say Y here if you have a Matrox G100, G200, G400 or G450 based
+  video card. If you select "Advanced lowlevel driver options", you
+  should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed
+  pixel and 32 bpp packed pixel. You can also use font widths
+  different from 8.
+
+  If you need support for G400 secondary head, you must first say Y to
+  "I2C support" and "I2C bit-banging support" in the character devices
+  section, and then to "Matrox I2C support" and "G400 second head
+  support" here in the framebuffer section.
+
+CONFIG_FB_MATROX_I2C
+  This drivers creates I2C buses which are needed for accessing the
+  DDC (I2C) bus present on all Matroxes, an I2C bus which
+  interconnects Matrox optional devices, like MGA-TVO on G200 and
+  G400, and the secondary head DDC bus, present on G400 only.
+
+  You can say Y or M here if you want to experiment with monitor
+  detection code. You must say Y or M here if you want to use either
+  second head of G400 or MGA-TVO on G200 or G400.
+
+  If you compile it as module, it will create a module named
+  i2c-matroxfb.o.
+
+CONFIG_FB_MATROX_MAVEN
+  WARNING !!! This support does not work with G450 !!!
+
+  Say Y or M here if you want to use a secondary head (meaning two
+  monitors in parallel) on G400 or MGA-TVO add-on on G200. Secondary
+  head is not compatible with accelerated XFree 3.3.x SVGA servers -
+  secondary head output is blanked while you are in X. With XFree
+  3.9.17 preview you can use both heads if you use SVGA over fbdev or
+  the fbdev driver on first head and the fbdev driver on second head.
+
+  If you compile it as module, two modules are created,
+  matroxfb_crtc2.o and matroxfb_maven.o. Matroxfb_maven is needed for
+  both G200 and G400, matroxfb_crtc2 is needed only by G400. You must
+  also load i2c-matroxfb to get it to run.
+
+  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
+  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.
+
+  Also do not forget that second head supports only 16 and 32 bpp
+  packed pixels, so it is a good idea to compile them into the kernel
+  too.  You can use only some font widths, as the driver uses generic
+  painting procedures (the secondary head does not use acceleration
+  engine).
+
+CONFIG_FB_MATROX_G450
+  Say Y or M here if you want to use a secondary head (meaning two
+  monitors in parallel) on G450.
+
+  If you compile it as module, two modules are created,
+  matroxfb_crtc2.o and matroxfb_g450.o. Both modules are needed if you
+  want two independent display devices.
+
+  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
+  primary and secondary head outputs.  Secondary head driver always
+  start in 640x480 resolution and you must use fbset to change it.
+
+  Also do not forget that second head supports only 16 and 32 bpp
+  packed pixels, so it is a good idea to compile them into the kernel
+  too. You can use only some font widths, as the driver uses generic
+  painting procedures (the secondary head does not use acceleration
+  engine).
+
+CONFIG_FB_MATROX_MULTIHEAD
+  Say Y here if you have more than one (supported) Matrox device in
+  your computer and you want to use all of them for different monitors
+  ("multihead"). If you have only one device, you should say N because
+  the driver compiled with Y is larger and a bit slower, especially on
+  ia32 (ix86).
+
+  If you said M to "Matrox unified accelerated driver" and N here, you
+  will still be able to use several Matrox devices simultaneously:
+  insert several instances of the module matroxfb.o into the kernel
+  with insmod, supplying the parameter "dev=N" where N is 0, 1, etc.
+  for the different Matrox devices. This method is slightly faster but
+  uses 40 KB of kernel memory per Matrox card.
+
+  There is no need for enabling 'Matrox multihead support' if you have
+  only one Matrox card in the box.
+
+CONFIG_FB_VOODOO1
+  Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or 
+  Voodoo2 (cvg) based graphics card.
+
+  This driver is also available as a module ( = code which can be 
+  inserted and removed from the running kernel whenever you want).
+  The module will be called sstfb.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+
+  WARNING: Do not use any application that uses the 3D engine
+  (namely glide) while using this driver.
+  Please read the file Documentation/fb/README-sstfb.txt for supported
+  options and other important info  support.
+
+CONFIG_FB_SBUS
+  Say Y if you want support for SBUS or UPA based frame buffer device.
+
+CONFIG_FB_CREATOR
+  This is the frame buffer device driver for the Creator and Creator3D
+  graphics boards.
+
+CONFIG_FB_CGSIX
+  This is the frame buffer device driver for the CGsix (GX, TurboGX)
+  frame buffer.
+
+CONFIG_FB_BWTWO
+  This is the frame buffer device driver for the BWtwo frame buffer.
+
+CONFIG_FB_CGTHREE
+  This is the frame buffer device driver for the CGthree frame buffer.
+
+CONFIG_FB_CGFOURTEEN
+  This is the frame buffer device driver for the CGfourteen frame
+  buffer on Desktop SPARCsystems with the SX graphics option.
+
+CONFIG_FB_P9100
+  This is the frame buffer device driver for the P9100 card
+  supported on Sparcbook 3 machines.
+
+CONFIG_FB_LEO
+  This is the frame buffer device driver for the SBUS-based Sun ZX
+  (leo) frame buffer cards.
+
+CONFIG_FB_IGA
+  This is the framebuffer device for the INTERGRAPHICS 1680 and
+  successor frame buffer cards.
+
+CONFIG_FB_TCX
+  This is the frame buffer device driver for the TCX 24/8bit frame
+  buffer.
+
+CONFIG_FB_HIT
+  This is the frame buffer device driver for the Hitachi HD64461 LCD
+  frame buffer card.
+
+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/>.
+
+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/>.
+
+CONFIG_FB_SIS_315
+  This is the frame buffer device driver for the SiS 315 graphics
+  card.  Specs available at <http://www.sis.com.tw/>.
+
+CONFIG_FB_IMSTT
+  The IMS Twin Turbo is a PCI-based frame buffer card bundled with
+  many Macintosh and compatible computers.
+
+CONFIG_FB_VIRTUAL
+  This is a `virtual' frame buffer device. It operates on a chunk of
+  unswappable kernel memory instead of on the memory of a graphics
+  board. This means you cannot see any output sent to this frame
+  buffer device, while it does consume precious memory. The main use
+  of this frame buffer device is testing and debugging the frame
+  buffer subsystem. Do NOT enable it for normal systems! To protect
+  the innocent, it has to be enabled explicitly at boot time using the
+  kernel option `video=vfb:'.
+
+  This driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called vfb.o. If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.
+
+  If unsure, say N.
+
+CONFIG_FB_ATY_CT
+  Say Y here to support use of ATI's 64-bit Rage boards (or other
+  boards based on the Mach64 CT, VT, GT, and LT chipsets) as a
+  framebuffer device.  The ATI product support page for these boards
+  is at <http://support.ati.com/products/pc/mach64/>.
+
+CONFIG_FB_ATY_GX
+  Say Y here to support use of the ATI Mach64 Graphics Expression
+  board (or other boards based on the Mach64 GX chipset) as a
+  framebuffer device.  The ATI product support page for these boards
+  is at
+  <http://support.ati.com/products/pc/mach64/graphics_xpression.html>.
+
+CONFIG_FB_RADEON
+  Choose this option if you want to use an ATI Radeon graphics card as
+  a framebuffer device.  There are both PCI and AGP versions.  You
+  don't need to choose this to run the Radeon in plain VGA mode.
+  There is a product page at
+  <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
+
+CONFIG_FB_SA1100
+  This is a framebuffer device for the SA-1100 LCD Controller.
+  See <http://www.linux-fbdev.org/> for information on framebuffer
+  devices.
+
+  If you plan to use the LCD display with your SA-1100 system, say
+  Y here.
+
+CONFIG_FBCON_ADVANCED
+  The frame buffer console uses character drawing routines that are
+  tailored to the specific organization of pixels in the memory of
+  your graphics hardware. These are called the low level frame buffer
+  console drivers. Note that they are used for text console output
+  only; they are NOT needed for graphical applications.
+
+  If you say N here, the needed low level drivers are automatically
+  enabled, depending on what frame buffer devices you selected above.
+  This is recommended for most users.
+
+  If you say Y here, you have more fine-grained control over which low
+  level drivers are enabled. You can e.g. leave out low level drivers
+  for color depths you do not intend to use for text consoles.
+
+  Low level frame buffer console drivers can be modules ( = code which
+  can be inserted and removed from the running kernel whenever you
+  want). The modules will be called fbcon-*.o. If you want to compile
+  (some of) them as modules, read <file:Documentation/modules.txt>.
+
+  If unsure, say N.
+
+CONFIG_FBCON_MFB
+  This is the low level frame buffer console driver for monochrome
+  (2 colors) packed pixels.
+
+CONFIG_FBCON_CFB2
+  This is the low level frame buffer console driver for 2 bits per
+  pixel (4 colors) packed pixels.
+
+CONFIG_FBCON_CFB4
+  This is the low level frame buffer console driver for 4 bits per
+  pixel (16 colors) packed pixels.
+
+CONFIG_FBCON_CFB8
+  This is the low level frame buffer console driver for 8 bits per
+  pixel (256 colors) packed pixels.
+
+CONFIG_FBCON_CFB16
+  This is the low level frame buffer console driver for 15 or 16 bits
+  per pixel (32K or 64K colors, also known as `hicolor') packed
+  pixels.
+
+CONFIG_FBCON_CFB24
+  This is the low level frame buffer console driver for 24 bits per
+  pixel (16M colors, also known as `truecolor') packed pixels. It is
+  NOT for `sparse' 32 bits per pixel mode.
+
+CONFIG_FBCON_CFB32
+  This is the low level frame buffer console driver for 32 bits per
+  pixel (16M colors, also known as `truecolor') sparse packed pixels.
+
+CONFIG_FBCON_AFB
+  This is the low level frame buffer console driver for 1 to 8
+  bitplanes (2 to 256 colors) on Amiga.
+
+CONFIG_FBCON_ILBM
+  This is the low level frame buffer console driver for 1 to 8
+  interleaved bitplanes (2 to 256 colors) on Amiga.
+
+CONFIG_FBCON_IPLAN2P2
+  This is the low level frame buffer console driver for 2 interleaved
+  bitplanes (4 colors) on Atari.
+
+CONFIG_FBCON_IPLAN2P4
+  This is the low level frame buffer console driver for 4 interleaved
+  bitplanes (16 colors) on Atari.
+
+CONFIG_FBCON_IPLAN2P8
+  This is the low level frame buffer console driver for 8 interleaved
+  bitplanes (256 colors) on Atari.
+
+CONFIG_FBCON_MAC
+  This is the low level frame buffer console driver for 1/2/4/8/16/32
+  bits per pixel packed pixels on Mac. It supports variable font
+  widths for low resolution screens.
+
+CONFIG_FBCON_HGA
+  This is the low level frame buffer console driver for Hercules mono
+  graphics cards.
+
+CONFIG_FBCON_VGA
+  This is the low level frame buffer console driver for VGA text mode;
+  it is used by frame buffer device drivers that support VGA text
+  mode.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.5.2/linux/drivers/video/Config.in	Wed Nov 14 15:16:31 2001
+++ linux/drivers/video/Config.in	Wed Jan 23 15:25:34 2002
@@ -143,6 +143,7 @@
 	    bool '    SIS 630/540/730 support' CONFIG_FB_SIS_300
 	    bool '    SIS 315H/315 support' CONFIG_FB_SIS_315
 	 fi
+	 tristate '  NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC
 	 tristate '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
 	 tristate '  3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1
       fi
@@ -268,7 +269,7 @@
 	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
 	   "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
 	   "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
-	   "$CONFIG_FB_SIS" = "y" ]; then
+	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB8 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -288,7 +289,7 @@
 	      "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
 	      "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
-	      "$CONFIG_FB_TX3912" = "m" ]; then
+	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB8 m
 	 fi
       fi
@@ -304,7 +305,8 @@
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
-	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" ]; then
+	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
+	   "$CONFIG_FB_NEOMAGIC" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB16 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
@@ -319,7 +321,8 @@
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
-	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then
+	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
+	      "$CONFIG_FB_NEOMAGIC" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB16 m
 	 fi
       fi
@@ -328,7 +331,7 @@
 	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
            "$CONFIG_FB_ATY128" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
 	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
-	   "$CONFIG_FB_VOODOO1" = "y" ]; then
+	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB24 y
       else
 	 if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
@@ -336,7 +339,7 @@
 	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
 	      "$CONFIG_FB_ATY128" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \
-	      "$CONFIG_FB_VOODOO1" = "m" ]; then
+	      "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
 	    define_tristate CONFIG_FBCON_CFB24 m
 	 fi
       fi
diff -u --recursive --new-file v2.5.2/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.5.2/linux/drivers/video/Makefile	Thu Oct 25 13:53:52 2001
+++ linux/drivers/video/Makefile	Wed Jan 23 15:25:34 2002
@@ -49,6 +49,7 @@
 obj-$(CONFIG_FB_ATARI)            += atafb.o
 obj-$(CONFIG_FB_ATY128)           += aty128fb.o
 obj-$(CONFIG_FB_RADEON)		  += radeonfb.o
+obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o
 obj-$(CONFIG_FB_IGA)              += igafb.o
 obj-$(CONFIG_FB_CONTROL)          += controlfb.o
 obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o
diff -u --recursive --new-file v2.5.2/linux/drivers/video/S3triofb.c linux/drivers/video/S3triofb.c
--- v2.5.2/linux/drivers/video/S3triofb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/S3triofb.c	Wed Jan 23 15:51:23 2002
@@ -554,7 +554,7 @@
 
     strcpy(fb_info.modename, "Trio64 ");
     strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
-    fb_info.node = -1;
+    fb_info.node = NODEV;
     fb_info.fbops = &s3trio_ops;
 #if 0
     fb_info.fbvar_num = 1;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c
--- v2.5.2/linux/drivers/video/acornfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/acornfb.c	Wed Jan 23 15:51:23 2002
@@ -1152,7 +1152,7 @@
 	 * some updates to the screen occasionally, but process switches
 	 * should cause the caches and buffers to be flushed often enough.
 	 */
-	if (io_remap_page_range(vma->vm_start, off,
+	if (io_remap_page_range(vma, vma->vm_start, off,
 				vma->vm_end - vma->vm_start,
 				vma->vm_page_prot))
 		return -EAGAIN;
@@ -1318,7 +1318,7 @@
 	strcpy(fb_info.modename, "Acorn");
 	strcpy(fb_info.fontname, "Acorn8x8");
 
-	fb_info.node		   = -1;
+	fb_info.node		   = NODEV;
 	fb_info.fbops		   = &acornfb_ops;
 	fb_info.disp		   = &global_disp;
 	fb_info.changevar	   = NULL;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/amifb.c linux/drivers/video/amifb.c
--- v2.5.2/linux/drivers/video/amifb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/amifb.c	Wed Jan 23 15:51:23 2002
@@ -1730,7 +1730,7 @@
 
 	strcpy(fb_info.modename, amifb_name);
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &amifb_ops;
 	fb_info.disp = &disp;
 	fb_info.switch_con = &amifbcon_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/atafb.c linux/drivers/video/atafb.c
--- v2.5.2/linux/drivers/video/atafb.c	Thu Oct 25 00:02:26 2001
+++ linux/drivers/video/atafb.c	Wed Jan 23 15:51:23 2002
@@ -2828,7 +2828,7 @@
 
 	strcpy(fb_info.modename, "Atari Builtin ");
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &atafb_ops;
 	fb_info.disp = &disp;
 	fb_info.switch_con = &atafb_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/aty/atyfb_base.c linux/drivers/video/aty/atyfb_base.c
--- v2.5.2/linux/drivers/video/aty/atyfb_base.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/video/aty/atyfb_base.c	Tue Jan 15 10:56:35 2002
@@ -343,7 +343,7 @@
     { 0x4751, 0x4751, 0x00, 0x00, m64n_gtc_ppl, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
 
     /* 3D RAGE XL */
-    { 0x4752, 0x4752, 0x00, 0x00, m64n_xl, 230, 120, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_XL_DLL },
+    { 0x4752, 0x4752, 0x00, 0x00, m64n_xl, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_XL_DLL },
 
     /* Mach64 LT PRO */
     { 0x4c42, 0x4c42, 0x00, 0x00, m64n_ltp_a,   230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP },
@@ -1394,7 +1394,7 @@
 		pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask);
 		pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag;
 
-		if (remap_page_range(vma->vm_start + page, map_offset,
+		if (remap_page_range(vma, vma->vm_start + page, map_offset,
 				     map_size, vma->vm_page_prot))
 			return -EAGAIN;
 
@@ -1986,7 +1986,7 @@
     disp = &info->disp;
 
     strcpy(info->fb_info.modename, atyfb_name);
-    info->fb_info.node = -1;
+    info->fb_info.node = NODEV;
     info->fb_info.fbops = &atyfb_ops;
     info->fb_info.disp = disp;
     strcpy(info->fb_info.fontname, fontname);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
--- v2.5.2/linux/drivers/video/aty128fb.c	Sun Nov 11 10:09:37 2001
+++ linux/drivers/video/aty128fb.c	Wed Jan 23 15:51:23 2002
@@ -1704,7 +1704,7 @@
 
     /* fill in info */
     strcpy(info->fb_info.modename, aty128fb_name);
-    info->fb_info.node  = -1;
+    info->fb_info.node  = NODEV;
     info->fb_info.fbops = &aty128fb_ops;
     info->fb_info.disp  = &info->disp;
     strcpy(info->fb_info.fontname, fontname);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c
--- v2.5.2/linux/drivers/video/chipsfb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/chipsfb.c	Wed Jan 23 15:51:23 2002
@@ -578,7 +578,7 @@
 	p->disp.scrollmode = SCROLL_YREDRAW;
 
 	strcpy(p->info.modename, p->fix.id);
-	p->info.node = -1;
+	p->info.node = NODEV;
 	p->info.fbops = &chipsfb_ops;
 	p->info.disp = &p->disp;
 	p->info.fontname[0] = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c
--- v2.5.2/linux/drivers/video/clgenfb.c	Mon Nov 19 15:19:42 2001
+++ linux/drivers/video/clgenfb.c	Thu Jan 24 11:51:10 2002
@@ -413,6 +413,7 @@
 static struct clgenfb_info boards[MAX_NUM_BOARDS];	/* the boards */
 
 static unsigned clgen_def_mode = 1;
+static int noaccel = 0;
 
 static int release_io_ports = 0;
 
@@ -1405,7 +1406,9 @@
 			break;
 
 		case BT_PICASSO4:
+#ifdef CONFIG_ZORRO
 			vga_wseq (fb_info->regs, CL_SEQRF, 0xb8);	/* ### INCOMPLETE!! */
+#endif
 /*          vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c); */
 			break;
 
@@ -2748,6 +2751,23 @@
 
 	DPRINTK ("clgen: (RAM start set to: 0x%p)\n", fb_info->fbmem);
 
+	if (noaccel)
+	{
+		printk("clgen: disabling text acceleration support\n");
+#ifdef FBCON_HAS_CFB8
+		fbcon_clgen_8.bmove = fbcon_cfb8_bmove;
+		fbcon_clgen_8.clear = fbcon_cfb8_clear;
+#endif
+#ifdef FBCON_HAS_CFB16
+		fbcon_clgen_16.bmove = fbcon_cfb16_bmove;
+		fbcon_clgen_16.clear = fbcon_cfb16_clear;
+#endif
+#ifdef FBCON_HAS_CFB32
+		fbcon_clgen_32.bmove = fbcon_cfb32_bmove;
+		fbcon_clgen_32.clear = fbcon_cfb32_clear;
+#endif
+	}
+
 	init_vgachip (fb_info);
 
 	/* set up a few more things, register framebuffer driver etc */
@@ -2758,7 +2778,7 @@
 		 sizeof (fb_info->gen.info.modename));
 	fb_info->gen.info.modename [sizeof (fb_info->gen.info.modename) - 1] = 0;
 
-	fb_info->gen.info.node = -1;
+	fb_info->gen.info.node = NODEV;
 	fb_info->gen.info.fbops = &clgenfb_ops;
 	fb_info->gen.info.disp = &disp;
 	fb_info->gen.info.changevar = NULL;
@@ -2851,6 +2871,8 @@
 			if (strcmp (this_opt, s) == 0)
 				clgen_def_mode = i;
 		}
+		if (!strcmp(this_opt, "noaccel"))
+			noaccel = 1;
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/video/controlfb.c linux/drivers/video/controlfb.c
--- v2.5.2/linux/drivers/video/controlfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/controlfb.c	Wed Jan 23 15:51:23 2002
@@ -444,7 +444,7 @@
        		return -EINVAL;
        off += start;
        vma->vm_pgoff = off >> PAGE_SHIFT;
-       if (io_remap_page_range(vma->vm_start, off,
+       if (io_remap_page_range(vma, vma->vm_start, off,
            vma->vm_end - vma->vm_start, vma->vm_page_prot))
                return -EAGAIN;
 
@@ -1376,7 +1376,7 @@
 static void __init control_init_info(struct fb_info *info, struct fb_info_control *p)
 {
 	strcpy(info->modename, "control");
-	info->node = -1;	/* ??? danj */
+	info->node = NODEV;
 	info->fbops = &controlfb_ops;
 	info->disp = &p->display;
 	strcpy(info->fontname, fontname);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c
--- v2.5.2/linux/drivers/video/cyberfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/cyberfb.c	Wed Jan 23 15:51:23 2002
@@ -1085,7 +1085,7 @@
 
 	    strcpy(fb_info.modename, cyberfb_name);
 	    fb_info.changevar = NULL;
-	    fb_info.node = -1;
+	    fb_info.node = NODEV;
 	    fb_info.fbops = &cyberfb_ops;
 	    fb_info.disp = &disp;
 	    fb_info.switch_con = &Cyberfb_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/dn_cfb4.c linux/drivers/video/dn_cfb4.c
--- v2.5.2/linux/drivers/video/dn_cfb4.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/video/dn_cfb4.c	Wed Jan 23 15:51:23 2002
@@ -305,7 +305,7 @@
 	fb_info.switch_con=&dnfbcon_switch;
 	fb_info.updatevar=&dnfbcon_updatevar;
 	fb_info.blank=&dnfbcon_blank;	
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &dn_fb_ops;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;	
 
diff -u --recursive --new-file v2.5.2/linux/drivers/video/dn_cfb8.c linux/drivers/video/dn_cfb8.c
--- v2.5.2/linux/drivers/video/dn_cfb8.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/video/dn_cfb8.c	Wed Jan 23 15:51:23 2002
@@ -292,7 +292,7 @@
 	fb_info.switch_con=&dnfbcon_switch;
 	fb_info.updatevar=&dnfbcon_updatevar;
 	fb_info.blank=&dnfbcon_blank;	
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &dn_fb_ops;
 	
 printk("dn_fb_init: register\n");
diff -u --recursive --new-file v2.5.2/linux/drivers/video/dnfb.c linux/drivers/video/dnfb.c
--- v2.5.2/linux/drivers/video/dnfb.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/video/dnfb.c	Wed Jan 23 15:51:23 2002
@@ -307,7 +307,7 @@
 	fb_info.switch_con=&dnfbcon_switch;
 	fb_info.updatevar=&dnfbcon_updatevar;
 	fb_info.blank=&dnfbcon_blank;	
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &dn_fb_ops;
 	
         dn_fb_get_var(&disp[0].var,0, &fb_info);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/epson1355fb.c linux/drivers/video/epson1355fb.c
--- v2.5.2/linux/drivers/video/epson1355fb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/epson1355fb.c	Wed Jan 23 15:51:23 2002
@@ -500,7 +500,7 @@
 	fb_info.gen.fbhw->detect();
 	strcpy(fb_info.gen.info.modename, "SED1355");
 	fb_info.gen.info.changevar = NULL;
-	fb_info.gen.info.node = -1;
+	fb_info.gen.info.node = NODEV;
 	fb_info.gen.info.fbops = &e1355fb_ops;
 	fb_info.gen.info.disp = &disp;
 	fb_info.gen.parsize = sizeof(struct e1355_par);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.5.2/linux/drivers/video/fbmem.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/video/fbmem.c	Wed Jan 23 15:25:34 2002
@@ -73,6 +73,8 @@
 extern int atyfb_setup(char*);
 extern int aty128fb_init(void);
 extern int aty128fb_setup(char*);
+extern int neofb_init(void);
+extern int neofb_setup(char*);
 extern int igafb_init(void);
 extern int igafb_setup(char*);
 extern int imsttfb_init(void);
@@ -173,6 +175,9 @@
 #ifdef CONFIG_FB_ATY128
 	{ "aty128fb", aty128fb_init, aty128fb_setup },
 #endif
+#ifdef CONFIG_FB_NEOMAGIC
+	{ "neo", neofb_init, neofb_setup },
+#endif
 #ifdef CONFIG_FB_VIRGE
 	{ "virge", virgefb_init, virgefb_setup },
 #endif
@@ -581,7 +586,7 @@
 	vma->vm_flags |= VM_IO;
 #if defined(__sparc_v9__)
 	vma->vm_flags |= (VM_SHM | VM_LOCKED);
-	if (io_remap_page_range(vma->vm_start, off,
+	if (io_remap_page_range(vma, vma->vm_start, off,
 				vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
 		return -EAGAIN;
 #else
@@ -614,7 +619,7 @@
 #else
 #warning What do we have to do here??
 #endif
-	if (io_remap_page_range(vma->vm_start, off,
+	if (io_remap_page_range(vma, vma->vm_start, off,
 			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 #endif /* !__sparc_v9__ */
diff -u --recursive --new-file v2.5.2/linux/drivers/video/fm2fb.c linux/drivers/video/fm2fb.c
--- v2.5.2/linux/drivers/video/fm2fb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/fm2fb.c	Wed Jan 23 15:51:23 2002
@@ -401,7 +401,7 @@
 	disp.scrollmode = SCROLL_YREDRAW;
 
 	strcpy(fb_info.modename, fb_fix.id);
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &fm2fb_ops;
 	fb_info.disp = &disp;
 	fb_info.fontname[0] = '\0';
diff -u --recursive --new-file v2.5.2/linux/drivers/video/g364fb.c linux/drivers/video/g364fb.c
--- v2.5.2/linux/drivers/video/g364fb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/g364fb.c	Wed Jan 23 15:51:23 2002
@@ -378,7 +378,7 @@
     disp.dispsw = &fbcon_g364cfb8;
 
     strcpy(fb_info.modename, fb_fix.id);
-    fb_info.node = -1;
+    fb_info.node = NODEV;
     fb_info.fbops = &g364fb_ops;
     fb_info.disp = &disp;
     fb_info.fontname[0] = '\0';
diff -u --recursive --new-file v2.5.2/linux/drivers/video/hgafb.c linux/drivers/video/hgafb.c
--- v2.5.2/linux/drivers/video/hgafb.c	Mon Nov 12 09:46:25 2001
+++ linux/drivers/video/hgafb.c	Wed Jan 23 15:51:23 2002
@@ -742,7 +742,7 @@
 	disp.scrollmode = SCROLL_YREDRAW;
 	
 	strcpy (fb_info.modename, hga_fix.id);
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;
 /*	fb_info.open = ??? */
 	fb_info.var = hga_default_var;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/hitfb.c linux/drivers/video/hitfb.c
--- v2.5.2/linux/drivers/video/hitfb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/hitfb.c	Wed Jan 23 15:51:23 2002
@@ -344,7 +344,7 @@
 int __init hitfb_init(void)
 {
     strcpy(fb_info.gen.info.modename, "Hitachi HD64461");
-    fb_info.gen.info.node = -1;
+    fb_info.gen.info.node = NODEV;
     fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
     fb_info.gen.info.fbops = &hitfb_ops;
     fb_info.gen.info.disp = &fb_info.disp;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/hpfb.c linux/drivers/video/hpfb.c
--- v2.5.2/linux/drivers/video/hpfb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/hpfb.c	Wed Jan 23 15:51:23 2002
@@ -328,7 +328,7 @@
 	 */
 	strcpy(fb_info.modename, "Topcat");
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &hpfb_ops;
 	fb_info.disp = &disp;
 	fb_info.switch_con = &hpfb_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/igafb.c linux/drivers/video/igafb.c
--- v2.5.2/linux/drivers/video/igafb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/igafb.c	Wed Jan 23 15:51:23 2002
@@ -283,7 +283,7 @@
 		pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask);
 		pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag;
 
-		if (remap_page_range(vma->vm_start + page, map_offset,
+		if (remap_page_range(vma, vma->vm_start + page, map_offset,
 				     map_size, vma->vm_page_prot))
 			return -EAGAIN;
 
@@ -568,7 +568,7 @@
 	}
 
 	strcpy(info->fb_info.modename, igafb_name);
-	info->fb_info.node = -1;
+	info->fb_info.node = NODEV;
 	info->fb_info.fbops = &igafb_ops;
 	info->fb_info.disp = &info->disp;
 	strcpy(info->fb_info.fontname, fontname);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- v2.5.2/linux/drivers/video/imsttfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/imsttfb.c	Wed Jan 23 15:51:23 2002
@@ -1866,7 +1866,7 @@
 
 	strcpy(p->info.modename, p->fix.id);
 	strcpy(p->info.fontname, fontname);
-	p->info.node = -1;
+	p->info.node = NODEV;
 	p->info.fbops = &imsttfb_ops;
 	p->info.disp = &p->disp;
 	p->info.changevar = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/macfb.c linux/drivers/video/macfb.c
--- v2.5.2/linux/drivers/video/macfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/macfb.c	Wed Jan 23 15:51:23 2002
@@ -1221,7 +1221,7 @@
 		}
 	
 	fb_info.changevar  = NULL;
-	fb_info.node       = -1;
+	fb_info.node       = NODEV;
 	fb_info.fbops      = &macfb_ops;
 	fb_info.disp       = &disp;
 	fb_info.switch_con = &macfb_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/matrox/matroxfb_base.h linux/drivers/video/matrox/matroxfb_base.h
--- v2.5.2/linux/drivers/video/matrox/matroxfb_base.h	Fri Nov  9 14:07:41 2001
+++ linux/drivers/video/matrox/matroxfb_base.h	Tue Jan 15 10:56:35 2002
@@ -124,10 +124,6 @@
 #endif
 #endif
 
-#ifdef __sparc__
-#error "Sorry, I have no idea how to do this on sparc... There is mapioaddr... With bus_type parameter..."
-#endif
-
 #if defined(__m68k__)
 #define MAP_BUSTOVIRT
 #else
diff -u --recursive --new-file v2.5.2/linux/drivers/video/maxinefb.c linux/drivers/video/maxinefb.c
--- v2.5.2/linux/drivers/video/maxinefb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/maxinefb.c	Wed Jan 23 15:51:23 2002
@@ -358,7 +358,7 @@
 	strcpy(fb_info.modename, "Maxine onboard graphics 1024x768x8");
 	/* fb_info.modename: maximum of 39 characters + trailing nullbyte, KM */
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &maxinefb_ops;
 	fb_info.disp = &disp;
 	fb_info.switch_con = &maxinefb_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/neofb.c linux/drivers/video/neofb.c
--- v2.5.2/linux/drivers/video/neofb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/neofb.c	Wed Jan 23 15:25:34 2002
@@ -0,0 +1,2421 @@
+/*
+ * linux/drivers/video/neofb.c -- NeoMagic Framebuffer Driver
+ *
+ * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
+ *
+ *
+ * Card specific code is based on XFree86's neomagic driver.
+ * Framebuffer framework code is based on code of cyber2000fb.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ *
+ * 0.3.1
+ *  - added module license (dok)
+ *
+ * 0.3
+ *  - hardware accelerated clear and move for 2200 and above (dok)
+ *  - maximum allowed dotclock is handled now (dok)
+ *
+ * 0.2.1
+ *  - correct panning after X usage (dok)
+ *  - added module and kernel parameters (dok)
+ *  - no stretching if external display is enabled (dok)
+ *
+ * 0.2
+ *  - initial version (dok)
+ *
+ *
+ * TODO
+ * - ioctl for internal/external switching
+ * - blanking
+ * - 32bit depth support, maybe impossible
+ * - disable pan-on-sync, need specs
+ *
+ * BUGS
+ * - white margin on bootup like with tdfxfb (colormap problem?)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include "neofb.h"
+
+
+#define NEOFB_VERSION "0.3.1"
+
+/* --------------------------------------------------------------------- */
+
+static int disabled   = 0;
+static int internal   = 0;
+static int external   = 0;
+static int nostretch  = 0;
+static int nopciburst = 0;
+
+
+#ifdef MODULE
+
+MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@convergence.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips");
+MODULE_PARM(disabled, "i");
+MODULE_PARM_DESC(disabled, "Disable this driver's initialization.");
+MODULE_PARM(internal, "i");
+MODULE_PARM_DESC(internal, "Enable output on internal LCD Display.");
+MODULE_PARM(external, "i");
+MODULE_PARM_DESC(external, "Enable output on external CRT.");
+MODULE_PARM(nostretch, "i");
+MODULE_PARM_DESC(nostretch, "Disable stretching of modes smaller than LCD.");
+MODULE_PARM(nopciburst, "i");
+MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");
+
+#endif
+
+
+/* --------------------------------------------------------------------- */
+
+static biosMode bios8[] = {	
+    { 320, 240, 0x40 },
+    { 300, 400, 0x42 },    
+    { 640, 400, 0x20 },
+    { 640, 480, 0x21 },
+    { 800, 600, 0x23 },
+    { 1024, 768, 0x25 },
+};
+
+static biosMode bios16[] = {
+    { 320, 200, 0x2e },
+    { 320, 240, 0x41 },
+    { 300, 400, 0x43 },
+    { 640, 480, 0x31 },
+    { 800, 600, 0x34 },
+    { 1024, 768, 0x37 },
+};
+
+static biosMode bios24[] = {
+    { 640, 480, 0x32 },
+    { 800, 600, 0x35 },
+    { 1024, 768, 0x38 }
+};
+
+#ifdef NO_32BIT_SUPPORT_YET
+/* FIXME: guessed values, wrong */
+static biosMode bios32[] = {
+    { 640, 480, 0x33 },
+    { 800, 600, 0x36 },
+    { 1024, 768, 0x39 }
+    };
+#endif
+
+static int neoFindMode (int xres, int yres, int depth)
+{
+  int xres_s;
+  int i, size;
+  biosMode *mode;
+
+  switch (depth)
+    {
+    case 8:
+      size = sizeof(bios8) / sizeof(biosMode);
+      mode = bios8;
+      break;
+    case 16:
+      size = sizeof(bios16) / sizeof(biosMode);
+      mode = bios16;
+      break;
+    case 24:
+      size = sizeof(bios24) / sizeof(biosMode);
+      mode = bios24;
+      break;
+#ifdef NO_32BIT_SUPPORT_YET
+    case 32:
+      size = sizeof(bios32) / sizeof(biosMode);
+      mode = bios32;
+      break;
+#endif
+    default:
+      return 0;
+    }
+
+  for (i = 0; i < size; i++)
+    {
+      if (xres <= mode[i].x_res)
+	{
+	  xres_s = mode[i].x_res;
+	  for (; i < size; i++)
+	    {
+	      if (mode[i].x_res != xres_s)
+		return mode[i-1].mode;
+	      if (yres <= mode[i].y_res)
+		return mode[i].mode;
+	    }
+	}
+    }
+  return mode[size - 1].mode;
+}
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Acceleration for Neo2200+
+ */
+static inline void neo2200_wait_idle (struct neofb_info *fb)
+{
+  int waitcycles;
+
+  while (fb->neo2200->bltStat & 1)
+    waitcycles++;
+}
+
+static inline void neo2200_wait_fifo (struct neofb_info *fb,
+                                      int requested_fifo_space)
+{
+  //  ndev->neo.waitfifo_calls++;
+  //  ndev->neo.waitfifo_sum += requested_fifo_space;
+
+  /* FIXME: does not work
+  if (neo_fifo_space < requested_fifo_space)
+    {
+      neo_fifo_waitcycles++;
+
+      while (1)
+        {
+          neo_fifo_space = (neo2200->bltStat >> 8);
+          if (neo_fifo_space >= requested_fifo_space)
+            break;
+        }
+    }
+  else
+    {
+      neo_fifo_cache_hits++;
+    }
+
+  neo_fifo_space -= requested_fifo_space;
+  */
+
+  neo2200_wait_idle (fb);
+}
+
+static inline void neo2200_accel_init (struct neofb_info        *fb,
+				       struct fb_var_screeninfo *var)
+{
+  Neo2200 *neo2200 = fb->neo2200;
+  u32 bltMod, pitch;
+
+  neo2200_wait_idle (fb);
+
+  switch (var->bits_per_pixel)
+    {
+    case 8:
+      bltMod = NEO_MODE1_DEPTH8;
+      pitch  = var->xres_virtual;
+      break;
+    case 15:
+    case 16:
+      bltMod = NEO_MODE1_DEPTH16;
+      pitch  = var->xres_virtual * 2;
+      break;
+    default:
+      printk( KERN_ERR "neofb: neo2200_accel_init: unexpected bits per pixel!\n" );
+      return;
+    }
+
+  neo2200->bltStat = bltMod << 16;
+  neo2200->pitch   = (pitch << 16) | pitch;
+}
+
+static void neo2200_accel_setup (struct display *p)
+{
+  struct neofb_info        *fb  = (struct neofb_info *)p->fb_info;
+  struct fb_var_screeninfo *var = &p->fb_info->var;
+
+  fb->dispsw->setup(p);
+
+  neo2200_accel_init (fb, var);
+}
+
+static void
+neo2200_accel_bmove (struct display *p, int sy, int sx, int dy, int dx,
+		     int height, int width)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+  struct fb_var_screeninfo *var = &p->fb_info->var;
+  Neo2200 *neo2200 = fb->neo2200;
+  u_long src, dst;
+  int bpp, pitch, inc_y;
+  u_int fh, fw;
+
+  /* setting blitting direction does not work, so this case is unaccelerated */
+  if (sx != dx)
+    {
+      neo2200_wait_idle (fb);
+      fb->dispsw->bmove(p, sy, sx, dy, dx, height, width);
+      return;
+    }
+
+  bpp    = (var->bits_per_pixel+7) / 8;
+  pitch  = var->xres_virtual * bpp;
+
+  fw     = fontwidth(p);
+  sx    *= fw * bpp;
+  dx    *= fw * bpp;
+  width *= fw;
+
+  fh     = fontheight(p);
+  sy    *= fh;
+  dy    *= fh;
+
+  if (sy > dy)
+    inc_y = fh;
+  else
+    {
+      inc_y  = -fh;
+      sy    += (height - 1) * fh;
+      dy    += (height - 1) * fh;
+    }
+
+  neo2200_wait_fifo (fb, 1);
+
+  /* set blt control */
+  neo2200->bltCntl = NEO_BC3_FIFO_EN      |
+                     NEO_BC3_SKIP_MAPPING |  0x0c0000;
+
+  /* looks silly, but setting the blitting direction did not work */
+  while (height--)
+    {
+      src = sx + sy * pitch;
+      dst = dx + dy * pitch;
+
+      neo2200_wait_fifo (fb, 3);
+
+      neo2200->srcStart = src;
+      neo2200->dstStart = dst;
+      neo2200->xyExt = (fh << 16) | (width & 0xffff);
+
+      sy += inc_y;
+      dy += inc_y;
+    }
+}
+
+static void
+neo2200_accel_clear (struct vc_data *conp, struct display *p, int sy, int sx,
+		     int height, int width)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+  struct fb_var_screeninfo *var = &p->fb_info->var;
+  Neo2200 *neo2200 = fb->neo2200;
+  u_long dst;
+  u_int fw, fh;
+  u32 bgx = attr_bgcol_ec(p, conp);
+
+  fw = fontwidth(p);
+  fh = fontheight(p);
+
+  dst    = sx * fw + sy * var->xres_virtual * fh;
+  width  = width * fw;
+  height = height * fh;
+
+  neo2200_wait_fifo (fb, 4);
+
+  /* set blt control */
+  neo2200->bltCntl  = NEO_BC3_FIFO_EN      |
+                      NEO_BC0_SRC_IS_FG    |
+                      NEO_BC3_SKIP_MAPPING |  0x0c0000;
+
+  switch (var->bits_per_pixel)
+    {
+    case 8:
+      neo2200->fgColor = bgx;
+      break;
+    case 16:
+      neo2200->fgColor = ((u16 *)(p->fb_info)->pseudo_palette)[bgx];
+      break;
+    }
+
+  neo2200->dstStart = dst * ((var->bits_per_pixel+7) / 8);
+
+  neo2200->xyExt    = (height << 16) | (width & 0xffff);
+}
+
+static void
+neo2200_accel_putc (struct vc_data *conp, struct display *p, int c,
+		    int yy, int xx)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+  neo2200_wait_idle (fb);
+  fb->dispsw->putc(conp, p, c, yy, xx);
+}
+
+static void
+neo2200_accel_putcs (struct vc_data *conp, struct display *p,
+		     const unsigned short *s, int count, int yy, int xx)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+  neo2200_wait_idle (fb);
+  fb->dispsw->putcs(conp, p, s, count, yy, xx);
+}
+
+static void neo2200_accel_revc (struct display *p, int xx, int yy)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+	
+  neo2200_wait_idle (fb);
+  fb->dispsw->revc (p, xx, yy);
+}
+
+static void
+neo2200_accel_clear_margins (struct vc_data *conp, struct display *p,
+			     int bottom_only)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+  fb->dispsw->clear_margins (conp, p, bottom_only);
+}
+
+static struct display_switch fbcon_neo2200_accel = {
+  setup:		neo2200_accel_setup,
+  bmove:		neo2200_accel_bmove,
+  clear:		neo2200_accel_clear,
+  putc:			neo2200_accel_putc,
+  putcs:		neo2200_accel_putcs,
+  revc:			neo2200_accel_revc,
+  clear_margins:	neo2200_accel_clear_margins,
+  fontwidthmask:	FONTWIDTH(8)|FONTWIDTH(16)
+};
+
+
+/* --------------------------------------------------------------------- */
+
+/*
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
+static int neo_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			 u_int transp, struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+
+  if (regno >= NR_PALETTE)
+    return -EINVAL;
+
+  info->palette[regno].red    = red;
+  info->palette[regno].green  = green;
+  info->palette[regno].blue   = blue;
+  info->palette[regno].transp = transp;
+
+  switch (fb->var.bits_per_pixel)
+    {
+#ifdef FBCON_HAS_CFB8
+    case 8:
+      outb(regno, 0x3c8);
+
+      outb(red   >> 10, 0x3c9);
+      outb(green >> 10, 0x3c9);
+      outb(blue  >> 10, 0x3c9);
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    case 16:
+      if (regno < 16)
+	((u16 *)fb->pseudo_palette)[regno] = ((red   & 0xf800)      ) |
+	                                     ((green & 0xfc00) >>  5) |
+                                             ((blue  & 0xf800) >> 11);
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+    case 24:
+      if (regno < 16)
+	((u32 *)fb->pseudo_palette)[regno] = ((red   & 0xff00) << 8) |
+                                             ((green & 0xff00)     ) |
+	                                     ((blue  & 0xff00) >> 8);
+      break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+#ifdef FBCON_HAS_CFB32
+    case 32:
+      if (regno < 16)
+	((u32 *)fb->pseudo_palette)[regno] = ((transp & 0xff00) << 16) |
+	                                     ((red    & 0xff00) <<  8) |
+                                             ((green  & 0xff00)      ) |
+	                                     ((blue   & 0xff00) >>  8);
+      break;
+#endif
+#endif
+
+    default:
+      return 1;
+    }
+
+  return 0;
+}
+
+static void vgaHWLock (void)
+{
+  /* Protect CRTC[0-7] */
+  VGAwCR (0x11, VGArCR (0x11) | 0x80);
+}
+
+static void vgaHWUnlock (void)
+{
+  /* Unprotect CRTC[0-7] */
+  VGAwCR (0x11, VGArCR (0x11) & ~0x80);
+}
+
+static void neoLock (void)
+{
+  VGAwGR (0x09, 0x00);
+  vgaHWLock();
+}
+
+static void neoUnlock (void)
+{
+  vgaHWUnlock();
+  VGAwGR (0x09, 0x26);
+}
+
+/*
+ * vgaHWSeqReset
+ *      perform a sequencer reset.
+ */
+void
+vgaHWSeqReset(int start)
+{
+  if (start)
+    VGAwSEQ (0x00, 0x01);		/* Synchronous Reset */
+  else
+    VGAwSEQ (0x00, 0x03);		/* End Reset */
+}
+
+void
+vgaHWProtect(int on)
+{
+  unsigned char tmp;
+  
+  if (on)
+    {
+      /*
+       * Turn off screen and disable sequencer.
+       */
+      tmp = VGArSEQ (0x01);
+
+      vgaHWSeqReset (1);			/* start synchronous reset */
+      VGAwSEQ (0x01, tmp | 0x20);	/* disable the display */
+
+      VGAenablePalette();
+    }
+  else
+    {
+      /*
+       * Reenable sequencer, then turn on screen.
+       */
+  
+      tmp = VGArSEQ (0x01);
+
+      VGAwSEQ (0x01, tmp & ~0x20);	/* reenable display */
+      vgaHWSeqReset (0);		/* clear synchronousreset */
+
+      VGAdisablePalette();
+    }
+}
+
+static void vgaHWRestore (const struct neofb_info *info,
+			  const struct neofb_par  *par)
+{
+  int i;
+
+  VGAwMISC (par->MiscOutReg);
+
+  for (i = 1; i < 5; i++)
+    VGAwSEQ (i, par->Sequencer[i]);
+  
+  /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
+  VGAwCR (17, par->CRTC[17] & ~0x80);
+
+  for (i = 0; i < 25; i++)
+    VGAwCR (i, par->CRTC[i]);
+
+  for (i = 0; i < 9; i++)
+    VGAwGR (i, par->Graphics[i]);
+
+  VGAenablePalette();
+
+  for (i = 0; i < 21; i++)
+    VGAwATTR (i, par->Attribute[i]);
+
+  VGAdisablePalette();
+}
+
+static void neofb_set_par (struct neofb_info       *info,
+			   const struct neofb_par  *par)
+{
+  unsigned char temp;
+  int i;
+  int clock_hi = 0;
+    
+  DBG("neofb_set_par");
+
+  neoUnlock();
+
+  vgaHWProtect (1);		/* Blank the screen */
+
+  /* linear colormap for non palettized modes */
+  switch (par->depth)
+    {
+    case 8:
+      break;
+    case 16:
+      for (i=0; i<64; i++)
+	{
+	  outb(i, 0x3c8);
+	  
+	  outb(i << 1, 0x3c9);
+	  outb(i, 0x3c9);
+	  outb(i << 1, 0x3c9);
+	}
+      break;
+    case 24:
+#ifdef NO_32BIT_SUPPORT_YET
+    case 32:
+#endif
+      for (i=0; i<256; i++)
+	{
+	  outb(i, 0x3c8);
+	  
+	  outb(i, 0x3c9);
+	  outb(i, 0x3c9);
+	  outb(i, 0x3c9);
+	}
+      break;
+    }
+    
+  /* alread unlocked above */
+  /* BOGUS  VGAwGR (0x09, 0x26);*/
+    
+  /* don't know what this is, but it's 0 from bootup anyway */
+  VGAwGR (0x15, 0x00);
+
+  /* was set to 0x01 by my bios in text and vesa modes */
+  VGAwGR (0x0A, par->GeneralLockReg);
+
+  /*
+   * The color mode needs to be set before calling vgaHWRestore
+   * to ensure the DAC is initialized properly.
+   *
+   * NOTE: Make sure we don't change bits make sure we don't change
+   * any reserved bits.
+   */
+  temp = VGArGR(0x90);
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      temp &= 0xF0; /* Save bits 7:4 */
+      temp |= (par->ExtColorModeSelect & ~0xF0);
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+    case FB_ACCEL_NEOMAGIC_NM2093:
+    case FB_ACCEL_NEOMAGIC_NM2097:
+    case FB_ACCEL_NEOMAGIC_NM2160:
+    case FB_ACCEL_NEOMAGIC_NM2200:
+    case FB_ACCEL_NEOMAGIC_NM2230:
+    case FB_ACCEL_NEOMAGIC_NM2360:
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      temp &= 0x70; /* Save bits 6:4 */
+      temp |= (par->ExtColorModeSelect & ~0x70);
+      break;
+    }
+
+  VGAwGR(0x90,temp);
+
+  /*
+   * In some rare cases a lockup might occur if we don't delay
+   * here. (Reported by Miles Lane)
+   */
+  //mdelay(200);
+
+  /*
+   * Disable horizontal and vertical graphics and text expansions so
+   * that vgaHWRestore works properly.
+   */
+  temp = VGArGR(0x25);
+  temp &= 0x39;
+  VGAwGR (0x25, temp);
+
+  /*
+   * Sleep for 200ms to make sure that the two operations above have
+   * had time to take effect.
+   */
+  mdelay(200);
+
+  /*
+   * This function handles restoring the generic VGA registers.  */
+  vgaHWRestore (info, par);
+
+
+  VGAwGR(0x0E, par->ExtCRTDispAddr);
+  VGAwGR(0x0F, par->ExtCRTOffset);
+  temp = VGArGR(0x10);
+  temp &= 0x0F; /* Save bits 3:0 */
+  temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */
+  VGAwGR(0x10, temp);
+
+  VGAwGR(0x11, par->SysIfaceCntl2);
+  VGAwGR(0x15, 0 /*par->SingleAddrPage*/);
+  VGAwGR(0x16, 0 /*par->DualAddrPage*/);
+
+  temp = VGArGR(0x20);
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      temp &= 0xFC; /* Save bits 7:2 */
+      temp |= (par->PanelDispCntlReg1 & ~0xFC);
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+    case FB_ACCEL_NEOMAGIC_NM2093:
+    case FB_ACCEL_NEOMAGIC_NM2097:
+    case FB_ACCEL_NEOMAGIC_NM2160:
+      temp &= 0xDC; /* Save bits 7:6,4:2 */
+      temp |= (par->PanelDispCntlReg1 & ~0xDC);
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2200:
+    case FB_ACCEL_NEOMAGIC_NM2230:
+    case FB_ACCEL_NEOMAGIC_NM2360:
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      temp &= 0x98; /* Save bits 7,4:3 */
+      temp |= (par->PanelDispCntlReg1 & ~0x98);
+      break;
+    }
+  VGAwGR(0x20, temp);
+
+  temp = VGArGR(0x25);
+  temp &= 0x38; /* Save bits 5:3 */
+  temp |= (par->PanelDispCntlReg2 & ~0x38);
+  VGAwGR(0x25, temp);
+
+  if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
+    {
+      temp = VGArGR(0x30);
+      temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
+      temp |= (par->PanelDispCntlReg3 & ~0xEF);
+      VGAwGR(0x30, temp);
+    }
+
+  VGAwGR(0x28, par->PanelVertCenterReg1);
+  VGAwGR(0x29, par->PanelVertCenterReg2);
+  VGAwGR(0x2a, par->PanelVertCenterReg3);
+
+  if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
+    {
+      VGAwGR(0x32, par->PanelVertCenterReg4);
+      VGAwGR(0x33, par->PanelHorizCenterReg1);
+      VGAwGR(0x34, par->PanelHorizCenterReg2);
+      VGAwGR(0x35, par->PanelHorizCenterReg3);
+    }
+
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2160)
+    VGAwGR(0x36, par->PanelHorizCenterReg4);
+
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+    {
+      VGAwGR(0x36, par->PanelHorizCenterReg4);
+      VGAwGR(0x37, par->PanelVertCenterReg5);
+      VGAwGR(0x38, par->PanelHorizCenterReg5);
+
+      clock_hi = 1;
+    }
+
+  /* Program VCLK3 if needed. */
+  if (par->ProgramVCLK
+      && ((VGArGR(0x9B) != par->VCLK3NumeratorLow)
+	  || (VGArGR(0x9F) !=  par->VCLK3Denominator)
+	  || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
+			   != (par->VCLK3NumeratorHigh & ~0x0F)))))
+    {
+      VGAwGR(0x9B, par->VCLK3NumeratorLow);
+      if (clock_hi)
+	{
+	  temp = VGArGR(0x8F);
+	  temp &= 0x0F; /* Save bits 3:0 */
+	  temp |= (par->VCLK3NumeratorHigh & ~0x0F);
+	  VGAwGR(0x8F, temp);
+	}
+      VGAwGR(0x9F, par->VCLK3Denominator);
+    }
+
+  if (par->biosMode)
+    VGAwCR(0x23, par->biosMode);
+    
+  VGAwGR (0x93, 0xc0); /* Gives 5x faster framebuffer writes !!! */
+
+  /* Program vertical extension register */
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+    {
+      VGAwCR(0x70, par->VerticalExt);
+    }
+
+
+  vgaHWProtect (0);		/* Turn on screen */
+
+  /* Calling this also locks offset registers required in update_start */
+  neoLock();
+}
+
+static void neofb_update_start (struct neofb_info *info, struct fb_var_screeninfo *var)
+{
+  int oldExtCRTDispAddr;
+  int Base; 
+
+  DBG("neofb_update_start");
+
+  Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
+  Base *= (var->bits_per_pixel + 7) / 8;
+
+  neoUnlock();
+
+  /*
+   * These are the generic starting address registers.
+   */
+  VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
+  VGAwCR(0x0D, (Base & 0x00FF));
+
+  /*
+   * Make sure we don't clobber some other bits that might already
+   * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
+   * be needed.
+   */
+  oldExtCRTDispAddr = VGArGR(0x0E);
+  VGAwGR(0x0E,(((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
+
+  neoLock();
+}
+
+/*
+ * Set the Colormap
+ */
+static int neofb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  struct display* disp = (con < 0) ? fb->disp : (fb_display + con);
+  struct fb_cmap *dcmap = &disp->cmap;
+  int err = 0;
+
+  /* no colormap allocated? */
+  if (!dcmap->len)
+    {
+      int size;
+
+      if (fb->var.bits_per_pixel == 8)
+	size = NR_PALETTE;
+      else
+	size = 32;
+
+      err = fb_alloc_cmap (dcmap, size, 0);
+    }
+
+  /*
+   * we should be able to remove this test once fbcon has been
+   * "improved" --rmk
+   */
+  if (!err && con == info->currcon)
+    {
+      err = fb_set_cmap (cmap, kspc, neo_setcolreg, fb);
+      dcmap = &fb->cmap;
+    }
+
+  if (!err)
+    fb_copy_cmap (cmap, dcmap, kspc ? 0 : 1);
+
+  return err;
+}
+
+/*
+ * neoCalcVCLK --
+ *
+ * Determine the closest clock frequency to the one requested.
+ */
+#define REF_FREQ 14.31818
+#define MAX_N 127
+#define MAX_D 31
+#define MAX_F 1
+
+static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, long freq)
+{
+  int n, d, f;
+  double f_out;
+  double f_diff;
+  int n_best = 0, d_best = 0, f_best = 0;
+  double f_best_diff = 999999.0;
+  double f_target = freq/1000.0;
+
+  for (f = 0; f <= MAX_F; f++)
+    for (n = 0; n <= MAX_N; n++)
+      for (d = 0; d <= MAX_D; d++)
+	{
+	  f_out = (n+1.0)/((d+1.0)*(1<<f))*REF_FREQ;
+	  f_diff = abs(f_out-f_target);
+	  if (f_diff < f_best_diff)
+	    {
+	      f_best_diff = f_diff;
+	      n_best = n;
+	      d_best = d;
+	      f_best = f;
+	    }
+	}
+
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+    {
+      /* NOT_DONE:  We are trying the full range of the 2200 clock.
+	 We should be able to try n up to 2047 */
+      par->VCLK3NumeratorLow  = n_best;
+      par->VCLK3NumeratorHigh = (f_best << 7);
+    }
+  else
+    par->VCLK3NumeratorLow  = n_best | (f_best << 7);
+
+  par->VCLK3Denominator = d_best;
+
+#ifdef NEOFB_DEBUG
+  printk ("neoVCLK: f:%f NumLow=%d NumHi=%d Den=%d Df=%f\n",
+	  f_target,
+	  par->VCLK3NumeratorLow,
+	  par->VCLK3NumeratorHigh,
+	  par->VCLK3Denominator,
+	  f_best_diff);
+#endif
+}
+
+/*
+ * vgaHWInit --
+ *      Handle the initialization, etc. of a screen.
+ *      Return FALSE on failure.
+ */
+
+static int vgaHWInit (const struct fb_var_screeninfo *var,
+		      const struct neofb_info        *info,
+		      struct neofb_par               *par,
+		      struct xtimings                *timings)
+{
+  par->MiscOutReg = 0x23;
+
+  if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
+    par->MiscOutReg |= 0x40;
+
+  if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
+    par->MiscOutReg |= 0x80;
+    
+  /*
+   * Time Sequencer
+   */
+  par->Sequencer[0] = 0x00;
+  par->Sequencer[1] = 0x01;
+  par->Sequencer[2] = 0x0F;
+  par->Sequencer[3] = 0x00;                             /* Font select */
+  par->Sequencer[4] = 0x0E;                             /* Misc */
+
+  /*
+   * CRTC Controller
+   */
+  par->CRTC[0]  = (timings->HTotal >> 3) - 5;
+  par->CRTC[1]  = (timings->HDisplay >> 3) - 1;
+  par->CRTC[2]  = (timings->HDisplay >> 3) - 1;
+  par->CRTC[3]  = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80;
+  par->CRTC[4]  = (timings->HSyncStart >> 3);
+  par->CRTC[5]  = ((((timings->HTotal >> 3) - 1) & 0x20) << 2)
+    | (((timings->HSyncEnd >> 3)) & 0x1F);
+  par->CRTC[6]  = (timings->VTotal - 2) & 0xFF;
+  par->CRTC[7]  = (((timings->VTotal - 2) & 0x100) >> 8)
+    | (((timings->VDisplay - 1) & 0x100) >> 7)
+    | ((timings->VSyncStart & 0x100) >> 6)
+    | (((timings->VDisplay - 1) & 0x100) >> 5)
+    | 0x10
+    | (((timings->VTotal - 2) & 0x200)   >> 4)
+    | (((timings->VDisplay - 1) & 0x200) >> 3)
+    | ((timings->VSyncStart & 0x200) >> 2);
+  par->CRTC[8]  = 0x00;
+  par->CRTC[9]  = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40;
+
+  if (timings->dblscan)
+    par->CRTC[9] |= 0x80;
+
+  par->CRTC[10] = 0x00;
+  par->CRTC[11] = 0x00;
+  par->CRTC[12] = 0x00;
+  par->CRTC[13] = 0x00;
+  par->CRTC[14] = 0x00;
+  par->CRTC[15] = 0x00;
+  par->CRTC[16] = timings->VSyncStart & 0xFF;
+  par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20;
+  par->CRTC[18] = (timings->VDisplay - 1) & 0xFF;
+  par->CRTC[19] = var->xres_virtual >> 4;
+  par->CRTC[20] = 0x00;
+  par->CRTC[21] = (timings->VDisplay - 1) & 0xFF; 
+  par->CRTC[22] = (timings->VTotal - 1) & 0xFF;
+  par->CRTC[23] = 0xC3;
+  par->CRTC[24] = 0xFF;
+
+  /*
+   * are these unnecessary?
+   * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+   * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+   */
+
+  /*
+   * Graphics Display Controller
+   */
+  par->Graphics[0] = 0x00;
+  par->Graphics[1] = 0x00;
+  par->Graphics[2] = 0x00;
+  par->Graphics[3] = 0x00;
+  par->Graphics[4] = 0x00;
+  par->Graphics[5] = 0x40;
+  par->Graphics[6] = 0x05;   /* only map 64k VGA memory !!!! */
+  par->Graphics[7] = 0x0F;
+  par->Graphics[8] = 0xFF;
+  
+
+  par->Attribute[0]  = 0x00; /* standard colormap translation */
+  par->Attribute[1]  = 0x01;
+  par->Attribute[2]  = 0x02;
+  par->Attribute[3]  = 0x03;
+  par->Attribute[4]  = 0x04;
+  par->Attribute[5]  = 0x05;
+  par->Attribute[6]  = 0x06;
+  par->Attribute[7]  = 0x07;
+  par->Attribute[8]  = 0x08;
+  par->Attribute[9]  = 0x09;
+  par->Attribute[10] = 0x0A;
+  par->Attribute[11] = 0x0B;
+  par->Attribute[12] = 0x0C;
+  par->Attribute[13] = 0x0D;
+  par->Attribute[14] = 0x0E;
+  par->Attribute[15] = 0x0F;
+  par->Attribute[16] = 0x41;
+  par->Attribute[17] = 0xFF;
+  par->Attribute[18] = 0x0F;
+  par->Attribute[19] = 0x00;
+  par->Attribute[20] = 0x00;
+
+  return 0;
+}
+
+static int neofb_decode_var (struct fb_var_screeninfo        *var,
+                             const struct neofb_info         *info,
+                             struct neofb_par                *par)
+{
+  struct xtimings timings;
+  int lcd_stretch;
+  int hoffset, voffset;
+  int memlen, vramlen;
+  int mode_ok = 0;
+  unsigned int pixclock = var->pixclock;
+
+  DBG("neofb_decode_var");
+
+  if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
+  timings.pixclock = 1000000000 / pixclock;
+  if (timings.pixclock < 1) timings.pixclock = 1;
+  timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
+  timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
+  timings.HDisplay = var->xres;
+  timings.HSyncStart = timings.HDisplay + var->right_margin;
+  timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
+  timings.HTotal = timings.HSyncEnd + var->left_margin;
+  timings.VDisplay = var->yres;
+  timings.VSyncStart = timings.VDisplay + var->lower_margin;
+  timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
+  timings.VTotal = timings.VSyncEnd + var->upper_margin;
+  timings.sync = var->sync;
+
+  if (timings.pixclock > info->maxClock)
+    return -EINVAL;
+
+  /* Is the mode larger than the LCD panel? */
+  if ((var->xres > info->NeoPanelWidth) ||
+      (var->yres > info->NeoPanelHeight))
+    {
+      printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",
+	      var->xres,
+	      var->yres,
+	      info->NeoPanelWidth,
+	      info->NeoPanelHeight);
+      return -EINVAL;
+    }
+
+  /* Is the mode one of the acceptable sizes? */
+  switch (var->xres)
+    {
+    case 1280:
+      if (var->yres == 1024)
+	mode_ok = 1;
+      break;
+    case 1024:
+      if (var->yres == 768)
+	mode_ok = 1;
+      break;
+    case  800:
+      if (var->yres == 600)
+	mode_ok = 1;
+      break;
+    case  640:
+      if (var->yres == 480)
+	mode_ok = 1;
+      break;
+    }
+
+  if (!mode_ok)
+    {
+      printk (KERN_INFO "Mode (%dx%d) won't display properly on LCD\n",
+	      var->xres, var->yres);
+      return -EINVAL;
+    }
+
+
+  switch (var->bits_per_pixel)
+    {
+#ifdef FBCON_HAS_CFB8
+    case 8:
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    case 16:
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+    case 24:
+      break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+# ifdef FBCON_HAS_CFB32
+    case 32:
+      break;
+# endif
+#endif
+
+    default:
+      return -EINVAL;
+    }
+
+  par->depth = var->bits_per_pixel;
+
+  vramlen = info->video.len;
+  if (vramlen > 4*1024*1024)
+    vramlen = 4*1024*1024;
+
+  if (var->yres_virtual < var->yres)
+    var->yres_virtual = var->yres;
+  if (var->xres_virtual < var->xres)
+    var->xres_virtual = var->xres;
+
+  memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+  if (memlen > vramlen)
+    {
+      var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
+      memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+    }
+
+  /* we must round yres/xres down, we already rounded y/xres_virtual up
+     if it was possible. We should return -EINVAL, but I disagree */
+  if (var->yres_virtual < var->yres)
+    var->yres = var->yres_virtual;
+  if (var->xres_virtual < var->xres)
+    var->xres = var->xres_virtual;
+  if (var->xoffset + var->xres > var->xres_virtual)
+    var->xoffset = var->xres_virtual - var->xres;
+  if (var->yoffset + var->yres > var->yres_virtual)
+    var->yoffset = var->yres_virtual - var->yres;
+
+
+  /*
+   * This will allocate the datastructure and initialize all of the
+   * generic VGA registers.
+   */
+
+  if (vgaHWInit (var, info, par, &timings))
+    return -EINVAL;
+
+  /*
+   * The default value assigned by vgaHW.c is 0x41, but this does
+   * not work for NeoMagic.
+   */
+  par->Attribute[16] = 0x01;
+
+  switch (var->bits_per_pixel)
+    {
+    case  8:
+      par->CRTC[0x13]   = var->xres_virtual >> 3;
+      par->ExtCRTOffset = var->xres_virtual >> 11;
+      par->ExtColorModeSelect = 0x11;
+      break;
+    case 16:
+      par->CRTC[0x13]   = var->xres_virtual >> 2;
+      par->ExtCRTOffset = var->xres_virtual >> 10;
+      par->ExtColorModeSelect = 0x13;
+      break;
+    case 24:
+      par->CRTC[0x13]   = (var->xres_virtual * 3) >> 3;
+      par->ExtCRTOffset = (var->xres_virtual * 3) >> 11;
+      par->ExtColorModeSelect = 0x14;
+      break;
+#ifdef NO_32BIT_SUPPORT_YET
+    case 32: /* FIXME: guessed values */
+      par->CRTC[0x13]   = var->xres_virtual >> 1;
+      par->ExtCRTOffset = var->xres_virtual >> 9;
+      par->ExtColorModeSelect = 0x15;
+      break;
+#endif
+    default:
+      break;
+    }
+	
+  par->ExtCRTDispAddr = 0x10;
+
+  /* Vertical Extension */
+  par->VerticalExt = (((timings.VTotal -2) & 0x400) >> 10 )
+    | (((timings.VDisplay -1) & 0x400) >> 9 )
+    | (((timings.VSyncStart) & 0x400) >> 8 )
+    | (((timings.VSyncStart) & 0x400) >> 7 );
+
+  /* Fast write bursts on unless disabled. */
+  if (info->pci_burst)
+    par->SysIfaceCntl1 = 0x30; 
+  else
+    par->SysIfaceCntl1 = 0x00; 
+
+  par->SysIfaceCntl2 = 0xc0; /* VESA Bios sets this to 0x80! */
+
+  /* Enable any user specified display devices. */
+  par->PanelDispCntlReg1 = 0x00;
+  if (info->internal_display)
+    par->PanelDispCntlReg1 |= 0x02;
+  if (info->external_display)
+    par->PanelDispCntlReg1 |= 0x01;
+
+  /* If the user did not specify any display devices, then... */
+  if (par->PanelDispCntlReg1 == 0x00) {
+    /* Default to internal (i.e., LCD) only. */
+    par->PanelDispCntlReg1 |= 0x02;
+  }
+
+  /* If we are using a fixed mode, then tell the chip we are. */
+  switch (var->xres)
+    {
+    case 1280:
+      par->PanelDispCntlReg1 |= 0x60;
+      break;
+    case 1024:
+      par->PanelDispCntlReg1 |= 0x40;
+      break;
+    case 800:
+      par->PanelDispCntlReg1 |= 0x20;
+      break;
+    case 640:
+    default:
+      break;
+    }
+  
+  /* Setup shadow register locking. */
+  switch (par->PanelDispCntlReg1 & 0x03)
+    {
+    case 0x01: /* External CRT only mode: */
+      par->GeneralLockReg = 0x00;
+      /* We need to program the VCLK for external display only mode. */
+      par->ProgramVCLK = 1;
+      break;
+    case 0x02: /* Internal LCD only mode: */
+    case 0x03: /* Simultaneous internal/external (LCD/CRT) mode: */
+      par->GeneralLockReg = 0x01;
+      /* Don't program the VCLK when using the LCD. */
+      par->ProgramVCLK = 0;
+      break;
+    }
+
+  /*
+   * If the screen is to be stretched, turn on stretching for the
+   * various modes.
+   *
+   * OPTION_LCD_STRETCH means stretching should be turned off!
+   */
+  par->PanelDispCntlReg2 = 0x00;
+  par->PanelDispCntlReg3 = 0x00;
+
+  if (info->lcd_stretch &&
+      (par->PanelDispCntlReg1 == 0x02) &&  /* LCD only */
+      (var->xres != info->NeoPanelWidth))
+    {
+      switch (var->xres)
+	{
+	case  320: /* Needs testing.  KEM -- 24 May 98 */
+	case  400: /* Needs testing.  KEM -- 24 May 98 */
+	case  640:
+	case  800:
+	case 1024:
+	  lcd_stretch = 1;
+	  par->PanelDispCntlReg2 |= 0xC6;
+	  break;
+	default:
+	  lcd_stretch = 0;
+	  /* No stretching in these modes. */
+	}
+    }
+  else
+    lcd_stretch = 0;
+
+  /*
+   * If the screen is to be centerd, turn on the centering for the
+   * various modes.
+   */
+  par->PanelVertCenterReg1  = 0x00;
+  par->PanelVertCenterReg2  = 0x00;
+  par->PanelVertCenterReg3  = 0x00;
+  par->PanelVertCenterReg4  = 0x00;
+  par->PanelVertCenterReg5  = 0x00;
+  par->PanelHorizCenterReg1 = 0x00;
+  par->PanelHorizCenterReg2 = 0x00;
+  par->PanelHorizCenterReg3 = 0x00;
+  par->PanelHorizCenterReg4 = 0x00;
+  par->PanelHorizCenterReg5 = 0x00;
+
+
+  if (par->PanelDispCntlReg1 & 0x02)
+    {
+      if (var->xres == info->NeoPanelWidth)
+	{
+	  /*
+	   * No centering required when the requested display width
+	   * equals the panel width.
+	   */
+	}
+      else
+	{
+	  par->PanelDispCntlReg2 |= 0x01;
+	  par->PanelDispCntlReg3 |= 0x10;
+
+	  /* Calculate the horizontal and vertical offsets. */
+	  if (!lcd_stretch)
+	    {
+	      hoffset = ((info->NeoPanelWidth - var->xres) >> 4) - 1;
+	      voffset = ((info->NeoPanelHeight - var->yres) >> 1) - 2;
+	    }
+	  else
+	    {
+	      /* Stretched modes cannot be centered. */
+	      hoffset = 0;
+	      voffset = 0;
+	    }
+
+	  switch (var->xres)
+	    {
+	    case  320: /* Needs testing.  KEM -- 24 May 98 */
+	      par->PanelHorizCenterReg3 = hoffset;
+	      par->PanelVertCenterReg2  = voffset;
+	      break;
+	    case  400: /* Needs testing.  KEM -- 24 May 98 */
+	      par->PanelHorizCenterReg4 = hoffset;
+	      par->PanelVertCenterReg1  = voffset;
+	      break;
+	    case  640:
+	      par->PanelHorizCenterReg1 = hoffset;
+	      par->PanelVertCenterReg3  = voffset;
+	      break;
+	    case  800:
+	      par->PanelHorizCenterReg2 = hoffset;
+	      par->PanelVertCenterReg4  = voffset;
+	      break;
+	    case 1024:
+	      par->PanelHorizCenterReg5 = hoffset;
+	      par->PanelVertCenterReg5  = voffset;
+	      break;
+	    case 1280:
+	    default:
+	      /* No centering in these modes. */
+	      break;
+	    }
+	}
+    }
+
+  par->biosMode = neoFindMode (var->xres, var->yres, var->bits_per_pixel);
+    
+  /*
+   * Calculate the VCLK that most closely matches the requested dot
+   * clock.
+   */
+  neoCalcVCLK (info, par, timings.pixclock);
+
+  /* Since we program the clocks ourselves, always use VCLK3. */
+  par->MiscOutReg |= 0x0C;
+
+  return 0;
+}
+
+static int neofb_set_var (struct fb_var_screeninfo *var, int con,
+                          struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  struct display *display;
+  struct neofb_par par;
+  int err, chgvar = 0;
+
+  DBG("neofb_set_var");
+
+  err = neofb_decode_var (var, info, &par);
+  if (err)
+    return err;
+
+  if (var->activate & FB_ACTIVATE_TEST)
+    return 0;
+
+  if (con < 0)
+    {
+      display = fb->disp;
+      chgvar = 0;
+    }
+  else
+    {
+      display = fb_display + con;
+
+      if (fb->var.xres != var->xres)
+	chgvar = 1;
+      if (fb->var.yres != var->yres)
+	chgvar = 1;
+      if (fb->var.xres_virtual != var->xres_virtual)
+	chgvar = 1;
+      if (fb->var.yres_virtual != var->yres_virtual)
+	chgvar = 1;
+      if (fb->var.bits_per_pixel != var->bits_per_pixel)
+	chgvar = 1;
+    }
+
+  if (!info->neo2200)
+    var->accel_flags &= ~FB_ACCELF_TEXT;
+
+  var->red.msb_right	= 0;
+  var->green.msb_right	= 0;
+  var->blue.msb_right	= 0;
+
+  switch (var->bits_per_pixel)
+    {
+#ifdef FBCON_HAS_CFB8
+    case 8:	/* PSEUDOCOLOUR, 256 */
+      var->transp.offset   = 0;
+      var->transp.length   = 0;
+      var->red.offset      = 0;
+      var->red.length      = 8;
+      var->green.offset	   = 0;
+      var->green.length	   = 8;
+      var->blue.offset	   = 0;
+      var->blue.length	   = 8;
+      
+      fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
+      info->dispsw         = &fbcon_cfb8;
+      display->dispsw_data = NULL;
+      display->next_line   = var->xres_virtual;
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    case 16: /* DIRECTCOLOUR, 64k */
+      var->transp.offset   = 0;
+      var->transp.length   = 0;
+      var->red.offset      = 11;
+      var->red.length      = 5;
+      var->green.offset    = 5;
+      var->green.length    = 6;
+      var->blue.offset     = 0;
+      var->blue.length     = 5;
+
+      fb->fix.visual       = FB_VISUAL_DIRECTCOLOR;
+      info->dispsw         = &fbcon_cfb16;
+      display->dispsw_data = fb->pseudo_palette;
+      display->next_line   = var->xres_virtual * 2;
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+    case 24: /* TRUECOLOUR, 16m */
+      var->transp.offset   = 0;
+      var->transp.length   = 0;
+      var->red.offset      = 16;
+      var->red.length      = 8;
+      var->green.offset    = 8;
+      var->green.length    = 8;
+      var->blue.offset     = 0;
+      var->blue.length     = 8;
+
+      fb->fix.visual       = FB_VISUAL_TRUECOLOR;
+      info->dispsw         = &fbcon_cfb24;
+      display->dispsw_data = fb->pseudo_palette;
+      display->next_line   = var->xres_virtual * 3;
+
+      var->accel_flags    &= ~FB_ACCELF_TEXT;
+      break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+# ifdef FBCON_HAS_CFB32
+    case 32: /* TRUECOLOUR, 16m */
+      var->transp.offset   = 24;
+      var->transp.length   = 8;
+      var->red.offset      = 16;
+      var->red.length      = 8;
+      var->green.offset    = 8;
+      var->green.length    = 8;
+      var->blue.offset     = 0;
+      var->blue.length     = 8;
+
+      fb->fix.visual       = FB_VISUAL_TRUECOLOR;
+      info->dispsw         = &fbcon_cfb32;
+      display->dispsw_data = fb->pseudo_palette;
+      display->next_line   = var->xres_virtual * 4;
+
+      var->accel_flags    &= ~FB_ACCELF_TEXT;
+      break;
+# endif
+#endif
+
+    default:
+      printk (KERN_WARNING "neofb: no support for %dbpp\n", var->bits_per_pixel);
+      info->dispsw      = &fbcon_dummy;
+      var->accel_flags &= ~FB_ACCELF_TEXT;
+      break;
+    }
+
+  if (var->accel_flags & FB_ACCELF_TEXT)
+    display->dispsw = &fbcon_neo2200_accel;
+  else
+    display->dispsw = info->dispsw;
+
+  fb->fix.line_length = display->next_line;
+
+  display->screen_base    = fb->screen_base;
+  display->line_length    = fb->fix.line_length;
+  display->visual         = fb->fix.visual;
+  display->type	          = fb->fix.type;
+  display->type_aux       = fb->fix.type_aux;
+  display->ypanstep       = fb->fix.ypanstep;
+  display->ywrapstep      = fb->fix.ywrapstep;
+  display->can_soft_blank = 1;
+  display->inverse        = 0;
+
+  fb->var = *var;
+  fb->var.activate &= ~FB_ACTIVATE_ALL;
+
+  /*
+   * Update the old var.  The fbcon drivers still use this.
+   * Once they are using cfb->fb.var, this can be dropped.
+   *					--rmk
+   */
+  display->var = fb->var;
+
+  /*
+   * If we are setting all the virtual consoles, also set the
+   * defaults used to create new consoles.
+   */
+  if (var->activate & FB_ACTIVATE_ALL)
+    fb->disp->var = fb->var;
+
+  if (chgvar && fb && fb->changevar)
+    fb->changevar (con);
+
+  if (con == info->currcon)
+    {
+      if (chgvar || con < 0)
+        neofb_set_par (info, &par);
+
+      neofb_update_start (info, var);
+      fb_set_cmap (&fb->cmap, 1, neo_setcolreg, fb);
+
+      if (var->accel_flags & FB_ACCELF_TEXT)
+	neo2200_accel_init (info, var);
+    }
+
+  return 0;
+}
+
+/*
+ *    Pan or Wrap the Display
+ */
+static int neofb_pan_display (struct fb_var_screeninfo *var, int con,
+			      struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  u_int y_bottom;
+
+  y_bottom = var->yoffset;
+
+  if (!(var->vmode & FB_VMODE_YWRAP))
+    y_bottom += var->yres;
+
+  if (var->xoffset > (var->xres_virtual - var->xres))
+    return -EINVAL;
+  if (y_bottom > fb->var.yres_virtual)
+    return -EINVAL;
+
+  neofb_update_start (info, var);
+
+  fb->var.xoffset = var->xoffset;
+  fb->var.yoffset = var->yoffset;
+
+  if (var->vmode & FB_VMODE_YWRAP)
+    fb->var.vmode |= FB_VMODE_YWRAP;
+  else
+    fb->var.vmode &= ~FB_VMODE_YWRAP;
+
+  return 0;
+}
+
+
+/*
+ *    Update the `var' structure (called by fbcon.c)
+ *
+ *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
+ *    Since it's called by a kernel driver, no range checking is done.
+ */
+static int neofb_updatevar (int con, struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+
+  neofb_update_start (info, &fb_display[con].var);
+
+  return 0;
+}
+
+static int neofb_switch (int con, struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  struct display *disp;
+  struct fb_cmap *cmap;
+
+  if (info->currcon >= 0)
+    {
+      disp = fb_display + info->currcon;
+
+      /*
+       * Save the old colormap and video mode.
+       */
+      disp->var = fb->var;
+      if (disp->cmap.len)
+	fb_copy_cmap(&fb->cmap, &disp->cmap, 0);
+    }
+
+  info->currcon = con;
+  disp = fb_display + con;
+
+  /*
+   * Install the new colormap and change the video mode.  By default,
+   * fbcon sets all the colormaps and video modes to the default
+   * values at bootup.
+   *
+   * Really, we want to set the colourmap size depending on the
+   * depth of the new video mode.  For now, we leave it at its
+   * default 256 entry.
+   */
+  if (disp->cmap.len)
+    cmap = &disp->cmap;
+  else
+    cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
+
+  fb_copy_cmap(cmap, &fb->cmap, 0);
+
+  disp->var.activate = FB_ACTIVATE_NOW;
+  neofb_set_var(&disp->var, con, fb);
+
+  return 0;
+}
+
+/*
+ *    (Un)Blank the display.
+ */
+static void neofb_blank (int blank, struct fb_info *fb)
+{
+  //  struct neofb_info *info = (struct neofb_info *)fb;
+
+  /*
+   *  Blank the screen if blank_mode != 0, else unblank. If
+   *  blank == NULL then the caller blanks by setting the CLUT
+   *  (Color Look Up Table) to all black. Return 0 if blanking
+   *  succeeded, != 0 if un-/blanking failed due to e.g. a
+   *  video mode which doesn't support it. Implements VESA
+   *  suspend and powerdown modes on hardware that supports
+   *  disabling hsync/vsync:
+   *    blank_mode == 2: suspend vsync
+   *    blank_mode == 3: suspend hsync
+   *    blank_mode == 4: powerdown
+   *
+   *  wms...Enable VESA DMPS compatible powerdown mode
+   *  run "setterm -powersave powerdown" to take advantage
+   */
+     
+  switch (blank)
+    {
+    case 4:	/* powerdown - both sync lines down */
+      break;	
+    case 3:	/* hsync off */
+      break;	
+    case 2:	/* vsync off */
+      break;	
+    case 1:	/* just software blanking of screen */
+      break;
+    default: /* case 0, or anything else: unblank */
+      break;
+    }
+}
+
+/*
+ * Get the currently displayed virtual consoles colormap.
+ */
+static int gen_get_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *fb)
+{
+  fb_copy_cmap (&fb->cmap, cmap, kspc ? 0 : 2);
+  return 0;
+}
+
+/*
+ * Get the currently displayed virtual consoles fixed part of the display.
+ */
+static int gen_get_fix (struct fb_fix_screeninfo *fix, int con, struct fb_info *fb)
+{
+  *fix = fb->fix;
+  return 0;
+}
+
+/*
+ * Get the current user defined part of the display.
+ */
+static int gen_get_var (struct fb_var_screeninfo *var, int con, struct fb_info *fb)
+{
+  *var = fb->var;
+  return 0;
+}
+
+static struct fb_ops neofb_ops = {
+  owner:          THIS_MODULE,
+  fb_set_var:     neofb_set_var,
+  fb_set_cmap:    neofb_set_cmap,
+  fb_pan_display: neofb_pan_display,
+  fb_get_fix:     gen_get_fix,
+  fb_get_var:     gen_get_var,
+  fb_get_cmap:    gen_get_cmap,
+};
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo __devinitdata neofb_var640x480x8 = {
+	accel_flags:	FB_ACCELF_TEXT,
+	xres:		640,
+	yres:		480,
+	xres_virtual:   640,
+	yres_virtual:   30000,
+	bits_per_pixel: 8,
+	pixclock:	39722,
+	left_margin:	48,
+	right_margin:	16,
+	upper_margin:	33,
+	lower_margin:	10,
+	hsync_len:	96,
+	vsync_len:	2,
+	sync:		0,
+	vmode:		FB_VMODE_NONINTERLACED
+};
+
+static struct fb_var_screeninfo __devinitdata neofb_var800x600x8 = {
+	accel_flags:	FB_ACCELF_TEXT,
+	xres:		800,
+	yres:		600,
+	xres_virtual:   800,
+	yres_virtual:   30000,
+	bits_per_pixel: 8,
+	pixclock:	25000,
+	left_margin:	88,
+	right_margin:	40,
+	upper_margin:	23,
+	lower_margin:	1,
+	hsync_len:	128,
+	vsync_len:	4,
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	vmode:		FB_VMODE_NONINTERLACED
+};
+
+static struct fb_var_screeninfo __devinitdata neofb_var1024x768x8 = {
+	accel_flags:	FB_ACCELF_TEXT,
+	xres:		1024,
+	yres:		768,
+	xres_virtual:   1024,
+	yres_virtual:   30000,
+	bits_per_pixel: 8,
+	pixclock:	15385,
+	left_margin:	160,
+	right_margin:	24,
+	upper_margin:	29,
+	lower_margin:	3,
+	hsync_len:	136,
+	vsync_len:	6,
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	vmode:		FB_VMODE_NONINTERLACED
+};
+
+#ifdef NOT_DONE
+static struct fb_var_screeninfo __devinitdata neofb_var1280x1024x8 = {
+	accel_flags:	FB_ACCELF_TEXT,
+	xres:		1280,
+	yres:		1024,
+	xres_virtual:   1280,
+	yres_virtual:   30000,
+	bits_per_pixel: 8,
+	pixclock:	9260,
+	left_margin:	248,
+	right_margin:	48,
+	upper_margin:	38,
+	lower_margin:	1,
+	hsync_len:	112,
+	vsync_len:	3,
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	vmode:		FB_VMODE_NONINTERLACED
+};
+#endif
+
+static struct fb_var_screeninfo *neofb_var = NULL;
+
+
+static int __devinit neo_map_mmio (struct neofb_info *info)
+{
+  DBG("neo_map_mmio");
+
+  info->mmio.pbase = pci_resource_start (info->pcidev, 1);
+  info->mmio.len   = MMIO_SIZE;
+
+  if (!request_mem_region (info->mmio.pbase, MMIO_SIZE, "memory mapped I/O"))
+    {
+      printk ("neofb: memory mapped IO in use\n");
+      return -EBUSY;
+    }
+
+  info->mmio.vbase = ioremap (info->mmio.pbase, MMIO_SIZE);
+  if (!info->mmio.vbase)
+    {
+      printk ("neofb: unable to map memory mapped IO\n");
+      release_mem_region (info->mmio.pbase, info->mmio.len);
+      return -ENOMEM;
+    }
+  else
+    printk (KERN_INFO "neofb: mapped io at %p\n", info->mmio.vbase);
+
+  info->fb.fix.mmio_start = info->mmio.pbase;
+  info->fb.fix.mmio_len   = info->mmio.len;
+
+  return 0;
+}
+
+static void __devinit neo_unmap_mmio (struct neofb_info *info)
+{
+  DBG("neo_unmap_mmio");
+
+  if (info->mmio.vbase)
+    {
+      iounmap (info->mmio.vbase);
+      info->mmio.vbase = NULL;
+
+      release_mem_region (info->mmio.pbase, info->mmio.len);
+    }
+}
+
+static int __devinit neo_map_video (struct neofb_info *info, int video_len)
+{
+  DBG("neo_map_video");
+
+  info->video.pbase = pci_resource_start (info->pcidev, 0);
+  info->video.len   = video_len;
+
+  if (!request_mem_region (info->video.pbase, info->video.len, "frame buffer"))
+    {
+      printk ("neofb: frame buffer in use\n");
+      return -EBUSY;
+    }
+
+  info->video.vbase = ioremap (info->video.pbase, info->video.len);
+  if (!info->video.vbase)
+    {
+      printk ("neofb: unable to map screen memory\n");
+      release_mem_region (info->video.pbase, info->video.len);
+      return -ENOMEM;
+    }
+  else
+    printk (KERN_INFO "neofb: mapped framebuffer at %p\n", info->video.vbase);
+
+  info->fb.fix.smem_start = info->video.pbase;
+  info->fb.fix.smem_len   = info->video.len;
+  info->fb.screen_base    = info->video.vbase;
+
+#ifdef CONFIG_MTRR
+  info->video.mtrr = mtrr_add (info->video.pbase, pci_resource_len (info->pcidev, 0), MTRR_TYPE_WRCOMB, 1);
+#endif
+
+  /* Clear framebuffer, it's all white in memory after boot */
+  memset (info->video.vbase, 0, info->video.len);
+
+  return 0;
+}
+
+static void __devinit neo_unmap_video (struct neofb_info *info)
+{
+  DBG("neo_unmap_video");
+
+  if (info->video.vbase)
+    {
+#ifdef CONFIG_MTRR
+      mtrr_del (info->video.mtrr, info->video.pbase, info->video.len);
+#endif
+
+      iounmap (info->video.vbase);
+      info->video.vbase = NULL;
+      info->fb.screen_base = NULL;
+
+      release_mem_region (info->video.pbase, info->video.len);
+    }
+}
+
+static int __devinit neo_init_hw (struct neofb_info *info)
+{
+  int videoRam = 896;
+  int maxClock = 65000;
+  int CursorMem = 1024;
+  int CursorOff = 0x100;
+  int linearSize = 1024;
+  int maxWidth = 1024;
+  int maxHeight = 1024;
+  unsigned char type, display;
+  int w;
+    
+  DBG("neo_init_hw");
+
+  neoUnlock();
+
+#if 0
+  printk (KERN_DEBUG "--- Neo extended register dump ---\n");
+  for (w=0; w<0x85; w++)
+    printk (KERN_DEBUG "CR %p: %p\n", (void*)w, (void*)VGArCR (w));
+  for (w=0; w<0xC7; w++)
+    printk (KERN_DEBUG "GR %p: %p\n", (void*)w, (void*)VGArGR (w));
+#endif
+
+  /* Determine the panel type */
+  VGAwGR(0x09,0x26);
+  type = VGArGR(0x21);
+  display = VGArGR(0x20);
+    
+  /* Determine panel width -- used in NeoValidMode. */
+  w = VGArGR(0x20);
+  VGAwGR(0x09,0x00);
+  switch ((w & 0x18) >> 3)
+    {
+    case 0x00:
+      info->NeoPanelWidth  = 640;
+      info->NeoPanelHeight = 480;
+      neofb_var = &neofb_var640x480x8;
+      break;
+    case 0x01:
+      info->NeoPanelWidth  = 800;
+      info->NeoPanelHeight = 600;
+      neofb_var = &neofb_var800x600x8;
+      break;
+    case 0x02:
+      info->NeoPanelWidth  = 1024;
+      info->NeoPanelHeight = 768;
+      neofb_var = &neofb_var1024x768x8;
+      break;
+    case 0x03:
+      /* 1280x1024 panel support needs to be added */
+#ifdef NOT_DONE
+      info->NeoPanelWidth  = 1280;
+      info->NeoPanelHeight = 1024;
+      neofb_var = &neofb_var1280x1024x8;
+      break;
+#else
+      printk (KERN_ERR "neofb: Only 640x480, 800x600 and 1024x768 panels are currently supported\n");
+      return -1;
+#endif
+    default:
+      info->NeoPanelWidth  = 640;
+      info->NeoPanelHeight = 480;
+      neofb_var = &neofb_var640x480x8;
+      break;
+    }
+
+  printk (KERN_INFO "Panel is a %dx%d %s %s display\n",
+	  info->NeoPanelWidth,
+	  info->NeoPanelHeight,
+	  (type & 0x02) ? "color" : "monochrome",
+	  (type & 0x10) ? "TFT" : "dual scan");
+
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      videoRam   = 896;
+      maxClock   = 65000;
+      CursorMem  = 2048;
+      CursorOff  = 0x100;
+      linearSize = 1024;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+    case FB_ACCEL_NEOMAGIC_NM2093:
+      videoRam   = 1152;
+      maxClock   = 80000;
+      CursorMem  = 2048;
+      CursorOff  = 0x100;
+      linearSize = 2048;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2097:
+      videoRam   = 1152;
+      maxClock   = 80000;
+      CursorMem  = 1024;
+      CursorOff  = 0x100;
+      linearSize = 2048;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2160:
+      videoRam   = 2048;
+      maxClock   = 90000;
+      CursorMem  = 1024;
+      CursorOff  = 0x100;
+      linearSize = 2048;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2200:
+      videoRam   = 2560;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 4096;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2230:
+      videoRam   = 3008;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 4096;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2360:
+      videoRam   = 4096;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 4096;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      videoRam   = 6144;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 8192;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    }
+
+  info->maxClock = maxClock;
+
+  return videoRam * 1024;
+}
+
+
+static struct neofb_info * __devinit neo_alloc_fb_info (struct pci_dev *dev,
+							const struct pci_device_id *id)
+{
+  struct neofb_info *info;
+
+  info = kmalloc (sizeof(struct neofb_info) + sizeof(struct display) +
+		  sizeof(u32) * 16, GFP_KERNEL);
+
+  if (!info)
+    return NULL;
+
+  memset (info, 0, sizeof(struct neofb_info) + sizeof(struct display));
+
+  info->currcon = -1;
+  info->pcidev  = dev;
+  info->accel   = id->driver_data;
+
+  info->pci_burst   = !nopciburst;
+  info->lcd_stretch = !nostretch;
+
+  if (!internal && !external)
+    {
+      info->internal_display = 1;
+      info->external_display = 0;
+    }
+  else
+    {
+      info->internal_display = internal;
+      info->external_display = external;
+    }
+
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      sprintf (info->fb.fix.id, "MagicGraph 128");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+      sprintf (info->fb.fix.id, "MagicGraph 128V");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2093:
+      sprintf (info->fb.fix.id, "MagicGraph 128ZV");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2097:
+      sprintf (info->fb.fix.id, "MagicGraph 128ZV+");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2160:
+      sprintf (info->fb.fix.id, "MagicGraph 128XD");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2200:
+      sprintf (info->fb.fix.id, "MagicGraph 256AV");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2230:
+      sprintf (info->fb.fix.id, "MagicGraph 256AV+");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2360:
+      sprintf (info->fb.fix.id, "MagicGraph 256ZX");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      sprintf (info->fb.fix.id, "MagicGraph 256XL+");
+      break;
+    }
+
+  info->fb.fix.type	   = FB_TYPE_PACKED_PIXELS;
+  info->fb.fix.type_aux	   = 0;
+  info->fb.fix.xpanstep	   = 0;
+  info->fb.fix.ypanstep	   = 4;
+  info->fb.fix.ywrapstep   = 0;
+  info->fb.fix.accel       = id->driver_data;
+
+  info->fb.var.nonstd      = 0;
+  info->fb.var.activate    = FB_ACTIVATE_NOW;
+  info->fb.var.height      = -1;
+  info->fb.var.width       = -1;
+  info->fb.var.accel_flags = 0;
+
+  strcpy (info->fb.modename, info->fb.fix.id);
+
+  info->fb.fbops          = &neofb_ops;
+  info->fb.changevar      = NULL;
+  info->fb.switch_con     = neofb_switch;
+  info->fb.updatevar      = neofb_updatevar;
+  info->fb.blank          = neofb_blank;
+  info->fb.flags          = FBINFO_FLAG_DEFAULT;
+  info->fb.disp           = (struct display *)(info + 1);
+  info->fb.pseudo_palette = (void *)(info->fb.disp + 1);
+
+  fb_alloc_cmap (&info->fb.cmap, NR_PALETTE, 0);
+
+  return info;
+}
+
+static void __devinit neo_free_fb_info (struct neofb_info *info)
+{
+  if (info)
+    {
+      /*
+       * Free the colourmap
+       */
+      fb_alloc_cmap (&info->fb.cmap, 0, 0);
+
+      kfree (info);
+    }
+}
+
+/* --------------------------------------------------------------------- */
+
+static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_id* id)
+{
+  struct neofb_info *info;
+  u_int h_sync, v_sync;
+  int err;
+  int video_len;
+
+  DBG("neofb_probe");
+
+  err = pci_enable_device (dev);
+  if (err)
+    return err;
+
+  err = -ENOMEM;
+  info = neo_alloc_fb_info (dev, id);
+  if (!info)
+    goto failed;
+
+  err = neo_map_mmio (info);
+  if (err)
+    goto failed;
+
+  video_len = neo_init_hw (info);
+  if (video_len < 0)
+    {
+      err = video_len;
+      goto failed;
+    }
+
+  err = neo_map_video (info, video_len);
+  if (err)
+    goto failed;
+
+  neofb_set_var (neofb_var, -1, &info->fb);
+
+  /*
+   * Calculate the hsync and vsync frequencies.  Note that
+   * we split the 1e12 constant up so that we can preserve
+   * the precision and fit the results into 32-bit registers.
+   *  (1953125000 * 512 = 1e12)
+   */
+  h_sync = 1953125000 / info->fb.var.pixclock;
+  h_sync = h_sync * 512 / (info->fb.var.xres + info->fb.var.left_margin +
+			   info->fb.var.right_margin + info->fb.var.hsync_len);
+  v_sync = h_sync / (info->fb.var.yres + info->fb.var.upper_margin +
+		     info->fb.var.lower_margin + info->fb.var.vsync_len);
+
+  printk(KERN_INFO "neofb v" NEOFB_VERSION ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+	 info->fb.fix.smem_len >> 10,
+	 info->fb.var.xres, info->fb.var.yres,
+	 h_sync / 1000, h_sync % 1000, v_sync);
+
+
+  err = register_framebuffer (&info->fb);
+  if (err < 0)
+    goto failed;
+
+  printk (KERN_INFO "fb%d: %s frame buffer device\n",
+	  GET_FB_IDX(info->fb.node), info->fb.modename);
+
+  /*
+   * Our driver data
+   */
+  dev->driver_data = info;
+
+  return 0;
+
+failed:
+  neo_unmap_video (info);
+  neo_unmap_mmio (info);
+  neo_free_fb_info (info);
+
+  return err;
+}
+
+static void __devexit neofb_remove (struct pci_dev *dev)
+{
+  struct neofb_info *info = (struct neofb_info *)dev->driver_data;
+
+  DBG("neofb_remove");
+
+  if (info)
+    {
+      /*
+       * If unregister_framebuffer fails, then
+       * we will be leaving hooks that could cause
+       * oopsen laying around.
+       */
+      if (unregister_framebuffer (&info->fb))
+	printk (KERN_WARNING "neofb: danger danger!  Oopsen imminent!\n");
+
+      neo_unmap_video (info);
+      neo_unmap_mmio (info);
+      neo_free_fb_info (info);
+
+      /*
+       * Ensure that the driver data is no longer
+       * valid.
+       */
+      dev->driver_data = NULL;
+    }
+}
+
+static struct pci_device_id neofb_devices[] __devinitdata = {
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380},
+
+  {0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, neofb_devices);
+
+static struct pci_driver neofb_driver = {
+  name:      "neofb",
+  id_table:  neofb_devices,
+  probe:     neofb_probe,
+  remove:    neofb_remove
+};
+
+/* **************************** init-time only **************************** */
+
+static void __init neo_init (void)
+{
+  DBG("neo_init");
+  pci_register_driver (&neofb_driver);
+}
+
+/* **************************** exit-time only **************************** */
+
+static void __exit neo_done (void)
+{
+  DBG("neo_done");
+  pci_unregister_driver (&neofb_driver);
+}
+
+
+#ifndef MODULE
+
+/* ************************* init in-kernel code ************************** */
+
+int __init neofb_setup (char *options)
+{
+  char *this_opt;
+
+  DBG("neofb_setup");
+
+  if (!options || !*options)
+    return 0;
+
+  for (this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,","))
+    {
+      if (!*this_opt) continue;
+
+      if (!strncmp(this_opt, "disabled", 8))
+	disabled = 1;
+      if (!strncmp(this_opt, "internal", 8))
+	internal = 1;
+      if (!strncmp(this_opt, "external", 8))
+	external = 1;
+      if (!strncmp(this_opt, "nostretch", 9))
+	nostretch = 1;
+      if (!strncmp(this_opt, "nopciburst", 10))
+	nopciburst = 1;
+    }
+
+  return 0;
+}
+
+static int __init initialized = 0;
+
+int __init neofb_init(void)
+{
+  DBG("neofb_init");
+
+  if (disabled)
+    return -ENXIO;
+
+  if (!initialized)
+    {
+      initialized = 1;
+      neo_init();
+    }
+
+  /* never return failure, user can hotplug card later... */
+  return 0;
+}
+
+#else
+
+/* *************************** init module code **************************** */
+
+int __init init_module(void)
+{
+  DBG("init_module");
+
+  if (disabled)
+    return -ENXIO;
+
+  neo_init();
+
+  /* never return failure; user can hotplug card later... */
+  return 0;
+}
+
+#endif	/* MODULE */
+
+module_exit(neo_done);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/neofb.h linux/drivers/video/neofb.h
--- v2.5.2/linux/drivers/video/neofb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/neofb.h	Wed Jan 23 15:25:34 2002
@@ -0,0 +1,294 @@
+/*
+ * linux/drivers/video/neofb.h -- NeoMagic Framebuffer Driver
+ *
+ * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+
+#ifdef NEOFB_DEBUG
+# define DBG(x)		printk (KERN_DEBUG "neofb: %s\n", (x));
+#else
+# define DBG(x)
+#endif
+
+
+#define PCI_CHIP_NM2070 0x0001
+#define PCI_CHIP_NM2090 0x0002
+#define PCI_CHIP_NM2093 0x0003
+#define PCI_CHIP_NM2097 0x0083
+#define PCI_CHIP_NM2160 0x0004
+#define PCI_CHIP_NM2200 0x0005
+#define PCI_CHIP_NM2230 0x0025
+#define PCI_CHIP_NM2360 0x0006
+#define PCI_CHIP_NM2380 0x0016
+
+
+struct xtimings {
+  unsigned int pixclock;
+  unsigned int HDisplay;
+  unsigned int HSyncStart;
+  unsigned int HSyncEnd;
+  unsigned int HTotal;
+  unsigned int VDisplay;
+  unsigned int VSyncStart;
+  unsigned int VSyncEnd;
+  unsigned int VTotal;
+  unsigned int sync;
+  int	       dblscan;
+  int	       interlaced;
+};
+
+
+/* --------------------------------------------------------------------- */
+
+typedef volatile struct {
+  __u32 bltStat;
+  __u32 bltCntl;
+  __u32 xpColor;
+  __u32 fgColor;
+  __u32 bgColor;
+  __u32 pitch;
+  __u32 clipLT;
+  __u32 clipRB;
+  __u32 srcBitOffset;
+  __u32 srcStart;
+  __u32 reserved0;
+  __u32 dstStart;
+  __u32 xyExt;
+
+  __u32 reserved1[19];
+
+  __u32 pageCntl;
+  __u32 pageBase;
+  __u32 postBase;
+  __u32 postPtr;
+  __u32 dataPtr;
+} Neo2200;
+
+#define NR_PALETTE	256
+
+#define MMIO_SIZE 0x200000
+
+#define NEO_EXT_CR_MAX 0x85
+#define NEO_EXT_GR_MAX 0xC7
+
+struct neofb_par {
+
+  int depth;
+
+  unsigned char MiscOutReg;     /* Misc */
+  unsigned char CRTC[25];       /* Crtc Controller */
+  unsigned char Sequencer[5];   /* Video Sequencer */
+  unsigned char Graphics[9];    /* Video Graphics */
+  unsigned char Attribute[21];  /* Video Atribute */
+
+  unsigned char GeneralLockReg;
+  unsigned char ExtCRTDispAddr;
+  unsigned char ExtCRTOffset;
+  unsigned char SysIfaceCntl1;
+  unsigned char SysIfaceCntl2;
+  unsigned char ExtColorModeSelect;
+  unsigned char biosMode;
+
+  unsigned char PanelDispCntlReg1;
+  unsigned char PanelDispCntlReg2;
+  unsigned char PanelDispCntlReg3;
+  unsigned char PanelVertCenterReg1;
+  unsigned char PanelVertCenterReg2;
+  unsigned char PanelVertCenterReg3;
+  unsigned char PanelVertCenterReg4;
+  unsigned char PanelVertCenterReg5;
+  unsigned char PanelHorizCenterReg1;
+  unsigned char PanelHorizCenterReg2;
+  unsigned char PanelHorizCenterReg3;
+  unsigned char PanelHorizCenterReg4;
+  unsigned char PanelHorizCenterReg5;
+
+  int           ProgramVCLK;
+  unsigned char VCLK3NumeratorLow;
+  unsigned char VCLK3NumeratorHigh;
+  unsigned char VCLK3Denominator;
+  unsigned char VerticalExt;
+};
+
+struct neofb_info {
+
+  struct fb_info  fb;
+  struct display_switch	*dispsw;
+
+  struct pci_dev *pcidev;
+
+  int   currcon;
+
+  int   accel;
+  char *name;
+
+  struct {
+    u8    *vbase;
+    u32    pbase;
+    u32    len;
+#ifdef CONFIG_MTRR
+    int    mtrr;
+#endif
+  } video;
+
+  struct {
+    u8    *vbase;
+    u32    pbase;
+    u32    len;
+  } mmio;
+
+  Neo2200 *neo2200;
+
+  /* Panels size */
+  int NeoPanelWidth;
+  int NeoPanelHeight;
+
+  int maxClock;
+
+  int pci_burst;
+  int lcd_stretch;
+  int internal_display;
+  int external_display;
+
+  struct {
+    u16 red, green, blue, transp;
+  } palette[NR_PALETTE];
+};
+
+
+typedef struct {
+    int x_res;
+    int y_res;
+    int mode;
+} biosMode;
+
+
+/* vga IO functions */
+static inline u8 VGArCR (u8 index)
+{
+  outb (index, 0x3d4);
+  return inb (0x3d5);
+}
+
+static inline void VGAwCR (u8 index, u8 val)
+{
+  outb (index, 0x3d4);
+  outb (val, 0x3d5);
+}
+
+static inline u8 VGArGR (u8 index)
+{
+  outb (index, 0x3ce);
+  return inb (0x3cf);
+}
+
+static inline void VGAwGR (u8 index, u8 val)
+{
+  outb (index, 0x3ce);
+  outb (val, 0x3cf);
+}
+
+static inline u8 VGArSEQ (u8 index)
+{
+  outb (index, 0x3c4);
+  return inb (0x3c5);
+}
+
+static inline void VGAwSEQ (u8 index, u8 val)
+{
+  outb (index, 0x3c4);
+  outb (val, 0x3c5);
+}
+
+
+static int paletteEnabled = 0;
+
+static inline void VGAenablePalette (void)
+{
+  u8 tmp;
+
+  tmp = inb (0x3da);
+  outb (0x00, 0x3c0);
+  paletteEnabled = 1;
+}
+
+static inline void VGAdisablePalette (void)
+{
+  u8 tmp;
+
+  tmp = inb (0x3da);
+  outb (0x20, 0x3c0);
+  paletteEnabled = 0;
+}
+
+static inline void VGAwATTR (u8 index, u8 value)
+{
+  u8 tmp;
+
+  if (paletteEnabled)
+    index &= ~0x20;
+  else
+    index |= 0x20;
+
+  tmp = inb (0x3da);
+  outb (index, 0x3c0);
+  outb (value, 0x3c0);
+}
+
+static inline void VGAwMISC (u8 value)
+{
+  outb (value, 0x3c2);
+}
+
+
+#define NEO_BS0_BLT_BUSY        0x00000001
+#define NEO_BS0_FIFO_AVAIL      0x00000002
+#define NEO_BS0_FIFO_PEND       0x00000004
+
+#define NEO_BC0_DST_Y_DEC       0x00000001
+#define NEO_BC0_X_DEC           0x00000002
+#define NEO_BC0_SRC_TRANS       0x00000004
+#define NEO_BC0_SRC_IS_FG       0x00000008
+#define NEO_BC0_SRC_Y_DEC       0x00000010
+#define NEO_BC0_FILL_PAT        0x00000020
+#define NEO_BC0_SRC_MONO        0x00000040
+#define NEO_BC0_SYS_TO_VID      0x00000080
+
+#define NEO_BC1_DEPTH8          0x00000100
+#define NEO_BC1_DEPTH16         0x00000200
+#define NEO_BC1_X_320           0x00000400
+#define NEO_BC1_X_640           0x00000800
+#define NEO_BC1_X_800           0x00000c00
+#define NEO_BC1_X_1024          0x00001000
+#define NEO_BC1_X_1152          0x00001400
+#define NEO_BC1_X_1280          0x00001800
+#define NEO_BC1_X_1600          0x00001c00
+#define NEO_BC1_DST_TRANS       0x00002000
+#define NEO_BC1_MSTR_BLT        0x00004000
+#define NEO_BC1_FILTER_Z        0x00008000
+
+#define NEO_BC2_WR_TR_DST       0x00800000
+
+#define NEO_BC3_SRC_XY_ADDR     0x01000000
+#define NEO_BC3_DST_XY_ADDR     0x02000000
+#define NEO_BC3_CLIP_ON         0x04000000
+#define NEO_BC3_FIFO_EN         0x08000000
+#define NEO_BC3_BLT_ON_ADDR     0x10000000
+#define NEO_BC3_SKIP_MAPPING    0x80000000
+
+#define NEO_MODE1_DEPTH8        0x0100
+#define NEO_MODE1_DEPTH16       0x0200
+#define NEO_MODE1_DEPTH24       0x0300
+#define NEO_MODE1_X_320         0x0400
+#define NEO_MODE1_X_640         0x0800
+#define NEO_MODE1_X_800         0x0c00
+#define NEO_MODE1_X_1024        0x1000
+#define NEO_MODE1_X_1152        0x1400
+#define NEO_MODE1_X_1280        0x1800
+#define NEO_MODE1_X_1600        0x1c00
+#define NEO_MODE1_BLT_ON_ADDR   0x2000
diff -u --recursive --new-file v2.5.2/linux/drivers/video/offb.c linux/drivers/video/offb.c
--- v2.5.2/linux/drivers/video/offb.c	Tue Oct  2 09:10:31 2001
+++ linux/drivers/video/offb.c	Wed Jan 23 15:51:23 2002
@@ -566,7 +566,7 @@
 
     strcpy(info->info.modename, "OFfb ");
     strncat(info->info.modename, full_name, sizeof(info->info.modename));
-    info->info.node = -1;
+    info->info.node = NODEV;
     info->info.fbops = &offb_ops;
     info->info.disp = disp;
     info->info.fontname[0] = '\0';
diff -u --recursive --new-file v2.5.2/linux/drivers/video/platinumfb.c linux/drivers/video/platinumfb.c
--- v2.5.2/linux/drivers/video/platinumfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/platinumfb.c	Wed Jan 23 15:51:23 2002
@@ -591,7 +591,7 @@
 	disp = &info->disp;
 
 	strcpy(info->fb_info.modename, "platinum");
-	info->fb_info.node = -1;
+	info->fb_info.node = NODEV;
 	info->fb_info.fbops = &platinumfb_ops;
 	info->fb_info.disp = disp;
 	strcpy(info->fb_info.fontname, fontname);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/pmag-ba-fb.c linux/drivers/video/pmag-ba-fb.c
--- v2.5.2/linux/drivers/video/pmag-ba-fb.c	Fri Sep 14 14:04:07 2001
+++ linux/drivers/video/pmag-ba-fb.c	Wed Jan 23 15:51:23 2002
@@ -386,7 +386,7 @@
 	 */
 	strcpy(ip->info.modename, "PMAG-BA");
 	ip->info.changevar = NULL;
-	ip->info.node = -1;
+	ip->info.node = NODEV;
 	ip->info.fbops = &pmagbafb_ops;
 	ip->info.disp = &disp;
 	ip->info.switch_con = &pmagbafb_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/pmagb-b-fb.c linux/drivers/video/pmagb-b-fb.c
--- v2.5.2/linux/drivers/video/pmagb-b-fb.c	Fri Sep 14 14:04:07 2001
+++ linux/drivers/video/pmagb-b-fb.c	Wed Jan 23 15:51:23 2002
@@ -389,7 +389,7 @@
 	 */
 	strcpy(ip->info.modename, "PMAGB-BA");
 	ip->info.changevar = NULL;
-	ip->info.node = -1;
+	ip->info.node = NODEV;
 	ip->info.fbops = &pmagbbfb_ops;
 	ip->info.disp = &disp;
 	ip->info.switch_con = &pmagbbfb_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/pvr2fb.c linux/drivers/video/pvr2fb.c
--- v2.5.2/linux/drivers/video/pvr2fb.c	Mon Oct 15 13:36:48 2001
+++ linux/drivers/video/pvr2fb.c	Wed Jan 23 15:51:23 2002
@@ -1034,7 +1034,7 @@
 	
 	strcpy(fb_info.modename, pvr2fb_name);
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &pvr2fb_ops;
 	fb_info.disp = &disp;
 	fb_info.switch_con = &pvr2fbcon_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/q40fb.c linux/drivers/video/q40fb.c
--- v2.5.2/linux/drivers/video/q40fb.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/video/q40fb.c	Wed Jan 23 15:51:23 2002
@@ -331,7 +331,7 @@
 	fb_info.switch_con=&q40con_switch;
 	fb_info.updatevar=&q40con_updatevar;
 	fb_info.blank=&q40con_blank;	
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &q40fb_ops;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;  /* not as module for now */
 	
diff -u --recursive --new-file v2.5.2/linux/drivers/video/radeonfb.c linux/drivers/video/radeonfb.c
--- v2.5.2/linux/drivers/video/radeonfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/radeonfb.c	Wed Jan 23 15:51:23 2002
@@ -1305,7 +1305,7 @@
 	info = &rinfo->info;
 
 	strcpy (info->modename, rinfo->name);
-        info->node = -1;
+        info->node = NODEV;
         info->flags = FBINFO_FLAG_DEFAULT;
         info->fbops = &radeon_fb_ops;
         info->display_fg = NULL;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/retz3fb.c linux/drivers/video/retz3fb.c
--- v2.5.2/linux/drivers/video/retz3fb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/retz3fb.c	Wed Jan 23 15:51:23 2002
@@ -1422,7 +1422,7 @@
 
 		strcpy(fb_info->modename, retz3fb_name);
 		fb_info->changevar = NULL;
-		fb_info->node = -1;
+		fb_info->node = NODEV;
 		fb_info->fbops = &retz3fb_ops;
 		fb_info->disp = &zinfo->disp;
 		fb_info->switch_con = &z3fb_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c
--- v2.5.2/linux/drivers/video/sbusfb.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/video/sbusfb.c	Tue Jan 15 10:56:35 2002
@@ -214,7 +214,7 @@
 		}
 		if (page + map_size > size)
 			map_size = size - page;
-		r = io_remap_page_range (vma->vm_start+page, map_offset, map_size, vma->vm_page_prot, fb->iospace);
+		r = io_remap_page_range(vma, vma->vm_start+page, map_offset, map_size, vma->vm_page_prot, fb->iospace);
 		if (r)
 			return -EAGAIN;
 		page += map_size;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/sgivwfb.c linux/drivers/video/sgivwfb.c
--- v2.5.2/linux/drivers/video/sgivwfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/sgivwfb.c	Wed Jan 23 15:51:23 2002
@@ -847,7 +847,7 @@
   offset += sgivwfb_mem_phys;
   pgprot_val(vma->vm_page_prot) = pgprot_val(vma->vm_page_prot) | _PAGE_PCD;
   vma->vm_flags |= VM_IO;
-  if (remap_page_range(vma->vm_start, offset, size, vma->vm_page_prot))
+  if (remap_page_range(vma, vma->vm_start, offset, size, vma->vm_page_prot))
     return -EAGAIN;
   vma->vm_file = file;
   printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n", offset, vma->vm_start);
@@ -890,7 +890,7 @@
 
   strcpy(fb_info.modename, sgivwfb_name);
   fb_info.changevar = NULL;
-  fb_info.node = -1;
+  fb_info.node = NODEV;
   fb_info.fbops = &sgivwfb_ops;
   fb_info.disp = &disp;
   fb_info.switch_con = &sgivwfbcon_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/sis/sis_main.c linux/drivers/video/sis/sis_main.c
--- v2.5.2/linux/drivers/video/sis/sis_main.c	Fri Nov  9 14:11:14 2001
+++ linux/drivers/video/sis/sis_main.c	Tue Jan 15 10:56:35 2002
@@ -2175,7 +2175,7 @@
 	if (boot_cpu_data.x86 > 3)
 		pgprot_val (vma->vm_page_prot) |= _PAGE_PCD;
 #endif
-	if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) 
+	if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) 
 		return -EAGAIN;
 	return 0;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/video/skeletonfb.c linux/drivers/video/skeletonfb.c
--- v2.5.2/linux/drivers/video/skeletonfb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/skeletonfb.c	Wed Jan 23 15:51:23 2002
@@ -306,7 +306,7 @@
     fb_info.gen.fbhw->detect();
     strcpy(fb_info.gen.info.modename, "XXX");
     fb_info.gen.info.changevar = NULL;
-    fb_info.gen.info.node = -1;
+    fb_info.gen.info.node = NODEV;
     fb_info.gen.info.fbops = &xxxfb_ops;
     fb_info.gen.info.disp = &disp;
     fb_info.gen.info.switch_con = &xxxfb_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/sstfb.c linux/drivers/video/sstfb.c
--- v2.5.2/linux/drivers/video/sstfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/sstfb.c	Wed Jan 23 15:51:23 2002
@@ -1797,7 +1797,7 @@
 		f_ddprintk("membase_phys: %#lx\n", fb_info.video.base);
 		f_ddprintk("fbbase_virt: %#lx\n", fb_info.video.vbase);
 
-		fb_info.info.node       = -1 ;
+		fb_info.info.node       = NODEV;
 		fb_info.info.flags      = FBINFO_FLAG_DEFAULT;
 		fb_info.info.fbops      = &sstfb_ops;
 		fb_info.info.disp       = &disp;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/stifb.c linux/drivers/video/stifb.c
--- v2.5.2/linux/drivers/video/stifb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/stifb.c	Wed Jan 23 15:51:23 2002
@@ -166,7 +166,7 @@
 	if ((fb_info.sti = sti_init_roms()) == NULL)
 		return -ENXIO;
 
-	fb_info.gen.info.node = -1;
+	fb_info.gen.info.node = NODEV;
 	fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
 	fb_info.gen.info.fbops = &stifb_ops;
 	fb_info.gen.info.disp = &disp;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/sun3fb.c linux/drivers/video/sun3fb.c
--- v2.5.2/linux/drivers/video/sun3fb.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/video/sun3fb.c	Wed Jan 23 15:51:23 2002
@@ -573,7 +573,7 @@
 	fix->type = FB_TYPE_PACKED_PIXELS;
 	fix->visual = FB_VISUAL_PSEUDOCOLOR;
 	
-	fb->info.node = -1;
+	fb->info.node = NODEV;
 	fb->info.fbops = &sun3fb_ops;
 	fb->info.disp = disp;
 	strcpy(fb->info.fontname, fontname);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c
--- v2.5.2/linux/drivers/video/tdfxfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/tdfxfb.c	Wed Jan 23 15:51:23 2002
@@ -1975,7 +1975,7 @@
 	strcpy(fb_info.fb_info.modename, "3Dfx "); 
 	strcat(fb_info.fb_info.modename, name);
 	fb_info.fb_info.changevar  = NULL;
-	fb_info.fb_info.node       = -1;
+	fb_info.fb_info.node       = NODEV;
 	fb_info.fb_info.fbops      = &tdfxfb_ops;
 	fb_info.fb_info.disp       = &fb_info.disp;
 	strcpy(fb_info.fb_info.fontname, fontname);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c
--- v2.5.2/linux/drivers/video/tgafb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/tgafb.c	Wed Jan 23 15:51:23 2002
@@ -937,7 +937,7 @@
 
     /* setup framebuffer */
 
-    fb_info.gen.info.node = -1;
+    fb_info.gen.info.node = NODEV;
     fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
     fb_info.gen.info.fbops = &tgafb_ops;
     fb_info.gen.info.disp = &disp;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/tx3912fb.c linux/drivers/video/tx3912fb.c
--- v2.5.2/linux/drivers/video/tx3912fb.c	Fri Sep  7 09:28:38 2001
+++ linux/drivers/video/tx3912fb.c	Wed Jan 23 15:51:23 2002
@@ -397,7 +397,7 @@
 
 	strcpy(fb_info.modename, TX3912FB_NAME);
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &tx3912fb_ops;
 	fb_info.disp = &global_disp;
 	fb_info.switch_con = &tx3912fbcon_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/valkyriefb.c linux/drivers/video/valkyriefb.c
--- v2.5.2/linux/drivers/video/valkyriefb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/valkyriefb.c	Wed Jan 23 15:51:23 2002
@@ -779,7 +779,7 @@
 static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p)
 {
 	strcpy(info->modename, p->fix.id);
-	info->node = -1;	/* ??? danj */
+	info->node = NODEV;
 	info->fbops = &valkyriefb_ops;
 	info->disp = &p->disp;
 	strcpy(info->fontname, fontname);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/vfb.c linux/drivers/video/vfb.c
--- v2.5.2/linux/drivers/video/vfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/vfb.c	Wed Jan 23 15:51:23 2002
@@ -404,7 +404,7 @@
 
     strcpy(fb_info.modename, vfb_name);
     fb_info.changevar = NULL;
-    fb_info.node = -1;
+    fb_info.node = NODEV;
     fb_info.fbops = &vfb_ops;
     fb_info.disp = &disp;
     fb_info.switch_con = &vfbcon_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/vga16fb.c linux/drivers/video/vga16fb.c
--- v2.5.2/linux/drivers/video/vga16fb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/vga16fb.c	Wed Jan 23 15:51:23 2002
@@ -926,7 +926,7 @@
 	/* name should not depend on EGA/VGA */
 	strcpy(vga16fb.fb_info.modename, "VGA16 VGA");
 	vga16fb.fb_info.changevar = NULL;
-	vga16fb.fb_info.node = -1;
+	vga16fb.fb_info.node = NODEV;
 	vga16fb.fb_info.fbops = &vga16fb_ops;
 	vga16fb.fb_info.disp=&disp;
 	vga16fb.fb_info.switch_con=&vga16fb_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/virgefb.c linux/drivers/video/virgefb.c
--- v2.5.2/linux/drivers/video/virgefb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/virgefb.c	Wed Jan 23 15:51:23 2002
@@ -1168,7 +1168,7 @@
 
 	    strcpy(fb_info.modename, virgefb_name);
 	    fb_info.changevar = NULL;
-	    fb_info.node = -1;
+	    fb_info.node = NODEV;
 	    fb_info.fbops = &virgefb_ops;
 	    fb_info.disp = &disp;
 	    fb_info.switch_con = &Cyberfb_switch;
diff -u --recursive --new-file v2.5.2/linux/drivers/zorro/Config.help linux/drivers/zorro/Config.help
--- v2.5.2/linux/drivers/zorro/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/drivers/zorro/Config.help	Fri Jan 25 16:04:13 2002
@@ -0,0 +1,12 @@
+CONFIG_ZORRO_NAMES
+  By default, the kernel contains a database of all known Zorro device
+  names to make the information in /proc/iomem comprehensible to the
+  user. This database increases the size of the kernel image by about
+  15KB, but it gets freed after the system boots up, so it doesn't
+  take up kernel memory. Anyway, if you are building an installation
+  floppy or kernel for an embedded system where kernel image size
+  really matters, you can disable this feature and you'll get device
+  ID numbers instead of names.
+
+  When in doubt, say Y.
+
diff -u --recursive --new-file v2.5.2/linux/drivers/zorro/zorro.c linux/drivers/zorro/zorro.c
--- v2.5.2/linux/drivers/zorro/zorro.c	Fri Sep  7 09:28:38 2001
+++ linux/drivers/zorro/zorro.c	Wed Jan 23 10:54:42 2002
@@ -170,6 +170,7 @@
 			m68k_memory[i].addr+m68k_memory[i].size, 0);
 }
 
+subsys_initcall(zorro_init);
 
 EXPORT_SYMBOL(zorro_find_device);
 EXPORT_SYMBOL(zorro_unused_z2ram);
diff -u --recursive --new-file v2.5.2/linux/fs/Config.help linux/fs/Config.help
--- v2.5.2/linux/fs/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/fs/Config.help	Fri Jan 25 16:03:57 2002
@@ -0,0 +1,1004 @@
+CONFIG_QUOTA
+  If you say Y here, you will be able to set per user limits for disk
+  usage (also called disk quotas). Currently, it works only for the
+  ext2 file system. You need additional software in order to use quota
+  support; for details, read the Quota mini-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. Probably the quota
+  support is only useful for multi user systems. If unsure, say N.
+
+CONFIG_MINIX_FS
+  Minix is a simple operating system used in many classes about OS's.
+  The minix file system (method to organize files on a hard disk
+  partition or a floppy disk) was the original file system for Linux,
+  but has been superseded by the second extended file system ext2fs.
+  You don't want to use the minix file system on your hard disk
+  because of certain built-in restrictions, but it is sometimes found
+  on older Linux floppy disks.  This option will enlarge your kernel
+  by about 28 KB. If unsure, say N.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module
+  will be called minix.o.  Note that the file system of your root
+  partition (the one containing the directory /) cannot be compiled as
+  a module.
+
+CONFIG_REISERFS_FS
+  Stores not just filenames but the files themselves in a balanced
+  tree.  Uses journaling.
+
+  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.
+
+  It is more easily extended to have features currently found in
+  database and keyword search systems than block allocation based file
+  systems are.  The next version will be so extended, and will support
+  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.
+
+  Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com.
+
+  If you like it, you can pay us to add new features to it that you
+  need, buy a support contract, or pay us to port it to another OS.
+
+CONFIG_REISERFS_CHECK
+  If you set this to Y, then ReiserFS will perform every check it can
+  possibly imagine of its internal consistency throughout its
+  operation.  It will also go substantially slower.  More than once we
+  have forgotten that this was on, and then gone despondent over the
+  latest benchmarks.:-) Use of this option allows our team to go all
+  out in checking for consistency when debugging without fear of its
+  effect on end users.  If you are on the verge of sending in a bug
+  report, say Y and you might get a useful error message.  Almost
+  everyone should say N.
+
+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 (+8 KB).  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 N.
+
+CONFIG_EXT2_FS
+  This is the de facto standard Linux file system (method to organize
+  files on a storage device) for hard disks.
+
+  You want to say Y here, unless you intend to use Linux exclusively
+  from inside a DOS partition using the UMSDOS file system. The
+  advantage of the latter is that you can get away without
+  repartitioning your hard drive (which often implies backing
+  everything up and restoring afterwards); the disadvantage is that
+  Linux becomes susceptible to DOS viruses and that UMSDOS is somewhat
+  slower than ext2fs. Even if you want to run Linux in this fashion,
+  it might be a good idea to have ext2fs around: it enables you to
+  read more floppy disks and facilitates the transition to a *real*
+  Linux partition later. Another (rare) case which doesn't require
+  ext2fs is a diskless Linux box which mounts all files over the
+  network using NFS (in this case it's sufficient to say Y to "NFS
+  file system support" below). Saying Y here will enlarge your kernel
+  by about 44 KB.
+
+  The Ext2fs-Undeletion mini-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, gives information about
+  how to retrieve deleted files on ext2fs file systems.
+
+  To change the behavior of ext2 file systems, you can use the tune2fs
+  utility ("man tune2fs"). To modify attributes of files and
+  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 from
+  <ftp://ibiblio.org/pub/Linux/system/filesystems/ext2/>) and from
+  within Windows NT using the ext2nt command line tool package from
+  <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
+  <http://jnewbigin-pc.it.swin.edu.au/Linux/Explore2fs.htm>.
+
+  If you want to compile this file system 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 ext2.o.  Be aware however that the file system
+  of your root partition (the one containing the directory /) cannot
+  be compiled as a module, and so this could be dangerous.  Most
+  everyone wants to say Y here.
+
+CONFIG_EXT3_FS
+  This is the journaling version of the Second extended file system
+  (often called ext3), 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
+  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
+  is consistent without the need for a lengthy check.
+
+  Other than adding the journal to the file system, the on-disk format
+  of ext3 is identical to ext2.  It is possible to freely switch
+  between using the ext3 driver and the ext2 driver, as long as the
+  file system has been cleanly unmounted, or e2fsck is run on the file
+  system.
+
+  To add a journal on an existing ext2 file system or change the
+  behavior of ext3 file systems, you can use the tune2fs utility ("man
+  tune2fs").  To modify attributes of files and directories on ext3
+  file systems, use chattr ("man chattr").  You need to be using
+  e2fsprogs version 1.20 or later in order to create ext3 journals
+  (available at <http://sourceforge.net/projects/e2fsprogs/>).
+
+  If you want to compile this file system 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 ext3.o.  Be aware however that the file system
+  of your root partition (the one containing the directory /) cannot
+  be compiled as a module, and so this may be dangerous.
+
+CONFIG_JBD
+  This is a generic journaling 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.
+
+  If you are using the ext3 file system, you need to say Y here. If
+  you are not using ext3 then you will probably want to say N.
+
+  If you want to compile this device 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 jbd.o.  If you are compiling ext3 into the kernel,
+  you cannot compile this code as a module.
+
+CONFIG_JBD_DEBUG
+  If you are using the ext3 journaled file system (or potentially any
+  other file system/device using JBD), this option allows you to
+  enable debugging output while the system is running, in order to
+  help track down any problems you are having.  By default the
+  debugging output will be turned off.
+
+  If you select Y here, then you will be able to turn on debugging
+  with "echo N > /proc/sys/fs/jbd-debug", where N is a number between
+  1 and 5, the higher the number, the more debugging output is
+  generated.  To turn debugging off again, do
+  "echo 0 > /proc/sys/fs/jbd-debug".
+
+CONFIG_BFS_FS
+  Boot File System (BFS) is a file system used under SCO UnixWare to
+  allow the bootloader access to the kernel image and other important
+  files during the boot process.  It is usually mounted under /stand
+  and corresponds to the slice marked as "STAND" in the UnixWare
+  partition.  You should say Y if you want to read or write the files
+  on your /stand slice from within Linux.  You then also need to say Y
+  to "UnixWare slices support", below.  More information about the BFS
+  file system is contained in the file
+  <file:Documentation/filesystems/bfs.txt>.
+
+  If you don't know what this is about, say N.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called bfs.o.  Note that the file system of your root
+  partition (the one containing the directory /) cannot be compiled as
+  a module.
+
+CONFIG_CRAMFS
+  Saying Y here includes support for CramFs (Compressed ROM File
+  System).  CramFs is designed to be a simple, small, and compressed
+  file system for ROM based embedded systems.  CramFs is read-only,
+  limited to 256MB file systems (with 16MB files), and doesn't support
+  16/32 bits uid/gid, hard links and timestamps.
+
+  See <file:Documentation/filesystems/cramfs.txt> and
+  <file:fs/cramfs/README> for further information.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called cramfs.o.  Note that the root file system (the one
+  containing the directory /) cannot be compiled as a module.
+
+  If unsure, say N.
+
+CONFIG_TMPFS
+  Tmpfs is a file system which keeps all files in virtual memory.
+
+  In contrast to RAM disks, which get allocated a fixed amount of
+  physical RAM, tmpfs grows and shrinks to accommodate the files it
+  contains and is able to swap unneeded pages out to swap space.
+
+  Everything is "virtual" in the sense that no files will be created
+  on your hard drive; if you reboot, everything in tmpfs will be
+  lost.
+
+  You should mount the file system somewhere to be able to use
+  POSIX shared memory. Adding the following line to /etc/fstab should
+  take care of things:
+
+  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).
+
+  You can set limits for the number of blocks and inodes used by the
+  file system with the mount options "size", "nr_blocks" and
+  "nr_inodes". These parameters accept a suffix k, m or g for kilo,
+  mega and giga and can be changed on remount.
+
+  The initial permissions of the root directory can be set with the
+  mount option "mode".
+
+CONFIG_RAMFS
+  Ramfs is a file system which keeps all files in RAM. It allows
+  read and write access.
+
+  It is more of an programming example than a useable file system.  If
+  you need a file system which lives in RAM with limit checking use
+  tmpfs.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ramfs.o.
+
+CONFIG_ISO9660_FS
+  This is the standard file system used on CD-ROMs.  It was previously
+  known as "High Sierra File System" and is called "hsfs" on other
+  Unix systems.  The so-called Rock-Ridge extensions which allow for
+  long Unix filenames and symbolic links are also supported by this
+  driver.  If you have a CD-ROM drive and want to do more with it than
+  just listen to audio CDs and watch its LEDs, say Y (and read
+  <file:Documentation/filesystems/isofs.txt> and the CD-ROM-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>), thereby
+  enlarging your kernel by about 27 KB; otherwise say N.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called isofs.o.
+
+CONFIG_JOLIET
+  Joliet is a Microsoft extension for the ISO 9660 CD-ROM file system
+  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
+  want to be able to read Joliet CD-ROMs under Linux.
+
+CONFIG_ZISOFS
+  This is a Linux-specific extension to RockRidge which lets you store
+  data in compressed form on a CD-ROM and have it transparently
+  decompressed when the CD-ROM is accessed.  See
+  <http://www.kernel.org/pub/linux/utils/fs/zisofs/> for the tools
+  necessary to create such a filesystem.  Say Y here if you want to be
+  able to read such compressed CD-ROMs.
+
+CONFIG_UDF_FS
+  This is the new file system used on some CD-ROMs and DVDs. Say Y if
+  you intend to mount DVD discs or CDRW's written in packet mode, or
+  if written to by other UDF utilities, such as DirectCD. This UDF
+  file system support is read-only. If you want to write to UDF
+  file systems on some media, you need to say Y to "UDF read-write
+  support" below in addition. Please read
+  <file:Documentation/filesystems/udf.txt>.
+
+  This file system support 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 udf.o. If you want to
+  compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+  If unsure, say N.
+
+CONFIG_UDF_RW
+  Say Y if you want to test write support for UDF file systems.
+  Due to lack of support for writing to CDR/CDRW's, this option
+  is only supported for hard discs, DVD-RAM, and loopback files.
+
+CONFIG_FAT_FS
+  If you want to use one of the FAT-based file systems (the MS-DOS,
+  VFAT (Windows 95) and UMSDOS (used to run Linux on top of an
+  ordinary DOS partition) file systems), then you must say Y or M here
+  to include FAT support. You will then be able to mount partitions or
+  diskettes with FAT-based file systems and transparently access the
+  files on them, i.e. MSDOS files will look and behave just like all
+  other Unix files.
+
+  This FAT support is not a file system in itself, it only provides
+  the foundation for the other file systems. You will have to say Y or
+  M to at least one of "MSDOS fs support" or "VFAT fs support" in
+  order to make use of it.
+
+  Another way to read and write MSDOS floppies and hard drive
+  partitions from within Linux (but not transparently) is with the
+  mtools ("man mtools") program suite. You don't need to say Y here in
+  order to do that.
+
+  If you need to move large files on floppies between a DOS and a
+  Linux box, say Y here, mount the floppy under Linux with an MSDOS
+  file system and use GNU tar's M option. GNU tar is a program
+  available for Unix and DOS ("man tar" or "info tar").
+
+  It is now also becoming possible to read and write compressed FAT
+  file systems; read <file:Documentation/filesystems/fat_cvf.txt> for
+  details.
+
+  The FAT support will enlarge your kernel by about 37 KB. If unsure,
+  say Y.
+
+  If you want to compile this as a module however ( = 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 fat.o.  Note that if you compile the FAT
+  support as a module, you cannot compile any of the FAT-based file
+  systems into the kernel -- they will have to be modules as well.
+  The file system of your root partition (the one containing the
+  directory /) cannot be a module, so don't say M here if you intend
+  to use UMSDOS as your root file system.
+
+CONFIG_MSDOS_FS
+  This allows you to mount MSDOS partitions of your hard drive (unless
+  they are compressed; to access compressed MSDOS partitions under
+  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://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
+  other Unix files.
+
+  If you want to use UMSDOS, the Unix-like file system on top of a
+  DOS file system, which allows you to run Linux from within a DOS
+  partition without repartitioning, you'll have to say Y or M here.
+
+  If you have Windows 95 or Windows NT installed on your MSDOS
+  partitions, you should use the VFAT file system (say Y to "VFAT fs
+  support" below), or you will not be able to see the long filenames
+  generated by Windows 95 / Windows NT.
+
+  This option will enlarge your kernel by about 7 KB. If unsure,
+  answer Y. This will only work if you said Y to "DOS FAT fs support"
+  as well. If you want to compile this as a module however ( = 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 msdos.o.
+
+CONFIG_VFAT_FS
+  This option provides support for normal Windows file systems with
+  long filenames.  That includes non-compressed FAT-based file systems
+  used by Windows 95, Windows 98, Windows NT 4.0, and the Unix
+  programs from the mtools package.
+
+  You cannot use the VFAT file system for your Linux root partition
+  (the one containing the directory /); use UMSDOS instead if you
+  want to run Linux from within a DOS partition (i.e. say Y to
+  "Unix like fs on top of std MSDOS fs", below).
+
+  The VFAT support enlarges your kernel by about 10 KB and it only
+  works if you said Y to the "DOS FAT fs support" above.  Please read
+  the file <file:Documentation/filesystems/vfat.txt> for details.  If
+  unsure, say Y.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called vfat.o.
+
+CONFIG_UMSDOS_FS
+  Say Y here if you want to run Linux from within an existing DOS
+  partition of your hard drive. The advantage of this is that you can
+  get away without repartitioning your hard drive (which often implies
+  backing everything up and restoring afterwards) and hence you're
+  able to quickly try out Linux or show it to your friends; the
+  disadvantage is that Linux becomes susceptible to DOS viruses and
+  that UMSDOS is somewhat slower than ext2fs.  Another use of UMSDOS
+  is to write files with long unix filenames to MSDOS floppies; it
+  also allows Unix-style soft-links and owner/permissions of files on
+  MSDOS floppies.  You will need a program called umssync in order to
+  make use of UMSDOS; read
+  <file:Documentation/filesystems/umsdos.txt>.
+
+  To get utilities for initializing/checking UMSDOS file system, or
+  latest patches and/or information, visit the UMSDOS home page at
+  <http://www.voyager.hr/~mnalis/umsdos/>.
+
+  This option enlarges your kernel by about 28 KB and it only works if
+  you said Y to both "DOS FAT fs support" and "MSDOS fs support"
+  above.  If you want to compile this as a module ( = code which can
+  be inserted in and removed from the running kernel whenever you
+  want), say M here and read <file:Documentation/modules.txt>.  The
+  module will be called umsdos.o.  Note that the file system of your
+  root partition (the one containing the directory /) cannot be a
+  module, so saying M could be dangerous.  If unsure, say N.
+
+CONFIG_PROC_FS
+  This is a virtual file system providing information about the status
+  of the system. "Virtual" means that it doesn't take up any space on
+  your hard disk: the files are created on the fly by the kernel when
+  you try to access them. Also, you cannot read the files with older
+  version of the program less: you need to use more or cat.
+
+  It's totally cool; for example, "cat /proc/interrupts" gives
+  information about what the different IRQs are used for at the moment
+  (there is a small number of Interrupt ReQuest lines in your computer
+  that are used by the attached devices to gain the CPU's attention --
+  often a source of trouble if two devices are mistakenly configured
+  to use the same IRQ). The program procinfo to display some
+  information about your system gathered from the /proc file system.
+
+  Before you can use the /proc file system, it has to be mounted,
+  meaning it has to be given a location in the directory hierarchy.
+  That location should be /proc. A command such as "mount -t proc proc
+  /proc" or the equivalent line in /etc/fstab does the job.
+
+  The /proc file system is explained in the file
+  <file:Documentation/filesystems/proc.txt> and on the proc(5) manpage
+  ("man 5 proc").
+
+  This option will enlarge your kernel by about 67 KB. Several
+  programs depend on this, so everyone should say Y here.
+
+CONFIG_DEVFS_FS
+  This is support for devfs, a virtual file system (like /proc) which
+  provides the file system interface to device drivers, normally found
+  in /dev. Devfs does not depend on major and minor number
+  allocations. Device drivers register entries in /dev which then
+  appear automatically, which means that the system administrator does
+  not have to create character and block special device files in the
+  /dev directory using the mknod command (or MAKEDEV script) anymore.
+
+  This is work in progress. If you want to use this, you *must* read
+  the material in <file:Documentation/filesystems/devfs/>, especially
+  the file README there.
+
+  If unsure, say N.
+
+CONFIG_DEVFS_MOUNT
+  This option appears if you have CONFIG_DEVFS_FS enabled. Setting
+  this to 'Y' will make the kernel automatically mount devfs onto /dev
+  when the system is booted, before the init thread is started.
+  You can override this with the "devfs=nomount" boot option.
+
+  If unsure, say N.
+
+CONFIG_DEVFS_DEBUG
+  If you say Y here, then the /dev file system code will generate
+  debugging messages. See the file
+  <file:Documentation/filesystems/devfs/boot-options> for more
+  details.
+
+  If unsure, say N.
+
+CONFIG_NFS_FS
+  If you are connected to some other (usually local) Unix computer
+  (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing
+  on that computer (the NFS server) using the Network File Sharing
+  protocol, say Y. "Mounting files" means that the client can access
+  the files with usual UNIX commands as if they were sitting on the
+  client's hard disk. For this to work, the server must run the
+  programs nfsd and mountd (but does not need to have NFS file system
+  support enabled in its kernel). NFS is explained in the Network
+  Administrator's Guide, available from
+  <http://www.linuxdoc.org/docs.html#guide>, on its man page: "man
+  nfs", and in the NFS-HOWTO.
+
+  A superior but less widely used alternative to NFS is provided by
+  the Coda file system; see "Coda file system support" below.
+
+  If you say Y here, you should have said Y to TCP/IP networking also.
+  This option would enlarge your kernel by about 27 KB.
+
+  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 nfs.o. If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.
+
+  If you are configuring a diskless machine which will mount its root
+  file system over NFS at boot time, say Y here and to "Kernel
+  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, 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.
+
+CONFIG_NFS_V3
+  Say Y here if you want your NFS client to be able to speak the newer
+  version 3 of the NFS protocol.
+
+  If unsure, say N.
+
+CONFIG_ROOT_NFS
+  If you want your Linux box to mount its whole root file system (the
+  one containing the directory /) from some other computer over the
+  net via NFS (presumably because your box doesn't have a hard disk),
+  say Y. Read <file:Documentation/nfsroot.txt> for details. It is
+  likely that in this case, you also want to say Y to "Kernel level IP
+  autoconfiguration" so that your box can discover its network address
+  at boot time.
+
+  Most people say N here.
+
+CONFIG_NFSD
+  If you want your Linux box to act as an NFS *server*, so that other
+  computers on your local network which support NFS can access certain
+  directories on your box transparently, you have two options: you can
+  use the self-contained user space program nfsd, in which case you
+  should say N here, or you can say Y and use the kernel based NFS
+  server. The advantage of the kernel based solution is that it is
+  faster.
+
+  In either case, you will need support software; the respective
+  locations are given in the file <file:Documentation/Changes> in the
+  NFS section.
+
+  If you say Y here, you will get support for version 2 of the NFS
+  protocol (NFSv2). If you also want NFSv3, say Y to the next question
+  as well.
+
+  Please read the NFS-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  The NFS server is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module is called nfsd.o.  If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.  If unsure,
+  say N.
+
+CONFIG_NFSD_V3
+  If you would like to include the NFSv3 server as well as the NFSv2
+  server, say Y here.  If unsure, say Y.
+
+CONFIG_HPFS_FS
+  OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS
+  is the file system used for organizing files on OS/2 hard disk
+  partitions. Say Y if you want to be able to read files from and
+  write files to an OS/2 HPFS partition on your hard drive. OS/2
+  floppies however are in regular MSDOS format, so you don't need this
+  option in order to be able to read them. Read
+  <file:Documentation/filesystems/hpfs.txt>.
+
+  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 hpfs.o.  If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.  If unsure,
+  say N.
+
+CONFIG_NTFS_FS
+  NTFS is the file system of Microsoft Windows NT. Say Y if you want
+  to get read access to files on NTFS partitions of your hard drive.
+  The Linux NTFS driver supports most of the mount options of the VFAT
+  driver, see <file:Documentation/filesystems/ntfs.txt>. Saying Y here
+  will give you read-only access to NTFS partitions.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ntfs.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_NTFS_RW
+  If you say Y here, you will (maybe) be able to write to NTFS file
+  systems as well as read from them. The read-write support in NTFS
+  is far from being complete and is not well tested. If you say Y
+  here, back up your NTFS volume first, since it will probably get
+  damaged. Also, download the Linux-NTFS project distribution from
+  Sourceforge at <http://linux-ntfs.sf.net/> and always run the
+  included ntfsfix utility after writing to an NTFS partition from
+  Linux to fix some of the damage done by the driver. You should run
+  ntfsfix _after_ unmounting the partition in Linux but _before_
+  rebooting into Windows. When Windows next boots, chkdsk will be
+  run automatically to fix the remaining damage.
+  Please note that write support is limited to Windows NT4 and
+  earlier versions.
+
+  If unsure, say N.
+
+CONFIG_SYSV_FS
+  SCO, Xenix and Coherent are commercial Unix systems for Intel
+  machines, and Version 7 was used on the DEC PDP-11. Saying Y
+  here would allow you to read from their floppies and hard disk
+  partitions.
+
+  If you have floppies or hard disk partitions like that, it is likely
+  that they contain binaries from those other Unix systems; in order
+  to run these binaries, you will want to install linux-abi which is a
+  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/>).
+  NOTE: that will work only for binaries from Intel-based systems;
+  PDP ones will have to wait until somebody ports Linux to -11 ;-)
+
+  If you only intend to mount files from some other Unix over the
+  network using NFS, you don't need the System V file system support
+  (but you need NFS file system support obviously).
+
+  Note that this option is generally not needed for floppies, since a
+  good portable way to transport files and directories between unixes
+  (and even other operating systems) is given by the tar program ("man
+  tar" or preferably "info tar").  Note also that this option has
+  nothing whatsoever to do with the option "System V IPC". Read about
+  the System V file system in
+  <file:Documentation/filesystems/sysv-fs.txt>.
+  Saying Y here will enlarge your kernel by about 27 KB.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called sysv.o.
+
+  If you haven't heard about all of this before, it's safe to say N.
+
+CONFIG_AFFS_FS
+  The Fast File System (FFS) is the common file system used on hard
+  disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20).  Say Y
+  if you want to be able to read and write files from and to an Amiga
+  FFS partition on your hard drive.  Amiga floppies however cannot be
+  read with this driver due to an incompatibility of the floppy
+  controller used in an Amiga and the standard floppy controller in
+  PCs and workstations. Read <file:Documentation/filesystems/affs.txt>
+  and <file:fs/affs/Changes>.
+
+  With this driver you can also mount disk files used by Bernd
+  Schmidt's Un*X Amiga Emulator
+  (<http://www.freiburg.linux.de/~uae/>).
+  If you want to do this, you will also need to say Y or M to "Loop
+  device support", above.
+
+  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 affs.o.  If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.  If unsure,
+  say N.
+
+CONFIG_HFS_FS
+  If you say Y here, you will be able to mount Macintosh-formatted
+  floppy disks and hard drive partitions with full read-write access.
+  Please read <file:fs/hfs/HFS.txt> to learn about the available mount
+  options.
+
+  This file system support 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 hfs.o.  If you want to
+  compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+CONFIG_ROMFS_FS
+  This is a very small read-only file system mainly intended for
+  initial ram disks of installation disks, but it could be used for
+  other read-only media as well.  Read
+  <file:Documentation/filesystems/romfs.txt> for details.
+
+  This file system support 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 romfs.o.  If you want to
+  compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  Note that the file system of your
+  root partition (the one containing the directory /) cannot be a
+  module.
+
+  If you don't know whether you need it, then you don't need it:
+  answer N.
+
+CONFIG_QNX4FS_FS
+  This is the file system used by the operating system QNX 4. Say Y if
+  you intend to mount QNX hard disks or floppies. Unless you say Y to
+  "QNX4FS read-write support" below, you will only be able to read
+  these file systems.
+
+  This file system support 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 qnx4.o. If you want to
+  compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+  If you don't know whether you need it, then you don't need it:
+  answer N.
+
+CONFIG_QNX4FS_RW
+  Say Y if you want to test write support for QNX4 file systems.
+
+CONFIG_AUTOFS_FS
+  The automounter is a tool to automatically mount remote file systems
+  on demand. This implementation is partially kernel-based to reduce
+  overhead in the already-mounted case; this is unlike the BSD
+  automounter (amd), which is a pure user space daemon.
+
+  To use the automounter you need the user-space tools from the autofs
+  package; you can find the location in <file:Documentation/Changes>.
+  You also want to answer Y to "NFS file system support", below.
+
+  If you want to use the newer version of the automounter with more
+  features, say N here and say Y to "Kernel automounter v4 support",
+  below.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called autofs.o.
+
+  If you are not a part of a fairly large, distributed network, you
+  probably do not need an automounter, and can say N here.
+
+CONFIG_AUTOFS4_FS
+  The automounter is a tool to automatically mount remote file systems
+  on demand. This implementation is partially kernel-based to reduce
+  overhead in the already-mounted case; this is unlike the BSD
+  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
+  want to answer Y to "NFS file system support", below.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called autofs4.o.  You will need to add "alias autofs
+  autofs4" to your modules configuration file.
+
+  If you are not a part of a fairly large, distributed network or
+  don't have a laptop which needs to dynamically reconfigure to the
+  local network, you probably do not need an automounter, and can say
+  N here.
+
+CONFIG_EFS_FS
+  EFS is an older file system used for non-ISO9660 CD-ROMs and hard
+  disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer
+  uses the XFS file system for hard disk partitions however).
+
+  This implementation only offers read-only access. If you don't know
+  what all this is about, it's safe to say N. For more information
+  about EFS see its home page at <http://aeschi.ch.eu.org/efs/>.
+
+  If you want to compile the EFS file system 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 efs.o.
+
+CONFIG_JFFS_FS
+  JFFS is the Journaling 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/>).
+
+CONFIG_JFFS_FS_VERBOSE
+  Determines the verbosity level of the JFFS debugging messages.
+
+CONFIG_JFFS2_FS
+  JFFS2 is the second generation of the Journalling Flash File System
+  for use on diskless embedded devices. It provides improved wear
+  levelling, compression and support for hard links. You cannot use
+  this on normal block devices, only on 'MTD' devices.
+
+  Further information should be made available soon at
+  <http://sources.redhat.com/jffs2/>.
+
+CONFIG_JFFS2_FS_DEBUG
+  This controls the amount of debugging messages produced by the JFFS2
+  code. Set it to zero for use in production systems. For evaluation,
+  testing and debugging, it's advisable to set it to one. This will
+  enable a few assertions and will print debugging messages at the
+  KERN_DEBUG loglevel, where they won't normally be visible. Level 2
+  is unlikely to be useful - it enables extra debugging in certain
+  areas which at one point needed debugging, but when the bugs were
+  located and fixed, the detailed messages were relegated to level 2.
+
+  If reporting bugs, please try to have available a full dump of the
+  messages at debug level 1 while the misbehaviour was occurring.
+
+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.
+
+CONFIG_UFS_FS
+  BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD,
+  OpenBSD and NeXTstep) use a file system called UFS. Some System V
+  Unixes can create and mount hard disk partitions and diskettes using
+  this file system as well. Saying Y here will allow you to read from
+  these partitions; if you also want to write to them, say Y to the
+  experimental "UFS file system write support", below. Please read the
+  file <file:Documentation/filesystems/ufs.txt> for more information.
+
+  If you only intend to mount files from some other Unix over the
+  network using NFS, you don't need the UFS file system support (but
+  you need NFS file system support obviously).
+
+  Note that this option is generally not needed for floppies, since a
+  good portable way to transport files and directories between unixes
+  (and even other operating systems) is given by the tar program ("man
+  tar" or preferably "info tar").
+
+  When accessing NeXTstep files, you may need to convert them from the
+  NeXT character set to the Latin1 character set; use the program
+  recode ("info recode") for this purpose.
+
+  If you want to compile the UFS file system 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 ufs.o.
+
+  If you haven't heard about all of this before, it's safe to say N.
+
+CONFIG_UFS_FS_WRITE
+  Say Y here if you want to try writing to UFS partitions. This is
+  experimental, so you should back up your UFS partitions beforehand.
+
+CONFIG_ADFS_FS
+  The Acorn Disc Filing System is the standard file system of the
+  RiscOS operating system which runs on Acorn's ARM-based Risc PC
+  systems and the Acorn Archimedes range of machines. If you say Y
+  here, Linux will be able to read from ADFS partitions on hard drives
+  and from ADFS-formatted floppy discs. If you also want to be able to
+  write to those devices, say Y to "ADFS write support" below.
+
+  The ADFS partition should be the first partition (i.e.,
+  /dev/[hs]d?1) on each of your drives. Please read the file
+  <file:Documentation/filesystems/adfs.txt> for further details.
+
+  This code is also available as a module called adfs.o ( = 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>.
+
+  If unsure, say N.
+
+CONFIG_ADFS_FS_RW
+  If you say Y here, you will be able to write to ADFS partitions on
+  hard drives and ADFS-formatted floppy disks. This is experimental
+  codes, so if you're unsure, say N.
+
+CONFIG_DEVPTS_FS
+  You should say Y here if you said Y to "Unix98 PTY support" above.
+  You'll then get a virtual file system which can be mounted on
+  /dev/pts with "mount -t devpts". This, together with the pseudo
+  terminal master multiplexer /dev/ptmx, is used for pseudo terminal
+  support as described in The Open Group's Unix98 standard: in order
+  to acquire a pseudo terminal, a process opens /dev/ptmx; the number
+  of the pseudo terminal is then made available to the process and the
+  pseudo terminal slave can be accessed as /dev/pts/<number>. What was
+  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
+
+  The GNU C library glibc 2.1 contains the requisite support for this
+  mode of operation; you also need client programs that use the Unix98
+  API. Please read <file:Documentation/Changes> for more information
+  about the Unix98 pty devices.
+
+  Note that the experimental "/dev file system support"
+  (CONFIG_DEVFS_FS)  is a more general facility.
+
+CONFIG_VXFS_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 file system 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.
+
+CONFIG_SMB_FS
+  SMB (Server Message Block) is the protocol Windows for Workgroups
+  (WfW), Windows 95/98, Windows NT and OS/2 Lan Manager use to share
+  files and printers over local networks.  Saying Y here allows you to
+  mount their file systems (often called "shares" in this context) and
+  access them just like any other Unix directory.  Currently, this
+  works only if the Windows machines use TCP/IP as the underlying
+  transport protocol, and not NetBEUI.  For details, read
+  <file:Documentation/filesystems/smbfs.txt> and the SMB-HOWTO,
+  available from <http://www.linuxdoc.org/docs.html#howto>.
+
+  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 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>.
+
+  If you want to compile the SMB 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 smbfs.o.  Most people say N, however.
+
+CONFIG_SMB_NLS_DEFAULT
+  Enabling this will make smbfs use nls translations by default. You
+  need to specify the local charset (CONFIG_NLS_DEFAULT) in the nls
+  settings and you need to give the default nls for the SMB server as
+  CONFIG_SMB_NLS_REMOTE.
+
+  The nls settings can be changed at mount time, if your smbmount
+  supports that, using the codepage and iocharset parameters.
+
+  smbmount from samba 2.2.0 or later supports this.
+
+CONFIG_SMB_NLS_REMOTE
+  This setting allows you to specify a default value for which
+  codepage the server uses. If this field is left blank no
+  translations will be done by default. The local codepage/charset
+  default to CONFIG_NLS_DEFAULT.
+
+  The nls settings can be changed at mount time, if your smbmount
+  supports that, using the codepage and iocharset parameters.
+
+  smbmount from samba 2.2.0 or later supports this.
+
+CONFIG_CODA_FS
+  Coda is an advanced network file system, similar to NFS in that it
+  enables you to mount file systems of a remote server and access them
+  with regular Unix commands as if they were sitting on your hard
+  disk.  Coda has several advantages over NFS: support for
+  disconnected operation (e.g. for laptops), read/write server
+  replication, security model for authentication and encryption,
+  persistent client caches and write back caching.
+
+  If you say Y here, your Linux box will be able to act as a Coda
+  *client*.  You will need user level code as well, both for the
+  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/>.
+
+  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.
+
+CONFIG_INTERMEZZO_FS
+  InterMezzo is a networked file system with disconnected operation
+  and kernel level write back caching.  It is most often used for
+  replicating potentially large trees or keeping laptop/desktop copies
+  in sync.
+
+  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/>.
+
+CONFIG_NCP_FS
+  NCP (NetWare Core Protocol) is a protocol that runs over IPX and is
+  used by Novell NetWare clients to talk to file servers.  It is to
+  IPX what NFS is to TCP/IP, if that helps.  Saying Y here allows you
+  to mount NetWare file server volumes and to access them just like
+  any other Unix directory.  For details, please read the file
+  <file:Documentation/filesystems/ncpfs.txt> in the kernel source and
+  the IPX-HOWTO from <http://www.linuxdoc.org/docs.html#howto>.
+
+  You do not have to say Y here if you want your Linux box to act as a
+  file *server* for Novell NetWare clients.
+
+  General information about how to connect Linux, Windows machines and
+  Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ncpfs.o.  Say N unless you are connected to a Novell
+  network.
+
+CONFIG_NCPFS_NLS
+  Allows you to use codepages and I/O charsets for file name
+  translation between the server file system and input/output. This
+  may be useful, if you want to access the server with other operating
+  systems, e.g. Windows 95. See also NLS for more Information.
+
+  To select codepages and I/O charsets use ncpfs-2.2.0.13 or newer.
+
diff -u --recursive --new-file v2.5.2/linux/fs/Config.in linux/fs/Config.in
--- v2.5.2/linux/fs/Config.in	Mon Jan 14 18:25:10 2002
+++ linux/fs/Config.in	Tue Jan 29 21:30:41 2002
@@ -31,7 +31,10 @@
 # msdos file systems
 tristate 'DOS FAT fs support' CONFIG_FAT_FS
 dep_tristate '  MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
-dep_tristate '    UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+#dep_tristate '    UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+# UMSDOS is temprory broken
+define_bool CONFIG_UMSDOS_FS n
+
 dep_tristate '  VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
 dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL
 dep_tristate 'Journalling Flash File System (JFFS) support' CONFIG_JFFS_FS $CONFIG_MTD
@@ -138,22 +141,10 @@
    define_bool CONFIG_SMB_FS n
 fi
 
-#
-# Do we need the compression support?
-#
 if [ "$CONFIG_ZISOFS" = "y" ]; then
    define_tristate CONFIG_ZISOFS_FS $CONFIG_ISO9660_FS
 else
    define_tristate CONFIG_ZISOFS_FS n
-fi
-if [ "$CONFIG_CRAMFS" = "y" -o "$CONFIG_ZISOFS_FS" = "y" ]; then
-   define_tristate CONFIG_ZLIB_FS_INFLATE y
-else
-  if [ "$CONFIG_CRAMFS" = "m" -o "$CONFIG_ZISOFS_FS" = "m" ]; then
-     define_tristate CONFIG_ZLIB_FS_INFLATE m
-  else
-     define_tristate CONFIG_ZLIB_FS_INFLATE n
-  fi
 fi
 
 mainmenu_option next_comment
diff -u --recursive --new-file v2.5.2/linux/fs/Makefile linux/fs/Makefile
--- v2.5.2/linux/fs/Makefile	Tue Dec 18 14:56:39 2001
+++ linux/fs/Makefile	Tue Jan 29 21:30:41 2002
@@ -14,7 +14,7 @@
 		bio.o super.o block_dev.o char_dev.o stat.o exec.o pipe.o \
 		namei.o fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
 		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
-		filesystems.o namespace.o seq_file.o
+		filesystems.o namespace.o seq_file.o xattr.o
 
 ifeq ($(CONFIG_QUOTA),y)
 obj-y += dquot.o
@@ -30,7 +30,6 @@
 subdir-$(CONFIG_EXT3_FS)	+= ext3    # Before ext2 so root fs can be ext3
 subdir-$(CONFIG_JBD)		+= jbd
 subdir-$(CONFIG_EXT2_FS)	+= ext2
-subdir-$(CONFIG_ZLIB_FS_INFLATE) += inflate_fs
 subdir-$(CONFIG_CRAMFS)		+= cramfs
 subdir-$(CONFIG_RAMFS)		+= ramfs
 subdir-$(CONFIG_CODA_FS)	+= coda
diff -u --recursive --new-file v2.5.2/linux/fs/Makefile.lib linux/fs/Makefile.lib
--- v2.5.2/linux/fs/Makefile.lib	Mon Jan 14 18:25:10 2002
+++ linux/fs/Makefile.lib	Tue Jan 15 14:15:53 2002
@@ -1,2 +1,2 @@
-obj-$(CONFIG_FS_JFFS2)		+= crc32.o
+obj-$(CONFIG_JFFS2_FS)		+= crc32.o
 obj-$(CONFIG_EFI_PARTITION)	+= crc32.o
diff -u --recursive --new-file v2.5.2/linux/fs/adfs/dir.c linux/fs/adfs/dir.c
--- v2.5.2/linux/fs/adfs/dir.c	Mon Sep 18 15:14:06 2000
+++ linux/fs/adfs/dir.c	Mon Jan 28 13:20:44 2002
@@ -146,9 +146,9 @@
 	if (ret)
 		goto out;
 
-	if (inode->u.adfs_i.parent_id != dir.parent_id) {
+	if (ADFS_I(inode)->parent_id != dir.parent_id) {
 		adfs_error(sb, "parent directory changed under me! (%lx but got %lx)\n",
-			   inode->u.adfs_i.parent_id, dir.parent_id);
+			   ADFS_I(inode)->parent_id, dir.parent_id);
 		ret = -EIO;
 		goto free_out;
 	}
diff -u --recursive --new-file v2.5.2/linux/fs/adfs/inode.c linux/fs/adfs/inode.c
--- v2.5.2/linux/fs/adfs/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/adfs/inode.c	Mon Jan 28 13:20:44 2002
@@ -65,7 +65,7 @@
 static int adfs_prepare_write(struct file *file, struct page *page, unsigned int from, unsigned int to)
 {
 	return cont_prepare_write(page, from, to, adfs_get_block,
-		&page->mapping->host->u.adfs_i.mmu_private);
+		&ADFS_I(page->mapping->host)->mmu_private);
 }
 
 static int _adfs_bmap(struct address_space *mapping, long block)
@@ -87,8 +87,8 @@
 {
 	unsigned int type;
 
-	if (inode->u.adfs_i.stamped)
-		type = (inode->u.adfs_i.loadaddr >> 8) & 0xfff;
+	if (ADFS_I(inode)->stamped)
+		type = (ADFS_I(inode)->loadaddr >> 8) & 0xfff;
 	else
 		type = (unsigned int) -1;
 
@@ -101,7 +101,7 @@
 static umode_t
 adfs_atts2mode(struct super_block *sb, struct inode *inode)
 {
-	unsigned int filetype, attr = inode->u.adfs_i.attr;
+	unsigned int filetype, attr = ADFS_I(inode)->attr;
 	umode_t mode, rmask;
 
 	if (attr & ADFS_NDA_DIRECTORY) {
@@ -151,7 +151,7 @@
 
 	/* FIXME: should we be able to alter a link? */
 	if (S_ISLNK(inode->i_mode))
-		return inode->u.adfs_i.attr;
+		return ADFS_I(inode)->attr;
 
 	if (S_ISDIR(inode->i_mode))
 		attr = ADFS_NDA_DIRECTORY;
@@ -183,11 +183,11 @@
 {
 	unsigned int high, low;
 
-	if (inode->u.adfs_i.stamped == 0)
+	if (ADFS_I(inode)->stamped == 0)
 		return CURRENT_TIME;
 
-	high = inode->u.adfs_i.loadaddr << 24;
-	low  = inode->u.adfs_i.execaddr;
+	high = ADFS_I(inode)->loadaddr << 24;
+	low  = ADFS_I(inode)->execaddr;
 
 	high |= low >> 8;
 	low  &= 255;
@@ -216,14 +216,14 @@
 {
 	unsigned int high, low;
 
-	if (inode->u.adfs_i.stamped) {
+	if (ADFS_I(inode)->stamped) {
 		/* convert 32-bit seconds to 40-bit centi-seconds */
 		low  = (secs & 255) * 100;
 		high = (secs / 256) * 100 + (low >> 8) + 0x336e996a;
 
-		inode->u.adfs_i.loadaddr = (high >> 24) |
-				(inode->u.adfs_i.loadaddr & ~0xff);
-		inode->u.adfs_i.execaddr = (low & 255) | (high << 8);
+		ADFS_I(inode)->loadaddr = (high >> 24) |
+				(ADFS_I(inode)->loadaddr & ~0xff);
+		ADFS_I(inode)->execaddr = (low & 255) | (high << 8);
 	}
 }
 
@@ -263,11 +263,11 @@
 	 * for this file.  This will need special handling
 	 * for cross-directory renames.
 	 */
-	inode->u.adfs_i.parent_id = obj->parent_id;
-	inode->u.adfs_i.loadaddr  = obj->loadaddr;
-	inode->u.adfs_i.execaddr  = obj->execaddr;
-	inode->u.adfs_i.attr      = obj->attr;
-	inode->u.adfs_i.stamped	  = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
+	ADFS_I(inode)->parent_id = obj->parent_id;
+	ADFS_I(inode)->loadaddr  = obj->loadaddr;
+	ADFS_I(inode)->execaddr  = obj->execaddr;
+	ADFS_I(inode)->attr      = obj->attr;
+	ADFS_I(inode)->stamped	  = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
 
 	inode->i_mode	 = adfs_atts2mode(sb, inode);
 	inode->i_mtime	 =
@@ -281,7 +281,7 @@
 		inode->i_op	= &adfs_file_inode_operations;
 		inode->i_fop	= &adfs_file_operations;
 		inode->i_mapping->a_ops = &adfs_aops;
-		inode->u.adfs_i.mmu_private = inode->i_size;
+		ADFS_I(inode)->mmu_private = inode->i_size;
 	}
 
 	insert_inode_hash(inode);
@@ -335,7 +335,7 @@
 	if (ia_valid & ATTR_CTIME)
 		inode->i_ctime = attr->ia_ctime;
 	if (ia_valid & ATTR_MODE) {
-		inode->u.adfs_i.attr = adfs_mode2atts(sb, inode);
+		ADFS_I(inode)->attr = adfs_mode2atts(sb, inode);
 		inode->i_mode = adfs_atts2mode(sb, inode);
 	}
 
@@ -362,10 +362,10 @@
 	lock_kernel();
 	obj.file_id	= inode->i_ino;
 	obj.name_len	= 0;
-	obj.parent_id	= inode->u.adfs_i.parent_id;
-	obj.loadaddr	= inode->u.adfs_i.loadaddr;
-	obj.execaddr	= inode->u.adfs_i.execaddr;
-	obj.attr	= inode->u.adfs_i.attr;
+	obj.parent_id	= ADFS_I(inode)->parent_id;
+	obj.loadaddr	= ADFS_I(inode)->loadaddr;
+	obj.execaddr	= ADFS_I(inode)->execaddr;
+	obj.attr	= ADFS_I(inode)->attr;
 	obj.size	= inode->i_size;
 
 	adfs_dir_update(sb, &obj);
diff -u --recursive --new-file v2.5.2/linux/fs/adfs/super.c linux/fs/adfs/super.c
--- v2.5.2/linux/fs/adfs/super.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/adfs/super.c	Mon Jan 28 13:20:44 2002
@@ -232,7 +232,51 @@
 	return 0;
 }
 
+static kmem_cache_t *adfs_inode_cachep;
+
+static struct inode *adfs_alloc_inode(struct super_block *sb)
+{
+	struct adfs_inode_info *ei;
+	ei = (struct adfs_inode_info *)kmem_cache_alloc(adfs_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void adfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(adfs_inode_cachep, ADFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct adfs_inode_info *ei = (struct adfs_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	adfs_inode_cachep = kmem_cache_create("adfs_inode_cache",
+					     sizeof(struct adfs_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (adfs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(adfs_inode_cachep))
+		printk(KERN_INFO "adfs_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations adfs_sops = {
+	alloc_inode:	adfs_alloc_inode,
+	destroy_inode:	adfs_destroy_inode,
 	write_inode:	adfs_write_inode,
 	put_super:	adfs_put_super,
 	statfs:		adfs_statfs,
@@ -435,12 +479,23 @@
 
 static int __init init_adfs_fs(void)
 {
-	return register_filesystem(&adfs_fs_type);
+	int err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&adfs_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_adfs_fs(void)
 {
 	unregister_filesystem(&adfs_fs_type);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
--- v2.5.2/linux/fs/affs/amigaffs.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/affs/amigaffs.c	Mon Jan 21 15:37:32 2002
@@ -419,7 +419,7 @@
 void
 mode_to_prot(struct inode *inode)
 {
-	u32 prot = AFFS_INODE->i_protect;
+	u32 prot = AFFS_I(inode)->i_protect;
 	mode_t mode = inode->i_mode;
 
 	if (!(mode & S_IXUSR))
@@ -441,7 +441,7 @@
 	if (mode & S_IWOTH)
 		prot |= FIBF_OTR_WRITE;
 
-	AFFS_INODE->i_protect = prot;
+	AFFS_I(inode)->i_protect = prot;
 }
 
 void
diff -u --recursive --new-file v2.5.2/linux/fs/affs/bitmap.c linux/fs/affs/bitmap.c
--- v2.5.2/linux/fs/affs/bitmap.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/affs/bitmap.c	Mon Jan 21 15:37:32 2002
@@ -155,16 +155,16 @@
 
 	pr_debug("AFFS: balloc(inode=%lu,goal=%u): ", inode->i_ino, goal);
 
-	if (inode->u.affs_i.i_pa_cnt) {
-		pr_debug("%d\n", inode->u.affs_i.i_lastalloc+1);
-		inode->u.affs_i.i_pa_cnt--;
-		return ++inode->u.affs_i.i_lastalloc;
+	if (AFFS_I(inode)->i_pa_cnt) {
+		pr_debug("%d\n", AFFS_I(inode)->i_lastalloc+1);
+		AFFS_I(inode)->i_pa_cnt--;
+		return ++AFFS_I(inode)->i_lastalloc;
 	}
 
 	if (!goal || goal > AFFS_SB->s_partition_size) {
 		if (goal)
 			affs_warning(sb, "affs_balloc", "invalid goal %d", goal);
-		//if (!inode->u.affs_i.i_last_block)
+		//if (!AFFS_I(inode)->i_last_block)
 		//	affs_warning(sb, "affs_balloc", "no last alloc block");
 		goal = AFFS_SB->s_reserved;
 	}
@@ -233,16 +233,16 @@
 	bit = ffs(tmp) - 1;
 	blk += bit + AFFS_SB->s_reserved;
 	mask2 = mask = 1 << (bit & 31);
-	inode->u.affs_i.i_lastalloc = blk;
+	AFFS_I(inode)->i_lastalloc = blk;
 
 	/* prealloc as much as possible within this word */
 	while ((mask2 <<= 1)) {
 		if (!(tmp & mask2))
 			break;
-		inode->u.affs_i.i_pa_cnt++;
+		AFFS_I(inode)->i_pa_cnt++;
 		mask |= mask2;
 	}
-	bm->bm_free -= inode->u.affs_i.i_pa_cnt + 1;
+	bm->bm_free -= AFFS_I(inode)->i_pa_cnt + 1;
 
 	*data = cpu_to_be32(tmp & ~mask);
 
diff -u --recursive --new-file v2.5.2/linux/fs/affs/file.c linux/fs/affs/file.c
--- v2.5.2/linux/fs/affs/file.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/affs/file.c	Mon Jan 21 15:37:32 2002
@@ -62,8 +62,8 @@
 {
 	if (atomic_read(&filp->f_count) != 1)
 		return 0;
-	pr_debug("AFFS: open(%d)\n", AFFS_INODE->i_opencnt);
-	AFFS_INODE->i_opencnt++;
+	pr_debug("AFFS: open(%d)\n", AFFS_I(inode)->i_opencnt);
+	AFFS_I(inode)->i_opencnt++;
 	return 0;
 }
 
@@ -72,9 +72,9 @@
 {
 	if (atomic_read(&filp->f_count) != 0)
 		return 0;
-	pr_debug("AFFS: release(%d)\n", AFFS_INODE->i_opencnt);
-	AFFS_INODE->i_opencnt--;
-	if (!AFFS_INODE->i_opencnt)
+	pr_debug("AFFS: release(%d)\n", AFFS_I(inode)->i_opencnt);
+	AFFS_I(inode)->i_opencnt--;
+	if (!AFFS_I(inode)->i_opencnt)
 		affs_free_prealloc(inode);
 
 	return 0;
@@ -88,49 +88,49 @@
 	u32 lc_max;
 	int i, j, key;
 
-	if (!AFFS_INODE->i_lc) {
+	if (!AFFS_I(inode)->i_lc) {
 		char *ptr = (char *)get_zeroed_page(GFP_NOFS);
 		if (!ptr)
 			return -ENOMEM;
-		AFFS_INODE->i_lc = (u32 *)ptr;
-		AFFS_INODE->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2);
+		AFFS_I(inode)->i_lc = (u32 *)ptr;
+		AFFS_I(inode)->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2);
 	}
 
-	lc_max = AFFS_LC_SIZE << AFFS_INODE->i_lc_shift;
+	lc_max = AFFS_LC_SIZE << AFFS_I(inode)->i_lc_shift;
 
-	if (AFFS_INODE->i_extcnt > lc_max) {
+	if (AFFS_I(inode)->i_extcnt > lc_max) {
 		u32 lc_shift, lc_mask, tmp, off;
 
 		/* need to recalculate linear cache, start from old size */
-		lc_shift = AFFS_INODE->i_lc_shift;
-		tmp = (AFFS_INODE->i_extcnt / AFFS_LC_SIZE) >> lc_shift;
+		lc_shift = AFFS_I(inode)->i_lc_shift;
+		tmp = (AFFS_I(inode)->i_extcnt / AFFS_LC_SIZE) >> lc_shift;
 		for (; tmp; tmp >>= 1)
 			lc_shift++;
 		lc_mask = (1 << lc_shift) - 1;
 
 		/* fix idx and old size to new shift */
-		lc_idx >>= (lc_shift - AFFS_INODE->i_lc_shift);
-		AFFS_INODE->i_lc_size >>= (lc_shift - AFFS_INODE->i_lc_shift);
+		lc_idx >>= (lc_shift - AFFS_I(inode)->i_lc_shift);
+		AFFS_I(inode)->i_lc_size >>= (lc_shift - AFFS_I(inode)->i_lc_shift);
 
 		/* first shrink old cache to make more space */
-		off = 1 << (lc_shift - AFFS_INODE->i_lc_shift);
+		off = 1 << (lc_shift - AFFS_I(inode)->i_lc_shift);
 		for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off)
-			AFFS_INODE->i_ac[i] = AFFS_INODE->i_ac[j];
+			AFFS_I(inode)->i_ac[i] = AFFS_I(inode)->i_ac[j];
 
-		AFFS_INODE->i_lc_shift = lc_shift;
-		AFFS_INODE->i_lc_mask = lc_mask;
+		AFFS_I(inode)->i_lc_shift = lc_shift;
+		AFFS_I(inode)->i_lc_mask = lc_mask;
 	}
 
 	/* fill cache to the needed index */
-	i = AFFS_INODE->i_lc_size;
-	AFFS_INODE->i_lc_size = lc_idx + 1;
+	i = AFFS_I(inode)->i_lc_size;
+	AFFS_I(inode)->i_lc_size = lc_idx + 1;
 	for (; i <= lc_idx; i++) {
 		if (!i) {
-			AFFS_INODE->i_lc[0] = inode->i_ino;
+			AFFS_I(inode)->i_lc[0] = inode->i_ino;
 			continue;
 		}
-		key = AFFS_INODE->i_lc[i - 1];
-		j = AFFS_INODE->i_lc_mask + 1;
+		key = AFFS_I(inode)->i_lc[i - 1];
+		j = AFFS_I(inode)->i_lc_mask + 1;
 		// unlock cache
 		for (; j > 0; j--) {
 			bh = affs_bread(sb, key);
@@ -140,7 +140,7 @@
 			affs_brelse(bh);
 		}
 		// lock cache
-		AFFS_INODE->i_lc[i] = key;
+		AFFS_I(inode)->i_lc[i] = key;
 	}
 
 	return 0;
@@ -182,7 +182,7 @@
 	affs_adjust_checksum(bh, blocknr - tmp);
 	mark_buffer_dirty_inode(bh, inode);
 
-	AFFS_INODE->i_extcnt++;
+	AFFS_I(inode)->i_extcnt++;
 	mark_inode_dirty(inode);
 
 	return new_bh;
@@ -192,8 +192,8 @@
 affs_get_extblock(struct inode *inode, u32 ext)
 {
 	/* inline the simplest case: same extended block as last time */
-	struct buffer_head *bh = AFFS_INODE->i_ext_bh;
-	if (ext == AFFS_INODE->i_ext_last)
+	struct buffer_head *bh = AFFS_I(inode)->i_ext_bh;
+	if (ext == AFFS_I(inode)->i_ext_last)
 		atomic_inc(&bh->b_count);
 	else
 		/* we have to do more (not inlined) */
@@ -211,13 +211,13 @@
 	u32 lc_idx, lc_off, ac_idx;
 	u32 tmp, idx;
 
-	if (ext == AFFS_INODE->i_ext_last + 1) {
+	if (ext == AFFS_I(inode)->i_ext_last + 1) {
 		/* read the next extended block from the current one */
-		bh = AFFS_INODE->i_ext_bh;
+		bh = AFFS_I(inode)->i_ext_bh;
 		ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
-		if (ext < AFFS_INODE->i_extcnt)
+		if (ext < AFFS_I(inode)->i_extcnt)
 			goto read_ext;
-		if (ext > AFFS_INODE->i_extcnt)
+		if (ext > AFFS_I(inode)->i_extcnt)
 			BUG();
 		bh = affs_alloc_extblock(inode, bh, ext);
 		if (IS_ERR(bh))
@@ -231,11 +231,11 @@
 		goto read_ext;
 	}
 
-	if (ext >= AFFS_INODE->i_extcnt) {
+	if (ext >= AFFS_I(inode)->i_extcnt) {
 		struct buffer_head *prev_bh;
 
 		/* allocate a new extended block */
-		if (ext > AFFS_INODE->i_extcnt)
+		if (ext > AFFS_I(inode)->i_extcnt)
 			BUG();
 
 		/* get previous extended block */
@@ -251,10 +251,10 @@
 
 again:
 	/* check if there is an extended cache and whether it's large enough */
-	lc_idx = ext >> AFFS_INODE->i_lc_shift;
-	lc_off = ext & AFFS_INODE->i_lc_mask;
+	lc_idx = ext >> AFFS_I(inode)->i_lc_shift;
+	lc_off = ext & AFFS_I(inode)->i_lc_mask;
 
-	if (lc_idx >= AFFS_INODE->i_lc_size) {
+	if (lc_idx >= AFFS_I(inode)->i_lc_size) {
 		int err;
 
 		err = affs_grow_extcache(inode, lc_idx);
@@ -265,14 +265,14 @@
 
 	/* every n'th key we find in the linear cache */
 	if (!lc_off) {
-		ext_key = AFFS_INODE->i_lc[lc_idx];
+		ext_key = AFFS_I(inode)->i_lc[lc_idx];
 		goto read_ext;
 	}
 
 	/* maybe it's still in the associative cache */
 	ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK;
-	if (AFFS_INODE->i_ac[ac_idx].ext == ext) {
-		ext_key = AFFS_INODE->i_ac[ac_idx].key;
+	if (AFFS_I(inode)->i_ac[ac_idx].ext == ext) {
+		ext_key = AFFS_I(inode)->i_ac[ac_idx].key;
 		goto read_ext;
 	}
 
@@ -281,14 +281,14 @@
 	idx = ac_idx;
 	while (--tmp, --lc_off > 0) {
 		idx = (idx - 1) & AFFS_AC_MASK;
-		if (AFFS_INODE->i_ac[idx].ext == tmp) {
-			ext_key = AFFS_INODE->i_ac[idx].key;
+		if (AFFS_I(inode)->i_ac[idx].ext == tmp) {
+			ext_key = AFFS_I(inode)->i_ac[idx].key;
 			goto find_ext;
 		}
 	}
 
 	/* fall back to the linear cache */
-	ext_key = AFFS_INODE->i_lc[lc_idx];
+	ext_key = AFFS_I(inode)->i_lc[lc_idx];
 find_ext:
 	/* read all extended blocks until we find the one we need */
 	//unlock cache
@@ -304,8 +304,8 @@
 
 	/* store it in the associative cache */
 	// recalculate ac_idx?
-	AFFS_INODE->i_ac[ac_idx].ext = ext;
-	AFFS_INODE->i_ac[ac_idx].key = ext_key;
+	AFFS_I(inode)->i_ac[ac_idx].ext = ext;
+	AFFS_I(inode)->i_ac[ac_idx].key = ext_key;
 
 read_ext:
 	/* finally read the right extended block */
@@ -317,9 +317,9 @@
 
 store_ext:
 	/* release old cached extended block and store the new one */
-	affs_brelse(AFFS_INODE->i_ext_bh);
-	AFFS_INODE->i_ext_last = ext;
-	AFFS_INODE->i_ext_bh = bh;
+	affs_brelse(AFFS_I(inode)->i_ext_bh);
+	AFFS_I(inode)->i_ext_last = ext;
+	AFFS_I(inode)->i_ext_bh = bh;
 	atomic_inc(&bh->b_count);
 
 	return bh;
@@ -341,8 +341,8 @@
 	if (block < 0)
 		goto err_small;
 
-	if (block >= AFFS_INODE->i_blkcnt) {
-		if (block > AFFS_INODE->i_blkcnt || !create)
+	if (block >= AFFS_I(inode)->i_blkcnt) {
+		if (block > AFFS_I(inode)->i_blkcnt || !create)
 			goto err_big;
 	} else
 		create = 0;
@@ -362,8 +362,8 @@
 		if (!blocknr)
 			goto err_alloc;
 		bh_result->b_state |= (1UL << BH_New);
-		AFFS_INODE->mmu_private += AFFS_SB->s_data_blksize;
-		AFFS_INODE->i_blkcnt++;
+		AFFS_I(inode)->mmu_private += AFFS_SB->s_data_blksize;
+		AFFS_I(inode)->i_blkcnt++;
 
 		/* store new block */
 		if (bh_result->b_blocknr)
@@ -418,7 +418,7 @@
 static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
 {
 	return cont_prepare_write(page, from, to, affs_get_block,
-		&page->mapping->host->u.affs_i.mmu_private);
+		&AFFS_I(page->mapping->host)->mmu_private);
 }
 static int _affs_bmap(struct address_space *mapping, long block)
 {
@@ -593,11 +593,11 @@
 		bidx++;
 	}
 	affs_brelse(bh);
-	inode->i_size = AFFS_INODE->mmu_private = size;
+	inode->i_size = AFFS_I(inode)->mmu_private = size;
 	return 0;
 
 out:
-	inode->i_size = AFFS_INODE->mmu_private = size;
+	inode->i_size = AFFS_I(inode)->mmu_private = size;
 	return PTR_ERR(bh);
 }
 
@@ -759,7 +759,7 @@
 	affs_brelse(bh);
 	tmp = (page->index << PAGE_CACHE_SHIFT) + from;
 	if (tmp > inode->i_size)
-		inode->i_size = AFFS_INODE->mmu_private = tmp;
+		inode->i_size = AFFS_I(inode)->mmu_private = tmp;
 
 	return written;
 
@@ -787,9 +787,9 @@
 
 	pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino);
 
-	while (inode->u.affs_i.i_pa_cnt) {
-		inode->u.affs_i.i_pa_cnt--;
-		affs_free_block(sb, ++inode->u.affs_i.i_lastalloc);
+	while (AFFS_I(inode)->i_pa_cnt) {
+		AFFS_I(inode)->i_pa_cnt--;
+		affs_free_block(sb, ++AFFS_I(inode)->i_lastalloc);
 	}
 }
 
@@ -814,7 +814,7 @@
 		ext = last_blk / AFFS_SB->s_hashsize;
 	}
 
-	if (inode->i_size > AFFS_INODE->mmu_private) {
+	if (inode->i_size > AFFS_I(inode)->mmu_private) {
 		struct address_space *mapping = inode->i_mapping;
 		struct page *page;
 		u32 size = inode->i_size - 1;
@@ -831,23 +831,23 @@
 		page_cache_release(page);
 		mark_inode_dirty(inode);
 		return;
-	} else if (inode->i_size == AFFS_INODE->mmu_private)
+	} else if (inode->i_size == AFFS_I(inode)->mmu_private)
 		return;
 
 	// lock cache
 	ext_bh = affs_get_extblock(inode, ext);
-	if (AFFS_INODE->i_lc) {
+	if (AFFS_I(inode)->i_lc) {
 		/* clear linear cache */
-		for (i = (ext + 1) >> AFFS_INODE->i_lc_shift; i < AFFS_LC_SIZE; i++)
-			AFFS_INODE->i_lc[i] = 0;
+		for (i = (ext + 1) >> AFFS_I(inode)->i_lc_shift; i < AFFS_LC_SIZE; i++)
+			AFFS_I(inode)->i_lc[i] = 0;
 		/* clear associative cache */
 		for (i = 0; i < AFFS_AC_SIZE; i++)
-			if (AFFS_INODE->i_ac[i].ext >= ext)
-				AFFS_INODE->i_ac[i].ext = 0;
+			if (AFFS_I(inode)->i_ac[i].ext >= ext)
+				AFFS_I(inode)->i_ac[i].ext = 0;
 	}
 	ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
 
-	blkcnt = AFFS_INODE->i_blkcnt;
+	blkcnt = AFFS_I(inode)->i_blkcnt;
 	i = 0;
 	blk = last_blk;
 	if (inode->i_size) {
@@ -868,13 +868,13 @@
 	affs_brelse(ext_bh);
 
 	if (inode->i_size) {
-		AFFS_INODE->i_blkcnt = last_blk + 1;
-		AFFS_INODE->i_extcnt = ext + 1;
+		AFFS_I(inode)->i_blkcnt = last_blk + 1;
+		AFFS_I(inode)->i_extcnt = ext + 1;
 	} else {
-		AFFS_INODE->i_blkcnt = 0;
-		AFFS_INODE->i_extcnt = 1;
+		AFFS_I(inode)->i_blkcnt = 0;
+		AFFS_I(inode)->i_extcnt = 1;
 	}
-	AFFS_INODE->mmu_private = inode->i_size;
+	AFFS_I(inode)->mmu_private = inode->i_size;
 	// unlock cache
 
 	while (ext_key) {
diff -u --recursive --new-file v2.5.2/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v2.5.2/linux/fs/affs/inode.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/affs/inode.c	Mon Jan 21 15:37:32 2002
@@ -68,12 +68,20 @@
 	inode->i_size = 0;
 	inode->i_nlink = 1;
 	inode->i_mode = 0;
-	memset(AFFS_INODE, 0, sizeof(struct affs_inode_info));
-	init_MUTEX(&AFFS_INODE->i_link_lock);
-	init_MUTEX(&AFFS_INODE->i_ext_lock);
-	AFFS_INODE->i_extcnt = 1;
-	AFFS_INODE->i_ext_last = ~1;
-	AFFS_INODE->i_protect = prot;
+	AFFS_I(inode)->i_extcnt = 1;
+	AFFS_I(inode)->i_ext_last = ~1;
+	AFFS_I(inode)->i_protect = prot;
+	AFFS_I(inode)->i_opencnt = 0;
+	AFFS_I(inode)->i_blkcnt = 0;
+	AFFS_I(inode)->i_lc = NULL;
+	AFFS_I(inode)->i_lc_size = 0;
+	AFFS_I(inode)->i_lc_shift = 0;
+	AFFS_I(inode)->i_lc_mask = 0;
+	AFFS_I(inode)->i_ac = NULL;
+	AFFS_I(inode)->i_ext_bh = NULL;
+	AFFS_I(inode)->mmu_private = 0;
+	AFFS_I(inode)->i_lastalloc = 0;
+	AFFS_I(inode)->i_pa_cnt = 0;
 
 	if (AFFS_SB->s_flags & SF_SETMODE)
 		inode->i_mode = AFFS_SB->s_mode;
@@ -136,11 +144,11 @@
 	case ST_FILE:
 		size = be32_to_cpu(tail->size);
 		inode->i_mode |= S_IFREG;
-		AFFS_INODE->mmu_private = inode->i_size = size;
+		AFFS_I(inode)->mmu_private = inode->i_size = size;
 		if (inode->i_size) {
-			AFFS_INODE->i_blkcnt = (size - 1) /
+			AFFS_I(inode)->i_blkcnt = (size - 1) /
 					       AFFS_SB->s_data_blksize + 1;
-			AFFS_INODE->i_extcnt = (AFFS_INODE->i_blkcnt - 1) /
+			AFFS_I(inode)->i_extcnt = (AFFS_I(inode)->i_blkcnt - 1) /
 					       AFFS_SB->s_hashsize + 1;
 		}
 		if (tail->link_chain)
@@ -196,7 +204,7 @@
 	if (tail->stype == be32_to_cpu(ST_ROOT)) {
 		secs_to_datestamp(inode->i_mtime,&AFFS_ROOT_TAIL(sb, bh)->root_change);
 	} else {
-		tail->protect = cpu_to_be32(AFFS_INODE->i_protect);
+		tail->protect = cpu_to_be32(AFFS_I(inode)->i_protect);
 		tail->size = cpu_to_be32(inode->i_size);
 		secs_to_datestamp(inode->i_mtime,&tail->change);
 		if (!(inode->i_ino == AFFS_SB->s_root_block)) {
@@ -255,7 +263,7 @@
 	lock_kernel();
 	affs_free_prealloc(inode);
 	if (atomic_read(&inode->i_count) == 1) {
-		if (inode->i_size != AFFS_INODE->mmu_private)
+		if (inode->i_size != AFFS_I(inode)->mmu_private)
 			affs_truncate(inode);
 		//if (inode->i_nlink)
 		//	affs_clear_inode(inode);
@@ -279,18 +287,18 @@
 void
 affs_clear_inode(struct inode *inode)
 {
-	unsigned long cache_page = (unsigned long) inode->u.affs_i.i_lc;
+	unsigned long cache_page = (unsigned long) AFFS_I(inode)->i_lc;
 
 	pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
 	if (cache_page) {
 		pr_debug("AFFS: freeing ext cache\n");
-		inode->u.affs_i.i_lc = NULL;
-		inode->u.affs_i.i_ac = NULL;
+		AFFS_I(inode)->i_lc = NULL;
+		AFFS_I(inode)->i_ac = NULL;
 		free_page(cache_page);
 	}
-	affs_brelse(AFFS_INODE->i_ext_bh);
-	AFFS_INODE->i_ext_last = ~1;
-	AFFS_INODE->i_ext_bh = NULL;
+	affs_brelse(AFFS_I(inode)->i_ext_bh);
+	AFFS_I(inode)->i_ext_last = ~1;
+	AFFS_I(inode)->i_ext_bh = NULL;
 }
 
 struct inode *
@@ -318,11 +326,20 @@
 	inode->i_ino     = block;
 	inode->i_nlink   = 1;
 	inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-	memset(AFFS_INODE, 0, sizeof(struct affs_inode_info));
-	AFFS_INODE->i_extcnt = 1;
-	AFFS_INODE->i_ext_last = ~1;
-	init_MUTEX(&AFFS_INODE->i_link_lock);
-	init_MUTEX(&AFFS_INODE->i_ext_lock);
+	AFFS_I(inode)->i_opencnt = 0;
+	AFFS_I(inode)->i_blkcnt = 0;
+	AFFS_I(inode)->i_lc = NULL;
+	AFFS_I(inode)->i_lc_size = 0;
+	AFFS_I(inode)->i_lc_shift = 0;
+	AFFS_I(inode)->i_lc_mask = 0;
+	AFFS_I(inode)->i_ac = NULL;
+	AFFS_I(inode)->i_ext_bh = NULL;
+	AFFS_I(inode)->mmu_private = 0;
+	AFFS_I(inode)->i_protect = 0;
+	AFFS_I(inode)->i_lastalloc = 0;
+	AFFS_I(inode)->i_pa_cnt = 0;
+	AFFS_I(inode)->i_extcnt = 1;
+	AFFS_I(inode)->i_ext_last = ~1;
 
 	insert_inode_hash(inode);
 
diff -u --recursive --new-file v2.5.2/linux/fs/affs/super.c linux/fs/affs/super.c
--- v2.5.2/linux/fs/affs/super.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/affs/super.c	Mon Jan 21 15:37:32 2002
@@ -78,7 +78,54 @@
 	pr_debug("AFFS: write_super() at %lu, clean=%d\n", CURRENT_TIME, clean);
 }
 
+static kmem_cache_t * affs_inode_cachep;
+
+static struct inode *affs_alloc_inode(struct super_block *sb)
+{
+	struct affs_inode_info *ei;
+	ei = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void affs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(affs_inode_cachep, AFFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct affs_inode_info *ei = (struct affs_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		init_MUTEX(&ei->i_link_lock);
+		init_MUTEX(&ei->i_ext_lock);
+		inode_init_once(&ei->vfs_inode);
+	}
+}
+ 
+static int init_inodecache(void)
+{
+	affs_inode_cachep = kmem_cache_create("affs_inode_cache",
+					     sizeof(struct affs_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (affs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(affs_inode_cachep))
+		printk(KERN_INFO "affs_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations affs_sops = {
+	alloc_inode:	affs_alloc_inode,
+	destroy_inode:	affs_destroy_inode,
 	read_inode:	affs_read_inode,
 	write_inode:	affs_write_inode,
 	put_inode:	affs_put_inode,
@@ -490,12 +537,23 @@
 
 static int __init init_affs_fs(void)
 {
-	return register_filesystem(&affs_fs_type);
+	int err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&affs_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_affs_fs(void)
 {
 	unregister_filesystem(&affs_fs_type);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/bfs/bfs_defs.h linux/fs/bfs/bfs_defs.h
--- v2.5.2/linux/fs/bfs/bfs_defs.h	Sun Feb  6 18:43:21 2000
+++ linux/fs/bfs/bfs_defs.h	Mon Jan 28 13:20:44 2002
@@ -9,9 +9,6 @@
 #define su_sbh		u.bfs_sb.si_sbh
 #define su_bfs_sb	u.bfs_sb.si_bfs_sb
 
-#define iu_dsk_ino	u.bfs_i.i_dsk_ino
-#define iu_sblock	u.bfs_i.i_sblock
-#define iu_eblock	u.bfs_i.i_eblock
-
 #define printf(format, args...) \
-	printk(KERN_ERR "BFS-fs: " __FUNCTION__ "(): " format, ## args)
+	printk(KERN_ERR "BFS-fs: %s(): " format, __FUNCTION__, ## args)
+
diff -u --recursive --new-file v2.5.2/linux/fs/bfs/dir.c linux/fs/bfs/dir.c
--- v2.5.2/linux/fs/bfs/dir.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/bfs/dir.c	Mon Jan 28 13:20:44 2002
@@ -39,7 +39,7 @@
 
 	while (f->f_pos < dir->i_size) {
 		offset = f->f_pos & (BFS_BSIZE-1);
-		block = dir->iu_sblock + (f->f_pos >> BFS_BSIZE_BITS);
+		block = BFS_I(dir)->i_sblock + (f->f_pos >> BFS_BSIZE_BITS);
 		bh = sb_bread(dir->i_sb, block);
 		if (!bh) {
 			f->f_pos += BFS_BSIZE - offset;
@@ -97,8 +97,10 @@
 	inode->i_fop = &bfs_file_operations;
 	inode->i_mapping->a_ops = &bfs_aops;
 	inode->i_mode = mode;
-	inode->i_ino = inode->iu_dsk_ino = ino;
-	inode->iu_sblock = inode->iu_eblock = 0;
+	inode->i_ino = ino;
+	BFS_I(inode)->i_dsk_ino = ino;
+	BFS_I(inode)->i_sblock = 0;
+	BFS_I(inode)->i_eblock = 0;
 	insert_inode_hash(inode);
         mark_inode_dirty(inode);
 	dump_imap("create",s);
@@ -262,8 +264,8 @@
 	if (namelen > BFS_NAMELEN)
 		return -ENAMETOOLONG;
 
-	sblock = dir->iu_sblock;
-	eblock = dir->iu_eblock;
+	sblock = BFS_I(dir)->i_sblock;
+	eblock = BFS_I(dir)->i_eblock;
 	for (block=sblock; block<=eblock; block++) {
 		bh = sb_bread(dir->i_sb, block);
 		if(!bh) 
@@ -313,7 +315,7 @@
 	block = offset = 0;
 	while (block * BFS_BSIZE + offset < dir->i_size) {
 		if (!bh) {
-			bh = sb_bread(dir->i_sb, dir->iu_sblock + block);
+			bh = sb_bread(dir->i_sb, BFS_I(dir)->i_sblock + block);
 			if (!bh) {
 				block++;
 				continue;
diff -u --recursive --new-file v2.5.2/linux/fs/bfs/file.c linux/fs/bfs/file.c
--- v2.5.2/linux/fs/bfs/file.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/bfs/file.c	Mon Jan 28 13:20:44 2002
@@ -60,14 +60,15 @@
 	long phys;
 	int err;
 	struct super_block *sb = inode->i_sb;
+	struct bfs_inode_info *bi = BFS_I(inode);
 	struct buffer_head *sbh = sb->su_sbh;
 
 	if (block < 0 || block > sb->su_blocks)
 		return -EIO;
 
-	phys = inode->iu_sblock + block;
+	phys = bi->i_sblock + block;
 	if (!create) {
-		if (phys <= inode->iu_eblock) {
+		if (phys <= bi->i_eblock) {
 			dprintf("c=%d, b=%08lx, phys=%08lx (granted)\n", create, block, phys);
 			map_bh(bh_result, sb, phys);
 		}
@@ -76,7 +77,7 @@
 
 	/* if the file is not empty and the requested block is within the range
 	   of blocks allocated for this file, we can grant it */
-	if (inode->i_size && phys <= inode->iu_eblock) {
+	if (inode->i_size && phys <= bi->i_eblock) {
 		dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", 
 				create, block, phys);
 		map_bh(bh_result, sb, phys);
@@ -88,12 +89,12 @@
 
 	/* if the last data block for this file is the last allocated block, we can
 	   extend the file trivially, without moving it anywhere */
-	if (inode->iu_eblock == sb->su_lf_eblk) {
+	if (bi->i_eblock == sb->su_lf_eblk) {
 		dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", 
 				create, block, phys);
 		map_bh(bh_result, sb, phys);
-		sb->su_freeb -= phys - inode->iu_eblock;
-		sb->su_lf_eblk = inode->iu_eblock = phys;
+		sb->su_freeb -= phys - bi->i_eblock;
+		sb->su_lf_eblk = bi->i_eblock = phys;
 		mark_inode_dirty(inode);
 		mark_buffer_dirty(sbh);
 		err = 0;
@@ -102,9 +103,9 @@
 
 	/* Ok, we have to move this entire file to the next free block */
 	phys = sb->su_lf_eblk + 1;
-	if (inode->iu_sblock) { /* if data starts on block 0 then there is no data */
-		err = bfs_move_blocks(inode->i_sb, inode->iu_sblock, 
-				inode->iu_eblock, phys);
+	if (bi->i_sblock) { /* if data starts on block 0 then there is no data */
+		err = bfs_move_blocks(inode->i_sb, bi->i_sblock, 
+				bi->i_eblock, phys);
 		if (err) {
 			dprintf("failed to move ino=%08lx -> fs corruption\n", inode->i_ino);
 			goto out;
@@ -113,13 +114,13 @@
 		err = 0;
 
 	dprintf("c=%d, b=%08lx, phys=%08lx (moved)\n", create, block, phys);
-	inode->iu_sblock = phys;
+	bi->i_sblock = phys;
 	phys += block;
-	sb->su_lf_eblk = inode->iu_eblock = phys;
+	sb->su_lf_eblk = bi->i_eblock = phys;
 
 	/* this assumes nothing can write the inode back while we are here
 	 * and thus update inode->i_blocks! (XXX)*/
-	sb->su_freeb -= inode->iu_eblock - inode->iu_sblock + 1 - inode->i_blocks;
+	sb->su_freeb -= bi->i_eblock - bi->i_sblock + 1 - inode->i_blocks;
 	mark_inode_dirty(inode);
 	mark_buffer_dirty(sbh);
 	map_bh(bh_result, sb, phys);
diff -u --recursive --new-file v2.5.2/linux/fs/bfs/inode.c linux/fs/bfs/inode.c
--- v2.5.2/linux/fs/bfs/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/bfs/inode.c	Mon Jan 28 13:20:44 2002
@@ -77,9 +77,9 @@
 	inode->i_atime = di->i_atime;
 	inode->i_mtime = di->i_mtime;
 	inode->i_ctime = di->i_ctime;
-	inode->iu_dsk_ino = di->i_ino; /* can be 0 so we store a copy */
-	inode->iu_sblock = di->i_sblock;
-	inode->iu_eblock = di->i_eblock;
+	BFS_I(inode)->i_dsk_ino = di->i_ino; /* can be 0 so we store a copy */
+	BFS_I(inode)->i_sblock = di->i_sblock;
+	BFS_I(inode)->i_eblock = di->i_eblock;
 
 	brelse(bh);
 }
@@ -121,8 +121,8 @@
 	di->i_atime = inode->i_atime;
 	di->i_mtime = inode->i_mtime;
 	di->i_ctime = inode->i_ctime;
-	di->i_sblock = inode->iu_sblock;
-	di->i_eblock = inode->iu_eblock;
+	di->i_sblock = BFS_I(inode)->i_sblock;
+	di->i_eblock = BFS_I(inode)->i_eblock;
 	di->i_eoffset = di->i_sblock * BFS_BSIZE + inode->i_size - 1;
 
 	mark_buffer_dirty(bh);
@@ -172,8 +172,8 @@
 	/* if this was the last file, make the previous 
 	   block "last files last block" even if there is no real file there,
 	   saves us 1 gap */
-	if (s->su_lf_eblk == inode->iu_eblock) {
-		s->su_lf_eblk = inode->iu_sblock - 1;
+	if (s->su_lf_eblk == BFS_I(inode)->i_eblock) {
+		s->su_lf_eblk = BFS_I(inode)->i_sblock - 1;
 		mark_buffer_dirty(s->su_sbh);
 	}
 	unlock_kernel();
@@ -206,7 +206,51 @@
 	s->s_dirt = 0;
 }
 
+static kmem_cache_t * bfs_inode_cachep;
+
+static struct inode *bfs_alloc_inode(struct super_block *sb)
+{
+	struct bfs_inode_info *bi;
+	bi = kmem_cache_alloc(bfs_inode_cachep, SLAB_KERNEL);
+	if (!bi)
+		return NULL;
+	return &bi->vfs_inode;
+}
+
+static void bfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(bfs_inode_cachep, BFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct bfs_inode_info *bi = foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&bi->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	bfs_inode_cachep = kmem_cache_create("bfs_inode_cache",
+					     sizeof(struct bfs_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (bfs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(bfs_inode_cachep))
+		printk(KERN_INFO "bfs_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations bfs_sops = {
+	alloc_inode:	bfs_alloc_inode,
+	destroy_inode:	bfs_destroy_inode,
 	read_inode:	bfs_read_inode,
 	write_inode:	bfs_write_inode,
 	delete_inode:	bfs_delete_inode,
@@ -293,14 +337,14 @@
 	s->su_lf_ioff = 0;
 	for (i=BFS_ROOT_INO; i<=s->su_lasti; i++) {
 		inode = iget(s,i);
-		if (inode->iu_dsk_ino == 0)
+		if (BFS_I(inode)->i_dsk_ino == 0)
 			s->su_freei++;
 		else {
 			set_bit(i, s->su_imap);
 			s->su_freeb -= inode->i_blocks;
-			if (inode->iu_eblock > s->su_lf_eblk) {
-				s->su_lf_eblk = inode->iu_eblock;
-				s->su_lf_sblk = inode->iu_sblock;
+			if (BFS_I(inode)->i_eblock > s->su_lf_eblk) {
+				s->su_lf_eblk = BFS_I(inode)->i_eblock;
+				s->su_lf_sblk = BFS_I(inode)->i_sblock;
 				s->su_lf_ioff = BFS_INO2OFF(i);
 			}
 		}
@@ -322,12 +366,23 @@
 
 static int __init init_bfs_fs(void)
 {
-	return register_filesystem(&bfs_fs_type);
+	int err = init_inodecache();
+	if (err)
+		goto out1;
+        err = register_filesystem(&bfs_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_bfs_fs(void)
 {
 	unregister_filesystem(&bfs_fs_type);
+	destroy_inodecache();
 }
 
 module_init(init_bfs_fs)
diff -u --recursive --new-file v2.5.2/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- v2.5.2/linux/fs/binfmt_misc.c	Sat Oct 20 19:14:42 2001
+++ linux/fs/binfmt_misc.c	Thu Jan 17 14:25:43 2002
@@ -49,6 +49,8 @@
 } Node;
 
 static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
+static struct vfsmount *bm_mnt;
+static int entry_count = 0;
 
 /* 
  * Check if we support the binfmt
@@ -390,10 +392,15 @@
 	Node *e = inode->u.generic_ip;
 
 	if (e) {
+		struct vfsmount *mnt;
 		write_lock(&entries_lock);
 		list_del(&e->list);
+		mnt = bm_mnt;
+		if (!--entry_count)
+			bm_mnt = NULL;
 		write_unlock(&entries_lock);
 		kfree(e);
+		mntput(mnt);
 	}
 }
 
@@ -404,8 +411,7 @@
 	write_lock(&entries_lock);
 	dentry = e->dentry;
 	if (dentry) {
-		list_del(&e->list);
-		INIT_LIST_HEAD(&e->list);
+		list_del_init(&e->list);
 		e->dentry = NULL;
 	}
 	write_unlock(&entries_lock);
@@ -484,12 +490,16 @@
 	write:		bm_entry_write,
 };
 
+static struct file_system_type bm_fs_type;
+
 /* /register */
 
 static ssize_t bm_register_write(struct file *file, const char *buffer,
 			       size_t count, loff_t *ppos)
 {
 	Node *e;
+	struct inode *inode;
+	struct vfsmount *mnt = NULL;
 	struct dentry *root, *dentry;
 	struct super_block *sb = file->f_vfsmnt->mnt_sb;
 	int err = 0;
@@ -503,31 +513,52 @@
 	down(&root->d_inode->i_sem);
 	dentry = lookup_one_len(e->name, root, strlen(e->name));
 	err = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		down(&root->d_inode->i_zombie);
-		if (dentry->d_inode) {
-			err = -EEXIST;
-		} else {
-			struct inode * inode = bm_get_inode(sb, S_IFREG | 0644);
-			err = -ENOMEM;
+	if (IS_ERR(dentry))
+		goto out;
 
-			if (inode) {
-				write_lock(&entries_lock);
+	down(&root->d_inode->i_zombie);
 
-				e->dentry = dget(dentry);
-				inode->u.generic_ip = e;
-				inode->i_fop = &bm_entry_operations;
-				d_instantiate(dentry, inode);
+	err = -EEXIST;
+	if (dentry->d_inode)
+		goto out2;
 
-				list_add(&e->list, &entries);
-				write_unlock(&entries_lock);
+	inode = bm_get_inode(sb, S_IFREG | 0644);
 
-				err = 0;
-			}
+	err = -ENOMEM;
+	if (!inode)
+		goto out2;
+
+	write_lock(&entries_lock);
+	if (!bm_mnt) {
+		write_unlock(&entries_lock);
+		mnt = kern_mount(&bm_fs_type);
+		if (IS_ERR(mnt)) {
+			err = PTR_ERR(mnt);
+			iput(inode);
+			inode = NULL;
+			goto out2;
 		}
-		up(&root->d_inode->i_zombie);
-		dput(dentry);
+		write_lock(&entries_lock);
+		if (!bm_mnt)
+			bm_mnt = mnt;
 	}
+	mntget(bm_mnt);
+	entry_count++;
+
+	e->dentry = dget(dentry);
+	inode->u.generic_ip = e;
+	inode->i_fop = &bm_entry_operations;
+	d_instantiate(dentry, inode);
+
+	list_add(&e->list, &entries);
+	write_unlock(&entries_lock);
+
+	mntput(mnt);
+	err = 0;
+out2:
+	up(&root->d_inode->i_zombie);
+	dput(dentry);
+out:
 	up(&root->d_inode->i_sem);
 	dput(root);
 
@@ -687,23 +718,13 @@
 
 static DECLARE_FSTYPE(bm_fs_type, "binfmt_misc", bm_read_super, FS_SINGLE|FS_LITTER);
 
-static struct vfsmount *bm_mnt;
-
 static int __init init_misc_binfmt(void)
 {
 	int err = register_filesystem(&bm_fs_type);
 	if (!err) {
-		bm_mnt = kern_mount(&bm_fs_type);
-		err = PTR_ERR(bm_mnt);
-		if (IS_ERR(bm_mnt))
+		err = register_binfmt(&misc_format);
+		if (err)
 			unregister_filesystem(&bm_fs_type);
-		else {
-			err = register_binfmt(&misc_format);
-			if (err) {
-				unregister_filesystem(&bm_fs_type);
-				kern_umount(bm_mnt);
-			}
-		}
 	}
 	return err;
 }
@@ -712,7 +733,6 @@
 {
 	unregister_binfmt(&misc_format);
 	unregister_filesystem(&bm_fs_type);
-	kern_umount(bm_mnt);
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.5.2/linux/fs/block_dev.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/block_dev.c	Tue Jan 29 21:15:47 2002
@@ -170,6 +170,8 @@
 	loff_t size = file->f_dentry->d_inode->i_bdev->bd_inode->i_size;
 	loff_t retval;
 
+	lock_kernel();
+
 	switch (origin) {
 		case 2:
 			offset += size;
@@ -186,6 +188,7 @@
 		}
 		retval = offset;
 	}
+	unlock_kernel();
 	return retval;
 }
 	
@@ -220,17 +223,19 @@
 static struct super_block *bd_read_super(struct super_block *sb, void *data, int silent)
 {
 	static struct super_operations sops = {};
-	struct inode *root = new_inode(sb);
-	if (!root)
-		return NULL;
-	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
-	root->i_uid = root->i_gid = 0;
-	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
+	struct inode *root;
+
 	sb->s_maxbytes = ~0ULL;
 	sb->s_blocksize = 1024;
 	sb->s_blocksize_bits = 10;
 	sb->s_magic = 0x62646576;
 	sb->s_op = &sops;
+	root = new_inode(sb);
+	if (!root)
+		return NULL;
+	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
+	root->i_uid = root->i_gid = 0;
+	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
 	sb->s_root = d_alloc(NULL, &(const struct qstr) { "bdev:", 5, 0 });
 	if (!sb->s_root) {
 		iput(root);
diff -u --recursive --new-file v2.5.2/linux/fs/buffer.c linux/fs/buffer.c
--- v2.5.2/linux/fs/buffer.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/buffer.c	Tue Jan 29 10:47:10 2002
@@ -582,23 +582,13 @@
 	return bh;
 }
 
-void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+void buffer_insert_list(struct buffer_head *bh, struct list_head *list)
 {
 	spin_lock(&lru_list_lock);
 	if (bh->b_inode)
 		list_del(&bh->b_inode_buffers);
-	bh->b_inode = inode;
-	list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers);
-	spin_unlock(&lru_list_lock);
-}
-
-void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
-{
-	spin_lock(&lru_list_lock);
-	if (bh->b_inode)
-		list_del(&bh->b_inode_buffers);
-	bh->b_inode = inode;
-	list_add(&bh->b_inode_buffers, &inode->i_dirty_data_buffers);
+	bh->b_inode = 1;
+	list_add(&bh->b_inode_buffers, list);
 	spin_unlock(&lru_list_lock);
 }
 
@@ -606,7 +596,7 @@
    remove_inode_queue functions.  */
 static void __remove_inode_queue(struct buffer_head *bh)
 {
-	bh->b_inode = NULL;
+	bh->b_inode = 0;
 	list_del(&bh->b_inode_buffers);
 }
 
@@ -734,6 +724,7 @@
 	wakeup_bdflush();
 	try_to_free_pages(zone, GFP_NOFS, 0);
 	run_task_queue(&tq_disk);
+	__set_current_state(TASK_RUNNING);
 	yield();
 }
 
@@ -826,73 +817,24 @@
  * any newly dirty buffers for write.
  */
 
-int fsync_inode_buffers(struct inode *inode)
-{
-	struct buffer_head *bh;
-	struct inode tmp;
-	int err = 0, err2;
-	
-	INIT_LIST_HEAD(&tmp.i_dirty_buffers);
-	
-	spin_lock(&lru_list_lock);
-
-	while (!list_empty(&inode->i_dirty_buffers)) {
-		bh = BH_ENTRY(inode->i_dirty_buffers.next);
-		list_del(&bh->b_inode_buffers);
-		if (!buffer_dirty(bh) && !buffer_locked(bh))
-			bh->b_inode = NULL;
-		else {
-			bh->b_inode = &tmp;
-			list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
-			if (buffer_dirty(bh)) {
-				get_bh(bh);
-				spin_unlock(&lru_list_lock);
-				ll_rw_block(WRITE, 1, &bh);
-				brelse(bh);
-				spin_lock(&lru_list_lock);
-			}
-		}
-	}
-
-	while (!list_empty(&tmp.i_dirty_buffers)) {
-		bh = BH_ENTRY(tmp.i_dirty_buffers.prev);
-		remove_inode_queue(bh);
-		get_bh(bh);
-		spin_unlock(&lru_list_lock);
-		wait_on_buffer(bh);
-		if (!buffer_uptodate(bh))
-			err = -EIO;
-		brelse(bh);
-		spin_lock(&lru_list_lock);
-	}
-	
-	spin_unlock(&lru_list_lock);
-	err2 = osync_inode_buffers(inode);
-
-	if (err)
-		return err;
-	else
-		return err2;
-}
-
-int fsync_inode_data_buffers(struct inode *inode)
+int fsync_buffers_list(struct list_head *list)
 {
 	struct buffer_head *bh;
-	struct inode tmp;
+	struct list_head tmp;
 	int err = 0, err2;
 	
-	INIT_LIST_HEAD(&tmp.i_dirty_data_buffers);
+	INIT_LIST_HEAD(&tmp);
 	
 	spin_lock(&lru_list_lock);
 
-	while (!list_empty(&inode->i_dirty_data_buffers)) {
-		bh = BH_ENTRY(inode->i_dirty_data_buffers.next);
+	while (!list_empty(list)) {
+		bh = BH_ENTRY(list->next);
 		list_del(&bh->b_inode_buffers);
 		if (!buffer_dirty(bh) && !buffer_locked(bh))
-			bh->b_inode = NULL;
+			bh->b_inode = 0;
 		else {
-			bh->b_inode = &tmp;
-			list_add(&bh->b_inode_buffers, &tmp.i_dirty_data_buffers);
+			bh->b_inode = 1;
+			list_add(&bh->b_inode_buffers, &tmp);
 			if (buffer_dirty(bh)) {
 				get_bh(bh);
 				spin_unlock(&lru_list_lock);
@@ -903,8 +845,8 @@
 		}
 	}
 
-	while (!list_empty(&tmp.i_dirty_data_buffers)) {
-		bh = BH_ENTRY(tmp.i_dirty_data_buffers.prev);
+	while (!list_empty(&tmp)) {
+		bh = BH_ENTRY(tmp.prev);
 		remove_inode_queue(bh);
 		get_bh(bh);
 		spin_unlock(&lru_list_lock);
@@ -916,7 +858,7 @@
 	}
 	
 	spin_unlock(&lru_list_lock);
-	err2 = osync_inode_data_buffers(inode);
+	err2 = osync_buffers_list(list);
 
 	if (err)
 		return err;
@@ -935,48 +877,19 @@
  * write will not be flushed to disk by the osync.
  */
 
-int osync_inode_buffers(struct inode *inode)
+int osync_buffers_list(struct list_head *list)
 {
 	struct buffer_head *bh;
-	struct list_head *list;
+	struct list_head *p;
 	int err = 0;
 
 	spin_lock(&lru_list_lock);
 	
  repeat:
 	
-	for (list = inode->i_dirty_buffers.prev; 
-	     bh = BH_ENTRY(list), list != &inode->i_dirty_buffers;
-	     list = bh->b_inode_buffers.prev) {
-		if (buffer_locked(bh)) {
-			get_bh(bh);
-			spin_unlock(&lru_list_lock);
-			wait_on_buffer(bh);
-			if (!buffer_uptodate(bh))
-				err = -EIO;
-			brelse(bh);
-			spin_lock(&lru_list_lock);
-			goto repeat;
-		}
-	}
-
-	spin_unlock(&lru_list_lock);
-	return err;
-}
-
-int osync_inode_data_buffers(struct inode *inode)
-{
-	struct buffer_head *bh;
-	struct list_head *list;
-	int err = 0;
-
-	spin_lock(&lru_list_lock);
-	
- repeat:
-
-	for (list = inode->i_dirty_data_buffers.prev; 
-	     bh = BH_ENTRY(list), list != &inode->i_dirty_data_buffers;
-	     list = bh->b_inode_buffers.prev) {
+	for (p = list->prev; 
+	     bh = BH_ENTRY(p), p != list;
+	     p = bh->b_inode_buffers.prev) {
 		if (buffer_locked(bh)) {
 			get_bh(bh);
 			spin_unlock(&lru_list_lock);
@@ -993,7 +906,6 @@
 	return err;
 }
 
-
 /*
  * Invalidate any and all dirty buffers on a given inode.  We are
  * probably unmounting the fs, but that doesn't mean we have already
@@ -1765,6 +1677,52 @@
 		submit_bh(READ, arr[i]);
 
 	return 0;
+}
+
+/* utility function for filesystems that need to do work on expanding
+ * truncates.  Uses prepare/commit_write to allow the filesystem to
+ * deal with the hole.  
+ */
+int generic_cont_expand(struct inode *inode, loff_t size)
+{
+	struct address_space *mapping = inode->i_mapping;
+	struct page *page;
+	unsigned long index, offset, limit;
+	int err;
+
+	err = -EFBIG;
+        limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+	if (limit != RLIM_INFINITY && size > (loff_t)limit) {
+		send_sig(SIGXFSZ, current, 0);
+		goto out;
+	}
+	if (size > inode->i_sb->s_maxbytes)
+		goto out;
+
+	offset = (size & (PAGE_CACHE_SIZE-1)); /* Within page */
+
+	/* ugh.  in prepare/commit_write, if from==to==start of block, we 
+	** skip the prepare.  make sure we never send an offset for the start
+	** of a block
+	*/
+	if ((offset & (inode->i_sb->s_blocksize - 1)) == 0) {
+		offset++;
+	}
+	index = size >> PAGE_CACHE_SHIFT;
+	err = -ENOMEM;
+	page = grab_cache_page(mapping, index);
+	if (!page)
+		goto out;
+	err = mapping->a_ops->prepare_write(NULL, page, offset, offset);
+	if (!err) {
+		err = mapping->a_ops->commit_write(NULL, page, offset, offset);
+	}
+	UnlockPage(page);
+	page_cache_release(page);
+	if (err > 0)
+		err = 0;
+out:
+	return err;
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/fs/coda/inode.c linux/fs/coda/inode.c
--- v2.5.2/linux/fs/coda/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/coda/inode.c	Wed Jan 23 15:32:20 2002
@@ -39,9 +39,60 @@
 static void coda_put_super(struct super_block *);
 static int coda_statfs(struct super_block *sb, struct statfs *buf);
 
+static kmem_cache_t * coda_inode_cachep;
+
+static struct inode *coda_alloc_inode(struct super_block *sb)
+{
+	struct coda_inode_info *ei;
+	ei = (struct coda_inode_info *)kmem_cache_alloc(coda_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	memset(&ei->c_fid, 0, sizeof(struct ViceFid));
+	ei->c_flags = 0;
+	INIT_LIST_HEAD(&ei->c_cilist);
+	ei->c_container = NULL;
+	ei->c_contcount = 0;
+	memset(&ei->c_cached_cred, 0, sizeof(struct coda_cred));
+	ei->c_cached_perm = 0;
+	return &ei->vfs_inode;
+}
+
+static void coda_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(coda_inode_cachep, ITOC(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct coda_inode_info *ei = (struct coda_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+int coda_init_inodecache(void)
+{
+	coda_inode_cachep = kmem_cache_create("coda_inode_cache",
+					     sizeof(struct coda_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (coda_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+void coda_destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(coda_inode_cachep))
+		printk(KERN_INFO "coda_inode_cache: not all structures were freed\n");
+}
+
 /* exported operations */
 struct super_operations coda_super_operations =
 {
+	alloc_inode:	coda_alloc_inode,
+	destroy_inode:	coda_destroy_inode,
 	read_inode:	coda_read_inode,
 	clear_inode:	coda_clear_inode,
 	put_super:	coda_put_super,
@@ -188,28 +239,7 @@
 
         if (!sbi) BUG();
 
-#if 0
-	/* check if the inode is already initialized */
-	if (inode->u.generic_ip) {
-            printk("coda_read_inode: initialized inode");
-            return;
-        }
-
-	inode->u.generic_ip = cii_alloc();
-	if (!inode->u.generic_ip) {
-		CDEBUG(D_CNODE, "coda_read_inode: failed to allocate inode info\n");
-		make_bad_inode(inode);
-		return;
-	}
-	memset(inode->u.generic_ip, 0, sizeof(struct coda_inode_info));
-#endif
-
 	cii = ITOC(inode);
-	if (!coda_isnullfid(&cii->c_fid)) {
-            printk("coda_read_inode: initialized inode");
-            return;
-        }
-
 	list_add(&cii->c_cilist, &sbi->sbi_cihead);
 }
 
@@ -226,11 +256,6 @@
         list_del_init(&cii->c_cilist);
 	inode->i_mapping = &inode->i_data;
 	coda_cache_clear_inode(inode);
-
-#if 0
-	cii_free(inode->u.generic_ip);
-	inode->u.generic_ip = NULL;
-#endif
 }
 
 int coda_notify_change(struct dentry *de, struct iattr *iattr)
diff -u --recursive --new-file v2.5.2/linux/fs/coda/psdev.c linux/fs/coda/psdev.c
--- v2.5.2/linux/fs/coda/psdev.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/coda/psdev.c	Mon Jan 21 15:37:32 2002
@@ -407,24 +407,35 @@
 MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
 MODULE_LICENSE("GPL");
 
+extern int coda_init_inodecache(void);
+extern void coda_destroy_inodecache(void);
 static int __init init_coda(void)
 {
 	int status;
 	printk(KERN_INFO "Coda Kernel/Venus communications, v5.3.15, coda@cs.cmu.edu\n");
 
+	status = coda_init_inodecache();
+	if (status)
+		goto out2;
 	status = init_coda_psdev();
 	if ( status ) {
 		printk("Problem (%d) in init_coda_psdev\n", status);
-		return status;
+		goto out1;
 	}
 	
 	status = register_filesystem(&coda_fs_type);
 	if (status) {
 		printk("coda: failed to register filesystem!\n");
-		devfs_unregister(devfs_handle);
-		devfs_unregister_chrdev(CODA_PSDEV_MAJOR,"coda_psdev");
-		coda_sysctl_clean();
+		goto out;
 	}
+	return 0;
+out:
+	devfs_unregister(devfs_handle);
+	devfs_unregister_chrdev(CODA_PSDEV_MAJOR,"coda_psdev");
+	coda_sysctl_clean();
+out1:
+	coda_destroy_inodecache();
+out2:
 	return status;
 }
 
@@ -439,6 +450,7 @@
 	devfs_unregister(devfs_handle);
 	devfs_unregister_chrdev(CODA_PSDEV_MAJOR, "coda_psdev");
 	coda_sysctl_clean();
+	coda_destroy_inodecache();
 }
 
 module_init(init_coda);
diff -u --recursive --new-file v2.5.2/linux/fs/cramfs/Makefile linux/fs/cramfs/Makefile
--- v2.5.2/linux/fs/cramfs/Makefile	Thu Oct 25 13:53:53 2001
+++ linux/fs/cramfs/Makefile	Tue Jan 29 21:30:41 2002
@@ -8,6 +8,4 @@
 
 obj-m := $(O_TARGET)
 
-CFLAGS_uncompress.o := -I $(TOPDIR)/fs/inflate_fs
-
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.5.2/linux/fs/devfs/base.c linux/fs/devfs/base.c
--- v2.5.2/linux/fs/devfs/base.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/devfs/base.c	Tue Jan 29 10:59:46 2002
@@ -1,6 +1,6 @@
 /*  devfs (Device FileSystem) driver.
 
-    Copyright (C) 1998-2001  Richard Gooch
+    Copyright (C) 1998-2002  Richard Gooch
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -604,6 +604,14 @@
     20020113   Richard Gooch <rgooch@atnf.csiro.au>
 	       Fixed (rare, old) race in <devfs_lookup>.
   v1.9
+    20020120   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed deadlock bug in <devfs_d_revalidate_wait>.
+	       Tag VFS deletable in <devfs_mk_symlink> if handle ignored.
+  v1.10
+    20020129   Richard Gooch <rgooch@atnf.csiro.au>
+	       Added KERN_* to remaining messages.
+	       Cleaned up declaration of <stat_read>.
+  v1.11
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -636,7 +644,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "1.9 (20020113)"
+#define DEVFS_VERSION            "1.11 (20020129)"
 
 #define DEVFS_NAME "devfs"
 
@@ -781,7 +789,7 @@
     umode_t mode;
     unsigned short namelen;      /*  I think 64k+ filenames are a way off... */
     unsigned char hide:1;
-    unsigned char vfs_created:1; /*  Whether created by driver or VFS        */
+    unsigned char vfs_deletable:1;/*  Whether the VFS may delete the entry   */
     char name[1];                /*  This is just a dummy: the allocated array
 				     is bigger. This is NULL-terminated      */
 };
@@ -844,8 +852,8 @@
 			 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 ssize_t stat_read (struct file *file, char *buf, size_t len,
+			  loff_t *ppos);
 static struct file_operations stat_fops =
 {
     read:    stat_read,
@@ -1774,7 +1782,8 @@
     DPRINTK (DEBUG_REGISTER, "(%s)\n", name);
     err = devfs_do_symlink (dir, name, flags, link, &de, info);
     if (err) return err;
-    if (handle != NULL) *handle = de;
+    if (handle == NULL) de->vfs_deletable = TRUE;
+    else *handle = de;
     devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
     return 0;
 }   /*  End Function devfs_mk_symlink  */
@@ -1817,7 +1826,7 @@
 	{
 	    PRINTK ("(%s): using old entry in dir: %p \"%s\"\n",
 		    name, dir, dir->name);
-	    old->vfs_created = FALSE;
+	    old->vfs_deletable = FALSE;
 	    devfs_put (dir);
 	    return old;
 	}
@@ -2426,10 +2435,10 @@
     if (bdops->check_media_change == NULL) goto out;
     if ( !bdops->check_media_change (dev) ) goto out;
     retval = 1;
-    printk ( KERN_DEBUG "VFS: Disk change detected on device %s\n",
+    printk (KERN_DEBUG "VFS: Disk change detected on device %s\n",
 	     kdevname (dev) );
-    if (invalidate_device(dev, 0))
-	printk("VFS: busy inodes on changed media..\n");
+    if ( invalidate_device (dev, 0) )
+	printk (KERN_WARNING "VFS: busy inodes on changed media..\n");
     /*  Ugly hack to disable messages about unable to read partition table  */
     tmp = warn_no_part;
     warn_no_part = 0;
@@ -2878,13 +2887,16 @@
     struct devfs_lookup_struct *lookup_info = dentry->d_fsdata;
     DECLARE_WAITQUEUE (wait, current);
 
-    if ( !dentry->d_inode && is_devfsd_or_child (fs_info) )
+    if ( is_devfsd_or_child (fs_info) )
     {
 	devfs_handle_t de = lookup_info->de;
 	struct inode *inode;
 
-	DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p de: %p by: \"%s\"\n",
-		 dentry->d_name.name, dentry, de, current->comm);
+	DPRINTK (DEBUG_I_LOOKUP,
+		 "(%s): dentry: %p inode: %p de: %p by: \"%s\"\n",
+		 dentry->d_name.name, dentry, dentry->d_inode, de,
+		 current->comm);
+	if (dentry->d_inode) return 1;
 	if (de == NULL)
 	{
 	    read_lock (&parent->u.dir.lock);
@@ -3015,7 +3027,7 @@
     de = get_devfs_entry_from_vfs_inode (inode);
     DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de);
     if (de == NULL) return -ENOENT;
-    if (!de->vfs_created) return -EPERM;
+    if (!de->vfs_deletable) return -EPERM;
     write_lock (&de->parent->u.dir.lock);
     unhooked = _devfs_unhook (de);
     write_unlock (&de->parent->u.dir.lock);
@@ -3044,7 +3056,7 @@
     DPRINTK (DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n",
 	     dentry->d_name.name, err);
     if (err < 0) return err;
-    de->vfs_created = TRUE;
+    de->vfs_deletable = TRUE;
     de->inode.uid = current->euid;
     de->inode.gid = current->egid;
     de->inode.atime = CURRENT_TIME;
@@ -3073,7 +3085,7 @@
     if (parent == NULL) return -ENOENT;
     de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
     if (!de) return -ENOMEM;
-    de->vfs_created = TRUE;
+    de->vfs_deletable = TRUE;
     if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
 	return err;
     de->inode.uid = current->euid;
@@ -3103,7 +3115,7 @@
     de = get_devfs_entry_from_vfs_inode (inode);
     if (de == NULL) return -ENOENT;
     if ( !S_ISDIR (de->mode) ) return -ENOTDIR;
-    if (!de->vfs_created) return -EPERM;
+    if (!de->vfs_deletable) 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;
@@ -3137,7 +3149,7 @@
     if (parent == NULL) return -ENOENT;
     de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
     if (!de) return -ENOMEM;
-    de->vfs_created = TRUE;
+    de->vfs_deletable = TRUE;
     if ( S_ISBLK (mode) || S_ISCHR (mode) )
     {
 	de->u.fcb.u.device.major = MAJOR (rdev);
@@ -3229,7 +3241,7 @@
     return sb;
 
 out_no_root:
-    printk ("devfs_read_super: get root inode failed\n");
+    PRINTK ("(): get root inode failed\n");
     if (root_inode) iput (root_inode);
     return NULL;
 }   /*  End Function devfs_read_super  */
@@ -3456,7 +3468,7 @@
 {
     int err;
 
-    printk ("%s: v%s Richard Gooch (rgooch@atnf.csiro.au)\n",
+    printk (KERN_INFO "%s: v%s Richard Gooch (rgooch@atnf.csiro.au)\n",
 	    DEVFS_NAME, DEVFS_VERSION);
     devfsd_buf_cache = kmem_cache_create ("devfsd_event",
 					  sizeof (struct devfsd_buf_entry),
@@ -3464,9 +3476,9 @@
     if (!devfsd_buf_cache) OOPS ("(): unable to allocate event slab\n");
 #ifdef CONFIG_DEVFS_DEBUG
     devfs_debug = devfs_debug_init;
-    printk ("%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug);
+    printk (KERN_INFO "%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug);
 #endif
-    printk ("%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options);
+    printk (KERN_INFO "%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options);
     err = register_filesystem (&devfs_fs_type);
     if (!err)
     {
@@ -3483,8 +3495,8 @@
 
     if ( !(boot_options & OPTION_MOUNT) ) return;
     err = do_mount ("none", "/dev", "devfs", 0, "");
-    if (err == 0) printk ("Mounted devfs on /dev\n");
-    else printk ("Warning: unable to mount devfs, err: %d\n", err);
+    if (err == 0) printk (KERN_INFO "Mounted devfs on /dev\n");
+    else PRINTK ("(): unable to mount devfs, err: %d\n", err);
 }   /*  End Function mount_devfs_fs  */
 
 module_init(init_devfs_fs)
diff -u --recursive --new-file v2.5.2/linux/fs/devpts/inode.c linux/fs/devpts/inode.c
--- v2.5.2/linux/fs/devpts/inode.c	Thu Oct 25 00:02:26 2001
+++ linux/fs/devpts/inode.c	Fri Jan 18 16:00:26 2002
@@ -139,6 +139,11 @@
 		printk("devpts: called with bogus options\n");
 		goto fail_free;
 	}
+	s->u.generic_sbp = (void *) sbi;
+	s->s_blocksize = 1024;
+	s->s_blocksize_bits = 10;
+	s->s_magic = DEVPTS_SUPER_MAGIC;
+	s->s_op = &devpts_sops;
 
 	inode = new_inode(s);
 	if (!inode)
@@ -153,11 +158,6 @@
 	inode->i_fop = &devpts_root_operations;
 	inode->i_nlink = 2;
 
-	s->u.generic_sbp = (void *) sbi;
-	s->s_blocksize = 1024;
-	s->s_blocksize_bits = 10;
-	s->s_magic = DEVPTS_SUPER_MAGIC;
-	s->s_op = &devpts_sops;
 	s->s_root = d_alloc_root(inode);
 	if (s->s_root)
 		return s;
diff -u --recursive --new-file v2.5.2/linux/fs/driverfs/inode.c linux/fs/driverfs/inode.c
--- v2.5.2/linux/fs/driverfs/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/driverfs/inode.c	Mon Jan 28 16:57:27 2002
@@ -31,7 +31,7 @@
 #include <linux/dcache.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/driverfs_fs.h>
+#include <linux/device.h>
 
 #include <asm/uaccess.h>
 
@@ -105,9 +105,11 @@
 static int driverfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev)
 {
 	struct inode *inode = driverfs_get_inode(dir->i_sb, mode, dev);
-	int error = -ENOSPC;
+	int error = -EPERM;
 
-	if (inode) {
+	/* only allow create if ->d_fsdata is not NULL (so we can assume it 
+	 * comes from the driverfs API below. */
+	if (dentry->d_fsdata && inode) {
 		d_instantiate(dentry, inode);
 		dget(dentry);
 		error = 0;
@@ -232,28 +234,26 @@
 	struct driver_file_entry * entry;
 	unsigned char *page;
 	ssize_t retval = 0;
+	struct device * dev;
 
 	entry = (struct driver_file_entry *)file->private_data;
 	if (!entry) {
 		DBG("%s: file entry is NULL\n",__FUNCTION__);
 		return -ENOENT;
 	}
+	if (!entry->show)
+		return 0;
 
-	if (!entry->ops || !entry->ops->read) {
-		DBG("%s: no read callback\n",__FUNCTION__);
-		return -ENOENT;
-	}
+	dev = list_entry(entry->parent,struct device, dir);
 
 	page = (unsigned char*)__get_free_page(GFP_KERNEL);
-	if (!page) {
-		retval = -ENOMEM;
-		goto done;
-	}
+	if (!page)
+		return -ENOMEM;
 
 	while (count > 0) {
 		ssize_t len;
 
-		len = entry->ops->read(page,count,*ppos,entry->data);
+		len = entry->show(dev,page,count,*ppos);
 
 		if (len <= 0) {
 			if (len < 0)
@@ -272,8 +272,6 @@
 		retval += len;
 	}
 	free_page((unsigned long)page);
-
- done:
 	return retval;
 }
 
@@ -294,24 +292,34 @@
 driverfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
 	struct driver_file_entry * entry;
+	struct device * dev;
 	ssize_t retval = 0;
+	char * page;
 
 	entry = (struct driver_file_entry *)file->private_data;
 	if (!entry) {
 		DBG("%s: file entry is NULL\n",__FUNCTION__);
 		return -ENOENT;
 	}
+	if (!entry->store)
+		return 0;
 
-	if (!entry->ops || !entry->ops->write) {
-		DBG("%s: no write callback\n",__FUNCTION__);
-		retval = -ENOENT;
+	dev = list_entry(entry->parent,struct device, dir);
+
+	page = (char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	if (count >= PAGE_SIZE)
+		count = PAGE_SIZE - 1;
+	if (copy_from_user(page,buf,count))
 		goto done;
-	}
+	*(page + count) = '\0';
 
 	while (count > 0) {
 		ssize_t len;
 
-		len = entry->ops->write(buf,count,*ppos,entry->data);
+		len = entry->store(dev,page + retval,count,*ppos);
 
 		if (len <= 0) {
 			if (len < 0)
@@ -323,8 +331,8 @@
 		*ppos += len;
 		buf += len;
 	}
-
  done:
+	free_page((unsigned long)page);
 	return retval;
 }
 
@@ -354,9 +362,28 @@
 
 static int driverfs_open_file(struct inode * inode, struct file * filp)
 {
-	if (filp && inode)
-		filp->private_data = inode->u.generic_ip;
+	struct driver_file_entry * entry;
+	struct device * dev;
 
+	entry = (struct driver_file_entry *)inode->u.generic_ip;
+	if (!entry)
+		return -EFAULT;
+	dev = (struct device *)list_entry(entry->parent,struct device,dir);
+	get_device(dev);
+	filp->private_data = entry;
+	return 0;
+}
+
+static int driverfs_release(struct inode * inode, struct file * filp)
+{
+	struct driver_file_entry * entry;
+	struct device * dev;
+
+	entry = (struct driver_file_entry *)filp->private_data;
+	if (!entry)
+		return -EFAULT;
+	dev = (struct device *)list_entry(entry->parent,struct device,dir);
+	put_device(dev);
 	return 0;
 }
 
@@ -378,18 +405,6 @@
 	return 0;
 }
 
-/* Similar to above - if this dentry goes away, free the
- * driver_dir_entry associated with it..
- */
-static int driverfs_d_delete_dir (struct dentry * dentry)
-{
-	struct driver_dir_entry * entry;
-	entry = (struct driver_dir_entry *)dentry->d_fsdata;
-	if (entry)
-		kfree(entry);
-	return 0;
-}
-
 static struct address_space_operations driverfs_aops = {
 
 };
@@ -400,6 +415,7 @@
 	llseek:		driverfs_file_lseek,
 	mmap:		generic_file_mmap,
 	open:		driverfs_open_file,
+	release:	driverfs_release,
 	fsync:		driverfs_sync_file,
 };
 
@@ -425,10 +441,6 @@
 	d_delete:	driverfs_d_delete_file,
 };
 
-static struct dentry_operations driverfs_dentry_dir_ops = {
-	d_delete:	driverfs_d_delete_dir,
-};
-
 static struct super_operations driverfs_ops = {
 	statfs:		driverfs_statfs,
 	put_inode:	force_delete,
@@ -546,33 +558,6 @@
 MODULE_LICENSE("GPL");
 
 /**
- * driverfs_create_dir_entry - allocate and initialise directory entry
- * @name:	name of the directory
- * @mode:	permissions of the dir
- */
-struct driver_dir_entry *
-driverfs_create_dir_entry(const char * name, mode_t mode)
-{
-	struct driver_dir_entry * entry;
-	int size = sizeof(struct driver_dir_entry) + strlen(name) + 1;
-
-
-	entry = kmalloc(size, GFP_KERNEL);
-	if (!entry)
-		return NULL;
-
-	memset(entry, 0, size);
-	strcpy((char *)entry + sizeof(struct driver_dir_entry), name);
-
-	entry->name = (char *)entry + sizeof(struct driver_dir_entry);
-
-	INIT_LIST_HEAD(&entry->files);
-	entry->mode = mode;
-
-	return entry;
-}
-
-/**
  * driverfs_create_dir - create a directory in the filesystem
  * @entry:	directory entry
  * @parent:	parent directory entry
@@ -662,16 +647,17 @@
 	dentry = lookup_hash(&qstr,parent_dentry);
 	if (IS_ERR(dentry))
 		error = PTR_ERR(dentry);
-	else
+	else {
+		dentry->d_fsdata = (void *)entry;
 		error = vfs_create(parent_dentry->d_inode,dentry,entry->mode);
-
+	}
 
 	/* Still good? Ok, then fill in the blanks: */
 	if (!error) {
-		dentry->d_fsdata = (void *)entry;
 		dentry->d_inode->u.generic_ip = (void *)entry;
 
 		entry->dentry = dentry;
+		entry->parent = parent;
 
 		list_add_tail(&entry->node,&parent->files);
 	}
@@ -784,39 +770,3 @@
  done:
 	put_mount();
 }
-
-/**
- * driverfs_create_entry - allocate and initialise a struct driver_file_entry
- * @name:	name of the file
- * @mode:	permissions of the file
- * @ops:	Operations for the file
- * @data:	data that will be passed back to the callback
- *
- */
-struct driver_file_entry *
-driverfs_create_entry (const char * name, mode_t mode,
-		       struct driverfs_operations * ops, void * data)
-{
-	struct driver_file_entry * entry;
-	int size;
-
-	size = sizeof(struct driver_file_entry) + strlen(name) + 1;
-
-	entry = kmalloc(size,GFP_KERNEL);
-	if (!entry)
-		return NULL;
-
-	memset(entry, 0, size);
-	strcpy((char *)entry + sizeof(struct driver_file_entry), name);
-
-	entry->name = (char *)entry + sizeof(struct driver_file_entry);
-
-	INIT_LIST_HEAD(&entry->node);
-
-	entry->mode = mode;
-	entry->ops = ops;
-	entry->data = data;
-
-	return entry;
-}
-
diff -u --recursive --new-file v2.5.2/linux/fs/efs/super.c linux/fs/efs/super.c
--- v2.5.2/linux/fs/efs/super.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/efs/super.c	Mon Jan 21 15:37:32 2002
@@ -12,21 +12,78 @@
 #include <linux/efs_fs.h>
 #include <linux/efs_vh.h>
 #include <linux/efs_fs_sb.h>
+#include <linux/slab.h>
 
 static DECLARE_FSTYPE_DEV(efs_fs_type, "efs", efs_read_super);
 
+static kmem_cache_t * efs_inode_cachep;
+
+static struct inode *efs_alloc_inode(struct super_block *sb)
+{
+	struct efs_inode_info *ei;
+	ei = (struct efs_inode_info *)kmem_cache_alloc(efs_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void efs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(efs_inode_cachep, INODE_INFO(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct efs_inode_info *ei = (struct efs_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	efs_inode_cachep = kmem_cache_create("efs_inode_cache",
+					     sizeof(struct efs_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (efs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(efs_inode_cachep))
+		printk(KERN_INFO "efs_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations efs_superblock_operations = {
+	alloc_inode:	efs_alloc_inode,
+	destroy_inode:	efs_destroy_inode,
 	read_inode:	efs_read_inode,
 	statfs:		efs_statfs,
 };
 
 static int __init init_efs_fs(void) {
+	int err;
 	printk("EFS: "EFS_VERSION" - http://aeschi.ch.eu.org/efs/\n");
-	return register_filesystem(&efs_fs_type);
+	err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&efs_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_efs_fs(void) {
 	unregister_filesystem(&efs_fs_type);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c
--- v2.5.2/linux/fs/ext2/balloc.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/ext2/balloc.c	Mon Jan 21 15:37:32 2002
@@ -12,8 +12,7 @@
  */
 
 #include <linux/config.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
 #include <linux/locks.h>
 #include <linux/quotaops.h>
 
@@ -42,19 +41,20 @@
 	unsigned long group_desc;
 	unsigned long desc;
 	struct ext2_group_desc * gdp;
+	struct ext2_sb_info *sbi = &sb->u.ext2_sb;
 
-	if (block_group >= sb->u.ext2_sb.s_groups_count) {
+	if (block_group >= sbi->s_groups_count) {
 		ext2_error (sb, "ext2_get_group_desc",
 			    "block_group >= groups_count - "
 			    "block_group = %d, groups_count = %lu",
-			    block_group, sb->u.ext2_sb.s_groups_count);
+			    block_group, sbi->s_groups_count);
 
 		return NULL;
 	}
 	
 	group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
 	desc = block_group % EXT2_DESC_PER_BLOCK(sb);
-	if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
+	if (!sbi->s_group_desc[group_desc]) {
 		ext2_error (sb, "ext2_get_group_desc",
 			    "Group descriptor not loaded - "
 			    "block_group = %d, group_desc = %lu, desc = %lu",
@@ -62,10 +62,9 @@
 		return NULL;
 	}
 	
-	gdp = (struct ext2_group_desc *) 
-	      sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
+	gdp = (struct ext2_group_desc *) sbi->s_group_desc[group_desc]->b_data;
 	if (bh)
-		*bh = sb->u.ext2_sb.s_group_desc[group_desc];
+		*bh = sbi->s_group_desc[group_desc];
 	return gdp + desc;
 }
 
@@ -73,37 +72,26 @@
  * Read the bitmap for a given block_group, reading into the specified 
  * slot in the superblock's bitmap cache.
  *
- * Return >=0 on success or a -ve error code.
+ * Return buffer_head on success or NULL in case of failure.
  */
 
-static int read_block_bitmap (struct super_block * sb,
-			       unsigned int block_group,
-			       unsigned long bitmap_nr)
+static struct buffer_head *read_block_bitmap(struct super_block *sb,
+						unsigned int block_group)
 {
 	struct ext2_group_desc * gdp;
 	struct buffer_head * bh = NULL;
-	int retval = -EIO;
 	
 	gdp = ext2_get_group_desc (sb, block_group, NULL);
 	if (!gdp)
 		goto error_out;
-	retval = 0;
 	bh = sb_bread(sb, le32_to_cpu(gdp->bg_block_bitmap));
-	if (!bh) {
+	if (!bh)
 		ext2_error (sb, "read_block_bitmap",
 			    "Cannot read block bitmap - "
 			    "block_group = %d, block_bitmap = %lu",
 			    block_group, (unsigned long) gdp->bg_block_bitmap);
-		retval = -EIO;
-	}
-	/*
-	 * On IO error, just leave a zero in the superblock's block pointer for
-	 * this group.  The IO will be retried next time.
-	 */
 error_out:
-	sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
-	sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
-	return retval;
+	return bh;
 }
 
 /*
@@ -117,134 +105,65 @@
  * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
  *    this function reads the bitmap without maintaining a LRU cache.
  * 
- * Return the slot used to store the bitmap, or a -ve error code.
+ * Return the buffer_head of the bitmap or ERR_PTR(-ve).
  */
-static int __load_block_bitmap (struct super_block * sb,
-			        unsigned int block_group)
+static struct buffer_head *load_block_bitmap(struct super_block * sb,
+						unsigned int block_group)
 {
-	int i, j, retval = 0;
-	unsigned long block_bitmap_number;
-	struct buffer_head * block_bitmap;
+	struct ext2_sb_info *sbi = &sb->u.ext2_sb;
+	int i, slot = 0;
+	struct buffer_head *bh = sbi->s_block_bitmap[0];
 
-	if (block_group >= sb->u.ext2_sb.s_groups_count)
+	if (block_group >= sbi->s_groups_count)
 		ext2_panic (sb, "load_block_bitmap",
 			    "block_group >= groups_count - "
 			    "block_group = %d, groups_count = %lu",
-			    block_group, sb->u.ext2_sb.s_groups_count);
-
-	if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
-		if (sb->u.ext2_sb.s_block_bitmap[block_group]) {
-			if (sb->u.ext2_sb.s_block_bitmap_number[block_group] ==
-			    block_group)
-				return block_group;
-			ext2_error (sb, "__load_block_bitmap",
-				    "block_group != block_bitmap_number");
-		}
-		retval = read_block_bitmap (sb, block_group, block_group);
-		if (retval < 0)
-			return retval;
-		return block_group;
-	}
-
-	for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
-		    sb->u.ext2_sb.s_block_bitmap_number[i] != block_group; i++)
-		;
-	if (i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
-  	    sb->u.ext2_sb.s_block_bitmap_number[i] == block_group) {
-		block_bitmap_number = sb->u.ext2_sb.s_block_bitmap_number[i];
-		block_bitmap = sb->u.ext2_sb.s_block_bitmap[i];
-		for (j = i; j > 0; j--) {
-			sb->u.ext2_sb.s_block_bitmap_number[j] =
-				sb->u.ext2_sb.s_block_bitmap_number[j - 1];
-			sb->u.ext2_sb.s_block_bitmap[j] =
-				sb->u.ext2_sb.s_block_bitmap[j - 1];
-		}
-		sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number;
-		sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap;
-
-		/*
-		 * There's still one special case here --- if block_bitmap == 0
-		 * then our last attempt to read the bitmap failed and we have
-		 * just ended up caching that failure.  Try again to read it.
-		 */
-		if (!block_bitmap)
-			retval = read_block_bitmap (sb, block_group, 0);
-	} else {
-		if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
-			sb->u.ext2_sb.s_loaded_block_bitmaps++;
-		else
-			brelse (sb->u.ext2_sb.s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
-		for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) {
-			sb->u.ext2_sb.s_block_bitmap_number[j] =
-				sb->u.ext2_sb.s_block_bitmap_number[j - 1];
-			sb->u.ext2_sb.s_block_bitmap[j] =
-				sb->u.ext2_sb.s_block_bitmap[j - 1];
-		}
-		retval = read_block_bitmap (sb, block_group, 0);
-	}
-	return retval;
-}
-
-/*
- * Load the block bitmap for a given block group.  First of all do a couple
- * of fast lookups for common cases and then pass the request onto the guts
- * of the bitmap loader.
- *
- * Return the slot number of the group in the superblock bitmap cache's on
- * success, or a -ve error code.
- *
- * There is still one inconsistency here --- if the number of groups in this
- * filesystems is <= EXT2_MAX_GROUP_LOADED, then we have no way of 
- * differentiating between a group for which we have never performed a bitmap
- * IO request, and a group for which the last bitmap read request failed.
- */
-static inline int load_block_bitmap (struct super_block * sb,
-				     unsigned int block_group)
-{
-	int slot;
+			    block_group, sbi->s_groups_count);
 	
 	/*
 	 * Do the lookup for the slot.  First of all, check if we're asking
 	 * for the same slot as last time, and did we succeed that last time?
 	 */
-	if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
-	    sb->u.ext2_sb.s_block_bitmap_number[0] == block_group &&
-	    sb->u.ext2_sb.s_block_bitmap[0]) {
-		return 0;
-	}
-	/*
-	 * Or can we do a fast lookup based on a loaded group on a filesystem
-	 * small enough to be mapped directly into the superblock?
-	 */
-	else if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED && 
-		 sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group &&
-		 sb->u.ext2_sb.s_block_bitmap[block_group]) {
+	if (sbi->s_loaded_block_bitmaps > 0 &&
+	    sbi->s_block_bitmap_number[0] == block_group && bh)
+		goto found;
+
+	if (sbi->s_groups_count <= EXT2_MAX_GROUP_LOADED) {
 		slot = block_group;
-	}
-	/*
-	 * If not, then do a full lookup for this block group.
-	 */
-	else {
-		slot = __load_block_bitmap (sb, block_group);
+		bh = sbi->s_block_bitmap[slot];
+		if (!bh)
+			goto read_it;
+		if (sbi->s_block_bitmap_number[slot] == slot)
+			goto found;
+		ext2_panic (sb, "__load_block_bitmap",
+			    "block_group != block_bitmap_number");
 	}
 
-	/*
-	 * <0 means we just got an error
-	 */
-	if (slot < 0)
-		return slot;
-	
-	/*
-	 * If it's a valid slot, we may still have cached a previous IO error,
-	 * in which case the bh in the superblock cache will be zero.
-	 */
-	if (!sb->u.ext2_sb.s_block_bitmap[slot])
-		return -EIO;
-	
-	/*
-	 * Must have been read in OK to get this far.
-	 */
-	return slot;
+	bh = NULL;
+	for (i = 0; i < sbi->s_loaded_block_bitmaps &&
+		    sbi->s_block_bitmap_number[i] != block_group; i++)
+		;
+	if (i < sbi->s_loaded_block_bitmaps)
+		bh = sbi->s_block_bitmap[i];
+	else if (sbi->s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
+		sbi->s_loaded_block_bitmaps++;
+	else
+		brelse (sbi->s_block_bitmap[--i]);
+
+	while (i--) {
+		sbi->s_block_bitmap_number[i+1] = sbi->s_block_bitmap_number[i];
+		sbi->s_block_bitmap[i+1] = sbi->s_block_bitmap[i];
+	}
+
+read_it:
+	if (!bh)
+		bh = read_block_bitmap(sb, block_group);
+	sbi->s_block_bitmap_number[slot] = block_group;
+	sbi->s_block_bitmap[slot] = bh;
+	if (!bh)
+		return ERR_PTR(-EIO);
+found:
+	return bh;
 }
 
 /* Free given blocks, update quota and i_blocks field */
@@ -256,7 +175,6 @@
 	unsigned long block_group;
 	unsigned long bit;
 	unsigned long i;
-	int bitmap_nr;
 	unsigned long overflow;
 	struct super_block * sb;
 	struct ext2_group_desc * gdp;
@@ -293,11 +211,10 @@
 		overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb);
 		count -= overflow;
 	}
-	bitmap_nr = load_block_bitmap (sb, block_group);
-	if (bitmap_nr < 0)
+	bh = load_block_bitmap (sb, block_group);
+	if (IS_ERR(bh))
 		goto error_return;
 	
-	bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 	gdp = ext2_get_group_desc (sb, block_group, &bh2);
 	if (!gdp)
 		goto error_return;
@@ -361,7 +278,6 @@
 	struct buffer_head * bh2;
 	char * p, * r;
 	int i, j, k, tmp;
-	int bitmap_nr;
 	struct super_block * sb;
 	struct ext2_group_desc * gdp;
 	struct ext2_super_block * es;
@@ -404,12 +320,10 @@
 		if (j)
 			goal_attempts++;
 #endif
-		bitmap_nr = load_block_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		bh = load_block_bitmap (sb, i);
+		if (IS_ERR(bh))
 			goto io_error;
 		
-		bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
-
 		ext2_debug ("goal is at %d:%d.\n", i, j);
 
 		if (!ext2_test_bit(j, bh->b_data)) {
@@ -477,11 +391,10 @@
 	}
 	if (k >= sb->u.ext2_sb.s_groups_count)
 		goto out;
-	bitmap_nr = load_block_bitmap (sb, i);
-	if (bitmap_nr < 0)
+	bh = load_block_bitmap (sb, i);
+	if (IS_ERR(bh))
 		goto io_error;
 	
-	bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 	r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(sb) >> 3);
 	j = (r - bh->b_data) << 3;
 	if (j < EXT2_BLOCKS_PER_GROUP(sb))
@@ -619,7 +532,6 @@
 #ifdef EXT2FS_DEBUG
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x;
-	int bitmap_nr;
 	struct ext2_group_desc * gdp;
 	int i;
 	
@@ -629,16 +541,16 @@
 	bitmap_count = 0;
 	gdp = NULL;
 	for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
+		struct buffer_head *bh;
 		gdp = ext2_get_group_desc (sb, i, NULL);
 		if (!gdp)
 			continue;
 		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
-		bitmap_nr = load_block_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		bh = load_block_bitmap (sb, i);
+		if (IS_ERR(bh))
 			continue;
 		
-		x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
-				     sb->s_blocksize);
+		x = ext2_count_free (bh, sb->s_blocksize);
 		printk ("group %d: stored = %d, counted = %lu\n",
 			i, le16_to_cpu(gdp->bg_free_blocks_count), x);
 		bitmap_count += x;
@@ -720,7 +632,6 @@
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x, j;
 	unsigned long desc_blocks;
-	int bitmap_nr;
 	struct ext2_group_desc * gdp;
 	int i;
 
@@ -733,11 +644,9 @@
 		if (!gdp)
 			continue;
 		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
-		bitmap_nr = load_block_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		bh = load_block_bitmap (sb, i);
+		if (IS_ERR(bh))
 			continue;
-
-		bh = EXT2_SB(sb)->s_block_bitmap[bitmap_nr];
 
 		if (ext2_bg_has_super(sb, i) && !ext2_test_bit(0, bh->b_data))
 			ext2_error(sb, __FUNCTION__,
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/bitmap.c linux/fs/ext2/bitmap.c
--- v2.5.2/linux/fs/ext2/bitmap.c	Wed Sep 27 13:41:33 2000
+++ linux/fs/ext2/bitmap.c	Mon Jan 21 15:37:32 2002
@@ -7,9 +7,7 @@
  * Universite Pierre et Marie Curie (Paris VI)
  */
 
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-
+#include "ext2.h"
 
 static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
 
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- v2.5.2/linux/fs/ext2/dir.c	Mon Sep 17 13:16:30 2001
+++ linux/fs/ext2/dir.c	Mon Jan 21 15:37:32 2002
@@ -21,8 +21,7 @@
  * and moved here. AV
  */
 
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
 #include <linux/pagemap.h>
 
 typedef struct ext2_dir_entry_2 ext2_dirent;
@@ -306,12 +305,13 @@
 	unsigned long start, n;
 	unsigned long npages = dir_pages(dir);
 	struct page *page = NULL;
+	struct ext2_inode_info *ei = EXT2_I(dir);
 	ext2_dirent * de;
 
 	/* OFFSET_CACHE */
 	*res_page = NULL;
 
-	start = dir->u.ext2_i.i_dir_start_lookup;
+	start = ei->i_dir_start_lookup;
 	if (start >= npages)
 		start = 0;
 	n = start;
@@ -336,7 +336,7 @@
 
 found:
 	*res_page = page;
-	dir->u.ext2_i.i_dir_start_lookup = n;
+	ei->i_dir_start_lookup = n;
 	return de;
 }
 
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/ext2.h linux/fs/ext2/ext2.h
--- v2.5.2/linux/fs/ext2/ext2.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/ext2/ext2.h	Tue Jan 29 21:41:28 2002
@@ -0,0 +1,120 @@
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+/*
+ * second extended file system inode data in memory
+ */
+struct ext2_inode_info {
+	__u32	i_data[15];
+	__u32	i_flags;
+	__u32	i_faddr;
+	__u8	i_frag_no;
+	__u8	i_frag_size;
+	__u16	i_osync;
+	__u32	i_file_acl;
+	__u32	i_dir_acl;
+	__u32	i_dtime;
+	__u32	i_block_group;
+	__u32	i_next_alloc_block;
+	__u32	i_next_alloc_goal;
+	__u32	i_prealloc_block;
+	__u32	i_prealloc_count;
+	__u32	i_dir_start_lookup;
+	struct inode	vfs_inode;
+};
+
+/*
+ * Function prototypes
+ */
+
+/*
+ * Ok, these declarations are also in <linux/kernel.h> but none of the
+ * ext2 source programs needs to include it so they are duplicated here.
+ */
+
+static inline struct ext2_inode_info *EXT2_I(struct inode *inode)
+{
+	return list_entry(inode, struct ext2_inode_info, vfs_inode);
+}
+
+/* balloc.c */
+extern int ext2_bg_has_super(struct super_block *sb, int group);
+extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);
+extern int ext2_new_block (struct inode *, unsigned long,
+			   __u32 *, __u32 *, int *);
+extern void ext2_free_blocks (struct inode *, unsigned long,
+			      unsigned long);
+extern unsigned long ext2_count_free_blocks (struct super_block *);
+extern void ext2_check_blocks_bitmap (struct super_block *);
+extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
+						    unsigned int block_group,
+						    struct buffer_head ** bh);
+
+/* dir.c */
+extern int ext2_add_link (struct dentry *, struct inode *);
+extern ino_t ext2_inode_by_name(struct inode *, struct dentry *);
+extern int ext2_make_empty(struct inode *, struct inode *);
+extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct dentry *, struct page **);
+extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *);
+extern int ext2_empty_dir (struct inode *);
+extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **);
+extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *);
+
+/* fsync.c */
+extern int ext2_sync_file (struct file *, struct dentry *, int);
+extern int ext2_fsync_inode (struct inode *, int);
+
+/* ialloc.c */
+extern struct inode * ext2_new_inode (struct inode *, int);
+extern void ext2_free_inode (struct inode *);
+extern unsigned long ext2_count_free_inodes (struct super_block *);
+extern void ext2_check_inodes_bitmap (struct super_block *);
+extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
+
+/* inode.c */
+extern void ext2_read_inode (struct inode *);
+extern void ext2_write_inode (struct inode *, int);
+extern void ext2_put_inode (struct inode *);
+extern void ext2_delete_inode (struct inode *);
+extern int ext2_sync_inode (struct inode *);
+extern void ext2_discard_prealloc (struct inode *);
+extern void ext2_truncate (struct inode *);
+
+/* ioctl.c */
+extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
+		       unsigned long);
+
+/* super.c */
+extern void ext2_error (struct super_block *, const char *, const char *, ...)
+	__attribute__ ((format (printf, 3, 4)));
+extern NORET_TYPE void ext2_panic (struct super_block *, const char *,
+				   const char *, ...)
+	__attribute__ ((NORET_AND format (printf, 3, 4)));
+extern void ext2_warning (struct super_block *, const char *, const char *, ...)
+	__attribute__ ((format (printf, 3, 4)));
+extern void ext2_update_dynamic_rev (struct super_block *sb);
+extern void ext2_put_super (struct super_block *);
+extern void ext2_write_super (struct super_block *);
+extern int ext2_remount (struct super_block *, int *, char *);
+extern struct super_block * ext2_read_super (struct super_block *,void *,int);
+extern int ext2_statfs (struct super_block *, struct statfs *);
+
+/*
+ * Inodes and files operations
+ */
+
+/* dir.c */
+extern struct file_operations ext2_dir_operations;
+
+/* file.c */
+extern struct inode_operations ext2_file_inode_operations;
+extern struct file_operations ext2_file_operations;
+
+/* inode.c */
+extern struct address_space_operations ext2_aops;
+
+/* namei.c */
+extern struct inode_operations ext2_dir_inode_operations;
+
+/* symlink.c */
+extern struct inode_operations ext2_fast_symlink_inode_operations;
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v2.5.2/linux/fs/ext2/file.c	Thu Oct 11 08:05:18 2001
+++ linux/fs/ext2/file.c	Mon Jan 21 15:37:32 2002
@@ -18,8 +18,7 @@
  * 	(jj@sunsite.ms.mff.cuni.cz)
  */
 
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
 #include <linux/sched.h>
 
 /*
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/fsync.c linux/fs/ext2/fsync.c
--- v2.5.2/linux/fs/ext2/fsync.c	Mon Sep 17 13:16:30 2001
+++ linux/fs/ext2/fsync.c	Mon Jan 21 15:37:32 2002
@@ -22,8 +22,7 @@
  * we can depend on generic_block_fdatasync() to sync the data blocks.
  */
 
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
 
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- v2.5.2/linux/fs/ext2/ialloc.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/ext2/ialloc.c	Mon Jan 28 13:20:38 2002
@@ -13,8 +13,7 @@
  */
 
 #include <linux/config.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
 #include <linux/locks.h>
 #include <linux/quotaops.h>
 
@@ -311,7 +310,7 @@
 	return group;
 }
 
-struct inode * ext2_new_inode (const struct inode * dir, int mode)
+struct inode * ext2_new_inode(struct inode * dir, int mode)
 {
 	struct super_block * sb;
 	struct buffer_head * bh;
@@ -321,6 +320,7 @@
 	struct inode * inode;
 	struct ext2_group_desc * desc;
 	struct ext2_super_block * es;
+	struct ext2_inode_info *ei;
 	int err;
 
 	sb = dir->i_sb;
@@ -328,13 +328,14 @@
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
 
+	ei = EXT2_I(inode);
 	lock_super (sb);
 	es = sb->u.ext2_sb.s_es;
 repeat:
 	if (S_ISDIR(mode))
-		group = find_group_dir(sb, dir->u.ext2_i.i_block_group);
+		group = find_group_dir(sb, EXT2_I(dir)->i_block_group);
 	else 
-		group = find_group_other(sb, dir->u.ext2_i.i_block_group);
+		group = find_group_other(sb, EXT2_I(dir)->i_block_group);
 
 	err = -ENOSPC;
 	if (group == -1)
@@ -385,15 +386,27 @@
 	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size (for stat), not the fs block size */
 	inode->i_blocks = 0;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-	inode->u.ext2_i.i_new_inode = 1;
-	inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags;
+	memset(ei->i_data, 0, sizeof(ei->i_data));
+	ei->i_flags = EXT2_I(dir)->i_flags;
 	if (S_ISLNK(mode))
-		inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL);
-	inode->u.ext2_i.i_block_group = group;
-	if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
+		ei->i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL);
+	ei->i_faddr = 0;
+	ei->i_frag_no = 0;
+	ei->i_frag_size = 0;
+	ei->i_osync = 0;
+	ei->i_file_acl = 0;
+	ei->i_dir_acl = 0;
+	ei->i_dtime = 0;
+	ei->i_block_group = group;
+	ei->i_next_alloc_block = 0;
+	ei->i_next_alloc_goal = 0;
+	ei->i_prealloc_block = 0;
+	ei->i_prealloc_count = 0;
+	ei->i_dir_start_lookup = 0;
+	if (ei->i_flags & EXT2_SYNC_FL)
 		inode->i_flags |= S_SYNC;
-	insert_inode_hash(inode);
 	inode->i_generation = sb->u.ext2_sb.s_next_generation++;
+	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
 
 	unlock_super (sb);
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.5.2/linux/fs/ext2/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/ext2/inode.c	Mon Jan 28 13:20:44 2002
@@ -22,8 +22,7 @@
  *  Assorted race fixes, rewrite of ext2_get_block() by Al Viro, 2000
  */
 
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
 #include <linux/sched.h>
@@ -57,7 +56,7 @@
 	    inode->i_ino == EXT2_ACL_IDX_INO ||
 	    inode->i_ino == EXT2_ACL_DATA_INO)
 		goto no_delete;
-	inode->u.ext2_i.i_dtime	= CURRENT_TIME;
+	EXT2_I(inode)->i_dtime	= CURRENT_TIME;
 	mark_inode_dirty(inode);
 	ext2_update_inode(inode, IS_SYNC(inode));
 	inode->i_size = 0;
@@ -75,13 +74,14 @@
 void ext2_discard_prealloc (struct inode * inode)
 {
 #ifdef EXT2_PREALLOCATE
+	struct ext2_inode_info *ei = EXT2_I(inode);
 	lock_kernel();
 	/* Writer: ->i_prealloc* */
-	if (inode->u.ext2_i.i_prealloc_count) {
-		unsigned short total = inode->u.ext2_i.i_prealloc_count;
-		unsigned long block = inode->u.ext2_i.i_prealloc_block;
-		inode->u.ext2_i.i_prealloc_count = 0;
-		inode->u.ext2_i.i_prealloc_block = 0;
+	if (ei->i_prealloc_count) {
+		unsigned short total = ei->i_prealloc_count;
+		unsigned long block = ei->i_prealloc_block;
+		ei->i_prealloc_count = 0;
+		ei->i_prealloc_block = 0;
 		/* Writer: end */
 		ext2_free_blocks (inode, block, total);
 	}
@@ -98,13 +98,14 @@
 
 
 #ifdef EXT2_PREALLOCATE
+	struct ext2_inode_info *ei = EXT2_I(inode);
 	/* Writer: ->i_prealloc* */
-	if (inode->u.ext2_i.i_prealloc_count &&
-	    (goal == inode->u.ext2_i.i_prealloc_block ||
-	     goal + 1 == inode->u.ext2_i.i_prealloc_block))
+	if (ei->i_prealloc_count &&
+	    (goal == ei->i_prealloc_block ||
+	     goal + 1 == ei->i_prealloc_block))
 	{		
-		result = inode->u.ext2_i.i_prealloc_block++;
-		inode->u.ext2_i.i_prealloc_count--;
+		result = ei->i_prealloc_block++;
+		ei->i_prealloc_count--;
 		/* Writer: end */
 		ext2_debug ("preallocation hit (%lu/%lu).\n",
 			    ++alloc_hits, ++alloc_attempts);
@@ -114,8 +115,8 @@
 			    alloc_hits, ++alloc_attempts);
 		if (S_ISREG(inode->i_mode))
 			result = ext2_new_block (inode, goal, 
-				 &inode->u.ext2_i.i_prealloc_count,
-				 &inode->u.ext2_i.i_prealloc_block, err);
+				 &ei->i_prealloc_count,
+				 &ei->i_prealloc_block, err);
 		else
 			result = ext2_new_block (inode, goal, 0, 0, err);
 	}
@@ -245,7 +246,7 @@
 
 	*err = 0;
 	/* i_data is not going away, no lock needed */
-	add_chain (chain, NULL, inode->u.ext2_i.i_data + *offsets);
+	add_chain (chain, NULL, EXT2_I(inode)->i_data + *offsets);
 	if (!p->key)
 		goto no_block;
 	while (--depth) {
@@ -287,7 +288,8 @@
 
 static inline unsigned long ext2_find_near(struct inode *inode, Indirect *ind)
 {
-	u32 *start = ind->bh ? (u32*) ind->bh->b_data : inode->u.ext2_i.i_data;
+	struct ext2_inode_info *ei = EXT2_I(inode);
+	u32 *start = ind->bh ? (u32*) ind->bh->b_data : ei->i_data;
 	u32 *p;
 
 	/* Try to find previous block */
@@ -303,8 +305,7 @@
 	 * It is going to be refered from inode itself? OK, just put it into
 	 * the same cylinder group then.
 	 */
-	return (inode->u.ext2_i.i_block_group * 
-		EXT2_BLOCKS_PER_GROUP(inode->i_sb)) +
+	return (ei->i_block_group * EXT2_BLOCKS_PER_GROUP(inode->i_sb)) +
 	       le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_first_data_block);
 }
 
@@ -327,10 +328,11 @@
 				 Indirect *partial,
 				 unsigned long *goal)
 {
+	struct ext2_inode_info *ei = EXT2_I(inode);
 	/* Writer: ->i_next_alloc* */
-	if (block == inode->u.ext2_i.i_next_alloc_block + 1) {
-		inode->u.ext2_i.i_next_alloc_block++;
-		inode->u.ext2_i.i_next_alloc_goal++;
+	if (block == ei->i_next_alloc_block + 1) {
+		ei->i_next_alloc_block++;
+		ei->i_next_alloc_goal++;
 	} 
 	/* Writer: end */
 	/* Reader: pointers, ->i_next_alloc* */
@@ -339,8 +341,8 @@
 		 * try the heuristic for sequential allocation,
 		 * failing that at least try to get decent locality.
 		 */
-		if (block == inode->u.ext2_i.i_next_alloc_block)
-			*goal = inode->u.ext2_i.i_next_alloc_goal;
+		if (block == ei->i_next_alloc_block)
+			*goal = ei->i_next_alloc_goal;
 		if (!*goal)
 			*goal = ext2_find_near(inode, partial);
 		return 0;
@@ -407,7 +409,7 @@
 		mark_buffer_uptodate(bh, 1);
 		unlock_buffer(bh);
 		mark_buffer_dirty_inode(bh, inode);
-		if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
+		if (IS_SYNC(inode) || EXT2_I(inode)->i_osync) {
 			ll_rw_block (WRITE, 1, &bh);
 			wait_on_buffer (bh);
 		}
@@ -447,6 +449,7 @@
 				     Indirect *where,
 				     int num)
 {
+	struct ext2_inode_info *ei = EXT2_I(inode);
 	int i;
 
 	/* Verify that place we are splicing to is still there and vacant */
@@ -459,8 +462,8 @@
 	/* That's it */
 
 	*where->p = where->key;
-	inode->u.ext2_i.i_next_alloc_block = block;
-	inode->u.ext2_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key);
+	ei->i_next_alloc_block = block;
+	ei->i_next_alloc_goal = le32_to_cpu(where[num-1].key);
 
 	/* Writer: end */
 
@@ -471,13 +474,13 @@
 	/* had we spliced it onto indirect block? */
 	if (where->bh) {
 		mark_buffer_dirty_inode(where->bh, inode);
-		if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
+		if (IS_SYNC(inode) || ei->i_osync) {
 			ll_rw_block (WRITE, 1, &where->bh);
 			wait_on_buffer(where->bh);
 		}
 	}
 
-	if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
+	if (IS_SYNC(inode) || ei->i_osync)
 		ext2_sync_inode (inode);
 	else
 		mark_inode_dirty(inode);
@@ -785,7 +788,7 @@
 
 void ext2_truncate (struct inode * inode)
 {
-	u32 *i_data = inode->u.ext2_i.i_data;
+	u32 *i_data = EXT2_I(inode)->i_data;
 	int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
 	int offsets[4];
 	Indirect chain[4];
@@ -886,6 +889,7 @@
 	unsigned long block;
 	unsigned long offset;
 	struct ext2_group_desc * gdp;
+	struct ext2_inode_info *ei = EXT2_I(inode);
 
 	if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO &&
 	     inode->i_ino != EXT2_ACL_DATA_INO &&
@@ -939,13 +943,13 @@
 	inode->i_atime = le32_to_cpu(raw_inode->i_atime);
 	inode->i_ctime = le32_to_cpu(raw_inode->i_ctime);
 	inode->i_mtime = le32_to_cpu(raw_inode->i_mtime);
-	inode->u.ext2_i.i_dtime = le32_to_cpu(raw_inode->i_dtime);
+	ei->i_dtime = le32_to_cpu(raw_inode->i_dtime);
 	/* We now have enough fields to check if the inode was active or not.
 	 * This is needed because nfsd might try to access dead inodes
 	 * the test is that same one that e2fsck uses
 	 * NeilBrown 1999oct15
 	 */
-	if (inode->i_nlink == 0 && (inode->i_mode == 0 || inode->u.ext2_i.i_dtime)) {
+	if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) {
 		/* this inode is deleted */
 		brelse (bh);
 		goto bad_inode;
@@ -953,25 +957,31 @@
 	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size (for stat), not the fs block size */
 	inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
 	inode->i_version = ++event;
-	inode->u.ext2_i.i_flags = le32_to_cpu(raw_inode->i_flags);
-	inode->u.ext2_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);
-	inode->u.ext2_i.i_frag_no = raw_inode->i_frag;
-	inode->u.ext2_i.i_frag_size = raw_inode->i_fsize;
-	inode->u.ext2_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
+	ei->i_flags = le32_to_cpu(raw_inode->i_flags);
+	ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
+	ei->i_frag_no = raw_inode->i_frag;
+	ei->i_frag_size = raw_inode->i_fsize;
+	ei->i_osync = 0;
+	ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
+	ei->i_dir_acl = 0;
 	if (S_ISREG(inode->i_mode))
 		inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
 	else
-		inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+		ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+	ei->i_dtime = 0;
 	inode->i_generation = le32_to_cpu(raw_inode->i_generation);
-	inode->u.ext2_i.i_prealloc_count = 0;
-	inode->u.ext2_i.i_block_group = block_group;
+	ei->i_next_alloc_block = 0;
+	ei->i_next_alloc_goal = 0;
+	ei->i_prealloc_count = 0;
+	ei->i_block_group = block_group;
+	ei->i_dir_start_lookup = 0;
 
 	/*
 	 * NOTE! The in-memory inode i_data array is in little-endian order
 	 * even on big-endian machines: we do NOT byteswap the block numbers!
 	 */
 	for (block = 0; block < EXT2_N_BLOCKS; block++)
-		inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
+		ei->i_data[block] = raw_inode->i_block[block];
 
 	if (inode->i_ino == EXT2_ACL_IDX_INO ||
 	    inode->i_ino == EXT2_ACL_DATA_INO)
@@ -996,19 +1006,19 @@
 				   le32_to_cpu(raw_inode->i_block[0]));
 	brelse (bh);
 	inode->i_attr_flags = 0;
-	if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) {
+	if (ei->i_flags & EXT2_SYNC_FL) {
 		inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS;
 		inode->i_flags |= S_SYNC;
 	}
-	if (inode->u.ext2_i.i_flags & EXT2_APPEND_FL) {
+	if (ei->i_flags & EXT2_APPEND_FL) {
 		inode->i_attr_flags |= ATTR_FLAG_APPEND;
 		inode->i_flags |= S_APPEND;
 	}
-	if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL) {
+	if (ei->i_flags & EXT2_IMMUTABLE_FL) {
 		inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;
 		inode->i_flags |= S_IMMUTABLE;
 	}
-	if (inode->u.ext2_i.i_flags & EXT2_NOATIME_FL) {
+	if (ei->i_flags & EXT2_NOATIME_FL) {
 		inode->i_attr_flags |= ATTR_FLAG_NOATIME;
 		inode->i_flags |= S_NOATIME;
 	}
@@ -1030,6 +1040,7 @@
 	unsigned long offset;
 	int err = 0;
 	struct ext2_group_desc * gdp;
+	struct ext2_inode_info *ei = EXT2_I(inode);
 
 	if ((inode->i_ino != EXT2_ROOT_INO &&
 	     inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||
@@ -1077,7 +1088,7 @@
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
-		if(!inode->u.ext2_i.i_dtime) {
+		if(!ei->i_dtime) {
 			raw_inode->i_uid_high = cpu_to_le16(high_16_bits(inode->i_uid));
 			raw_inode->i_gid_high = cpu_to_le16(high_16_bits(inode->i_gid));
 		} else {
@@ -1096,14 +1107,14 @@
 	raw_inode->i_ctime = cpu_to_le32(inode->i_ctime);
 	raw_inode->i_mtime = cpu_to_le32(inode->i_mtime);
 	raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
-	raw_inode->i_dtime = cpu_to_le32(inode->u.ext2_i.i_dtime);
-	raw_inode->i_flags = cpu_to_le32(inode->u.ext2_i.i_flags);
-	raw_inode->i_faddr = cpu_to_le32(inode->u.ext2_i.i_faddr);
-	raw_inode->i_frag = inode->u.ext2_i.i_frag_no;
-	raw_inode->i_fsize = inode->u.ext2_i.i_frag_size;
-	raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl);
+	raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
+	raw_inode->i_flags = cpu_to_le32(ei->i_flags);
+	raw_inode->i_faddr = cpu_to_le32(ei->i_faddr);
+	raw_inode->i_frag = ei->i_frag_no;
+	raw_inode->i_fsize = ei->i_frag_size;
+	raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);
 	if (S_ISDIR(inode->i_mode))
-		raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl);
+		raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl);
 	else {
 		raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
 		if (inode->i_size > 0x7fffffffULL) {
@@ -1129,7 +1140,7 @@
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 		raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
 	else for (block = 0; block < EXT2_N_BLOCKS; block++)
-		raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
+		raw_inode->i_block[block] = ei->i_data[block];
 	mark_buffer_dirty(bh);
 	if (do_sync) {
 		ll_rw_block (WRITE, 1, &bh);
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/ioctl.c linux/fs/ext2/ioctl.c
--- v2.5.2/linux/fs/ext2/ioctl.c	Wed Sep 27 13:41:33 2000
+++ linux/fs/ext2/ioctl.c	Mon Jan 21 15:37:32 2002
@@ -7,8 +7,7 @@
  * Universite Pierre et Marie Curie (Paris VI)
  */
 
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
 #include <linux/sched.h>
 #include <asm/uaccess.h>
 
@@ -16,13 +15,14 @@
 int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 		unsigned long arg)
 {
+	struct ext2_inode_info *ei = EXT2_I(inode);
 	unsigned int flags;
 
 	ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg);
 
 	switch (cmd) {
 	case EXT2_IOC_GETFLAGS:
-		flags = inode->u.ext2_i.i_flags & EXT2_FL_USER_VISIBLE;
+		flags = ei->i_flags & EXT2_FL_USER_VISIBLE;
 		return put_user(flags, (int *) arg);
 	case EXT2_IOC_SETFLAGS: {
 		unsigned int oldflags;
@@ -36,7 +36,7 @@
 		if (get_user(flags, (int *) arg))
 			return -EFAULT;
 
-		oldflags = inode->u.ext2_i.i_flags;
+		oldflags = ei->i_flags;
 
 		/*
 		 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
@@ -51,7 +51,7 @@
 
 		flags = flags & EXT2_FL_USER_MODIFIABLE;
 		flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE;
-		inode->u.ext2_i.i_flags = flags;
+		ei->i_flags = flags;
 
 		if (flags & EXT2_SYNC_FL)
 			inode->i_flags |= S_SYNC;
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.5.2/linux/fs/ext2/namei.c	Wed Oct  3 22:57:36 2001
+++ linux/fs/ext2/namei.c	Mon Jan 21 15:37:32 2002
@@ -29,8 +29,7 @@
  *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
 #include <linux/pagemap.h>
 
 /*
@@ -134,7 +133,7 @@
 	if (IS_ERR(inode))
 		goto out;
 
-	if (l > sizeof (inode->u.ext2_i.i_data)) {
+	if (l > sizeof (EXT2_I(inode)->i_data)) {
 		/* slow symlink */
 		inode->i_op = &page_symlink_inode_operations;
 		inode->i_mapping->a_ops = &ext2_aops;
@@ -144,7 +143,7 @@
 	} else {
 		/* fast symlink */
 		inode->i_op = &ext2_fast_symlink_inode_operations;
-		memcpy((char*)&inode->u.ext2_i.i_data,symname,l);
+		memcpy((char*)(EXT2_I(inode)->i_data),symname,l);
 		inode->i_size = l-1;
 	}
 	mark_inode_dirty(inode);
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v2.5.2/linux/fs/ext2/super.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/ext2/super.c	Mon Jan 21 15:37:32 2002
@@ -19,8 +19,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/string.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/locks.h>
@@ -148,7 +147,51 @@
 	return;
 }
 
+static kmem_cache_t * ext2_inode_cachep;
+
+static struct inode *ext2_alloc_inode(struct super_block *sb)
+{
+	struct ext2_inode_info *ei;
+	ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void ext2_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(ext2_inode_cachep, EXT2_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct ext2_inode_info *ei = (struct ext2_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	ext2_inode_cachep = kmem_cache_create("ext2_inode_cache",
+					     sizeof(struct ext2_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (ext2_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(ext2_inode_cachep))
+		printk(KERN_INFO "ext2_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations ext2_sops = {
+	alloc_inode:	ext2_alloc_inode,
+	destroy_inode:	ext2_destroy_inode,
 	read_inode:	ext2_read_inode,
 	write_inode:	ext2_write_inode,
 	put_inode:	ext2_put_inode,
@@ -804,12 +847,23 @@
 
 static int __init init_ext2_fs(void)
 {
-        return register_filesystem(&ext2_fs_type);
+	int err = init_inodecache();
+	if (err)
+		goto out1;
+        err = register_filesystem(&ext2_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_ext2_fs(void)
 {
 	unregister_filesystem(&ext2_fs_type);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c
--- v2.5.2/linux/fs/ext2/symlink.c	Wed Sep 27 13:41:33 2000
+++ linux/fs/ext2/symlink.c	Mon Jan 21 15:37:32 2002
@@ -17,19 +17,18 @@
  *  ext2 symlink handling code
  */
 
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
 
 static int ext2_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
-	char *s = (char *)dentry->d_inode->u.ext2_i.i_data;
-	return vfs_readlink(dentry, buffer, buflen, s);
+	struct ext2_inode_info *ei = EXT2_I(dentry->d_inode);
+	return vfs_readlink(dentry, buffer, buflen, (char *)ei->i_data);
 }
 
 static int ext2_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char *s = (char *)dentry->d_inode->u.ext2_i.i_data;
-	return vfs_follow_link(nd, s);
+	struct ext2_inode_info *ei = EXT2_I(dentry->d_inode);
+	return vfs_follow_link(nd, (char *)ei->i_data);
 }
 
 struct inode_operations ext2_fast_symlink_inode_operations = {
diff -u --recursive --new-file v2.5.2/linux/fs/ext3/ialloc.c linux/fs/ext3/ialloc.c
--- v2.5.2/linux/fs/ext3/ialloc.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/ext3/ialloc.c	Mon Jan 28 22:49:27 2002
@@ -293,7 +293,7 @@
  * group to find a free inode.
  */
 struct inode * ext3_new_inode (handle_t *handle,
-				const struct inode * dir, int mode)
+				struct inode * dir, int mode)
 {
 	struct super_block * sb;
 	struct buffer_head * bh;
@@ -304,6 +304,7 @@
 	struct ext3_group_desc * gdp;
 	struct ext3_group_desc * tmp;
 	struct ext3_super_block * es;
+	struct ext3_inode_info *ei;
 	int err = 0;
 
 	/* Cannot create files in a deleted directory */
@@ -314,7 +315,7 @@
 	inode = new_inode(sb);
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
-	init_rwsem(&inode->u.ext3_i.truncate_sem);
+	ei = EXT3_I(inode);
 
 	lock_super (sb);
 	es = sb->u.ext3_sb.s_es;
@@ -346,7 +347,7 @@
 		/*
 		 * Try to place the inode in its parent directory
 		 */
-		i = dir->u.ext3_i.i_block_group;
+		i = EXT3_I(dir)->i_block_group;
 		tmp = ext3_get_group_desc (sb, i, &bh2);
 		if (tmp && le16_to_cpu(tmp->bg_free_inodes_count))
 			gdp = tmp;
@@ -372,7 +373,7 @@
 			/*
 			 * That failed: try linear search for a free inode
 			 */
-			i = dir->u.ext3_i.i_block_group + 1;
+			i = EXT3_I(dir)->i_block_group + 1;
 			for (j = 2; j < sb->u.ext3_sb.s_groups_count; j++) {
 				if (++i >= sb->u.ext3_sb.s_groups_count)
 					i = 0;
@@ -479,31 +480,38 @@
 	inode->i_blksize = PAGE_SIZE;
 	inode->i_blocks = 0;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-	inode->u.ext3_i.i_flags = dir->u.ext3_i.i_flags & ~EXT3_INDEX_FL;
+
+	memset(ei->i_data, 0, sizeof(ei->i_data));
+	ei->i_next_alloc_block = 0;
+	ei->i_next_alloc_goal = 0;
+	ei->i_dir_start_lookup = 0;
+	ei->i_disksize = 0;
+
+	ei->i_flags = EXT3_I(dir)->i_flags & ~EXT3_INDEX_FL;
 	if (S_ISLNK(mode))
-		inode->u.ext3_i.i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL);
+		ei->i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL);
 #ifdef EXT3_FRAGMENTS
-	inode->u.ext3_i.i_faddr = 0;
-	inode->u.ext3_i.i_frag_no = 0;
-	inode->u.ext3_i.i_frag_size = 0;
+	ei->i_faddr = 0;
+	ei->i_frag_no = 0;
+	ei->i_frag_size = 0;
 #endif
-	inode->u.ext3_i.i_file_acl = 0;
-	inode->u.ext3_i.i_dir_acl = 0;
-	inode->u.ext3_i.i_dtime = 0;
-	INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
+	ei->i_file_acl = 0;
+	ei->i_dir_acl = 0;
+	ei->i_dtime = 0;
 #ifdef EXT3_PREALLOCATE
-	inode->u.ext3_i.i_prealloc_count = 0;
+	ei->i_prealloc_block = 0;
+	ei->i_prealloc_count = 0;
 #endif
-	inode->u.ext3_i.i_block_group = i;
+	ei->i_block_group = i;
 	
-	if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL)
+	if (ei->i_flags & EXT3_SYNC_FL)
 		inode->i_flags |= S_SYNC;
 	if (IS_SYNC(inode))
 		handle->h_sync = 1;
 	insert_inode_hash(inode);
 	inode->i_generation = event++;
 
-	inode->u.ext3_i.i_state = EXT3_STATE_NEW;
+	ei->i_state = EXT3_STATE_NEW;
 	err = ext3_mark_inode_dirty(handle, inode);
 	if (err) goto fail;
 	
diff -u --recursive --new-file v2.5.2/linux/fs/ext3/inode.c linux/fs/ext3/inode.c
--- v2.5.2/linux/fs/ext3/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/ext3/inode.c	Mon Jan 21 15:37:32 2002
@@ -196,7 +196,7 @@
 	 * (Well, we could do this if we need to, but heck - it works)
 	 */
 	ext3_orphan_del(handle, inode);
-	inode->u.ext3_i.i_dtime	= CURRENT_TIME;
+	EXT3_I(inode)->i_dtime	= CURRENT_TIME;
 
 	/* 
 	 * One subtle ordering requirement: if anything has gone wrong
@@ -220,13 +220,14 @@
 void ext3_discard_prealloc (struct inode * inode)
 {
 #ifdef EXT3_PREALLOCATE
+	struct ext3_inode_info *ei = EXT3_I(inode);
 	lock_kernel();
 	/* Writer: ->i_prealloc* */
-	if (inode->u.ext3_i.i_prealloc_count) {
-		unsigned short total = inode->u.ext3_i.i_prealloc_count;
-		unsigned long block = inode->u.ext3_i.i_prealloc_block;
-		inode->u.ext3_i.i_prealloc_count = 0;
-		inode->u.ext3_i.i_prealloc_block = 0;
+	if (ei->i_prealloc_count) {
+		unsigned short total = ei->i_prealloc_count;
+		unsigned long block = ei->i_prealloc_block;
+		ei->i_prealloc_count = 0;
+		ei->i_prealloc_block = 0;
 		/* Writer: end */
 		ext3_free_blocks (inode, block, total);
 	}
@@ -243,13 +244,14 @@
 	unsigned long result;
 
 #ifdef EXT3_PREALLOCATE
+	struct ext3_inode_info *ei = EXT3_I(inode);
 	/* Writer: ->i_prealloc* */
-	if (inode->u.ext3_i.i_prealloc_count &&
-	    (goal == inode->u.ext3_i.i_prealloc_block ||
-	     goal + 1 == inode->u.ext3_i.i_prealloc_block))
+	if (ei->i_prealloc_count &&
+	    (goal == ei->i_prealloc_block ||
+	     goal + 1 == ei->i_prealloc_block))
 	{
-		result = inode->u.ext3_i.i_prealloc_block++;
-		inode->u.ext3_i.i_prealloc_count--;
+		result = ei->i_prealloc_block++;
+		ei->i_prealloc_count--;
 		/* Writer: end */
 		ext3_debug ("preallocation hit (%lu/%lu).\n",
 			    ++alloc_hits, ++alloc_attempts);
@@ -259,8 +261,8 @@
 			    alloc_hits, ++alloc_attempts);
 		if (S_ISREG(inode->i_mode))
 			result = ext3_new_block (inode, goal, 
-				 &inode->u.ext3_i.i_prealloc_count,
-				 &inode->u.ext3_i.i_prealloc_block, err);
+				 &ei->i_prealloc_count,
+				 &ei->i_prealloc_block, err);
 		else
 			result = ext3_new_block (inode, goal, 0, 0, err);
 		/*
@@ -394,7 +396,7 @@
 
 	*err = 0;
 	/* i_data is not going away, no lock needed */
-	add_chain (chain, NULL, inode->u.ext3_i.i_data + *offsets);
+	add_chain (chain, NULL, EXT3_I(inode)->i_data + *offsets);
 	if (!p->key)
 		goto no_block;
 	while (--depth) {
@@ -437,7 +439,8 @@
 
 static inline unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
 {
-	u32 *start = ind->bh ? (u32*) ind->bh->b_data : inode->u.ext3_i.i_data;
+	struct ext3_inode_info *ei = EXT3_I(inode);
+	u32 *start = ind->bh ? (u32*) ind->bh->b_data : ei->i_data;
 	u32 *p;
 
 	/* Try to find previous block */
@@ -453,8 +456,7 @@
 	 * It is going to be refered from inode itself? OK, just put it into
 	 * the same cylinder group then.
 	 */
-	return (inode->u.ext3_i.i_block_group * 
-		EXT3_BLOCKS_PER_GROUP(inode->i_sb)) +
+	return (ei->i_block_group * EXT3_BLOCKS_PER_GROUP(inode->i_sb)) +
 	       le32_to_cpu(inode->i_sb->u.ext3_sb.s_es->s_first_data_block);
 }
 
@@ -474,14 +476,15 @@
 static int ext3_find_goal(struct inode *inode, long block, Indirect chain[4],
 			  Indirect *partial, unsigned long *goal)
 {
+	struct ext3_inode_info *ei = EXT3_I(inode);
 	/* Writer: ->i_next_alloc* */
-	if (block == inode->u.ext3_i.i_next_alloc_block + 1) {
-		inode->u.ext3_i.i_next_alloc_block++;
-		inode->u.ext3_i.i_next_alloc_goal++;
+	if (block == ei->i_next_alloc_block + 1) {
+		ei->i_next_alloc_block++;
+		ei->i_next_alloc_goal++;
 	}
 #ifdef SEARCH_FROM_ZERO
-	inode->u.ext3_i.i_next_alloc_block = 0;
-	inode->u.ext3_i.i_next_alloc_goal = 0;
+	ei->i_next_alloc_block = 0;
+	ei->i_next_alloc_goal = 0;
 #endif
 	/* Writer: end */
 	/* Reader: pointers, ->i_next_alloc* */
@@ -490,8 +493,8 @@
 		 * try the heuristic for sequential allocation,
 		 * failing that at least try to get decent locality.
 		 */
-		if (block == inode->u.ext3_i.i_next_alloc_block)
-			*goal = inode->u.ext3_i.i_next_alloc_goal;
+		if (block == ei->i_next_alloc_block)
+			*goal = ei->i_next_alloc_goal;
 		if (!*goal)
 			*goal = ext3_find_near(inode, partial);
 #ifdef SEARCH_FROM_ZERO
@@ -619,6 +622,7 @@
 {
 	int i;
 	int err = 0;
+	struct ext3_inode_info *ei = EXT3_I(inode);
 
 	/*
 	 * If we're splicing into a [td]indirect block (as opposed to the
@@ -641,11 +645,11 @@
 	/* That's it */
 
 	*where->p = where->key;
-	inode->u.ext3_i.i_next_alloc_block = block;
-	inode->u.ext3_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key);
+	ei->i_next_alloc_block = block;
+	ei->i_next_alloc_goal = le32_to_cpu(where[num-1].key);
 #ifdef SEARCH_FROM_ZERO
-	inode->u.ext3_i.i_next_alloc_block = 0;
-	inode->u.ext3_i.i_next_alloc_goal = 0;
+	ei->i_next_alloc_block = 0;
+	ei->i_next_alloc_goal = 0;
 #endif
 	/* Writer: end */
 
@@ -729,6 +733,7 @@
 	unsigned long goal;
 	int left;
 	int depth = ext3_block_to_path(inode, iblock, offsets);
+	struct ext3_inode_info *ei = EXT3_I(inode);
 	loff_t new_size;
 
 	J_ASSERT(handle != NULL || create == 0);
@@ -780,7 +785,7 @@
 	/*
 	 * Block out ext3_truncate while we alter the tree
 	 */
-	down_read(&inode->u.ext3_i.truncate_sem);
+	down_read(&ei->truncate_sem);
 	err = ext3_alloc_branch(handle, inode, left, goal,
 					offsets+(partial-chain), partial);
 
@@ -792,7 +797,7 @@
 	if (!err)
 		err = ext3_splice_branch(handle, inode, iblock, chain,
 					 partial, left);
-	up_read(&inode->u.ext3_i.truncate_sem);
+	up_read(&ei->truncate_sem);
 	if (err == -EAGAIN)
 		goto changed;
 	if (err)
@@ -805,8 +810,8 @@
 	 * truncate is in progress.  It is racy between multiple parallel
 	 * instances of get_block, but we have the BKL.
 	 */
-	if (new_size > inode->u.ext3_i.i_disksize)
-		inode->u.ext3_i.i_disksize = new_size;
+	if (new_size > ei->i_disksize)
+		ei->i_disksize = new_size;
 
 	bh_result->b_state |= (1UL << BH_New);
 	goto got_it;
@@ -916,7 +921,7 @@
 		struct buffer_head *tmp_bh;
 
 		for (i = 1;
-		     inode->u.ext3_i.i_prealloc_count &&
+		     EXT3_I(inode)->i_prealloc_count &&
 		     i < EXT3_SB(inode->i_sb)->s_es->s_prealloc_dir_blocks;
 		     i++) {
 			/*
@@ -1126,8 +1131,8 @@
 			kunmap(page);
 		}
 	}
-	if (inode->i_size > inode->u.ext3_i.i_disksize) {
-		inode->u.ext3_i.i_disksize = inode->i_size;
+	if (inode->i_size > EXT3_I(inode)->i_disksize) {
+		EXT3_I(inode)->i_disksize = inode->i_size;
 		ret2 = ext3_mark_inode_dirty(handle, inode);
 		if (!ret) 
 			ret = ret2;
@@ -1826,7 +1831,8 @@
 void ext3_truncate(struct inode * inode)
 {
 	handle_t *handle;
-	u32 *i_data = inode->u.ext3_i.i_data;
+	struct ext3_inode_info *ei = EXT3_I(inode);
+	u32 *i_data = ei->i_data;
 	int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb);
 	int offsets[4];
 	Indirect chain[4];
@@ -1878,13 +1884,13 @@
 	 * on-disk inode. We do this via i_disksize, which is the value which
 	 * ext3 *really* writes onto the disk inode.
 	 */
-	inode->u.ext3_i.i_disksize = inode->i_size;
+	ei->i_disksize = inode->i_size;
 
 	/*
 	 * From here we block out all ext3_get_block() callers who want to
 	 * modify the block allocation tree.
 	 */
-	down_write(&inode->u.ext3_i.truncate_sem);
+	down_write(&ei->truncate_sem);
 
 	if (n == 1) {		/* direct blocks */
 		ext3_free_data(handle, inode, NULL, i_data+offsets[0],
@@ -1948,7 +1954,7 @@
 		case EXT3_TIND_BLOCK:
 			;
 	}
-	up_write(&inode->u.ext3_i.truncate_sem);
+	up_write(&ei->truncate_sem);
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	ext3_mark_inode_dirty(handle, inode);
 
@@ -2041,6 +2047,7 @@
 {
 	struct ext3_iloc iloc;
 	struct ext3_inode *raw_inode;
+	struct ext3_inode_info *ei = EXT3_I(inode);
 	struct buffer_head *bh;
 	int block;
 	
@@ -2048,7 +2055,6 @@
 		goto bad_inode;
 	bh = iloc.bh;
 	raw_inode = iloc.raw_inode;
-	init_rwsem(&inode->u.ext3_i.truncate_sem);
 	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
 	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
 	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
@@ -2061,7 +2067,12 @@
 	inode->i_atime = le32_to_cpu(raw_inode->i_atime);
 	inode->i_ctime = le32_to_cpu(raw_inode->i_ctime);
 	inode->i_mtime = le32_to_cpu(raw_inode->i_mtime);
-	inode->u.ext3_i.i_dtime = le32_to_cpu(raw_inode->i_dtime);
+
+	ei->i_state = 0;
+	ei->i_next_alloc_block = 0;
+	ei->i_next_alloc_goal = 0;
+	ei->i_dir_start_lookup = 0;
+	ei->i_dtime = le32_to_cpu(raw_inode->i_dtime);
 	/* We now have enough fields to check if the inode was active or not.
 	 * This is needed because nfsd might try to access dead inodes
 	 * the test is that same one that e2fsck uses
@@ -2084,33 +2095,33 @@
 					 * size */  
 	inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
 	inode->i_version = ++event;
-	inode->u.ext3_i.i_flags = le32_to_cpu(raw_inode->i_flags);
+	ei->i_flags = le32_to_cpu(raw_inode->i_flags);
 #ifdef EXT3_FRAGMENTS
-	inode->u.ext3_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);
-	inode->u.ext3_i.i_frag_no = raw_inode->i_frag;
-	inode->u.ext3_i.i_frag_size = raw_inode->i_fsize;
+	ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
+	ei->i_frag_no = raw_inode->i_frag;
+	ei->i_frag_size = raw_inode->i_fsize;
 #endif
-	inode->u.ext3_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
+	ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
 	if (!S_ISREG(inode->i_mode)) {
-		inode->u.ext3_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+		ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
 	} else {
 		inode->i_size |=
 			((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
 	}
-	inode->u.ext3_i.i_disksize = inode->i_size;
+	ei->i_disksize = inode->i_size;
 	inode->i_generation = le32_to_cpu(raw_inode->i_generation);
 #ifdef EXT3_PREALLOCATE
-	inode->u.ext3_i.i_prealloc_count = 0;
+	ei->i_prealloc_count = 0;
 #endif
-	inode->u.ext3_i.i_block_group = iloc.block_group;
+	ei->i_block_group = iloc.block_group;
 
 	/*
 	 * NOTE! The in-memory inode i_data array is in little-endian order
 	 * even on big-endian machines: we do NOT byteswap the block numbers!
 	 */
 	for (block = 0; block < EXT3_N_BLOCKS; block++)
-		inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block];
-	INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
+		ei->i_data[block] = iloc.raw_inode->i_block[block];
+	INIT_LIST_HEAD(&ei->i_orphan);
 
 	brelse (iloc.bh);
 
@@ -2135,19 +2146,19 @@
 		init_special_inode(inode, inode->i_mode,
 				   le32_to_cpu(iloc.raw_inode->i_block[0]));
 	/* inode->i_attr_flags = 0;				unused */
-	if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL) {
+	if (ei->i_flags & EXT3_SYNC_FL) {
 		/* inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS; unused */
 		inode->i_flags |= S_SYNC;
 	}
-	if (inode->u.ext3_i.i_flags & EXT3_APPEND_FL) {
+	if (ei->i_flags & EXT3_APPEND_FL) {
 		/* inode->i_attr_flags |= ATTR_FLAG_APPEND;	unused */
 		inode->i_flags |= S_APPEND;
 	}
-	if (inode->u.ext3_i.i_flags & EXT3_IMMUTABLE_FL) {
+	if (ei->i_flags & EXT3_IMMUTABLE_FL) {
 		/* inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;	unused */
 		inode->i_flags |= S_IMMUTABLE;
 	}
-	if (inode->u.ext3_i.i_flags & EXT3_NOATIME_FL) {
+	if (ei->i_flags & EXT3_NOATIME_FL) {
 		/* inode->i_attr_flags |= ATTR_FLAG_NOATIME;	unused */
 		inode->i_flags |= S_NOATIME;
 	}
@@ -2169,6 +2180,7 @@
 				struct ext3_iloc *iloc)
 {
 	struct ext3_inode *raw_inode = iloc->raw_inode;
+	struct ext3_inode_info *ei = EXT3_I(inode);
 	struct buffer_head *bh = iloc->bh;
 	int err = 0, rc, block;
 
@@ -2186,7 +2198,7 @@
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
-		if(!inode->u.ext3_i.i_dtime) {
+		if(!ei->i_dtime) {
 			raw_inode->i_uid_high =
 				cpu_to_le16(high_16_bits(inode->i_uid));
 			raw_inode->i_gid_high =
@@ -2204,34 +2216,34 @@
 		raw_inode->i_gid_high = 0;
 	}
 	raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
-	raw_inode->i_size = cpu_to_le32(inode->u.ext3_i.i_disksize);
+	raw_inode->i_size = cpu_to_le32(ei->i_disksize);
 	raw_inode->i_atime = cpu_to_le32(inode->i_atime);
 	raw_inode->i_ctime = cpu_to_le32(inode->i_ctime);
 	raw_inode->i_mtime = cpu_to_le32(inode->i_mtime);
 	raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
-	raw_inode->i_dtime = cpu_to_le32(inode->u.ext3_i.i_dtime);
-	raw_inode->i_flags = cpu_to_le32(inode->u.ext3_i.i_flags);
+	raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
+	raw_inode->i_flags = cpu_to_le32(ei->i_flags);
 #ifdef EXT3_FRAGMENTS
-	raw_inode->i_faddr = cpu_to_le32(inode->u.ext3_i.i_faddr);
-	raw_inode->i_frag = inode->u.ext3_i.i_frag_no;
-	raw_inode->i_fsize = inode->u.ext3_i.i_frag_size;
+	raw_inode->i_faddr = cpu_to_le32(ei->i_faddr);
+	raw_inode->i_frag = ei->i_frag_no;
+	raw_inode->i_fsize = ei->i_frag_size;
 #else
 	/* 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 (EXT3_I(inode)->i_state & EXT3_STATE_NEW) {
+	if (ei->i_state & EXT3_STATE_NEW) {
 		raw_inode->i_faddr = 0;
 		raw_inode->i_frag = 0;
 		raw_inode->i_fsize = 0;
 	}
 #endif
-	raw_inode->i_file_acl = cpu_to_le32(inode->u.ext3_i.i_file_acl);
+	raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);
 	if (!S_ISREG(inode->i_mode)) {
-		raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext3_i.i_dir_acl);
+		raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl);
 	} else {
 		raw_inode->i_size_high =
-			cpu_to_le32(inode->u.ext3_i.i_disksize >> 32);
-		if (inode->u.ext3_i.i_disksize > 0x7fffffffULL) {
+			cpu_to_le32(ei->i_disksize >> 32);
+		if (ei->i_disksize > 0x7fffffffULL) {
 			struct super_block *sb = inode->i_sb;
 			if (!EXT3_HAS_RO_COMPAT_FEATURE(sb,
 					EXT3_FEATURE_RO_COMPAT_LARGE_FILE) ||
@@ -2259,13 +2271,13 @@
 		raw_inode->i_block[0] =
 			cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
 	else for (block = 0; block < EXT3_N_BLOCKS; block++)
-		raw_inode->i_block[block] = inode->u.ext3_i.i_data[block];
+		raw_inode->i_block[block] = ei->i_data[block];
 
 	BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
 	rc = ext3_journal_dirty_metadata(handle, bh);
 	if (!err)
 		err = rc;
-	EXT3_I(inode)->i_state &= ~EXT3_STATE_NEW;
+	ei->i_state &= ~EXT3_STATE_NEW;
 
 out_brelse:
 	brelse (bh);
@@ -2373,7 +2385,7 @@
 		}
 		
 		error = ext3_orphan_add(handle, inode);
-		inode->u.ext3_i.i_disksize = attr->ia_size;
+		EXT3_I(inode)->i_disksize = attr->ia_size;
 		rc = ext3_mark_inode_dirty(handle, inode);
 		if (!error)
 			error = rc;
@@ -2616,9 +2628,9 @@
 	 */
 
 	if (val)
-		inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
+		EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
 	else
-		inode->u.ext3_i.i_flags &= ~EXT3_JOURNAL_DATA_FL;
+		EXT3_I(inode)->i_flags &= ~EXT3_JOURNAL_DATA_FL;
 
 	journal_unlock_updates(journal);
 
diff -u --recursive --new-file v2.5.2/linux/fs/ext3/ioctl.c linux/fs/ext3/ioctl.c
--- v2.5.2/linux/fs/ext3/ioctl.c	Fri Nov  9 14:25:04 2001
+++ linux/fs/ext3/ioctl.c	Mon Jan 21 15:37:32 2002
@@ -18,13 +18,14 @@
 int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 		unsigned long arg)
 {
+	struct ext3_inode_info *ei = EXT3_I(inode);
 	unsigned int flags;
 
 	ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg);
 
 	switch (cmd) {
 	case EXT3_IOC_GETFLAGS:
-		flags = inode->u.ext3_i.i_flags & EXT3_FL_USER_VISIBLE;
+		flags = ei->i_flags & EXT3_FL_USER_VISIBLE;
 		return put_user(flags, (int *) arg);
 	case EXT3_IOC_SETFLAGS: {
 		handle_t *handle = NULL;
@@ -42,7 +43,7 @@
 		if (get_user(flags, (int *) arg))
 			return -EFAULT;
 
-		oldflags = inode->u.ext3_i.i_flags;
+		oldflags = ei->i_flags;
 
 		/* The JOURNAL_DATA flag is modifiable only by root */
 		jflag = flags & EXT3_JOURNAL_DATA_FL;
@@ -79,7 +80,7 @@
 		
 		flags = flags & EXT3_FL_USER_MODIFIABLE;
 		flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE;
-		inode->u.ext3_i.i_flags = flags;
+		ei->i_flags = flags;
 
 		if (flags & EXT3_SYNC_FL)
 			inode->i_flags |= S_SYNC;
diff -u --recursive --new-file v2.5.2/linux/fs/ext3/namei.c linux/fs/ext3/namei.c
--- v2.5.2/linux/fs/ext3/namei.c	Fri Nov  9 14:25:04 2001
+++ linux/fs/ext3/namei.c	Mon Jan 21 15:37:32 2002
@@ -124,7 +124,7 @@
 	sb = dir->i_sb;
 
 	nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb);
-	start = dir->u.ext3_i.i_dir_start_lookup;
+	start = EXT3_I(dir)->i_dir_start_lookup;
 	if (start >= nblocks)
 		start = 0;
 	block = start;
@@ -165,7 +165,7 @@
 		i = search_dirblock(bh, dir, dentry,
 			    block << EXT3_BLOCK_SIZE_BITS(sb), res_dir);
 		if (i == 1) {
-			dir->u.ext3_i.i_dir_start_lookup = block;
+			EXT3_I(dir)->i_dir_start_lookup = block;
 			ret = bh;
 			goto cleanup_and_exit;
 		} else {
@@ -295,9 +295,9 @@
 				de = (struct ext3_dir_entry_2 *) bh->b_data;
 				de->inode = 0;
 				de->rec_len = le16_to_cpu(sb->s_blocksize);
-				dir->u.ext3_i.i_disksize =
+				EXT3_I(dir)->i_disksize =
 					dir->i_size = offset + sb->s_blocksize;
-				dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+				EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
 				ext3_mark_inode_dirty(handle, dir);
 			} else {
 
@@ -353,7 +353,7 @@
 			 * and/or different from the directory change time.
 			 */
 			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-			dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+			EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
 			ext3_mark_inode_dirty(handle, dir);
 			dir->i_version = ++event;
 			BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
@@ -521,7 +521,7 @@
 
 	inode->i_op = &ext3_dir_inode_operations;
 	inode->i_fop = &ext3_dir_operations;
-	inode->i_size = inode->u.ext3_i.i_disksize = inode->i_sb->s_blocksize;
+	inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
 	inode->i_blocks = 0;	
 	dir_block = ext3_bread (handle, inode, 0, 1, &err);
 	if (!dir_block) {
@@ -557,7 +557,7 @@
 	if (err)
 		goto out_no_entry;
 	dir->i_nlink++;
-	dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+	EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
 	ext3_mark_inode_dirty(handle, dir);
 	d_instantiate(dentry, inode);
 out_stop:
@@ -655,7 +655,7 @@
 	int err = 0, rc;
 	
 	lock_super(sb);
-	if (!list_empty(&inode->u.ext3_i.i_orphan))
+	if (!list_empty(&EXT3_I(inode)->i_orphan))
 		goto out_unlock;
 
 	/* Orphan handling is only valid for files with data blocks
@@ -696,7 +696,7 @@
 	 * This is safe: on error we're going to ignore the orphan list
 	 * anyway on the next recovery. */
 	if (!err)
-		list_add(&inode->u.ext3_i.i_orphan, &EXT3_SB(sb)->s_orphan);
+		list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan);
 
 	jbd_debug(4, "superblock will point to %ld\n", inode->i_ino);
 	jbd_debug(4, "orphan inode %ld will point to %d\n",
@@ -714,25 +714,25 @@
 int ext3_orphan_del(handle_t *handle, struct inode *inode)
 {
 	struct list_head *prev;
+	struct ext3_inode_info *ei = EXT3_I(inode);
 	struct ext3_sb_info *sbi;
 	ino_t ino_next; 
 	struct ext3_iloc iloc;
 	int err = 0;
 	
 	lock_super(inode->i_sb);
-	if (list_empty(&inode->u.ext3_i.i_orphan)) {
+	if (list_empty(&ei->i_orphan)) {
 		unlock_super(inode->i_sb);
 		return 0;
 	}
 
 	ino_next = NEXT_ORPHAN(inode);
-	prev = inode->u.ext3_i.i_orphan.prev;
+	prev = ei->i_orphan.prev;
 	sbi = EXT3_SB(inode->i_sb);
 
 	jbd_debug(4, "remove inode %ld from orphan list\n", inode->i_ino);
 
-	list_del(&inode->u.ext3_i.i_orphan);
-	INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
+	list_del_init(&ei->i_orphan);
 
 	/* If we're on an error path, we may not have a valid
 	 * transaction handle with which to update the orphan list on
@@ -756,7 +756,7 @@
 	} else {
 		struct ext3_iloc iloc2;
 		struct inode *i_prev =
-			list_entry(prev, struct inode, u.ext3_i.i_orphan);
+			&list_entry(prev, struct ext3_inode_info, i_orphan)->vfs_inode;
 		
 		jbd_debug(4, "orphan inode %ld will point to %ld\n",
 			  i_prev->i_ino, ino_next);
@@ -832,7 +832,7 @@
 	ext3_mark_inode_dirty(handle, inode);
 	dir->i_nlink--;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+	EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
 	ext3_mark_inode_dirty(handle, dir);
 
 end_rmdir:
@@ -878,7 +878,7 @@
 	if (retval)
 		goto end_unlink;
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+	EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
 	ext3_mark_inode_dirty(handle, dir);
 	inode->i_nlink--;
 	if (!inode->i_nlink)
@@ -916,7 +916,7 @@
 	if (IS_ERR(inode))
 		goto out_stop;
 
-	if (l > sizeof (inode->u.ext3_i.i_data)) {
+	if (l > sizeof (EXT3_I(inode)->i_data)) {
 		inode->i_op = &page_symlink_inode_operations;
 		inode->i_mapping->a_ops = &ext3_aops;
 		/*
@@ -929,10 +929,10 @@
 			goto out_no_entry;
 	} else {
 		inode->i_op = &ext3_fast_symlink_inode_operations;
-		memcpy((char*)&inode->u.ext3_i.i_data,symname,l);
+		memcpy((char*)&EXT3_I(inode)->i_data,symname,l);
 		inode->i_size = l-1;
 	}
-	inode->u.ext3_i.i_disksize = inode->i_size;
+	EXT3_I(inode)->i_disksize = inode->i_size;
 	ext3_mark_inode_dirty(handle, inode);
 	err = ext3_add_nondir(handle, dentry, inode);
 out_stop:
@@ -1077,7 +1077,7 @@
 		new_inode->i_ctime = CURRENT_TIME;
 	}
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-	old_dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+	EXT3_I(old_dir)->i_flags &= ~EXT3_INDEX_FL;
 	if (dir_bh) {
 		BUFFER_TRACE(dir_bh, "get_write_access");
 		ext3_journal_get_write_access(handle, dir_bh);
@@ -1089,7 +1089,7 @@
 			new_inode->i_nlink--;
 		} else {
 			new_dir->i_nlink++;
-			new_dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+			EXT3_I(new_dir)->i_flags &= ~EXT3_INDEX_FL;
 			ext3_mark_inode_dirty(handle, new_dir);
 		}
 	}
diff -u --recursive --new-file v2.5.2/linux/fs/ext3/super.c linux/fs/ext3/super.c
--- v2.5.2/linux/fs/ext3/super.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/ext3/super.c	Mon Jan 21 15:37:32 2002
@@ -376,7 +376,10 @@
 	return ret;
 }
 
-#define orphan_list_entry(l) list_entry((l), struct inode, u.ext3_i.i_orphan)
+static inline struct inode *orphan_list_entry(struct list_head *l)
+{
+	return &list_entry(l, struct ext3_inode_info, i_orphan)->vfs_inode;
+}
 
 static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi)
 {
@@ -444,7 +447,54 @@
 	return;
 }
 
+static kmem_cache_t * ext3_inode_cachep;
+
+static struct inode *ext3_alloc_inode(struct super_block *sb)
+{
+	struct ext3_inode_info *ei;
+	ei = (struct ext3_inode_info *)kmem_cache_alloc(ext3_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void ext3_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(ext3_inode_cachep, EXT3_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct ext3_inode_info *ei = (struct ext3_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		INIT_LIST_HEAD(&ei->i_orphan);
+		init_rwsem(&ei->truncate_sem);
+		inode_init_once(&ei->vfs_inode);
+	}
+}
+ 
+static int init_inodecache(void)
+{
+	ext3_inode_cachep = kmem_cache_create("ext3_inode_cache",
+					     sizeof(struct ext3_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (ext3_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(ext3_inode_cachep))
+		printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations ext3_sops = {
+	alloc_inode:	ext3_alloc_inode,
+	destroy_inode:	ext3_destroy_inode,
 	read_inode:	ext3_read_inode,	/* BKL held */
 	write_inode:	ext3_write_inode,	/* BKL not held.  Don't need */
 	dirty_inode:	ext3_dirty_inode,	/* BKL not held.  We take it */
@@ -1723,12 +1773,23 @@
 
 static int __init init_ext3_fs(void)
 {
-        return register_filesystem(&ext3_fs_type);
+	int err = init_inodecache();
+	if (err)
+		goto out1;
+        err = register_filesystem(&ext3_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_ext3_fs(void)
 {
 	unregister_filesystem(&ext3_fs_type);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/ext3/symlink.c linux/fs/ext3/symlink.c
--- v2.5.2/linux/fs/ext3/symlink.c	Fri Nov  9 14:25:04 2001
+++ linux/fs/ext3/symlink.c	Mon Jan 21 15:37:32 2002
@@ -23,14 +23,14 @@
 
 static int ext3_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
-	char *s = (char *)dentry->d_inode->u.ext3_i.i_data;
-	return vfs_readlink(dentry, buffer, buflen, s);
+	struct ext3_inode_info *ei = EXT3_I(dentry->d_inode);
+	return vfs_readlink(dentry, buffer, buflen, (char*)ei->i_data);
 }
 
 static int ext3_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char *s = (char *)dentry->d_inode->u.ext3_i.i_data;
-	return vfs_follow_link(nd, s);
+	struct ext3_inode_info *ei = EXT3_I(dentry->d_inode);
+	return vfs_follow_link(nd, (char*)ei->i_data);
 }
 
 struct inode_operations ext3_fast_symlink_inode_operations = {
diff -u --recursive --new-file v2.5.2/linux/fs/fat/buffer.c linux/fs/fat/buffer.c
--- v2.5.2/linux/fs/fat/buffer.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/fat/buffer.c	Mon Jan 28 13:20:44 2002
@@ -4,19 +4,10 @@
  *
  */
 
-#include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/string.h>
 #include <linux/fs.h>
-#include <linux/blkdev.h>
 #include <linux/msdos_fs.h>
 #include <linux/fat_cvf.h>
-
-#if 0
-#  define PRINTK(x) printk x
-#else
-#  define PRINTK(x)
-#endif
 
 struct buffer_head *fat_bread(struct super_block *sb, int block)
 {
diff -u --recursive --new-file v2.5.2/linux/fs/fat/cache.c linux/fs/fat/cache.c
--- v2.5.2/linux/fs/fat/cache.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/fat/cache.c	Mon Jan 28 13:20:44 2002
@@ -8,11 +8,8 @@
  *  May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers.
  */
 
+#include <linux/fs.h>
 #include <linux/msdos_fs.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
 #include <linux/fat_cvf.h>
 
 #if 0
diff -u --recursive --new-file v2.5.2/linux/fs/fat/cvf.c linux/fs/fat/cvf.c
--- v2.5.2/linux/fs/fat/cvf.c	Tue Jul 24 14:23:53 2001
+++ linux/fs/fat/cvf.c	Mon Jan 28 13:20:44 2002
@@ -8,15 +8,13 @@
  *
  */
  
-#include<linux/sched.h>
-#include<linux/fs.h>
-#include<linux/msdos_fs.h>
-#include<linux/msdos_fs_sb.h>
-#include<linux/string.h>
-#include<linux/fat_cvf.h>
-#include<linux/config.h>
+#include <linux/fs.h>
+#include <linux/msdos_fs.h>
+#include <linux/msdos_fs_sb.h>
+#include <linux/fat_cvf.h>
+#include <linux/config.h>
 #ifdef CONFIG_KMOD
-#include<linux/kmod.h>
+#include <linux/kmod.h>
 #endif
 
 #define MAX_CVF_FORMATS 3
diff -u --recursive --new-file v2.5.2/linux/fs/fat/dir.c linux/fs/fat/dir.c
--- v2.5.2/linux/fs/fat/dir.c	Fri Oct 12 13:48:42 2001
+++ linux/fs/fat/dir.c	Mon Jan 28 13:20:44 2002
@@ -13,17 +13,10 @@
  *  Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de>
  */
 
-#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
 #include <linux/msdos_fs.h>
-#include <linux/nls.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/ioctl.h>
 #include <linux/dirent.h>
-#include <linux/mm.h>
-#include <linux/ctype.h>
 
 #include <asm/uaccess.h>
 
@@ -538,7 +531,6 @@
 	if (!memcmp(de->name,MSDOS_DOT,11))
 		inum = inode->i_ino;
 	else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
-/*		inum = fat_parent_ino(inode,0); */
 		inum = filp->f_dentry->d_parent->d_inode->i_ino;
 	} else {
 		struct inode *tmp = fat_iget(sb, ino);
@@ -727,7 +719,13 @@
 	offset = curr = 0;
 	*bh = NULL;
 	row = 0;
-	while (fat_get_entry(dir,&curr,bh,de,ino) > -1) {
+	while (fat_get_entry(dir, &curr, bh, de, ino) > -1) {
+		/* check the maximum size of directory */
+		if (curr >= FAT_MAX_DIR_SIZE) {
+			fat_brelse(sb, *bh);
+			return -ENOSPC;
+		}
+
 		if (IS_FREE((*de)->name)) {
 			if (++row == slots)
 				return offset;
@@ -739,10 +737,13 @@
 	if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32)) 
 		return -ENOSPC;
 	new_bh = fat_extend_dir(dir);
-	if (!new_bh)
-		return -ENOSPC;
+	if (IS_ERR(new_bh))
+		return PTR_ERR(new_bh);
 	fat_brelse(sb, new_bh);
-	do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots);
+	do {
+		fat_get_entry(dir, &curr, bh, de, ino);
+	} while (++row < slots);
+
 	return offset;
 }
 
@@ -753,7 +754,10 @@
 	struct msdos_dir_entry *de;
 	__u16 date, time;
 
-	if ((bh = fat_extend_dir(dir)) == NULL) return -ENOSPC;
+	bh = fat_extend_dir(dir);
+	if (IS_ERR(bh))
+		return PTR_ERR(bh);
+
 	/* zeroed out, so... */
 	fat_date_unix2dos(dir->i_mtime,&time,&date);
 	de = (struct msdos_dir_entry*)&bh->b_data[0];
diff -u --recursive --new-file v2.5.2/linux/fs/fat/fatfs_syms.c linux/fs/fat/fatfs_syms.c
--- v2.5.2/linux/fs/fat/fatfs_syms.c	Fri Oct 12 13:48:42 2001
+++ linux/fs/fat/fatfs_syms.c	Mon Jan 28 13:20:44 2002
@@ -39,10 +39,13 @@
 EXPORT_SYMBOL(fat_truncate);
 EXPORT_SYMBOL(fat_brelse);
 
+int __init fat_init_inodecache(void);
+void __exit fat_destroy_inodecache(void);
 static int __init init_fat_fs(void)
 {
 	fat_hash_init();
-	return 0;
+	return fat_init_inodecache();
 }
 
 module_init(init_fat_fs)
+module_exit(fat_destroy_inodecache)
diff -u --recursive --new-file v2.5.2/linux/fs/fat/file.c linux/fs/fat/file.c
--- v2.5.2/linux/fs/fat/file.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/fat/file.c	Mon Jan 28 13:20:44 2002
@@ -8,18 +8,9 @@
 
 #include <linux/sched.h>
 #include <linux/locks.h>
-#include <linux/fs.h>
 #include <linux/msdos_fs.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/pagemap.h>
 #include <linux/fat_cvf.h>
 
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
 #define PRINTK(x)
 #define Printk(x) printk x
 
@@ -65,8 +56,11 @@
 		return -EIO;
 	}
 	if (!(iblock % MSDOS_SB(inode->i_sb)->cluster_size)) {
-		if (fat_add_cluster(inode) < 0)
-			return -ENOSPC;
+		int error;
+
+		error = fat_add_cluster(inode);
+		if (error < 0)
+			return error;
 	}
 	MSDOS_I(inode)->mmu_private += sb->s_blocksize;
 	phys = fat_bmap(inode, iblock);
diff -u --recursive --new-file v2.5.2/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.5.2/linux/fs/fat/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/fat/inode.c	Mon Jan 28 13:20:44 2002
@@ -11,23 +11,14 @@
  */
 
 #include <linux/module.h>
-#include <linux/msdos_fs.h>
-#include <linux/nls.h>
-#include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/bitops.h>
-#include <linux/major.h>
-#include <linux/blkdev.h>
-#include <linux/fs.h>
-#include <linux/stat.h>
 #include <linux/locks.h>
-#include <linux/fat_cvf.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
+#include <linux/msdos_fs.h>
+#include <linux/fat_cvf.h>
 
-#include <asm/uaccess.h>
+//#include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
 extern struct cvf_format default_cvf;
@@ -103,8 +94,7 @@
 {
 	spin_lock(&fat_inode_lock);
 	MSDOS_I(inode)->i_location = 0;
-	list_del(&MSDOS_I(inode)->i_fat_hash);
-	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
+	list_del_init(&MSDOS_I(inode)->i_fat_hash);
 	spin_unlock(&fat_inode_lock);
 }
 
@@ -118,11 +108,11 @@
 	spin_lock(&fat_inode_lock);
 	list_for_each(walk, p) {
 		i = list_entry(walk, struct msdos_inode_info, i_fat_hash);
-		if (i->i_fat_inode->i_sb != sb)
+		if (i->vfs_inode.i_sb != sb)
 			continue;
 		if (i->i_location != i_pos)
 			continue;
-		inode = igrab(i->i_fat_inode);
+		inode = igrab(&i->vfs_inode);
 		if (inode)
 			break;
 	}
@@ -172,7 +162,7 @@
 	lock_kernel();
 	spin_lock(&fat_inode_lock);
 	fat_cache_inval_inode(inode);
-	list_del(&MSDOS_I(inode)->i_fat_hash);
+	list_del_init(&MSDOS_I(inode)->i_fat_hash);
 	spin_unlock(&fat_inode_lock);
 	unlock_kernel();
 }
@@ -208,7 +198,7 @@
 }
 
 
-static int parse_options(char *options,int *fat, int *debug,
+static int parse_options(char *options, int *debug,
 			 struct fat_mount_options *opts,
 			 char *cvf_format, char *cvf_options)
 {
@@ -227,7 +217,7 @@
 	opts->shortname = 0;
 	opts->utf8 = 0;
 	opts->iocharset = NULL;
-	*debug = *fat = 0;
+	*debug = 0;
 
 	if (!options)
 		goto out;
@@ -305,13 +295,8 @@
 			else *debug = 1;
 		}
 		else if (!strcmp(this_char,"fat")) {
-			if (!value || !*value) ret = 0;
-			else {
-				*fat = simple_strtoul(value,&value,0);
-				if (*value || (*fat != 12 && *fat != 16 &&
-					       *fat != 32)) 
-					ret = 0;
-			}
+			printk("FAT: fat option is obsolete, "
+			       "not supported now\n");
 		}
 		else if (!strcmp(this_char,"quiet")) {
 			if (value) ret = 0;
@@ -328,8 +313,6 @@
 		else if (!strcmp(this_char,"codepage") && value) {
 			opts->codepage = simple_strtoul(value,&value,0);
 			if (*value) ret = 0;
-			else printk ("MSDOS FS: Using codepage %d\n",
-					opts->codepage);
 		}
 		else if (!strcmp(this_char,"iocharset") && value) {
 			p = value;
@@ -348,7 +331,6 @@
 					opts->iocharset = buffer;
 					memcpy(buffer, p, len);
 					buffer[len] = 0;
-					printk("MSDOS FS: IO charset %s\n", buffer);
 				} else
 					ret = 0;
 			}
@@ -373,15 +355,39 @@
 	return ret;
 }
 
+static void fat_calc_dir_size(struct inode *inode)
+{
+	struct super_block *sb = inode->i_sb;
+	int nr;
+
+	inode->i_size = 0;
+	if (MSDOS_I(inode)->i_start == 0)
+		return;
+
+	nr = MSDOS_I(inode)->i_start;
+	do {
+		inode->i_size += 1 << MSDOS_SB(sb)->cluster_bits;
+		if (!(nr = fat_access(sb, nr, -1))) {
+			printk("FAT: Directory %ld: bad FAT\n",
+			       inode->i_ino);
+			break;
+		}
+		if (inode->i_size > FAT_MAX_DIR_SIZE) {
+			fat_fs_panic(sb, "Directory %ld: "
+				     "exceeded the maximum size of directory",
+				     inode->i_ino);
+			inode->i_size = FAT_MAX_DIR_SIZE;
+			break;
+		}
+	} while (nr != -1);
+}
+
 static void fat_read_root(struct inode *inode)
 {
 	struct super_block *sb = inode->i_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	int nr;
 
-	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
 	MSDOS_I(inode)->i_location = 0;
-	MSDOS_I(inode)->i_fat_inode = inode;
 	inode->i_uid = sbi->options.fs_uid;
 	inode->i_gid = sbi->options.fs_gid;
 	inode->i_version++;
@@ -391,16 +397,7 @@
 	inode->i_fop = &fat_dir_operations;
 	if (sbi->fat_bits == 32) {
 		MSDOS_I(inode)->i_start = sbi->root_cluster;
-		if ((nr = MSDOS_I(inode)->i_start) != 0) {
-			while (nr != -1) {
-				inode->i_size += 1 << sbi->cluster_bits;
-				if (!(nr = fat_access(sb, nr, -1))) {
-					printk("Directory %ld: bad FAT\n",
-					       inode->i_ino);
-					break;
-				}
-			}
-		}
+		fat_calc_dir_size(inode);
 	} else {
 		MSDOS_I(inode)->i_start = 0;
 		inode->i_size = sbi->dir_entries * sizeof(struct msdos_dir_entry);
@@ -524,7 +521,53 @@
 	return 3;
 }
 
+static kmem_cache_t *fat_inode_cachep;
+
+static struct inode *fat_alloc_inode(struct super_block *sb)
+{
+	struct msdos_inode_info *ei;
+	ei = (struct msdos_inode_info *)kmem_cache_alloc(fat_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void fat_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(fat_inode_cachep, MSDOS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct msdos_inode_info *ei = (struct msdos_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		INIT_LIST_HEAD(&ei->i_fat_hash);
+		inode_init_once(&ei->vfs_inode);
+	}
+}
+ 
+int __init fat_init_inodecache(void)
+{
+	fat_inode_cachep = kmem_cache_create("fat_inode_cache",
+					     sizeof(struct msdos_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (fat_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+void __exit fat_destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(fat_inode_cachep))
+		printk(KERN_INFO "fat_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations fat_sops = { 
+	alloc_inode:	fat_alloc_inode,
+	destroy_inode:	fat_destroy_inode,
 	write_inode:	fat_write_inode,
 	delete_inode:	fat_delete_inode,
 	put_super:	fat_put_super,
@@ -550,11 +593,9 @@
 	struct buffer_head *bh;
 	struct fat_boot_sector *b;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	char *p;
-	int logical_sector_size, hard_blksize, fat_clusters = 0;
+	int logical_sector_size, fat_clusters, debug, cp;
 	unsigned int total_sectors, rootdir_sectors;
-	int fat32, debug, error, fat, cp;
-	struct fat_mount_options opts;
+	long error = -EIO;
 	char buf[50];
 	int i;
 	char cvf_format[21];
@@ -562,22 +603,20 @@
 
 	cvf_format[0] = '\0';
 	cvf_options[0] = '\0';
-	sbi->cvf_format = NULL;
 	sbi->private_data = NULL;
 
-	sbi->dir_ops = fs_dir_inode_ops;
-
-	sb->s_maxbytes = MAX_NON_LFS;
+	sb->s_magic = MSDOS_SUPER_MAGIC;
 	sb->s_op = &fat_sops;
+	sbi->dir_ops = fs_dir_inode_ops;
+	sbi->cvf_format = &default_cvf;
 
-	opts.isvfat = sbi->options.isvfat;
-	if (!parse_options((char *) data, &fat, &debug, &opts,
+	if (!parse_options((char *)data, &debug, &sbi->options,
 			   cvf_format, cvf_options))
 		goto out_fail;
-	/* N.B. we should parse directly into the sb structure */
-	memcpy(&(sbi->options), &opts, sizeof(struct fat_mount_options));
 
 	fat_cache_init();
+	/* set up enough so that it can read an inode */
+	init_MUTEX(&sbi->fat_lock);
 
 	sb_min_blocksize(sb, 512);
 	bh = sb_bread(sb, 0);
@@ -586,37 +625,37 @@
 		goto out_fail;
 	}
 
-/*
- * The DOS3 partition size limit is *not* 32M as many people think.  
- * Instead, it is 64K sectors (with the usual sector size being
- * 512 bytes, leading to a 32M limit).
- * 
- * DOS 3 partition managers got around this problem by faking a 
- * larger sector size, ie treating multiple physical sectors as 
- * a single logical sector.
- * 
- * We can accommodate this scheme by adjusting our cluster size,
- * fat_start, and data_start by an appropriate value.
- *
- * (by Drew Eckhardt)
- */
-
-
 	b = (struct fat_boot_sector *) bh->b_data;
+	if (!b->secs_track) {
+		if (!silent)
+			printk("FAT: bogus sectors-per-track value\n");
+		brelse(bh);
+		goto out_invalid;
+	}
+	if (!b->heads) {
+		if (!silent)
+			printk("FAT: bogus number-of-heads value\n");
+		brelse(bh);
+		goto out_invalid;
+	}
 	logical_sector_size =
 		CF_LE_W(get_unaligned((unsigned short *) &b->sector_size));
 	if (!logical_sector_size
-	    || (logical_sector_size & (logical_sector_size - 1))) {
-		printk("FAT: bogus logical sector size %d\n",
-		       logical_sector_size);
+	    || (logical_sector_size & (logical_sector_size - 1))
+	    || (logical_sector_size < 512)
+	    || (PAGE_CACHE_SIZE < logical_sector_size)) {
+		if (!silent)
+			printk("FAT: bogus logical sector size %d\n",
+			       logical_sector_size);
 		brelse(bh);
 		goto out_invalid;
 	}
-
 	sbi->cluster_size = b->cluster_size;
 	if (!sbi->cluster_size
 	    || (sbi->cluster_size & (sbi->cluster_size - 1))) {
-		printk("FAT: bogus cluster size %d\n", sbi->cluster_size);
+		if (!silent)
+			printk("FAT: bogus cluster size %d\n",
+			       sbi->cluster_size);
 		brelse(bh);
 		goto out_invalid;
 	}
@@ -625,47 +664,62 @@
 		printk("FAT: logical sector size too small for device"
 		       " (logical sector size = %d)\n", logical_sector_size);
 		brelse(bh);
-		goto out_invalid;
+		goto out_fail;
 	}
+	if (logical_sector_size > sb->s_blocksize) {
+		brelse(bh);
 
-	hard_blksize = sb->s_blocksize;
+		if (!sb_set_blocksize(sb, logical_sector_size)) {
+			printk("FAT: unable to set blocksize %d\n",
+			       logical_sector_size);
+			goto out_fail;
+		}
+		bh = sb_bread(sb, 0);
+		if (bh == NULL) {
+			printk("FAT: unable to read boot sector"
+			       " (logical sector size = %lu)\n",
+			       sb->s_blocksize);
+			goto out_fail;
+		}
+		b = (struct fat_boot_sector *) bh->b_data;
+	}
 
-	sbi->cluster_bits = ffs(logical_sector_size * sbi->cluster_size) - 1;
+	sbi->cluster_bits = ffs(sb->s_blocksize * sbi->cluster_size) - 1;
 	sbi->fats = b->fats;
+	sbi->fat_bits = 0;		/* Don't know yet */
 	sbi->fat_start = CF_LE_W(b->reserved);
-	if (!b->fat_length && b->fat32_length) {
+	sbi->fat_length = CF_LE_W(b->fat_length);
+	sbi->root_cluster = 0;
+	sbi->free_clusters = -1;	/* Don't know yet */
+	sbi->prev_free = 0;
+
+	if (!sbi->fat_length && b->fat32_length) {
 		struct fat_boot_fsinfo *fsinfo;
 		struct buffer_head *fsinfo_bh;
-		int fsinfo_block, fsinfo_offset;
 
 		/* Must be FAT32 */
-		fat32 = 1;
+		sbi->fat_bits = 32;
 		sbi->fat_length = CF_LE_L(b->fat32_length);
 		sbi->root_cluster = CF_LE_L(b->root_cluster);
 
-		sbi->fsinfo_sector = CF_LE_W(b->info_sector);
 		/* MC - if info_sector is 0, don't multiply by 0 */
+		sbi->fsinfo_sector = CF_LE_W(b->info_sector);
 		if (sbi->fsinfo_sector == 0)
 			sbi->fsinfo_sector = 1;
 
-		fsinfo_block =
-			(sbi->fsinfo_sector * logical_sector_size) / hard_blksize;
-		fsinfo_offset =
-			(sbi->fsinfo_sector * logical_sector_size) % hard_blksize;
-		fsinfo_bh = bh;
-		if (fsinfo_block != 0) {
-			fsinfo_bh = sb_bread(sb, fsinfo_block);
-			if (fsinfo_bh == NULL) {
-				printk("FAT: bread failed, FSINFO block"
-				       " (blocknr = %d)\n", fsinfo_block);
-				brelse(bh);
-				goto out_invalid;
-			}
+		fsinfo_bh = sb_bread(sb, sbi->fsinfo_sector);
+		if (fsinfo_bh == NULL) {
+			printk("FAT: bread failed, FSINFO block"
+			       " (sector = %lu)\n", sbi->fsinfo_sector);
+			brelse(bh);
+			goto out_fail;
 		}
-		fsinfo = (struct fat_boot_fsinfo *)&fsinfo_bh->b_data[fsinfo_offset];
+
+		fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data;
 		if (!IS_FSINFO(fsinfo)) {
 			printk("FAT: Did not find valid FSINFO signature.\n"
-			       "Found signature1 0x%x signature2 0x%x sector=%ld.\n",
+			       "     Found signature1 0x%08x signature2 0x%08x"
+			       " (sector = %lu)\n",
 			       CF_LE_L(fsinfo->signature1),
 			       CF_LE_L(fsinfo->signature2),
 			       sbi->fsinfo_sector);
@@ -673,144 +727,113 @@
 			sbi->free_clusters = CF_LE_L(fsinfo->free_clusters);
 		}
 
-		if (fsinfo_block != 0)
-			brelse(fsinfo_bh);
-	} else {
-		fat32 = 0;
-		sbi->fat_length = CF_LE_W(b->fat_length);
-		sbi->root_cluster = 0;
-		sbi->free_clusters = -1; /* Don't know yet */
+		brelse(fsinfo_bh);
 	}
 
-	sbi->dir_per_block = logical_sector_size / sizeof(struct msdos_dir_entry);
+	sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry);
 	sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
 
 	sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length;
 	sbi->dir_entries =
 		CF_LE_W(get_unaligned((unsigned short *)&b->dir_entries));
+	if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
+		printk("FAT: bogus directroy-entries per block\n");
+		brelse(bh);
+		goto out_invalid;
+	}
+
 	rootdir_sectors = sbi->dir_entries
-		* sizeof(struct msdos_dir_entry) / logical_sector_size;
+		* sizeof(struct msdos_dir_entry) / sb->s_blocksize;
 	sbi->data_start = sbi->dir_start + rootdir_sectors;
 	total_sectors = CF_LE_W(get_unaligned((unsigned short *)&b->sectors));
 	if (total_sectors == 0)
 		total_sectors = CF_LE_L(b->total_sect);
 	sbi->clusters = (total_sectors - sbi->data_start) / sbi->cluster_size;
 
-	error = 0;
-	if (!error) {
-		sbi->fat_bits = fat32 ? 32 :
-			(fat ? fat :
-			 (sbi->clusters > MSDOS_FAT12 ? 16 : 12));
-		fat_clusters =
-			sbi->fat_length * logical_sector_size * 8 / sbi->fat_bits;
-		error = !sbi->fats || (sbi->dir_entries & (sbi->dir_per_block - 1))
-			|| sbi->clusters + 2 > fat_clusters + MSDOS_MAX_EXTRA
-			|| logical_sector_size < 512
-			|| PAGE_CACHE_SIZE < logical_sector_size
-			|| !b->secs_track || !b->heads;
-	}
-	brelse(bh);
+	if (sbi->fat_bits != 32)
+		sbi->fat_bits = (sbi->clusters > MSDOS_FAT12) ? 16 : 12;
 
-	if (error)
-		goto out_invalid;
+	/* check that FAT table does not overflow */
+	fat_clusters = sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits;
+	if (sbi->clusters > fat_clusters - 2)
+		sbi->clusters = fat_clusters - 2;
+
+	brelse(bh);
 
-	sb_set_blocksize(sb, logical_sector_size);
-	sbi->cvf_format = &default_cvf;
 	if (!strcmp(cvf_format, "none"))
 		i = -1;
 	else
-		i = detect_cvf(sb,cvf_format);
-	if (i >= 0)
-		error = cvf_formats[i]->mount_cvf(sb, cvf_options);
-	if (error || debug) {
-		/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
-		printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
-		       "uid=%d,gid=%d,umask=%03o%s]\n",
-		       sbi->fat_bits,opts.name_check,
-		       opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
-		       MSDOS_CAN_BMAP(sbi) ? ",bmap" : "");
-		printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%ld,ds=%ld,de=%d,data=%ld,"
-		       "se=%u,ts=%u,ls=%d,rc=%ld,fc=%u]\n",
-		       b->media, sbi->cluster_size, sbi->fats,
-		       sbi->fat_start, sbi->fat_length, sbi->dir_start,
-		       sbi->dir_entries, sbi->data_start,
-		       CF_LE_W(get_unaligned((unsigned short *)&b->sectors)),
-		       CF_LE_L(b->total_sect), logical_sector_size,
-		       sbi->root_cluster, sbi->free_clusters);
-		printk ("hard sector size = %d\n", hard_blksize);
-	}
-	if (i < 0)
-		if (sbi->clusters + 2 > fat_clusters)
-			sbi->clusters = fat_clusters - 2;
-	if (error)
-		goto out_invalid;
-
-	sb->s_magic = MSDOS_SUPER_MAGIC;
-	/* set up enough so that it can read an inode */
-	init_MUTEX(&sbi->fat_lock);
-	sbi->prev_free = 0;
+		i = detect_cvf(sb, cvf_format);
+	if (i >= 0) {
+		if (cvf_formats[i]->mount_cvf(sb, cvf_options))
+			goto out_invalid;
+	}
 
-	cp = opts.codepage ? opts.codepage : 437;
+	cp = sbi->options.codepage ? sbi->options.codepage : 437;
 	sprintf(buf, "cp%d", cp);
 	sbi->nls_disk = load_nls(buf);
 	if (! sbi->nls_disk) {
 		/* Fail only if explicit charset specified */
-		if (opts.codepage != 0)
+		if (sbi->options.codepage != 0) {
+			printk("FAT: codepage %s not found\n", buf);
 			goto out_fail;
+		}
 		sbi->options.codepage = 0; /* already 0?? */
 		sbi->nls_disk = load_nls_default();
 	}
+	if (!silent)
+		printk("FAT: Using codepage %s\n", sbi->nls_disk->charset);
 
-	sbi->nls_io = NULL;
-	if (sbi->options.isvfat && !opts.utf8) {
-		p = opts.iocharset ? opts.iocharset : CONFIG_NLS_DEFAULT;
-		sbi->nls_io = load_nls(p);
-		if (! sbi->nls_io)
-			/* Fail only if explicit charset specified */
-			if (opts.iocharset)
-				goto out_unload_nls;
+	if (sbi->options.isvfat && !sbi->options.utf8) {
+		if (sbi->options.iocharset != NULL) {
+			sbi->nls_io = load_nls(sbi->options.iocharset);
+			if (!sbi->nls_io) {
+				printk("FAT: IO charset %s not found\n",
+				       sbi->options.iocharset);
+				goto out_fail;
+			}
+		} else
+			sbi->nls_io = load_nls_default();
+		if (!silent)
+			printk("FAT: Using IO charset %s\n",
+			       sbi->nls_io->charset);
 	}
-	if (! sbi->nls_io)
-		sbi->nls_io = load_nls_default();
 
 	root_inode = new_inode(sb);
 	if (!root_inode)
-		goto out_unload_nls;
+		goto out_fail;
+
 	root_inode->i_ino = MSDOS_ROOT_INO;
 	root_inode->i_version = 0;
 	fat_read_root(root_inode);
 	insert_inode_hash(root_inode);
 	sb->s_root = d_alloc_root(root_inode);
-	if (!sb->s_root)
-		goto out_no_root;
+	if (!sb->s_root) {
+		printk("FAT: get root inode failed\n");
+		iput(root_inode);
+		goto out_fail;
+	}
 	if(i >= 0) {
 		sbi->cvf_format = cvf_formats[i];
 		++cvf_format_use_count[i];
 	}
 	return sb;
 
-out_no_root:
-	printk("FAT: get root inode failed\n");
-	iput(root_inode);
-	unload_nls(sbi->nls_io);
-out_unload_nls:
-	unload_nls(sbi->nls_disk);
-	goto out_fail;
 out_invalid:
-	if (!silent) {
-		printk("VFS: Can't find a valid FAT filesystem on dev %s.\n",
-			sb->s_id);
-	}
+	error = 0;
+
 out_fail:
-	if (opts.iocharset) {
-		printk("FAT: freeing iocharset=%s\n", opts.iocharset);
-		kfree(opts.iocharset);
-	}
-	if(sbi->private_data)
+	if (sbi->nls_io)
+		unload_nls(sbi->nls_io);
+	if (sbi->nls_disk)
+		unload_nls(sbi->nls_disk);
+	if (sbi->options.iocharset)
+		kfree(sbi->options.iocharset);
+	if (sbi->private_data)
 		kfree(sbi->private_data);
 	sbi->private_data = NULL;
- 
-	return NULL;
+
+	return ERR_PTR(error);
 }
 
 int fat_statfs(struct super_block *sb,struct statfs *buf)
@@ -882,11 +905,8 @@
 {
 	struct super_block *sb = inode->i_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	int nr;
 
-	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
 	MSDOS_I(inode)->i_location = 0;
-	MSDOS_I(inode)->i_fat_inode = inode;
 	inode->i_uid = sbi->options.fs_uid;
 	inode->i_gid = sbi->options.fs_gid;
 	inode->i_version++;
@@ -913,15 +933,7 @@
 			inode->i_nlink = 1;
 		}
 #endif
-		if ((nr = MSDOS_I(inode)->i_start) != 0)
-			while (nr != -1) {
-				inode->i_size += 1 << sbi->cluster_bits;
-				if (!(nr = fat_access(sb, nr, -1))) {
-					printk("Directory %ld: bad FAT\n",
-					    inode->i_ino);
-					break;
-				}
-			}
+		fat_calc_dir_size(inode);
 		MSDOS_I(inode)->mmu_private = inode->i_size;
 	} else { /* not a directory */
 		inode->i_generation |= 1;
diff -u --recursive --new-file v2.5.2/linux/fs/fat/misc.c linux/fs/fat/misc.c
--- v2.5.2/linux/fs/fat/misc.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/fat/misc.c	Mon Jan 28 13:20:44 2002
@@ -8,11 +8,6 @@
 
 #include <linux/fs.h>
 #include <linux/msdos_fs.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
 
 #if 0
 #  define PRINTK(x)	printk x
@@ -38,15 +33,25 @@
  * read-only. The file system can be made writable again by remounting it.
  */
 
-void fat_fs_panic(struct super_block *s,const char *msg)
+static char panic_msg[512];
+
+void fat_fs_panic(struct super_block *s, const char *fmt, ...)
 {
 	int not_ro;
+	va_list args;
+
+	va_start (args, fmt);
+	vsnprintf (panic_msg, sizeof(panic_msg), fmt, args);
+	va_end (args);
 
 	not_ro = !(s->s_flags & MS_RDONLY);
-	if (not_ro) s->s_flags |= MS_RDONLY;
-	printk("Filesystem panic (dev %s).\n  %s\n", s->s_id, msg);
 	if (not_ro)
-		printk("  File system has been set read-only\n");
+		s->s_flags |= MS_RDONLY;
+
+	printk("FAT: Filesystem panic (dev %s)\n"
+	       "    %s\n", s->s_id, panic_msg);
+	if (not_ro)
+		printk("    File system has been set read-only\n");
 }
 
 
@@ -102,13 +107,14 @@
 	/* Sanity check */
 	if (!IS_FSINFO(fsinfo)) {
 		printk("FAT: Did not find valid FSINFO signature.\n"
-		       "Found signature1 0x%x signature2 0x%x sector=%ld.\n",
+		       "     Found signature1 0x%08x signature2 0x%08x"
+		       " (sector = %lu)\n",
 		       CF_LE_L(fsinfo->signature1), CF_LE_L(fsinfo->signature2),
 		       MSDOS_SB(sb)->fsinfo_sector);
-		return;
+	} else {
+		fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
+		fat_mark_buffer_dirty(sb, bh);
 	}
-	fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
-	fat_mark_buffer_dirty(sb, bh);
 	fat_brelse(sb, bh);
 }
 
@@ -120,14 +126,13 @@
 {
 	struct super_block *sb = inode->i_sb;
 	int count, nr, limit, last, curr, file_cluster;
-	int cluster_size = MSDOS_SB(sb)->cluster_size;
-	int res = -ENOSPC;
+	int cluster_bits = MSDOS_SB(sb)->cluster_bits;
 	
 	lock_fat(sb);
 	
 	if (MSDOS_SB(sb)->free_clusters == 0) {
 		unlock_fat(sb);
-		return res;
+		return -ENOSPC;
 	}
 	limit = MSDOS_SB(sb)->clusters;
 	nr = limit; /* to keep GCC happy */
@@ -139,7 +144,7 @@
 	if (count >= limit) {
 		MSDOS_SB(sb)->free_clusters = 0;
 		unlock_fat(sb);
-		return res;
+		return -ENOSPC;
 	}
 	
 	MSDOS_SB(sb)->prev_free = (count + MSDOS_SB(sb)->prev_free + 1) % limit;
@@ -163,13 +168,20 @@
 	*/
 	last = file_cluster = 0;
 	if ((curr = MSDOS_I(inode)->i_start) != 0) {
+		int max_cluster = MSDOS_I(inode)->mmu_private >> cluster_bits;
+
 		fat_cache_lookup(inode, INT_MAX, &last, &curr);
 		file_cluster = last;
-		while (curr && curr != -1){
+		while (curr && curr != -1) {
 			file_cluster++;
-			if (!(curr = fat_access(sb, last = curr,-1))) {
+			if (!(curr = fat_access(sb, last = curr, -1))) {
 				fat_fs_panic(sb, "File without EOF");
-				return res;
+				return -EIO;
+			}
+			if (file_cluster > max_cluster) {
+				fat_fs_panic(sb,"inode %lu: bad cluster counts",
+					     inode->i_ino);
+				return -EIO;
 			}
 		}
 	}
@@ -181,14 +193,12 @@
 		MSDOS_I(inode)->i_logstart = nr;
 		mark_inode_dirty(inode);
 	}
-	if (file_cluster
-	    != inode->i_blocks / cluster_size / (sb->s_blocksize / 512)) {
+	if (file_cluster != (inode->i_blocks >> (cluster_bits - 9))) {
 		printk ("file_cluster badly computed!!! %d <> %ld\n",
-			file_cluster,
-			inode->i_blocks / cluster_size / (sb->s_blocksize / 512));
+			file_cluster, inode->i_blocks >> (cluster_bits - 9));
 		fat_cache_inval_inode(inode);
 	}
-	inode->i_blocks += (1 << MSDOS_SB(sb)->cluster_bits) / 512;
+	inode->i_blocks += (1 << cluster_bits) >> 9;
 
 	return nr;
 }
@@ -202,24 +212,23 @@
 
 	if (MSDOS_SB(sb)->fat_bits != 32) {
 		if (inode->i_ino == MSDOS_ROOT_INO)
-			return res;
+			return ERR_PTR(-ENOSPC);
 	}
 
 	nr = fat_add_cluster(inode);
 	if (nr < 0)
-		return res;
+		return ERR_PTR(nr);
 	
 	sector = MSDOS_SB(sb)->data_start + (nr - 2) * cluster_size;
 	last_sector = sector + cluster_size;
-	if (MSDOS_SB(sb)->cvf_format && MSDOS_SB(sb)->cvf_format->zero_out_cluster)
+	if (MSDOS_SB(sb)->cvf_format
+	    && MSDOS_SB(sb)->cvf_format->zero_out_cluster) {
+		res = ERR_PTR(-EIO);
 		MSDOS_SB(sb)->cvf_format->zero_out_cluster(inode, nr);
-	else {
+	} else {
 		for ( ; sector < last_sector; sector++) {
-#ifdef DEBUG
-			printk("zeroing sector %d\n", sector);
-#endif
 			if (!(bh = fat_getblk(sb, sector)))
-				printk("getblk failed\n");
+				printk("FAT: fat_getblk() failed\n");
 			else {
 				memset(bh->b_data, 0, sb->s_blocksize);
 				fat_set_uptodate(sb, bh, 1);
@@ -230,6 +239,8 @@
 					fat_brelse(sb, bh);
 			}
 		}
+		if (res == NULL)
+			res = ERR_PTR(-EIO);
 	}
 	if (inode->i_size & (sb->s_blocksize - 1)) {
 		fat_fs_panic(sb, "Odd directory size");
@@ -472,7 +483,8 @@
     int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry
     **res_de)
 {
-	int count,cluster;
+	int count, cluster;
+	unsigned long dir_size = 0;
 
 #ifdef DEBUG
 	printk("raw_scan_nonroot: start=%d\n",start);
@@ -484,6 +496,13 @@
 			    count,name,number,ino,res_bh,res_de)) >= 0)
 				return cluster;
 		}
+		dir_size += 1 << MSDOS_SB(sb)->cluster_bits;
+		if (dir_size > FAT_MAX_DIR_SIZE) {
+			fat_fs_panic(sb, "Directory %d: "
+				     "exceeded the maximum size of directory",
+				     start);
+			break;
+		}
 		if (!(start = fat_access(sb,start,-1))) {
 			fat_fs_panic(sb,"FAT error");
 			break;
@@ -491,8 +510,8 @@
 #ifdef DEBUG
 	printk("next start: %d\n",start);
 #endif
-	}
-	while (start != -1);
+	} while (start != -1);
+
 	return -ENOENT;
 }
 
diff -u --recursive --new-file v2.5.2/linux/fs/fcntl.c linux/fs/fcntl.c
--- v2.5.2/linux/fs/fcntl.c	Mon Sep 17 13:16:30 2001
+++ linux/fs/fcntl.c	Tue Jan 15 11:07:01 2002
@@ -20,6 +20,28 @@
 extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
 extern int fcntl_getlease(struct file *filp);
 
+void set_close_on_exec(unsigned int fd, int flag)
+{
+	struct files_struct *files = current->files;
+	write_lock(&files->file_lock);
+	if (flag)
+		FD_SET(fd, files->close_on_exec);
+	else
+		FD_CLR(fd, files->close_on_exec);
+	write_unlock(&files->file_lock);
+}
+
+static inline int get_close_on_exec(unsigned int fd)
+{
+	struct files_struct *files = current->files;
+	int res;
+	read_lock(&files->file_lock);
+	res = FD_ISSET(fd, files->close_on_exec);
+	read_unlock(&files->file_lock);
+	return res;
+}
+
+
 /* Expand files.  Return <0 on error; 0 nothing done; 1 files expanded,
  * we may have blocked. 
  *
diff -u --recursive --new-file v2.5.2/linux/fs/file.c linux/fs/file.c
--- v2.5.2/linux/fs/file.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/file.c	Tue Jan 15 11:07:01 2002
@@ -11,6 +11,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/file.h>
 
 #include <asm/bitops.h>
 
diff -u --recursive --new-file v2.5.2/linux/fs/hfs/file_cap.c linux/fs/hfs/file_cap.c
--- v2.5.2/linux/fs/hfs/file_cap.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/hfs/file_cap.c	Tue Jan 29 21:15:47 2002
@@ -91,6 +91,8 @@
 {
 	long long retval;
 
+	lock_kernel();
+
 	switch (origin) {
 		case 2:
 			offset += file->f_dentry->d_inode->i_size;
@@ -106,6 +108,7 @@
 		}
 		retval = offset;
 	}
+	unlock_kernel();
 	return retval;
 }
 
diff -u --recursive --new-file v2.5.2/linux/fs/hfs/file_hdr.c linux/fs/hfs/file_hdr.c
--- v2.5.2/linux/fs/hfs/file_hdr.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/hfs/file_hdr.c	Tue Jan 29 21:15:47 2002
@@ -347,6 +347,8 @@
 {
 	long long retval;
 
+	lock_kernel();
+
 	switch (origin) {
 		case 2:
 			offset += file->f_dentry->d_inode->i_size;
@@ -362,6 +364,7 @@
 		}
 		retval = offset;
 	}
+	unlock_kernel();
 	return retval;
 }
 
diff -u --recursive --new-file v2.5.2/linux/fs/hfs/inode.c linux/fs/hfs/inode.c
--- v2.5.2/linux/fs/hfs/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/hfs/inode.c	Mon Jan 28 13:20:34 2002
@@ -233,7 +233,7 @@
 static int hfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
 {
 	return cont_prepare_write(page,from,to,hfs_get_block,
-		&page->mapping->host->u.hfs_i.mmu_private);
+		&HFS_I(page->mapping->host)->mmu_private);
 }
 static int hfs_bmap(struct address_space *mapping, long block)
 {
@@ -322,7 +322,13 @@
 		inode->i_uid = hsb->s_uid;
 		inode->i_gid = hsb->s_gid;
 
-		memset(HFS_I(inode), 0, sizeof(struct hfs_inode_info));
+		HFS_I(inode)->mmu_private = 0;
+		HFS_I(inode)->fork = NULL;
+		HFS_I(inode)->convert = 0;
+		HFS_I(inode)->file_type = 0;
+		HFS_I(inode)->dir_size = 0;
+		HFS_I(inode)->default_layout = NULL;
+		HFS_I(inode)->layout = NULL;
 		HFS_I(inode)->magic = HFS_INO_MAGIC;
 		HFS_I(inode)->entry = entry;
 		HFS_I(inode)->tz_secondswest = hfs_to_utc(0);
@@ -372,7 +378,7 @@
 		inode->i_op = &hfs_file_inode_operations;
 		inode->i_fop = &hfs_file_operations;
 		inode->i_mapping->a_ops = &hfs_aops;
-		inode->u.hfs_i.mmu_private = inode->i_size;
+		HFS_I(inode)->mmu_private = inode->i_size;
 	} else { /* Directory */
 		struct hfs_dir *hdir = &entry->u.dir;
 
@@ -432,7 +438,7 @@
 		inode->i_op = &hfs_file_inode_operations;
 		inode->i_fop = &hfs_file_operations;
 		inode->i_mapping->a_ops = &hfs_aops;
-		inode->u.hfs_i.mmu_private = inode->i_size;
+		HFS_I(inode)->mmu_private = inode->i_size;
 	} else { /* Directory */
 		struct hfs_dir *hdir = &entry->u.dir;
 
@@ -478,7 +484,7 @@
 		inode->i_op = &hfs_file_inode_operations;
 		inode->i_fop = &hfs_file_operations;
 		inode->i_mapping->a_ops = &hfs_aops;
-		inode->u.hfs_i.mmu_private = inode->i_size;
+		HFS_I(inode)->mmu_private = inode->i_size;
 	} else { /* Directory */
 		struct hfs_dir *hdir = &entry->u.dir;
 
diff -u --recursive --new-file v2.5.2/linux/fs/hfs/super.c linux/fs/hfs/super.c
--- v2.5.2/linux/fs/hfs/super.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/hfs/super.c	Mon Jan 28 13:20:34 2002
@@ -39,9 +39,53 @@
 static int hfs_statfs(struct super_block *, struct statfs *);
 static void hfs_write_super(struct super_block *);
 
+static kmem_cache_t * hfs_inode_cachep;
+
+static struct inode *hfs_alloc_inode(struct super_block *sb)
+{
+	struct hfs_inode_info *ei;
+	ei = (struct hfs_inode_info *)kmem_cache_alloc(hfs_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void hfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(hfs_inode_cachep, HFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct hfs_inode_info *ei = (struct hfs_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	hfs_inode_cachep = kmem_cache_create("hfs_inode_cache",
+					     sizeof(struct hfs_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (hfs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(hfs_inode_cachep))
+		printk(KERN_INFO "hfs_inode_cache: not all structures were freed\n");
+}
+
 /*================ Global variables ================*/
 
 static struct super_operations hfs_super_operations = { 
+	alloc_inode:	hfs_alloc_inode,
+	destroy_inode:	hfs_destroy_inode,
 	read_inode:	hfs_read_inode,
 	put_inode:	hfs_put_inode,
 	put_super:	hfs_put_super,
@@ -472,13 +516,25 @@
 
 static int __init init_hfs_fs(void)
 {
+	int err = init_inodecache();
+	if (err)
+		goto out1;
         hfs_cat_init();
-	return register_filesystem(&hfs_fs);
+	err = register_filesystem(&hfs_fs);
+	if (err)
+		goto out;
+	return 0;
+out:
+	hfs_cat_free();
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_hfs_fs(void) {
 	hfs_cat_free();
 	unregister_filesystem(&hfs_fs);
+	destroy_inodecache();
 }
 
 module_init(init_hfs_fs)
diff -u --recursive --new-file v2.5.2/linux/fs/hpfs/anode.c linux/fs/hpfs/anode.c
--- v2.5.2/linux/fs/hpfs/anode.c	Mon Jun 11 19:15:27 2001
+++ linux/fs/hpfs/anode.c	Mon Jan 21 15:37:32 2002
@@ -42,9 +42,10 @@
 				return -1;
 			}
 			if (inode) {
-				inode->i_hpfs_file_sec = btree->u.external[i].file_secno;
-				inode->i_hpfs_disk_sec = btree->u.external[i].disk_secno;
-				inode->i_hpfs_n_secs = btree->u.external[i].length;
+				struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
+				hpfs_inode->i_file_sec = btree->u.external[i].file_secno;
+				hpfs_inode->i_disk_sec = btree->u.external[i].disk_secno;
+				hpfs_inode->i_n_secs = btree->u.external[i].length;
 			}
 			brelse(bh);
 			return a;
diff -u --recursive --new-file v2.5.2/linux/fs/hpfs/buffer.c linux/fs/hpfs/buffer.c
--- v2.5.2/linux/fs/hpfs/buffer.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/hpfs/buffer.c	Mon Jan 21 15:37:32 2002
@@ -47,38 +47,72 @@
 
 void hpfs_lock_inode(struct inode *i)
 {
-	if (i) down(&i->i_hpfs_sem);
+	if (i) {
+		struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
+		down(&hpfs_inode->i_sem);
+	}
 }
 
 void hpfs_unlock_inode(struct inode *i)
 {
-	if (i) up(&i->i_hpfs_sem);
+	if (i) {
+		struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
+		up(&hpfs_inode->i_sem);
+	}
 }
 
 void hpfs_lock_2inodes(struct inode *i1, struct inode *i2)
 {
-	if (!i1) { if (i2) down(&i2->i_hpfs_sem); return; }
-	if (!i2) { if (i1) down(&i1->i_hpfs_sem); return; }
+	struct hpfs_inode_info *hpfs_i1 = NULL, *hpfs_i2 = NULL;
+
+	if (!i1) {
+		if (i2) {
+			hpfs_i2 = hpfs_i(i2);
+			down(&hpfs_i2->i_sem);
+		}
+		return;
+	}
+	if (!i2) {
+		if (i1) {
+			hpfs_i1 = hpfs_i(i1);
+			down(&hpfs_i1->i_sem);
+		}
+		return;
+	}
 	if (i1->i_ino < i2->i_ino) {
-		down(&i1->i_hpfs_sem);
-		down(&i2->i_hpfs_sem);
+		down(&hpfs_i1->i_sem);
+		down(&hpfs_i2->i_sem);
 	} else if (i1->i_ino > i2->i_ino) {
-		down(&i2->i_hpfs_sem);
-		down(&i1->i_hpfs_sem);
-	} else down(&i1->i_hpfs_sem);
+		down(&hpfs_i2->i_sem);
+		down(&hpfs_i1->i_sem);
+	} else down(&hpfs_i1->i_sem);
 }
 
 void hpfs_unlock_2inodes(struct inode *i1, struct inode *i2)
 {
-	if (!i1) { if (i2) up(&i2->i_hpfs_sem); return; }
-	if (!i2) { if (i1) up(&i1->i_hpfs_sem); return; }
+	struct hpfs_inode_info *hpfs_i1 = NULL, *hpfs_i2 = NULL;
+
+	if (!i1) {
+		if (i2) {
+			hpfs_i2 = hpfs_i(i2);
+			up(&hpfs_i2->i_sem);
+		}
+		return;
+	}
+	if (!i2) {
+		if (i1) {
+			hpfs_i1 = hpfs_i(i1);
+			up(&hpfs_i1->i_sem);
+		}
+		return;
+	}
 	if (i1->i_ino < i2->i_ino) {
-		up(&i2->i_hpfs_sem);
-		up(&i1->i_hpfs_sem);
+		up(&hpfs_i2->i_sem);
+		up(&hpfs_i1->i_sem);
 	} else if (i1->i_ino > i2->i_ino) {
-		up(&i1->i_hpfs_sem);
-		up(&i2->i_hpfs_sem);
-	} else up(&i1->i_hpfs_sem);
+		up(&hpfs_i1->i_sem);
+		up(&hpfs_i2->i_sem);
+	} else up(&hpfs_i1->i_sem);
 }
 
 void hpfs_lock_3inodes(struct inode *i1, struct inode *i2, struct inode *i3)
@@ -87,13 +121,16 @@
 	if (!i2) { hpfs_lock_2inodes(i1, i3); return; }
 	if (!i3) { hpfs_lock_2inodes(i1, i2); return; }
 	if (i1->i_ino < i2->i_ino && i1->i_ino < i3->i_ino) {
-		down(&i1->i_hpfs_sem);
+		struct hpfs_inode_info *hpfs_i1 = hpfs_i(i1);
+		down(&hpfs_i1->i_sem);
 		hpfs_lock_2inodes(i2, i3);
 	} else if (i2->i_ino < i1->i_ino && i2->i_ino < i3->i_ino) {
-		down(&i2->i_hpfs_sem);
+		struct hpfs_inode_info *hpfs_i2 = hpfs_i(i2);
+		down(&hpfs_i2->i_sem);
 		hpfs_lock_2inodes(i1, i3);
 	} else if (i3->i_ino < i1->i_ino && i3->i_ino < i2->i_ino) {
-		down(&i3->i_hpfs_sem);
+		struct hpfs_inode_info *hpfs_i3 = hpfs_i(i3);
+		down(&hpfs_i3->i_sem);
 		hpfs_lock_2inodes(i1, i2);
 	} else if (i1->i_ino != i2->i_ino) hpfs_lock_2inodes(i1, i2);
 	else hpfs_lock_2inodes(i1, i3);
@@ -105,14 +142,17 @@
 	if (!i2) { hpfs_unlock_2inodes(i1, i3); return; }
 	if (!i3) { hpfs_unlock_2inodes(i1, i2); return; }
 	if (i1->i_ino < i2->i_ino && i1->i_ino < i3->i_ino) {
+		struct hpfs_inode_info *hpfs_i1 = hpfs_i(i1);
 		hpfs_unlock_2inodes(i2, i3);
-		up(&i1->i_hpfs_sem);
+		up(&hpfs_i1->i_sem);
 	} else if (i2->i_ino < i1->i_ino && i2->i_ino < i3->i_ino) {
+		struct hpfs_inode_info *hpfs_i2 = hpfs_i(i2);
 		hpfs_unlock_2inodes(i1, i3);
-		up(&i2->i_hpfs_sem);
+		up(&hpfs_i2->i_sem);
 	} else if (i3->i_ino < i1->i_ino && i3->i_ino < i2->i_ino) {
+		struct hpfs_inode_info *hpfs_i3 = hpfs_i(i3);
 		hpfs_unlock_2inodes(i1, i2);
-		up(&i3->i_hpfs_sem);
+		up(&hpfs_i3->i_sem);
 	} else if (i1->i_ino != i2->i_ino) hpfs_unlock_2inodes(i1, i2);
 	else hpfs_unlock_2inodes(i1, i3);
 }
diff -u --recursive --new-file v2.5.2/linux/fs/hpfs/dir.c linux/fs/hpfs/dir.c
--- v2.5.2/linux/fs/hpfs/dir.c	Mon Jun 11 19:15:27 2001
+++ linux/fs/hpfs/dir.c	Tue Jan 29 21:15:47 2002
@@ -27,11 +27,15 @@
 	loff_t pos;
 	struct quad_buffer_head qbh;
 	struct inode *i = filp->f_dentry->d_inode;
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
 	struct super_block *s = i->i_sb;
+
+	lock_kernel();
+
 	/*printk("dir lseek\n");*/
 	if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok;
 	hpfs_lock_inode(i);
-	pos = ((loff_t) hpfs_de_as_down_as_possible(s, i->i_hpfs_dno) << 4) + 1;
+	pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1;
 	while (pos != new_off) {
 		if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh);
 		else goto fail;
@@ -39,16 +43,19 @@
 	}
 	hpfs_unlock_inode(i);
 	ok:
+	unlock_kernel();
 	return filp->f_pos = new_off;
 	fail:
 	hpfs_unlock_inode(i);
 	/*printk("illegal lseek: %016llx\n", new_off);*/
+	unlock_kernel();
 	return -ESPIPE;
 }
 
 int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
 	struct quad_buffer_head qbh;
 	struct hpfs_dirent *de;
 	int lc;
@@ -59,7 +66,7 @@
 	if (inode->i_sb->s_hpfs_chk) {
 		if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode"))
 			return -EFSERROR;
-		if (hpfs_chk_sectors(inode->i_sb, inode->i_hpfs_dno, 4, "dir_dnode"))
+		if (hpfs_chk_sectors(inode->i_sb, hpfs_inode->i_dno, 4, "dir_dnode"))
 			return -EFSERROR;
 	}
 	if (inode->i_sb->s_hpfs_chk >= 2) {
@@ -72,9 +79,9 @@
 			e = 1;
 			hpfs_error(inode->i_sb, "not a directory, fnode %08x",inode->i_ino);
 		}
-		if (inode->i_hpfs_dno != fno->u.external[0].disk_secno) {
+		if (hpfs_inode->i_dno != fno->u.external[0].disk_secno) {
 			e = 1;
-			hpfs_error(inode->i_sb, "corrupted inode: i_hpfs_dno == %08x, fnode -> dnode == %08x", inode->i_hpfs_dno, fno->u.external[0].disk_secno);
+			hpfs_error(inode->i_sb, "corrupted inode: i_dno == %08x, fnode -> dnode == %08x", hpfs_inode->i_dno, fno->u.external[0].disk_secno);
 		}
 		brelse(bh);
 		if (e) return -EFSERROR;
@@ -115,14 +122,14 @@
 			filp->f_pos = 11;
 		}
 		if (filp->f_pos == 11) {
-			if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir, DT_DIR) < 0) {
+			if (filldir(dirent, "..", 2, filp->f_pos, hpfs_inode->i_parent_dir, DT_DIR) < 0) {
 				hpfs_unlock_inode(inode);
 				return 0;
 			}
 			filp->f_pos = 1;
 		}
 		if (filp->f_pos == 1) {
-			filp->f_pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, inode->i_hpfs_dno) << 4) + 1;
+			filp->f_pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1;
 			hpfs_add_pos(inode, &filp->f_pos);
 			filp->f_version = inode->i_version;
 		}
@@ -180,6 +187,7 @@
 	ino_t ino;
 	int err;
 	struct inode *result = NULL;
+	struct hpfs_inode_info *hpfs_result;
 
 	if ((err = hpfs_chk_name((char *)name, &len))) {
 		if (err == -ENAMETOOLONG) return ERR_PTR(-ENAMETOOLONG);
@@ -191,7 +199,7 @@
 	 * '.' and '..' will never be passed here.
 	 */
 
-	de = map_dirent(dir, dir->i_hpfs_dno, (char *) name, len, NULL, &qbh);
+	de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *) name, len, NULL, &qbh);
 
 	/*
 	 * This is not really a bailout, just means file not found.
@@ -215,7 +223,8 @@
 		hpfs_error(dir->i_sb, "hpfs_lookup: can't get inode");
 		goto bail1;
 	}
-	if (!de->directory) result->i_hpfs_parent_dir = dir->i_ino;
+	hpfs_result = hpfs_i(result);
+	if (!de->directory) hpfs_result->i_parent_dir = dir->i_ino;
 	hpfs_unlock_iget(dir->i_sb);
 
 	hpfs_decide_conv(result, (char *)name, len);
@@ -235,14 +244,14 @@
 			result->i_ctime = 1;
 		result->i_mtime = local_to_gmt(dir->i_sb, de->write_date);
 		result->i_atime = local_to_gmt(dir->i_sb, de->read_date);
-		result->i_hpfs_ea_size = de->ea_size;
-		if (!result->i_hpfs_ea_mode && de->read_only)
+		hpfs_result->i_ea_size = de->ea_size;
+		if (!hpfs_result->i_ea_mode && de->read_only)
 			result->i_mode &= ~0222;
 		if (!de->directory) {
 			if (result->i_size == -1) {
 				result->i_size = de->file_size;
 				result->i_data.a_ops = &hpfs_aops;
-				result->u.hpfs_i.mmu_private = result->i_size;
+				hpfs_i(result)->mmu_private = result->i_size;
 			/*
 			 * i_blocks should count the fnode and any anodes.
 			 * We count 1 for the fnode and don't bother about
diff -u --recursive --new-file v2.5.2/linux/fs/hpfs/dnode.c linux/fs/hpfs/dnode.c
--- v2.5.2/linux/fs/hpfs/dnode.c	Tue Sep  5 14:07:29 2000
+++ linux/fs/hpfs/dnode.c	Mon Jan 21 15:37:32 2002
@@ -23,39 +23,43 @@
 
 void hpfs_add_pos(struct inode *inode, loff_t *pos)
 {
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
 	int i = 0;
 	loff_t **ppos;
-	if (inode->i_hpfs_rddir_off)
-		for (; inode->i_hpfs_rddir_off[i]; i++)
-			if (inode->i_hpfs_rddir_off[i] == pos) return;
+
+	if (hpfs_inode->i_rddir_off)
+		for (; hpfs_inode->i_rddir_off[i]; i++)
+			if (hpfs_inode->i_rddir_off[i] == pos) return;
 	if (!(i&0x0f)) {
 		if (!(ppos = kmalloc((i+0x11) * sizeof(loff_t*), GFP_KERNEL))) {
 			printk("HPFS: out of memory for position list\n");
 			return;
 		}
-		if (inode->i_hpfs_rddir_off) {
-			memcpy(ppos, inode->i_hpfs_rddir_off, i * sizeof(loff_t));
-			kfree(inode->i_hpfs_rddir_off);
+		if (hpfs_inode->i_rddir_off) {
+			memcpy(ppos, hpfs_inode->i_rddir_off, i * sizeof(loff_t));
+			kfree(hpfs_inode->i_rddir_off);
 		}
-		inode->i_hpfs_rddir_off = ppos;
+		hpfs_inode->i_rddir_off = ppos;
 	}
-	inode->i_hpfs_rddir_off[i] = pos;
-	inode->i_hpfs_rddir_off[i + 1] = NULL;
+	hpfs_inode->i_rddir_off[i] = pos;
+	hpfs_inode->i_rddir_off[i + 1] = NULL;
 }
 
 void hpfs_del_pos(struct inode *inode, loff_t *pos)
 {
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
 	loff_t **i, **j;
-	if (!inode->i_hpfs_rddir_off) goto not_f;
-	for (i = inode->i_hpfs_rddir_off; *i; i++) if (*i == pos) goto fnd;
+
+	if (!hpfs_inode->i_rddir_off) goto not_f;
+	for (i = hpfs_inode->i_rddir_off; *i; i++) if (*i == pos) goto fnd;
 	goto not_f;
 	fnd:
 	for (j = i + 1; *j; j++) ;
 	*i = *(j - 1);
 	*(j - 1) = NULL;
-	if (j - 1 == inode->i_hpfs_rddir_off) {
-		kfree(inode->i_hpfs_rddir_off);
-		inode->i_hpfs_rddir_off = NULL;
+	if (j - 1 == hpfs_inode->i_rddir_off) {
+		kfree(hpfs_inode->i_rddir_off);
+		hpfs_inode->i_rddir_off = NULL;
 	}
 	return;
 	not_f:
@@ -66,9 +70,11 @@
 static void for_all_poss(struct inode *inode, void (*f)(loff_t *, loff_t, loff_t),
 			 loff_t p1, loff_t p2)
 {
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
 	loff_t **i;
-	if (!inode->i_hpfs_rddir_off) return;
-	for (i = inode->i_hpfs_rddir_off; *i; i++) (*f)(*i, p1, p2);
+
+	if (!hpfs_inode->i_rddir_off) return;
+	for (i = hpfs_inode->i_rddir_off; *i; i++) (*f)(*i, p1, p2);
 	return;
 }
 
@@ -339,7 +345,7 @@
 	fnode->u.external[0].disk_secno = rdno;
 	mark_buffer_dirty(bh);
 	brelse(bh);
-	d->up = ad->up = i->i_hpfs_dno = rdno;
+	d->up = ad->up = hpfs_i(i)->i_dno = rdno;
 	d->root_dnode = ad->root_dnode = 0;
 	hpfs_mark_4buffers_dirty(&qbh);
 	hpfs_brelse4(&qbh);
@@ -363,13 +369,14 @@
 int hpfs_add_dirent(struct inode *i, unsigned char *name, unsigned namelen,
 		    struct hpfs_dirent *new_de, int cdepth)
 {
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
 	struct dnode *d;
 	struct hpfs_dirent *de, *de_end;
 	struct quad_buffer_head qbh;
 	dnode_secno dno;
 	int c;
 	int c1, c2 = 0;
-	dno = i->i_hpfs_dno;
+	dno = hpfs_inode->i_dno;
 	down:
 	if (i->i_sb->s_hpfs_chk)
 		if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_dirent")) return 1;
@@ -494,6 +501,7 @@
 
 static void delete_empty_dnode(struct inode *i, dnode_secno dno)
 {
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
 	struct quad_buffer_head qbh;
 	struct dnode *dnode;
 	dnode_secno down, up, ndown;
@@ -538,7 +546,7 @@
 				mark_buffer_dirty(bh);
 				brelse(bh);
 			}
-			i->i_hpfs_dno = down;
+			hpfs_inode->i_dno = down;
 			for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, (loff_t) 12);
 			return;
 		}
diff -u --recursive --new-file v2.5.2/linux/fs/hpfs/ea.c linux/fs/hpfs/ea.c
--- v2.5.2/linux/fs/hpfs/ea.c	Tue Sep  5 14:07:29 2000
+++ linux/fs/hpfs/ea.c	Mon Jan 21 15:37:32 2002
@@ -355,7 +355,7 @@
 	if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 5 + h[1], size, data)) goto bail;
 	fnode->ea_size_l = pos;
 	ret:
-	inode->i_hpfs_ea_size += 5 + strlen(key) + size;
+	hpfs_i(inode)->i_ea_size += 5 + strlen(key) + size;
 	return;
 	bail:
 	if (fnode->ea_secno)
diff -u --recursive --new-file v2.5.2/linux/fs/hpfs/file.c linux/fs/hpfs/file.c
--- v2.5.2/linux/fs/hpfs/file.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/hpfs/file.c	Mon Jan 21 15:37:32 2002
@@ -45,12 +45,13 @@
 
 secno hpfs_bmap(struct inode *inode, unsigned file_secno)
 {
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
 	unsigned n, disk_secno;
 	struct fnode *fnode;
 	struct buffer_head *bh;
-	if (BLOCKS(inode->u.hpfs_i.mmu_private) <= file_secno) return 0;
-	n = file_secno - inode->i_hpfs_file_sec;
-	if (n < inode->i_hpfs_n_secs) return inode->i_hpfs_disk_sec + n;
+	if (BLOCKS(hpfs_i(inode)->mmu_private) <= file_secno) return 0;
+	n = file_secno - hpfs_inode->i_file_sec;
+	if (n < hpfs_inode->i_n_secs) return hpfs_inode->i_disk_sec + n;
 	if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0;
 	disk_secno = hpfs_bplus_lookup(inode->i_sb, inode, &fnode->btree, file_secno, bh);
 	if (disk_secno == -1) return 0;
@@ -61,9 +62,9 @@
 void hpfs_truncate(struct inode *i)
 {
 	if (IS_IMMUTABLE(i)) return /*-EPERM*/;
-	i->i_hpfs_n_secs = 0;
+	hpfs_i(i)->i_n_secs = 0;
 	i->i_blocks = 1 + ((i->i_size + 511) >> 9);
-	i->u.hpfs_i.mmu_private = i->i_size;
+	hpfs_i(i)->mmu_private = i->i_size;
 	hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9));
 	hpfs_write_inode(i);
 }
@@ -77,7 +78,7 @@
 		return 0;
 	}
 	if (!create) return 0;
-	if (iblock<<9 != inode->u.hpfs_i.mmu_private) {
+	if (iblock<<9 != hpfs_i(inode)->mmu_private) {
 		BUG();
 		return -EIO;
 	}
@@ -86,7 +87,7 @@
 		return -ENOSPC;
 	}
 	inode->i_blocks++;
-	inode->u.hpfs_i.mmu_private += 512;
+	hpfs_i(inode)->mmu_private += 512;
 	bh_result->b_state |= 1UL << BH_New;
 	map_bh(bh_result, inode->i_sb, s);
 	return 0;
@@ -103,7 +104,7 @@
 static int hpfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
 {
 	return cont_prepare_write(page,from,to,hpfs_get_block,
-		&page->mapping->host->u.hpfs_i.mmu_private);
+		&hpfs_i(page->mapping->host)->mmu_private);
 }
 static int _hpfs_bmap(struct address_space *mapping, long block)
 {
@@ -126,7 +127,7 @@
 	if (retval > 0) {
 		struct inode *inode = file->f_dentry->d_inode;
 		inode->i_mtime = CURRENT_TIME;
-		inode->i_hpfs_dirty = 1;
+		hpfs_i(inode)->i_dirty = 1;
 	}
 	return retval;
 }
diff -u --recursive --new-file v2.5.2/linux/fs/hpfs/hpfs_fn.h linux/fs/hpfs/hpfs_fn.h
--- v2.5.2/linux/fs/hpfs/hpfs_fn.h	Mon Jan 14 18:25:10 2002
+++ linux/fs/hpfs/hpfs_fn.h	Mon Jan 21 15:37:32 2002
@@ -11,6 +11,7 @@
 
 #include <linux/fs.h>
 #include <linux/hpfs_fs.h>
+#include <linux/hpfs_fs_i.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
@@ -302,6 +303,11 @@
 int hpfs_rmdir(struct inode *, struct dentry *);
 int hpfs_symlink_readpage(struct file *, struct page *);
 int hpfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+
+static inline struct hpfs_inode_info *hpfs_i(struct inode *inode)
+{
+	return list_entry(inode, struct hpfs_inode_info, vfs_inode);
+}
 
 /* super.c */
 
diff -u --recursive --new-file v2.5.2/linux/fs/hpfs/inode.c linux/fs/hpfs/inode.c
--- v2.5.2/linux/fs/hpfs/inode.c	Mon Sep 10 07:31:25 2001
+++ linux/fs/hpfs/inode.c	Mon Jan 21 15:37:32 2002
@@ -59,31 +59,32 @@
 	struct buffer_head *bh;
 	struct fnode *fnode;
 	struct super_block *sb = i->i_sb;
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
 	unsigned char *ea;
 	int ea_size;
-	init_MUTEX(&i->i_hpfs_sem);
+
 	i->i_uid = sb->s_hpfs_uid;
 	i->i_gid = sb->s_hpfs_gid;
 	i->i_mode = sb->s_hpfs_mode;
-	i->i_hpfs_conv = sb->s_hpfs_conv;
+	hpfs_inode->i_conv = sb->s_hpfs_conv;
 	i->i_blksize = 512;
 	i->i_size = -1;
 	i->i_blocks = -1;
 	
-	i->i_hpfs_dno = 0;
-	i->i_hpfs_n_secs = 0;
-	i->i_hpfs_file_sec = 0;
-	i->i_hpfs_disk_sec = 0;
-	i->i_hpfs_dpos = 0;
-	i->i_hpfs_dsubdno = 0;
-	i->i_hpfs_ea_mode = 0;
-	i->i_hpfs_ea_uid = 0;
-	i->i_hpfs_ea_gid = 0;
-	i->i_hpfs_ea_size = 0;
+	hpfs_inode->i_dno = 0;
+	hpfs_inode->i_n_secs = 0;
+	hpfs_inode->i_file_sec = 0;
+	hpfs_inode->i_disk_sec = 0;
+	hpfs_inode->i_dpos = 0;
+	hpfs_inode->i_dsubdno = 0;
+	hpfs_inode->i_ea_mode = 0;
+	hpfs_inode->i_ea_uid = 0;
+	hpfs_inode->i_ea_gid = 0;
+	hpfs_inode->i_ea_size = 0;
 	i->i_version = ++event;
 
-	i->i_hpfs_rddir_off = NULL;
-	i->i_hpfs_dirty = 0;
+	hpfs_inode->i_rddir_off = NULL;
+	hpfs_inode->i_dirty = 0;
 
 	i->i_atime = 0;
 	i->i_mtime = 0;
@@ -112,14 +113,14 @@
 		if ((ea = hpfs_get_ea(i->i_sb, fnode, "UID", &ea_size))) {
 			if (ea_size == 2) {
 				i->i_uid = ea[0] + (ea[1] << 8);
-				i->i_hpfs_ea_uid = 1;
+				hpfs_inode->i_ea_uid = 1;
 			}
 			kfree(ea);
 		}
 		if ((ea = hpfs_get_ea(i->i_sb, fnode, "GID", &ea_size))) {
 			if (ea_size == 2) {
 				i->i_gid = ea[0] + (ea[1] << 8);
-				i->i_hpfs_ea_gid = 1;
+				hpfs_inode->i_ea_gid = 1;
 			}
 			kfree(ea);
 		}
@@ -139,7 +140,7 @@
 			umode_t mode = sb->s_hpfs_mode;
 			if (ea_size == 2) {
 				mode = ea[0] + (ea[1] << 8);
-				i->i_hpfs_ea_mode = 1;
+				hpfs_inode->i_ea_mode = 1;
 			}
 			kfree(ea);
 			i->i_mode = mode;
@@ -165,60 +166,61 @@
 		i->i_mode |= S_IFDIR;
 		i->i_op = &hpfs_dir_iops;
 		i->i_fop = &hpfs_dir_ops;
-		i->i_hpfs_parent_dir = fnode->up;
-		i->i_hpfs_dno = fnode->u.external[0].disk_secno;
+		hpfs_inode->i_parent_dir = fnode->up;
+		hpfs_inode->i_dno = fnode->u.external[0].disk_secno;
 		if (sb->s_hpfs_chk >= 2) {
 			struct buffer_head *bh0;
-			if (hpfs_map_fnode(sb, i->i_hpfs_parent_dir, &bh0)) brelse(bh0);
+			if (hpfs_map_fnode(sb, hpfs_inode->i_parent_dir, &bh0)) brelse(bh0);
 		}
 		n_dnodes = 0; n_subdirs = 0;
-		hpfs_count_dnodes(i->i_sb, i->i_hpfs_dno, &n_dnodes, &n_subdirs, NULL);
+		hpfs_count_dnodes(i->i_sb, hpfs_inode->i_dno, &n_dnodes, &n_subdirs, NULL);
 		i->i_blocks = 4 * n_dnodes;
 		i->i_size = 2048 * n_dnodes;
 		i->i_nlink = 2 + n_subdirs;
 	} else {
 		i->i_mode |= S_IFREG;
-		if (!i->i_hpfs_ea_mode) i->i_mode &= ~0111;
+		if (!hpfs_inode->i_ea_mode) i->i_mode &= ~0111;
 		i->i_op = &hpfs_file_iops;
 		i->i_fop = &hpfs_file_ops;
 		i->i_nlink = 1;
 		i->i_size = fnode->file_size;
 		i->i_blocks = ((i->i_size + 511) >> 9) + 1;
 		i->i_data.a_ops = &hpfs_aops;
-		i->u.hpfs_i.mmu_private = i->i_size;
+		hpfs_i(i)->mmu_private = i->i_size;
 	}
 	brelse(bh);
 }
 
 void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode)
 {
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
 	if (fnode->acl_size_l || fnode->acl_size_s) {
 		/* Some unknown structures like ACL may be in fnode,
 		   we'd better not overwrite them */
 		hpfs_error(i->i_sb, "fnode %08x has some unknown HPFS386 stuctures", i->i_ino);
 	} else if (i->i_sb->s_hpfs_eas >= 2) {
 		unsigned char ea[4];
-		if ((i->i_uid != i->i_sb->s_hpfs_uid) || i->i_hpfs_ea_uid) {
+		if ((i->i_uid != i->i_sb->s_hpfs_uid) || hpfs_inode->i_ea_uid) {
 			ea[0] = i->i_uid & 0xff;
 			ea[1] = i->i_uid >> 8;
 			hpfs_set_ea(i, fnode, "UID", ea, 2);
-			i->i_hpfs_ea_uid = 1;
+			hpfs_inode->i_ea_uid = 1;
 		}
-		if ((i->i_gid != i->i_sb->s_hpfs_gid) || i->i_hpfs_ea_gid) {
+		if ((i->i_gid != i->i_sb->s_hpfs_gid) || hpfs_inode->i_ea_gid) {
 			ea[0] = i->i_gid & 0xff;
 			ea[1] = i->i_gid >> 8;
 			hpfs_set_ea(i, fnode, "GID", ea, 2);
-			i->i_hpfs_ea_gid = 1;
+			hpfs_inode->i_ea_gid = 1;
 		}
 		if (!S_ISLNK(i->i_mode))
 			if ((i->i_mode != ((i->i_sb->s_hpfs_mode & ~(S_ISDIR(i->i_mode) ? 0 : 0111))
 			  | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))
 			  && i->i_mode != ((i->i_sb->s_hpfs_mode & ~(S_ISDIR(i->i_mode) ? 0222 : 0333))
-			  | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))) || i->i_hpfs_ea_mode) {
+			  | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))) || hpfs_inode->i_ea_mode) {
 				ea[0] = i->i_mode & 0xff;
 				ea[1] = i->i_mode >> 8;
 				hpfs_set_ea(i, fnode, "MODE", ea, 2);
-				i->i_hpfs_ea_mode = 1;
+				hpfs_inode->i_ea_mode = 1;
 			}
 		if (S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode)) {
 			int d = kdev_t_to_nr(i->i_rdev);
@@ -233,17 +235,18 @@
 
 void hpfs_write_inode(struct inode *i)
 {
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
 	struct inode *parent;
 	if (!i->i_nlink) return;
 	if (i->i_ino == i->i_sb->s_hpfs_root) return;
-	if (i->i_hpfs_rddir_off && !atomic_read(&i->i_count)) {
-		if (*i->i_hpfs_rddir_off) printk("HPFS: write_inode: some position still there\n");
-		kfree(i->i_hpfs_rddir_off);
-		i->i_hpfs_rddir_off = NULL;
+	if (hpfs_inode->i_rddir_off && !atomic_read(&i->i_count)) {
+		if (*hpfs_inode->i_rddir_off) printk("HPFS: write_inode: some position still there\n");
+		kfree(hpfs_inode->i_rddir_off);
+		hpfs_inode->i_rddir_off = NULL;
 	}
-	i->i_hpfs_dirty = 0;
+	hpfs_inode->i_dirty = 0;
 	hpfs_lock_iget(i->i_sb, 1);
-	parent = iget(i->i_sb, i->i_hpfs_parent_dir);
+	parent = iget(i->i_sb, hpfs_inode->i_parent_dir);
 	hpfs_unlock_iget(i->i_sb);
 	hpfs_lock_inode(parent);
 	hpfs_write_inode_nolock(i);
@@ -253,6 +256,7 @@
 
 void hpfs_write_inode_nolock(struct inode *i)
 {
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
 	struct buffer_head *bh;
 	struct fnode *fnode;
 	struct quad_buffer_head qbh;
@@ -276,17 +280,17 @@
 		de->read_date = gmt_to_local(i->i_sb, i->i_atime);
 		de->creation_date = gmt_to_local(i->i_sb, i->i_ctime);
 		de->read_only = !(i->i_mode & 0222);
-		de->ea_size = i->i_hpfs_ea_size;
+		de->ea_size = hpfs_inode->i_ea_size;
 		hpfs_mark_4buffers_dirty(&qbh);
 		hpfs_brelse4(&qbh);
 	}
 	if (S_ISDIR(i->i_mode)) {
-		if ((de = map_dirent(i, i->i_hpfs_dno, "\001\001", 2, NULL, &qbh))) {
+		if ((de = map_dirent(i, hpfs_inode->i_dno, "\001\001", 2, NULL, &qbh))) {
 			de->write_date = gmt_to_local(i->i_sb, i->i_mtime);
 			de->read_date = gmt_to_local(i->i_sb, i->i_atime);
 			de->creation_date = gmt_to_local(i->i_sb, i->i_ctime);
 			de->read_only = !(i->i_mode & 0222);
-			de->ea_size = /*i->i_hpfs_ea_size*/0;
+			de->ea_size = /*hpfs_inode->i_ea_size*/0;
 			de->file_size = 0;
 			hpfs_mark_4buffers_dirty(&qbh);
 			hpfs_brelse4(&qbh);
@@ -312,9 +316,10 @@
 
 void hpfs_write_if_changed(struct inode *inode)
 {
-	if (inode->i_hpfs_dirty) {
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
+
+	if (hpfs_inode->i_dirty)
 		hpfs_write_inode(inode);
-	}
 }
 
 void hpfs_delete_inode(struct inode *inode)
diff -u --recursive --new-file v2.5.2/linux/fs/hpfs/name.c linux/fs/hpfs/name.c
--- v2.5.2/linux/fs/hpfs/name.c	Tue Jun  1 23:25:47 1999
+++ linux/fs/hpfs/name.c	Mon Jan 21 15:37:32 2002
@@ -20,8 +20,9 @@
 
 void hpfs_decide_conv(struct inode *inode, unsigned char *name, unsigned len)
 {
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
 	int i;
-	if (inode->i_hpfs_conv != CONV_AUTO) return;
+	if (hpfs_inode->i_conv != CONV_AUTO) return;
 	for (i = 0; *text_postfix[i]; i++) {
 		int l = strlen(text_postfix[i]);
 		if (l <= len)
@@ -34,10 +35,10 @@
 			if (!hpfs_compare_names(inode->i_sb, text_prefix[i], l, name, l, 0))
 				goto text;
 	}
-	inode->i_hpfs_conv = CONV_BINARY;
+	hpfs_inode->i_conv = CONV_BINARY;
 	return;
 	text:
-	inode->i_hpfs_conv = CONV_TEXT;
+	hpfs_inode->i_conv = CONV_TEXT;
 	return;
 }
 
diff -u --recursive --new-file v2.5.2/linux/fs/hpfs/namei.c linux/fs/hpfs/namei.c
--- v2.5.2/linux/fs/hpfs/namei.c	Fri Dec 29 14:07:57 2000
+++ linux/fs/hpfs/namei.c	Mon Jan 21 15:37:32 2002
@@ -25,7 +25,7 @@
 	struct hpfs_dirent dee;
 	int err;
 	if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
-	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail;
+	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh))) goto bail;
 	if (!(dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0, 1))) goto bail1;
 	memset(&dee, 0, sizeof dee);
 	dee.directory = 1;
@@ -69,9 +69,9 @@
 	dir->i_nlink++;
 	hpfs_lock_iget(dir->i_sb, 1);
 	if ((result = iget(dir->i_sb, fno))) {
-		result->i_hpfs_parent_dir = dir->i_ino;
+		hpfs_i(result)->i_parent_dir = dir->i_ino;
 		result->i_ctime = result->i_mtime = result->i_atime = local_to_gmt(dir->i_sb, dee.creation_date);
-		result->i_hpfs_ea_size = 0;
+		hpfs_i(result)->i_ea_size = 0;
 		if (dee.read_only) result->i_mode &= ~0222;
 		if (result->i_uid != current->fsuid ||
 		    result->i_gid != current->fsgid ||
@@ -109,7 +109,7 @@
 	struct hpfs_dirent dee;
 	int err;
 	if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
-	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail;
+	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh))) goto bail;
 	memset(&dee, 0, sizeof dee);
 	if (!(mode & 0222)) dee.read_only = 1;
 	dee.archive = 1;
@@ -133,15 +133,15 @@
 	hpfs_lock_iget(dir->i_sb, 2);
 	if ((result = iget(dir->i_sb, fno))) {
 		hpfs_decide_conv(result, (char *)name, len);
-		result->i_hpfs_parent_dir = dir->i_ino;
+		hpfs_i(result)->i_parent_dir = dir->i_ino;
 		result->i_ctime = result->i_mtime = result->i_atime = local_to_gmt(dir->i_sb, dee.creation_date);
-		result->i_hpfs_ea_size = 0;
+		hpfs_i(result)->i_ea_size = 0;
 		if (dee.read_only) result->i_mode &= ~0222;
 		if (result->i_blocks == -1) result->i_blocks = 1;
 		if (result->i_size == -1) {
 			result->i_size = 0;
 			result->i_data.a_ops = &hpfs_aops;
-			result->u.hpfs_i.mmu_private = 0;
+			hpfs_i(result)->mmu_private = 0;
 		}
 		if (result->i_uid != current->fsuid ||
 		    result->i_gid != current->fsgid ||
@@ -177,7 +177,7 @@
 	int err;
 	if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
 	if (dir->i_sb->s_hpfs_eas < 2) return -EPERM;
-	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail;
+	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh))) goto bail;
 	memset(&dee, 0, sizeof dee);
 	if (!(mode & 0222)) dee.read_only = 1;
 	dee.archive = 1;
@@ -199,9 +199,9 @@
 	mark_buffer_dirty(bh);
 	hpfs_lock_iget(dir->i_sb, 2);
 	if ((result = iget(dir->i_sb, fno))) {
-		result->i_hpfs_parent_dir = dir->i_ino;
+		hpfs_i(result)->i_parent_dir = dir->i_ino;
 		result->i_ctime = result->i_mtime = result->i_atime = local_to_gmt(dir->i_sb, dee.creation_date);
-		result->i_hpfs_ea_size = 0;
+		hpfs_i(result)->i_ea_size = 0;
 		/*if (result->i_blocks == -1) result->i_blocks = 1;
 		if (result->i_size == -1) result->i_size = 0;*/
 		result->i_uid = current->fsuid;
@@ -240,7 +240,7 @@
 	int err;
 	if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
 	if (dir->i_sb->s_hpfs_eas < 2) return -EPERM;
-	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail;
+	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh))) goto bail;
 	memset(&dee, 0, sizeof dee);
 	dee.archive = 1;
 	dee.hidden = name[0] == '.';
@@ -262,9 +262,9 @@
 	brelse(bh);
 	hpfs_lock_iget(dir->i_sb, 2);
 	if ((result = iget(dir->i_sb, fno))) {
-		result->i_hpfs_parent_dir = dir->i_ino;
+		hpfs_i(result)->i_parent_dir = dir->i_ino;
 		result->i_ctime = result->i_mtime = result->i_atime = local_to_gmt(dir->i_sb, dee.creation_date);
-		result->i_hpfs_ea_size = 0;
+		hpfs_i(result)->i_ea_size = 0;
 		/*if (result->i_blocks == -1) result->i_blocks = 1;
 		if (result->i_size == -1) result->i_size = 0;*/
 		result->i_mode = S_IFLNK | 0777;
@@ -307,7 +307,7 @@
 	hpfs_adjust_length((char *)name, &len);
 	again:
 	hpfs_lock_2inodes(dir, inode);
-	if (!(de = map_dirent(dir, dir->i_hpfs_dno, (char *)name, len, &dno, &qbh))) {
+	if (!(de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh))) {
 		hpfs_unlock_2inodes(dir, inode);
 		return -ENOENT;
 	}
@@ -368,7 +368,7 @@
 	int r;
 	hpfs_adjust_length((char *)name, &len);
 	hpfs_lock_2inodes(dir, inode);
-	if (!(de = map_dirent(dir, dir->i_hpfs_dno, (char *)name, len, &dno, &qbh))) {
+	if (!(de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh))) {
 		hpfs_unlock_2inodes(dir, inode);
 		return -ENOENT;
 	}	
@@ -382,7 +382,7 @@
 		hpfs_unlock_2inodes(dir, inode);
 		return -ENOTDIR;
 	}
-	hpfs_count_dnodes(dir->i_sb, inode->i_hpfs_dno, NULL, NULL, &n_items);
+	hpfs_count_dnodes(dir->i_sb, hpfs_i(inode)->i_dno, NULL, NULL, &n_items);
 	if (n_items) {
 		hpfs_brelse4(&qbh);
 		hpfs_unlock_2inodes(dir, inode);
@@ -458,7 +458,7 @@
 		goto end1;
 	}
 
-	if (!(dep = map_dirent(old_dir, old_dir->i_hpfs_dno, (char *)old_name, old_len, &dno, &qbh))) {
+	if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, (char *)old_name, old_len, &dno, &qbh))) {
 		hpfs_error(i->i_sb, "lookup succeeded but map dirent failed");
 		err = -ENOENT;
 		goto end1;
@@ -469,7 +469,7 @@
 	if (new_inode) {
 		int r;
 		if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) {
-			if ((nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1))) {
+			if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, (char *)new_name, new_len, NULL, &qbh1))) {
 				new_inode->i_nlink = 0;
 				copy_de(nde, &de);
 				memcpy(nde->name, new_name, new_len);
@@ -497,7 +497,7 @@
 	}
 	
 	if (new_dir == old_dir)
-		if (!(dep = map_dirent(old_dir, old_dir->i_hpfs_dno, (char *)old_name, old_len, &dno, &qbh))) {
+		if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, (char *)old_name, old_len, &dno, &qbh))) {
 			hpfs_unlock_creation(i->i_sb);
 			hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2");
 			err = -ENOENT;
@@ -513,7 +513,7 @@
 	hpfs_unlock_creation(i->i_sb);
 	
 	end:
-	i->i_hpfs_parent_dir = new_dir->i_ino;
+	hpfs_i(i)->i_parent_dir = new_dir->i_ino;
 	if (S_ISDIR(i->i_mode)) {
 		new_dir->i_nlink++;
 		old_dir->i_nlink--;
@@ -526,7 +526,7 @@
 		mark_buffer_dirty(bh);
 		brelse(bh);
 	}
-	i->i_hpfs_conv = i->i_sb->s_hpfs_conv;
+	hpfs_i(i)->i_conv = i->i_sb->s_hpfs_conv;
 	hpfs_decide_conv(i, (char *)new_name, new_len);
 	end1:
 	hpfs_unlock_3inodes(old_dir, new_dir, i);
diff -u --recursive --new-file v2.5.2/linux/fs/hpfs/super.c linux/fs/hpfs/super.c
--- v2.5.2/linux/fs/hpfs/super.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/hpfs/super.c	Mon Jan 21 15:37:32 2002
@@ -148,10 +148,56 @@
 	return 0;
 }
 
+static kmem_cache_t * hpfs_inode_cachep;
+
+static struct inode *hpfs_alloc_inode(struct super_block *sb)
+{
+	struct hpfs_inode_info *ei;
+	ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void hpfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		init_MUTEX(&ei->i_sem);
+		inode_init_once(&ei->vfs_inode);
+	}
+}
+ 
+static int init_inodecache(void)
+{
+	hpfs_inode_cachep = kmem_cache_create("hpfs_inode_cache",
+					     sizeof(struct hpfs_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (hpfs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(hpfs_inode_cachep))
+		printk(KERN_INFO "hpfs_inode_cache: not all structures were freed\n");
+}
+
 /* Super operations */
 
 static struct super_operations hpfs_sops =
 {
+	alloc_inode:	hpfs_alloc_inode,
+	destroy_inode:	hpfs_destroy_inode,
         read_inode:	hpfs_read_inode,
 	delete_inode:	hpfs_delete_inode,
 	put_super:	hpfs_put_super,
@@ -545,8 +591,8 @@
 		s->s_root->d_inode->i_atime = local_to_gmt(s, de->read_date);
 		s->s_root->d_inode->i_mtime = local_to_gmt(s, de->write_date);
 		s->s_root->d_inode->i_ctime = local_to_gmt(s, de->creation_date);
-		s->s_root->d_inode->i_hpfs_ea_size = de->ea_size;
-		s->s_root->d_inode->i_hpfs_parent_dir = s->s_root->d_inode->i_ino;
+		hpfs_i(s->s_root->d_inode)->i_ea_size = de->ea_size;
+		hpfs_i(s->s_root->d_inode)->i_parent_dir = s->s_root->d_inode->i_ino;
 		if (s->s_root->d_inode->i_size == -1) s->s_root->d_inode->i_size = 2048;
 		if (s->s_root->d_inode->i_blocks == -1) s->s_root->d_inode->i_blocks = 5;
 	}
@@ -568,12 +614,23 @@
 
 static int __init init_hpfs_fs(void)
 {
-	return register_filesystem(&hpfs_fs_type);
+	int err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&hpfs_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_hpfs_fs(void)
 {
 	unregister_filesystem(&hpfs_fs_type);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/inode.c linux/fs/inode.c
--- v2.5.2/linux/fs/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/inode.c	Thu Jan 17 14:30:00 2002
@@ -75,13 +75,53 @@
 
 static kmem_cache_t * inode_cachep;
 
-#define alloc_inode() \
-	 ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
+static struct inode *alloc_inode(struct super_block *sb)
+{
+	static struct address_space_operations empty_aops;
+	static struct inode_operations empty_iops;
+	static struct file_operations empty_fops;
+	struct inode *inode;
+
+	if (sb->s_op->alloc_inode)
+		inode = sb->s_op->alloc_inode(sb);
+	else
+		inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);
+
+	if (inode) {
+		inode->i_sb = sb;
+		inode->i_dev = sb->s_dev;
+		inode->i_blkbits = sb->s_blocksize_bits;
+		inode->i_flags = 0;
+		atomic_set(&inode->i_count, 1);
+		inode->i_sock = 0;
+		inode->i_op = &empty_iops;
+		inode->i_fop = &empty_fops;
+		inode->i_nlink = 1;
+		atomic_set(&inode->i_writecount, 0);
+		inode->i_size = 0;
+		inode->i_blocks = 0;
+		inode->i_generation = 0;
+		memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
+		inode->i_pipe = NULL;
+		inode->i_bdev = NULL;
+		inode->i_cdev = NULL;
+		inode->i_data.a_ops = &empty_aops;
+		inode->i_data.host = inode;
+		inode->i_data.gfp_mask = GFP_HIGHUSER;
+		inode->i_mapping = &inode->i_data;
+		memset(&inode->u, 0, sizeof(inode->u));
+	}
+	return inode;
+}
+
 static void destroy_inode(struct inode *inode) 
 {
 	if (inode_has_buffers(inode))
 		BUG();
-	kmem_cache_free(inode_cachep, (inode));
+	if (inode->i_sb->s_op->destroy_inode)
+		inode->i_sb->s_op->destroy_inode(inode);
+	else
+		kmem_cache_free(inode_cachep, (inode));
 }
 
 
@@ -90,27 +130,30 @@
  * once, because the fields are idempotent across use
  * of the inode, so let the slab aware of that.
  */
+void inode_init_once(struct inode *inode)
+{
+	memset(inode, 0, sizeof(*inode));
+	init_waitqueue_head(&inode->i_wait);
+	INIT_LIST_HEAD(&inode->i_hash);
+	INIT_LIST_HEAD(&inode->i_data.clean_pages);
+	INIT_LIST_HEAD(&inode->i_data.dirty_pages);
+	INIT_LIST_HEAD(&inode->i_data.locked_pages);
+	INIT_LIST_HEAD(&inode->i_dentry);
+	INIT_LIST_HEAD(&inode->i_dirty_buffers);
+	INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
+	INIT_LIST_HEAD(&inode->i_devices);
+	sema_init(&inode->i_sem, 1);
+	sema_init(&inode->i_zombie, 1);
+	spin_lock_init(&inode->i_data.i_shared_lock);
+}
+
 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
 {
 	struct inode * inode = (struct inode *) foo;
 
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR)
-	{
-		memset(inode, 0, sizeof(*inode));
-		init_waitqueue_head(&inode->i_wait);
-		INIT_LIST_HEAD(&inode->i_hash);
-		INIT_LIST_HEAD(&inode->i_data.clean_pages);
-		INIT_LIST_HEAD(&inode->i_data.dirty_pages);
-		INIT_LIST_HEAD(&inode->i_data.locked_pages);
-		INIT_LIST_HEAD(&inode->i_dentry);
-		INIT_LIST_HEAD(&inode->i_dirty_buffers);
-		INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
-		INIT_LIST_HEAD(&inode->i_devices);
-		sema_init(&inode->i_sem, 1);
-		sema_init(&inode->i_zombie, 1);
-		spin_lock_init(&inode->i_data.i_shared_lock);
-	}
+		inode_init_once(inode);
 }
 
 /*
@@ -768,72 +811,28 @@
 	return inode;
 }
 
-/*
- * This just initializes the inode fields
- * to known values before returning the inode..
- *
- * i_sb, i_ino, i_count, i_state and the lists have
- * been initialized elsewhere..
- */
-static void clean_inode(struct inode *inode)
-{
-	static struct address_space_operations empty_aops;
-	static struct inode_operations empty_iops;
-	static struct file_operations empty_fops;
-	memset(&inode->u, 0, sizeof(inode->u));
-	inode->i_sock = 0;
-	inode->i_op = &empty_iops;
-	inode->i_fop = &empty_fops;
-	inode->i_nlink = 1;
-	atomic_set(&inode->i_writecount, 0);
-	inode->i_size = 0;
-	inode->i_blocks = 0;
-	inode->i_generation = 0;
-	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
-	inode->i_pipe = NULL;
-	inode->i_bdev = NULL;
-	inode->i_cdev = NULL;
-	inode->i_data.a_ops = &empty_aops;
-	inode->i_data.host = inode;
-	inode->i_data.gfp_mask = GFP_HIGHUSER;
-	inode->i_mapping = &inode->i_data;
-}
-
 /**
- * get_empty_inode 	- obtain an inode
+ *	new_inode 	- obtain an inode
+ *	@sb: superblock
  *
- * This is called by things like the networking layer
- * etc that want to get an inode without any inode
- * number, or filesystems that allocate new inodes with
- * no pre-existing information.
- *
- * On a successful return the inode pointer is returned. On a failure
- * a %NULL pointer is returned. The returned inode is not on any superblock
- * lists.
+ *	Allocates a new inode for given superblock.
  */
  
-struct inode * get_empty_inode(void)
+struct inode *new_inode(struct super_block *sb)
 {
 	static unsigned long last_ino;
 	struct inode * inode;
 
 	spin_lock_prefetch(&inode_lock);
 	
-	inode = alloc_inode();
-	if (inode)
-	{
+	inode = alloc_inode(sb);
+	if (inode) {
 		spin_lock(&inode_lock);
 		inodes_stat.nr_inodes++;
 		list_add(&inode->i_list, &inode_in_use);
-		inode->i_sb = NULL;
-		inode->i_dev = NODEV;
-		inode->i_blkbits = 0;
 		inode->i_ino = ++last_ino;
-		inode->i_flags = 0;
-		atomic_set(&inode->i_count, 1);
 		inode->i_state = 0;
 		spin_unlock(&inode_lock);
-		clean_inode(inode);
 	}
 	return inode;
 }
@@ -848,7 +847,7 @@
 {
 	struct inode * inode;
 
-	inode = alloc_inode();
+	inode = alloc_inode(sb);
 	if (inode) {
 		struct inode * old;
 
@@ -859,16 +858,9 @@
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
 			list_add(&inode->i_hash, head);
-			inode->i_sb = sb;
-			inode->i_dev = sb->s_dev;
-			inode->i_blkbits = sb->s_blocksize_bits;
 			inode->i_ino = ino;
-			inode->i_flags = 0;
-			atomic_set(&inode->i_count, 1);
 			inode->i_state = I_LOCK;
 			spin_unlock(&inode_lock);
-
-			clean_inode(inode);
 
 			/* reiserfs specific hack right here.  We don't
 			** want this to last, and are looking for VFS changes
diff -u --recursive --new-file v2.5.2/linux/fs/intermezzo/journal_ext3.c linux/fs/intermezzo/journal_ext3.c
--- v2.5.2/linux/fs/intermezzo/journal_ext3.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/intermezzo/journal_ext3.c	Mon Jan 21 15:37:32 2002
@@ -188,7 +188,7 @@
 void presto_e3_journal_file_data(struct inode *inode)
 {
 #ifdef EXT3_JOURNAL_DATA_FL
-        inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
+        EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
 #else
 #warning You must have a facility to enable journaled writes for recovery!
 #endif
diff -u --recursive --new-file v2.5.2/linux/fs/intermezzo/journal_obdfs.c linux/fs/intermezzo/journal_obdfs.c
--- v2.5.2/linux/fs/intermezzo/journal_obdfs.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/intermezzo/journal_obdfs.c	Mon Jan 21 15:37:32 2002
@@ -163,7 +163,7 @@
 void presto_obdfs_journal_file_data(struct inode *inode)
 {
 #ifdef EXT3_JOURNAL_DATA_FL
-        inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
+        EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
 #else
 #warning You must have a facility to enable journaled writes for recovery!
 #endif
diff -u --recursive --new-file v2.5.2/linux/fs/intermezzo/journal_reiserfs.c linux/fs/intermezzo/journal_reiserfs.c
--- v2.5.2/linux/fs/intermezzo/journal_reiserfs.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/intermezzo/journal_reiserfs.c	Mon Jan 21 15:37:32 2002
@@ -101,7 +101,7 @@
 void presto_reiserfs_journal_file_data(struct inode *inode)
 {
 #ifdef EXT3_JOURNAL_DATA_FL
-        inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
+        EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
 #else
 #warning You must have a facility to enable journaled writes for recovery!
 #endif
diff -u --recursive --new-file v2.5.2/linux/fs/intermezzo/kml_reint.c linux/fs/intermezzo/kml_reint.c
--- v2.5.2/linux/fs/intermezzo/kml_reint.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/kml_reint.c	Tue Jan 15 14:33:55 2002
@@ -17,7 +17,6 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/mmu_context.h>
 #include <linux/intermezzo_fs.h>
 #include <linux/intermezzo_kml.h>
 #include <linux/intermezzo_psdev.h>
diff -u --recursive --new-file v2.5.2/linux/fs/isofs/Makefile linux/fs/isofs/Makefile
--- v2.5.2/linux/fs/isofs/Makefile	Thu Oct 25 13:53:53 2001
+++ linux/fs/isofs/Makefile	Tue Jan 29 21:30:41 2002
@@ -15,6 +15,4 @@
 
 obj-m  := $(O_TARGET)
 
-CFLAGS_compress.o := -I $(TOPDIR)/fs/inflate_fs
-
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.5.2/linux/fs/isofs/compress.c linux/fs/isofs/compress.c
--- v2.5.2/linux/fs/isofs/compress.c	Tue Nov  6 08:34:40 2001
+++ linux/fs/isofs/compress.c	Mon Jan 28 13:20:44 2002
@@ -72,8 +72,8 @@
 	unsigned long bufmask  = bufsize - 1;
 	int err = -EIO;
 	int i;
-	unsigned int header_size = inode->u.isofs_i.i_format_parm[0];
-	unsigned int zisofs_block_shift = inode->u.isofs_i.i_format_parm[1];
+	unsigned int header_size = ISOFS_I(inode)->i_format_parm[0];
+	unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
 	/* unsigned long zisofs_block_size = 1UL << zisofs_block_shift; */
 	unsigned int zisofs_block_page_shift = zisofs_block_shift-PAGE_CACHE_SHIFT;
 	unsigned long zisofs_block_pages = 1UL << zisofs_block_page_shift;
diff -u --recursive --new-file v2.5.2/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.5.2/linux/fs/isofs/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/isofs/inode.c	Mon Jan 28 13:20:44 2002
@@ -78,7 +78,51 @@
 static void isofs_read_inode(struct inode *);
 static int isofs_statfs (struct super_block *, struct statfs *);
 
+static kmem_cache_t *isofs_inode_cachep;
+
+static struct inode *isofs_alloc_inode(struct super_block *sb)
+{
+	struct iso_inode_info *ei;
+	ei = (struct iso_inode_info *)kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void isofs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct iso_inode_info *ei = (struct iso_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	isofs_inode_cachep = kmem_cache_create("isofs_inode_cache",
+					     sizeof(struct iso_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (isofs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(isofs_inode_cachep))
+		printk(KERN_INFO "iso_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations isofs_sops = {
+	alloc_inode:	isofs_alloc_inode,
+	destroy_inode:	isofs_destroy_inode,
 	read_inode:	isofs_read_inode,
 	put_super:	isofs_put_super,
 	statfs:		isofs_statfs,
@@ -871,6 +915,7 @@
 	unsigned int firstext;
 	unsigned long nextino;
 	int section, rv;
+	struct iso_inode_info *ei = ISOFS_I(inode);
 
 	lock_kernel();
 
@@ -883,9 +928,9 @@
 	b_off = iblock;
 	
 	offset    = 0;
-	firstext  = inode->u.isofs_i.i_first_extent;
-	sect_size = inode->u.isofs_i.i_section_size >> ISOFS_BUFFER_BITS(inode);
-	nextino   = inode->u.isofs_i.i_next_section_ino;
+	firstext  = ei->i_first_extent;
+	sect_size = ei->i_section_size >> ISOFS_BUFFER_BITS(inode);
+	nextino   = ei->i_next_section_ino;
 	section   = 0;
 
 	while ( nblocks ) {
@@ -912,9 +957,9 @@
 				ninode = iget(inode->i_sb, nextino);
 				if (!ninode)
 					goto abort;
-				firstext  = ninode->u.isofs_i.i_first_extent;
-				sect_size = ninode->u.isofs_i.i_section_size;
-				nextino   = ninode->u.isofs_i.i_next_section_ino;
+				firstext  = ISOFS_I(ninode)->i_first_extent;
+				sect_size = ISOFS_I(ninode)->i_section_size;
+				nextino   = ISOFS_I(ninode)->i_next_section_ino;
 				iput(ninode);
 				
 				if (++section > 100) {
@@ -1020,9 +1065,10 @@
 	int i = 0;
 	int more_entries = 0;
 	struct iso_directory_record * tmpde = NULL;
+	struct iso_inode_info *ei = ISOFS_I(inode);
 
 	inode->i_size = 0;
-	inode->u.isofs_i.i_next_section_ino = 0;
+	ei->i_next_section_ino = 0;
 
 	block = f_pos >> ISOFS_BUFFER_BITS(inode);
 	offset = f_pos & (bufsize-1);
@@ -1074,7 +1120,7 @@
 
 		inode->i_size += isonum_733(de->size);
 		if (i == 1)
-			inode->u.isofs_i.i_next_section_ino = f_pos;
+			ei->i_next_section_ino = f_pos;
 
 		more_entries = de->flags[-high_sierra] & 0x80;
 
@@ -1121,6 +1167,7 @@
 	unsigned int de_len;
 	unsigned long offset;
 	int volume_seq_no, i;
+	struct iso_inode_info *ei = ISOFS_I(inode);
 
 	bh = sb_bread(inode->i_sb, block);
 	if (!bh)
@@ -1148,7 +1195,7 @@
 	}
 
 	/* Assume it is a normal-format file unless told otherwise */
-	inode->u.isofs_i.i_file_format = isofs_file_normal;
+	ei->i_file_format = isofs_file_normal;
 
 	if (de->flags[-high_sierra] & 2) {
 		inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
@@ -1175,11 +1222,15 @@
 	inode->i_gid = inode->i_sb->u.isofs_sb.s_gid;
 	inode->i_blocks = inode->i_blksize = 0;
 
+	ei->i_format_parm[0] = 0;
+	ei->i_format_parm[1] = 0;
+	ei->i_format_parm[2] = 0;
 
-	inode->u.isofs_i.i_section_size = isonum_733 (de->size);
+	ei->i_section_size = isonum_733 (de->size);
 	if(de->flags[-high_sierra] & 0x80) {
 		if(isofs_read_level3_size(inode)) goto fail;
 	} else {
+		ei->i_next_section_ino = 0;
 		inode->i_size = isonum_733 (de->size);
 	}
 
@@ -1233,7 +1284,7 @@
 	inode->i_mtime = inode->i_atime = inode->i_ctime =
 		iso_date(de->date, high_sierra);
 
-	inode->u.isofs_i.i_first_extent = (isonum_733 (de->extent) +
+	ei->i_first_extent = (isonum_733 (de->extent) +
 					   isonum_711 (de->ext_attr_length));
 
 	/* Set the number of blocks for stat() - should be done before RR */
@@ -1279,7 +1330,7 @@
 	{
 		if (S_ISREG(inode->i_mode)) {
 			inode->i_fop = &generic_ro_fops;
-			switch ( inode->u.isofs_i.i_file_format ) {
+			switch ( ei->i_file_format ) {
 #ifdef CONFIG_ZISOFS
 			case isofs_file_compressed:
 				inode->i_data.a_ops = &zisofs_aops;
@@ -1348,14 +1399,26 @@
 
 static int __init init_iso9660_fs(void)
 {
+	int err = init_inodecache();
+	if (err)
+		goto out;
 #ifdef CONFIG_ZISOFS
-	int err;
-
 	err = zisofs_init();
-	if ( err )
-		return err;
+	if (err)
+		goto out1;
+#endif
+	err = register_filesystem(&iso9660_fs_type);
+	if (err)
+		goto out2;
+	return 0;
+out2:
+#ifdef CONFIG_ZISOFS
+	zisofs_cleanup();
+out1:
 #endif
-        return register_filesystem(&iso9660_fs_type);
+	destroy_inodecache();
+out:
+	return err;
 }
 
 static void __exit exit_iso9660_fs(void)
@@ -1364,6 +1427,7 @@
 #ifdef CONFIG_ZISOFS
 	zisofs_cleanup();
 #endif
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/isofs/namei.c linux/fs/isofs/namei.c
--- v2.5.2/linux/fs/isofs/namei.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/isofs/namei.c	Mon Jan 28 13:20:44 2002
@@ -65,7 +65,7 @@
 	unsigned int block, f_pos, offset;
 	struct buffer_head * bh = NULL;
 
-	if (!dir->u.isofs_i.i_first_extent)
+	if (!ISOFS_I(dir)->i_first_extent)
 		return 0;
   
 	f_pos = 0;
diff -u --recursive --new-file v2.5.2/linux/fs/isofs/rock.c linux/fs/isofs/rock.c
--- v2.5.2/linux/fs/isofs/rock.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/isofs/rock.c	Mon Jan 28 13:20:44 2002
@@ -365,9 +365,9 @@
 	printk(KERN_WARNING "Attempt to read inode for relocated directory\n");
 	goto out;
       case SIG('C','L'):
-	inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location);
+	ISOFS_I(inode)->i_first_extent = isonum_733(rr->u.CL.location);
 	reloc = iget(inode->i_sb,
-		     (inode->u.isofs_i.i_first_extent <<
+		     (ISOFS_I(inode)->i_first_extent <<
 		      inode -> i_sb -> u.isofs_sb.s_log_zone_size));
 	if (!reloc)
 		goto out;
@@ -394,10 +394,10 @@
 				      printk(KERN_WARNING "isofs: Can't handle ZF block size of 2^%d\n", block_shift);
 			      } else {
 				/* Note: we don't change i_blocks here */
-				      inode->u.isofs_i.i_file_format = isofs_file_compressed;
+				      ISOFS_I(inode)->i_file_format = isofs_file_compressed;
 				/* Parameters to compression algorithm (header size, block size) */
-				      inode->u.isofs_i.i_format_parm[0] = isonum_711(&rr->u.ZF.parms[0]);
-				      inode->u.isofs_i.i_format_parm[1] = isonum_711(&rr->u.ZF.parms[1]);
+				      ISOFS_I(inode)->i_format_parm[0] = isonum_711(&rr->u.ZF.parms[0]);
+				      ISOFS_I(inode)->i_format_parm[1] = isonum_711(&rr->u.ZF.parms[1]);
 				      inode->i_size = isonum_733(rr->u.ZF.real_size);
 			      }
 		      } else {
diff -u --recursive --new-file v2.5.2/linux/fs/isofs/util.c linux/fs/isofs/util.c
--- v2.5.2/linux/fs/isofs/util.c	Thu Oct 25 13:53:53 2001
+++ linux/fs/isofs/util.c	Mon Jan 28 13:20:44 2002
@@ -3,6 +3,7 @@
  */
 
 #include <linux/time.h>
+#include <linux/fs.h>
 #include <linux/iso_fs.h>
 
 /* 
diff -u --recursive --new-file v2.5.2/linux/fs/jbd/commit.c linux/fs/jbd/commit.c
--- v2.5.2/linux/fs/jbd/commit.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/jbd/commit.c	Tue Jan 15 13:53:51 2002
@@ -224,14 +224,13 @@
 		}
 	} while (jh != last_jh);
 
-	if (bufs || current->need_resched) {
+	if (bufs || need_resched()) {
 		jbd_debug(2, "submit %d writes\n", bufs);
 		spin_unlock(&journal_datalist_lock);
 		unlock_journal(journal);
 		if (bufs)
 			ll_rw_block(WRITE, bufs, wbuf);
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 		journal_brelse_array(wbuf, bufs);
 		lock_journal(journal);
 		spin_lock(&journal_datalist_lock);
@@ -458,8 +457,7 @@
 				bh->b_end_io = journal_end_buffer_io_sync;
 				submit_bh(WRITE, bh);
 			}
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 			lock_journal(journal);
 
 			/* Force a new descriptor to be generated next
diff -u --recursive --new-file v2.5.2/linux/fs/jffs/inode-v23.c linux/fs/jffs/inode-v23.c
--- v2.5.2/linux/fs/jffs/inode-v23.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/jffs/inode-v23.c	Mon Jan 28 13:20:44 2002
@@ -357,7 +357,7 @@
 	inode->i_nlink = raw_inode->nlink;
 	inode->i_uid = raw_inode->uid;
 	inode->i_gid = raw_inode->gid;
-	inode->i_rdev = 0;
+	inode->i_rdev = NODEV;
 	inode->i_size = raw_inode->dsize;
 	inode->i_atime = raw_inode->atime;
 	inode->i_mtime = raw_inode->mtime;
diff -u --recursive --new-file v2.5.2/linux/fs/jffs/jffs_fm.c linux/fs/jffs/jffs_fm.c
--- v2.5.2/linux/fs/jffs/jffs_fm.c	Thu Oct  4 15:13:18 2001
+++ linux/fs/jffs/jffs_fm.c	Mon Jan 28 13:20:44 2002
@@ -46,7 +46,7 @@
 	}
 	DJM(no_jffs_fmcontrol++);
 
-	mtd = get_mtd_device(NULL, MINOR(dev));
+	mtd = get_mtd_device(NULL, minor(dev));
 
 	if (!mtd) {
 		kfree(fmc);
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/Makefile linux/fs/jffs2/Makefile
--- v2.5.2/linux/fs/jffs2/Makefile	Mon Jan 14 18:25:10 2002
+++ linux/fs/jffs2/Makefile	Tue Jan 29 21:30:41 2002
@@ -11,7 +11,7 @@
 
 
 COMPR_OBJS	:= compr.o compr_rubin.o compr_rtime.o pushpull.o \
-			compr_zlib.o zlib.o
+			compr_zlib.o
 JFFS2_OBJS	:= dir.o file.o ioctl.o nodelist.o malloc.o \
 	read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \
 	symlink.o build.o erase.o background.o
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/background.c linux/fs/jffs2/background.c
--- v2.5.2/linux/fs/jffs2/background.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/jffs2/background.c	Tue Jan 15 13:53:51 2002
@@ -127,8 +127,7 @@
 			schedule();
 		}
                 
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
                 /* Put_super will send a SIGKILL and then wait on the sem. 
                  */
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/compr_zlib.c linux/fs/jffs2/compr_zlib.c
--- v2.5.2/linux/fs/jffs2/compr_zlib.c	Thu Oct  4 15:13:18 2001
+++ linux/fs/jffs2/compr_zlib.c	Tue Jan 29 21:30:41 2002
@@ -35,7 +35,11 @@
  *
  */
 
+#ifdef __KERNEL__
+#include <linux/zlib.h>
+#else
 #include "zlib.h"
+#endif
 
 #ifdef __KERNEL__
 #include <linux/kernel.h>
@@ -44,16 +48,6 @@
 #include <linux/jffs2.h>
 #include "nodelist.h"
 
-static void *zalloc(void *opaque, unsigned nr, unsigned size)
-{
-	/* How much does it request? Should we use vmalloc? Or be dynamic? */
-	return kmalloc(nr * size, GFP_KERNEL);
-}
-
-static void zfree(void *opaque, void *addr)
-{
-	kfree(addr);
-}
 #else
 #define min(x,y) ((x)<(y)?(x):(y))
 #ifndef D1
@@ -86,14 +80,18 @@
 		return -1;
 
 #ifdef __KERNEL__
-	strm.zalloc = zalloc;
-	strm.zfree = zfree;
+	strm.workspace = kmalloc(zlib_deflate_workspacesize(),
+				 GFP_KERNEL);
+	if (strm.workspace == NULL) {
+		printk(KERN_WARNING "deflateInit alloc of workspace failed\n");
+		return -1;
+	}
 #else
 	strm.zalloc = (void *)0;
 	strm.zfree = (void *)0;
 #endif
 
-	if (Z_OK != deflateInit(&strm, 3)) {
+	if (Z_OK != zlib_deflateInit(&strm, 3)) {
 		printk(KERN_WARNING "deflateInit failed\n");
 		return -1;
 	}
@@ -108,24 +106,24 @@
 		strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
 		D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n",
 			  strm.avail_in, strm.avail_out));
-		ret = deflate(&strm, Z_PARTIAL_FLUSH);
+		ret = zlib_deflate(&strm, Z_PARTIAL_FLUSH);
 		D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", 
 			  strm.avail_in, strm.avail_out, strm.total_in, strm.total_out));
 		if (ret != Z_OK) {
 			D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret));
-			deflateEnd(&strm);
-			return -1;
+			goto out_err;
 		}
 	}
 	strm.avail_out += STREAM_END_SPACE;
 	strm.avail_in = 0;
-	ret = deflate(&strm, Z_FINISH);
+	ret = zlib_deflate(&strm, Z_FINISH);
 	if (ret != Z_STREAM_END) {
 		D1(printk(KERN_DEBUG "final deflate returned %d\n", ret));
-		deflateEnd(&strm);
-		return -1;
+		goto out_err;
+
 	}
-	deflateEnd(&strm);
+	zlib_deflateEnd(&strm);
+	kfree(strm.workspace);
 
 	D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", strm.total_in, strm.total_out));
 
@@ -136,6 +134,11 @@
 	*dstlen = strm.total_out;
 	*sourcelen = strm.total_in;
 	return 0;
+
+ out_err:
+	zlib_deflateEnd(&strm);
+	kfree(strm.workspace);
+	return -1;
 }
 
 void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
@@ -145,14 +148,18 @@
 	int ret;
 
 #ifdef __KERNEL__
-	strm.zalloc = zalloc;
-	strm.zfree = zfree;
+	strm.workspace = kmalloc(zlib_inflate_workspacesize(),
+				 GFP_KERNEL);
+	if (strm.workspace == NULL) {
+		printk(KERN_WARNING "inflateInit alloc of workspace failed\n");
+		return;
+	}
 #else
 	strm.zalloc = (void *)0;
 	strm.zfree = (void *)0;
 #endif
 
-	if (Z_OK != inflateInit(&strm)) {
+	if (Z_OK != zlib_inflateInit(&strm)) {
 		printk(KERN_WARNING "inflateInit failed\n");
 		return;
 	}
@@ -164,10 +171,11 @@
 	strm.avail_out = destlen;
 	strm.total_out = 0;
 
-	while((ret = inflate(&strm, Z_FINISH)) == Z_OK)
+	while((ret = zlib_inflate(&strm, Z_FINISH)) == Z_OK)
 		;
 	if (ret != Z_STREAM_END) {
 		printk(KERN_NOTICE "inflate returned %d\n", ret);
 	}
-	inflateEnd(&strm);
+	zlib_inflateEnd(&strm);
+	kfree(strm.workspace);
 }
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/dir.c linux/fs/jffs2/dir.c
--- v2.5.2/linux/fs/jffs2/dir.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/jffs2/dir.c	Mon Jan 28 13:20:44 2002
@@ -42,6 +42,7 @@
 #include <linux/jffs2.h>
 #include <linux/jffs2_fs_i.h>
 #include <linux/jffs2_fs_sb.h>
+#include <linux/sched.h>
 #include "nodelist.h"
 
 static int jffs2_readdir (struct file *, void *, filldir_t);
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/erase.c linux/fs/jffs2/erase.c
--- v2.5.2/linux/fs/jffs2/erase.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/jffs2/erase.c	Tue Jan 15 13:53:51 2002
@@ -131,8 +131,7 @@
 		
 		jffs2_erase_block(c, jeb);
 		/* Be nice */
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 		spin_lock_bh(&c->erase_completion_lock);
 	}
 	spin_unlock_bh(&c->erase_completion_lock);
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/malloc.c linux/fs/jffs2/malloc.c
--- v2.5.2/linux/fs/jffs2/malloc.c	Fri Sep 14 14:04:07 2001
+++ linux/fs/jffs2/malloc.c	Mon Jan 28 13:20:44 2002
@@ -49,6 +49,7 @@
 
 /* These are initialised to NULL in the kernel startup code.
    If you're porting to other operating systems, beware */
+static kmem_cache_t *jffs2_inode_cachep;
 static kmem_cache_t *full_dnode_slab;
 static kmem_cache_t *raw_dirent_slab;
 static kmem_cache_t *raw_inode_slab;
@@ -80,6 +81,31 @@
 	}
 }
 
+struct inode *jffs2_alloc_inode(struct super_block *sb)
+{
+	struct jffs2_inode_info *ei;
+	ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+void jffs2_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		init_MUTEX(&ei->sem);
+		inode_init_once(&ei->vfs_inode);
+	}
+}
+
 int __init jffs2_create_slab_caches(void)
 {
 	full_dnode_slab = kmem_cache_create("jffs2_full_dnode", sizeof(struct jffs2_full_dnode), 0, JFFS2_SLAB_POISON, NULL, NULL);
@@ -106,6 +132,13 @@
 	if (!node_frag_slab)
 		goto err;
 
+	jffs2_inode_cachep = kmem_cache_create("jffs2_inode_cache",
+					     sizeof(struct jffs2_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (!jffs2_inode_cachep)
+		goto err;
+
 	inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), 0, JFFS2_SLAB_POISON, NULL, NULL);
 
 	if (inode_cache_slab)
@@ -131,6 +164,8 @@
 		kmem_cache_destroy(node_frag_slab);
 	if(inode_cache_slab)
 		kmem_cache_destroy(inode_cache_slab);
+	if(jffs2_inode_cachep)
+		kmem_cache_destroy(jffs2_inode_cachep);
 
 }
 
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/nodemgmt.c linux/fs/jffs2/nodemgmt.c
--- v2.5.2/linux/fs/jffs2/nodemgmt.c	Thu Oct  4 15:13:18 2001
+++ linux/fs/jffs2/nodemgmt.c	Tue Jan 15 13:53:51 2002
@@ -101,8 +101,7 @@
 			if (ret)
 				return ret;
 
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 
 			if (signal_pending(current))
 				return -EINTR;
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/readinode.c linux/fs/jffs2/readinode.c
--- v2.5.2/linux/fs/jffs2/readinode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/jffs2/readinode.c	Mon Jan 28 13:20:44 2002
@@ -259,9 +259,13 @@
 	f = JFFS2_INODE_INFO(inode);
 	c = JFFS2_SB_INFO(inode->i_sb);
 
-	memset(f, 0, sizeof(*f));
+	f->highest_version = 0;
+	f->fraglist = NULL;
+	f->metadata = NULL;
+	f->dents = NULL;
+	f->flags = 0;
+	f->usercompr = 0;
 	D2(printk(KERN_DEBUG "getting inocache\n"));
-	init_MUTEX(&f->sem);
 	f->inocache = jffs2_get_ino_cache(c, inode->i_ino);
 	D2(printk(KERN_DEBUG "jffs2_read_inode(): Got inocache at %p\n", f->inocache));
 
@@ -437,7 +441,7 @@
 	case S_IFSOCK:
 	case S_IFIFO:
 		inode->i_op = &jffs2_file_inode_operations;
-		init_special_inode(inode, inode->i_mode, kdev_t_to_nr(MKDEV(rdev>>8, rdev&0xff)));
+		init_special_inode(inode, inode->i_mode, kdev_t_to_nr(mk_kdev(rdev>>8, rdev&0xff)));
 		break;
 
 	default:
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/super.c linux/fs/jffs2/super.c
--- v2.5.2/linux/fs/jffs2/super.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/jffs2/super.c	Mon Jan 28 13:20:44 2002
@@ -59,9 +59,13 @@
 static int jffs2_statfs (struct super_block *, struct statfs *);
 int jffs2_remount_fs (struct super_block *, int *, char *);
 extern void jffs2_clear_inode (struct inode *);
-
+extern void jffs2_destroy_inode (struct inode *);
+extern struct inode *jffs2_alloc_inode (struct super_block *);
+ 
 static struct super_operations jffs2_super_operations =
 {
+	alloc_inode:	jffs2_alloc_inode,
+	destroy_inode:	jffs2_destroy_inode,
 	read_inode:	jffs2_read_inode,
 //	delete_inode:	jffs2_delete_inode,
 	put_super:	jffs2_put_super,
@@ -208,7 +212,7 @@
 	c = JFFS2_SB_INFO(sb);
 	memset(c, 0, sizeof(*c));
 	
-	c->mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
+	c->mtd = get_mtd_device(NULL, minor(sb->s_dev));
 	if (!c->mtd) {
 		D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev)));
 		return NULL;
@@ -350,12 +354,6 @@
 	if (sizeof(struct jffs2_sb_info) > sizeof (((struct super_block *)NULL)->u)) {
 		printk(KERN_ERR "JFFS2 error: struct jffs2_sb_info (%d bytes) doesn't fit in the super_block union (%d bytes)\n", 
 		       sizeof(struct jffs2_sb_info), sizeof (((struct super_block *)NULL)->u));
-		return -EIO;
-	}
-
-	if (sizeof(struct jffs2_inode_info) > sizeof (((struct inode *)NULL)->u)) {
-		printk(KERN_ERR "JFFS2 error: struct jffs2_inode_info (%d bytes) doesn't fit in the inode union (%d bytes)\n", 
-		       sizeof(struct jffs2_inode_info), sizeof (((struct inode *)NULL)->u));
 		return -EIO;
 	}
 #endif
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/write.c linux/fs/jffs2/write.c
--- v2.5.2/linux/fs/jffs2/write.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/jffs2/write.c	Mon Jan 28 13:20:44 2002
@@ -73,8 +73,13 @@
 	/* Alloc jffs2_inode_info when that's split in 2.5 */
 
 	f = JFFS2_INODE_INFO(inode);
-	memset(f, 0, sizeof(*f));
-	init_MUTEX_LOCKED(&f->sem);
+	down(&f->sem);
+	f->highest_version = 0;
+	f->fraglist = NULL;
+	f->metadata = NULL;
+	f->dents = NULL;
+	f->flags = 0;
+	f->usercompr = 0;
 	f->inocache = ic;
 	inode->i_nlink = f->inocache->nlink = 1;
 	f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/zlib.c linux/fs/jffs2/zlib.c
--- v2.5.2/linux/fs/jffs2/zlib.c	Fri Sep 14 14:04:07 2001
+++ linux/fs/jffs2/zlib.c	Wed Dec 31 16:00:00 1969
@@ -1,5371 +0,0 @@
-/*
- * This file is derived from various .h and .c files from the zlib-1.0.4
- * distribution by Jean-loup Gailly and Mark Adler, with some additions
- * by Paul Mackerras to aid in implementing Deflate compression and
- * decompression for PPP packets.  See zlib.h for conditions of
- * distribution and use.
- *
- * Changes that have been made include:
- * - added Z_PACKET_FLUSH (see zlib.h for details)
- * - added inflateIncomp and deflateOutputPending
- * - allow strm->next_out to be NULL, meaning discard the output
- *
- * $Id: zlib.c,v 1.3 1997/12/23 10:47:42 paulus Exp $
- */
-
-/* 
- *  ==FILEVERSION 971210==
- *
- * This marker is used by the Linux installation script to determine
- * whether an up-to-date version of this file is already installed.
- */
-
-#define NO_DUMMY_DECL
-#define NO_ZCFUNCS
-#define MY_ZCALLOC
-
-#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
-#define inflate	inflate_ppp	/* FreeBSD already has an inflate :-( */
-#endif
-
-
-/* +++ zutil.h */
-/* zutil.h -- internal interface and configuration of the compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */
-
-#ifndef _Z_UTIL_H
-#define _Z_UTIL_H
-
-#include "zlib.h"
-
-#if defined(KERNEL) || defined(_KERNEL)
-/* Assume this is a *BSD or SVR4 kernel */
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/systm.h>
-#  define HAVE_MEMCPY
-#  define memcpy(d, s, n)	bcopy((s), (d), (n))
-#  define memset(d, v, n)	bzero((d), (n))
-#  define memcmp		bcmp
-
-#else
-#if defined(__KERNEL__)
-/* Assume this is a Linux kernel */
-#include <linux/string.h>
-#define HAVE_MEMCPY
-
-#else /* not kernel */
-
-#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
-#   include <stddef.h>
-#   include <errno.h>
-#else
-    extern int errno;
-#endif
-#ifdef STDC
-#  include <string.h>
-#  include <stdlib.h>
-#endif
-#endif /* __KERNEL__ */
-#endif /* _KERNEL || KERNEL */
-
-#ifndef local
-#  define local static
-#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
-
-typedef unsigned char  uch;
-typedef uch FAR uchf;
-typedef unsigned short ush;
-typedef ush FAR ushf;
-typedef unsigned long  ulg;
-
-extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
-/* (size given to avoid silly warnings with Visual C++) */
-
-#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
-
-#define ERR_RETURN(strm,err) \
-  return (strm->msg = (char*)ERR_MSG(err), (err))
-/* To be used only when the state is known to be valid */
-
-        /* common constants */
-
-#ifndef DEF_WBITS
-#  define DEF_WBITS MAX_WBITS
-#endif
-/* default windowBits for decompression. MAX_WBITS is for compression only */
-
-#if MAX_MEM_LEVEL >= 8
-#  define DEF_MEM_LEVEL 8
-#else
-#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
-#endif
-/* default memLevel */
-
-#define STORED_BLOCK 0
-#define STATIC_TREES 1
-#define DYN_TREES    2
-/* The three kinds of block type */
-
-#define MIN_MATCH  3
-#define MAX_MATCH  258
-/* The minimum and maximum match lengths */
-
-#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
-
-        /* target dependencies */
-
-#ifdef MSDOS
-#  define OS_CODE  0x00
-#  ifdef __TURBOC__
-#    include <alloc.h>
-#  else /* MSC or DJGPP */
-#    include <malloc.h>
-#  endif
-#endif
-
-#ifdef OS2
-#  define OS_CODE  0x06
-#endif
-
-#ifdef WIN32 /* Window 95 & Windows NT */
-#  define OS_CODE  0x0b
-#endif
-
-#if defined(VAXC) || defined(VMS)
-#  define OS_CODE  0x02
-#  define FOPEN(name, mode) \
-     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
-#endif
-
-#ifdef AMIGA
-#  define OS_CODE  0x01
-#endif
-
-#if defined(ATARI) || defined(atarist)
-#  define OS_CODE  0x05
-#endif
-
-#ifdef MACOS
-#  define OS_CODE  0x07
-#endif
-
-#ifdef __50SERIES /* Prime/PRIMOS */
-#  define OS_CODE  0x0F
-#endif
-
-#ifdef TOPS20
-#  define OS_CODE  0x0a
-#endif
-
-#if defined(_BEOS_) || defined(RISCOS)
-#  define fdopen(fd,mode) NULL /* No fdopen() */
-#endif
-
-        /* Common defaults */
-
-#ifndef OS_CODE
-#  define OS_CODE  0x03  /* assume Unix */
-#endif
-
-#ifndef FOPEN
-#  define FOPEN(name, mode) fopen((name), (mode))
-#endif
-
-         /* functions */
-
-#ifdef HAVE_STRERROR
-   extern char *strerror OF((int));
-#  define zstrerror(errnum) strerror(errnum)
-#else
-#  define zstrerror(errnum) ""
-#endif
-
-#if defined(pyr)
-#  define NO_MEMCPY
-#endif
-#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
- /* Use our own functions for small and medium model with MSC <= 5.0.
-  * You may have to use the same strategy for Borland C (untested).
-  */
-#  define NO_MEMCPY
-#endif
-#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
-#  define HAVE_MEMCPY
-#endif
-#ifdef HAVE_MEMCPY
-#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
-#    define zmemcpy _fmemcpy
-#    define zmemcmp _fmemcmp
-#    define zmemzero(dest, len) _fmemset(dest, 0, len)
-#  else
-#    define zmemcpy memcpy
-#    define zmemcmp memcmp
-#    define zmemzero(dest, len) memset(dest, 0, len)
-#  endif
-#else
-   extern void zmemcpy  OF((Bytef* dest, Bytef* source, uInt len));
-   extern int  zmemcmp  OF((Bytef* s1,   Bytef* s2, uInt len));
-   extern void zmemzero OF((Bytef* dest, uInt len));
-#endif
-
-/* Diagnostic functions */
-#ifdef DEBUG_ZLIB
-#  include <stdio.h>
-#  ifndef verbose
-#    define verbose 0
-#  endif
-   extern void z_error    OF((char *m));
-#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
-#  define Trace(x) fprintf x
-#  define Tracev(x) {if (verbose) fprintf x ;}
-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-#  define Assert(cond,msg)
-#  define Trace(x)
-#  define Tracev(x)
-#  define Tracevv(x)
-#  define Tracec(c,x)
-#  define Tracecv(c,x)
-#endif
-
-
-typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len));
-
-voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
-void   zcfree  OF((voidpf opaque, voidpf ptr));
-
-#define ZALLOC(strm, items, size) \
-           (*((strm)->zalloc))((strm)->opaque, (items), (size))
-#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
-#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
-
-#endif /* _Z_UTIL_H */
-/* --- zutil.h */
-
-/* +++ deflate.h */
-/* deflate.h -- internal compression state
- * Copyright (C) 1995-1996 Jean-loup Gailly
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */
-
-#ifndef _DEFLATE_H
-#define _DEFLATE_H
-
-/* #include "zutil.h" */
-
-/* ===========================================================================
- * Internal compression state.
- */
-
-#define LENGTH_CODES 29
-/* number of length codes, not counting the special END_BLOCK code */
-
-#define LITERALS  256
-/* number of literal bytes 0..255 */
-
-#define L_CODES (LITERALS+1+LENGTH_CODES)
-/* number of Literal or Length codes, including the END_BLOCK code */
-
-#define D_CODES   30
-/* number of distance codes */
-
-#define BL_CODES  19
-/* number of codes used to transfer the bit lengths */
-
-#define HEAP_SIZE (2*L_CODES+1)
-/* maximum heap size */
-
-#define MAX_BITS 15
-/* All codes must not exceed MAX_BITS bits */
-
-#define INIT_STATE    42
-#define BUSY_STATE   113
-#define FINISH_STATE 666
-/* Stream status */
-
-
-/* Data structure describing a single value and its code string. */
-typedef struct ct_data_s {
-    union {
-        ush  freq;       /* frequency count */
-        ush  code;       /* bit string */
-    } fc;
-    union {
-        ush  dad;        /* father node in Huffman tree */
-        ush  len;        /* length of bit string */
-    } dl;
-} FAR ct_data;
-
-#define Freq fc.freq
-#define Code fc.code
-#define Dad  dl.dad
-#define Len  dl.len
-
-typedef struct static_tree_desc_s  static_tree_desc;
-
-typedef struct tree_desc_s {
-    ct_data *dyn_tree;           /* the dynamic tree */
-    int     max_code;            /* largest code with non zero frequency */
-    static_tree_desc *stat_desc; /* the corresponding static tree */
-} FAR tree_desc;
-
-typedef ush Pos;
-typedef Pos FAR Posf;
-typedef unsigned IPos;
-
-/* A Pos is an index in the character window. We use short instead of int to
- * save space in the various tables. IPos is used only for parameter passing.
- */
-
-typedef struct deflate_state {
-    z_streamp strm;      /* pointer back to this zlib stream */
-    int   status;        /* as the name implies */
-    Bytef *pending_buf;  /* output still pending */
-    ulg   pending_buf_size; /* size of pending_buf */
-    Bytef *pending_out;  /* next pending byte to output to the stream */
-    int   pending;       /* nb of bytes in the pending buffer */
-    int   noheader;      /* suppress zlib header and adler32 */
-    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
-    Byte  method;        /* STORED (for zip only) or DEFLATED */
-    int   last_flush;    /* value of flush param for previous deflate call */
-
-                /* used by deflate.c: */
-
-    uInt  w_size;        /* LZ77 window size (32K by default) */
-    uInt  w_bits;        /* log2(w_size)  (8..16) */
-    uInt  w_mask;        /* w_size - 1 */
-
-    Bytef *window;
-    /* Sliding window. Input bytes are read into the second half of the window,
-     * and move to the first half later to keep a dictionary of at least wSize
-     * bytes. With this organization, matches are limited to a distance of
-     * wSize-MAX_MATCH bytes, but this ensures that IO is always
-     * performed with a length multiple of the block size. Also, it limits
-     * the window size to 64K, which is quite useful on MSDOS.
-     * To do: use the user input buffer as sliding window.
-     */
-
-    ulg window_size;
-    /* Actual size of window: 2*wSize, except when the user input buffer
-     * is directly used as sliding window.
-     */
-
-    Posf *prev;
-    /* Link to older string with same hash index. To limit the size of this
-     * array to 64K, this link is maintained only for the last 32K strings.
-     * An index in this array is thus a window index modulo 32K.
-     */
-
-    Posf *head; /* Heads of the hash chains or NIL. */
-
-    uInt  ins_h;          /* hash index of string to be inserted */
-    uInt  hash_size;      /* number of elements in hash table */
-    uInt  hash_bits;      /* log2(hash_size) */
-    uInt  hash_mask;      /* hash_size-1 */
-
-    uInt  hash_shift;
-    /* Number of bits by which ins_h must be shifted at each input
-     * step. It must be such that after MIN_MATCH steps, the oldest
-     * byte no longer takes part in the hash key, that is:
-     *   hash_shift * MIN_MATCH >= hash_bits
-     */
-
-    long block_start;
-    /* Window position at the beginning of the current output block. Gets
-     * negative when the window is moved backwards.
-     */
-
-    uInt match_length;           /* length of best match */
-    IPos prev_match;             /* previous match */
-    int match_available;         /* set if previous match exists */
-    uInt strstart;               /* start of string to insert */
-    uInt match_start;            /* start of matching string */
-    uInt lookahead;              /* number of valid bytes ahead in window */
-
-    uInt prev_length;
-    /* Length of the best match at previous step. Matches not greater than this
-     * are discarded. This is used in the lazy match evaluation.
-     */
-
-    uInt max_chain_length;
-    /* To speed up deflation, hash chains are never searched beyond this
-     * length.  A higher limit improves compression ratio but degrades the
-     * speed.
-     */
-
-    uInt max_lazy_match;
-    /* Attempt to find a better match only when the current match is strictly
-     * smaller than this value. This mechanism is used only for compression
-     * levels >= 4.
-     */
-#   define max_insert_length  max_lazy_match
-    /* Insert new strings in the hash table only if the match length is not
-     * greater than this length. This saves time but degrades compression.
-     * max_insert_length is used only for compression levels <= 3.
-     */
-
-    int level;    /* compression level (1..9) */
-    int strategy; /* favor or force Huffman coding*/
-
-    uInt good_match;
-    /* Use a faster search when the previous match is longer than this */
-
-    int nice_match; /* Stop searching when current match exceeds this */
-
-                /* used by trees.c: */
-    /* Didn't use ct_data typedef below to supress compiler warning */
-    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
-    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
-    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
-
-    struct tree_desc_s l_desc;               /* desc. for literal tree */
-    struct tree_desc_s d_desc;               /* desc. for distance tree */
-    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
-
-    ush bl_count[MAX_BITS+1];
-    /* number of codes at each bit length for an optimal tree */
-
-    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
-    int heap_len;               /* number of elements in the heap */
-    int heap_max;               /* element of largest frequency */
-    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
-     * The same heap array is used to build all trees.
-     */
-
-    uch depth[2*L_CODES+1];
-    /* Depth of each subtree used as tie breaker for trees of equal frequency
-     */
-
-    uchf *l_buf;          /* buffer for literals or lengths */
-
-    uInt  lit_bufsize;
-    /* Size of match buffer for literals/lengths.  There are 4 reasons for
-     * limiting lit_bufsize to 64K:
-     *   - frequencies can be kept in 16 bit counters
-     *   - if compression is not successful for the first block, all input
-     *     data is still in the window so we can still emit a stored block even
-     *     when input comes from standard input.  (This can also be done for
-     *     all blocks if lit_bufsize is not greater than 32K.)
-     *   - if compression is not successful for a file smaller than 64K, we can
-     *     even emit a stored file instead of a stored block (saving 5 bytes).
-     *     This is applicable only for zip (not gzip or zlib).
-     *   - creating new Huffman trees less frequently may not provide fast
-     *     adaptation to changes in the input data statistics. (Take for
-     *     example a binary file with poorly compressible code followed by
-     *     a highly compressible string table.) Smaller buffer sizes give
-     *     fast adaptation but have of course the overhead of transmitting
-     *     trees more frequently.
-     *   - I can't count above 4
-     */
-
-    uInt last_lit;      /* running index in l_buf */
-
-    ushf *d_buf;
-    /* Buffer for distances. To simplify the code, d_buf and l_buf have
-     * the same number of elements. To use different lengths, an extra flag
-     * array would be necessary.
-     */
-
-    ulg opt_len;        /* bit length of current block with optimal trees */
-    ulg static_len;     /* bit length of current block with static trees */
-    ulg compressed_len; /* total bit length of compressed file */
-    uInt matches;       /* number of string matches in current block */
-    int last_eob_len;   /* bit length of EOB code for last block */
-
-#ifdef DEBUG_ZLIB
-    ulg bits_sent;      /* bit length of the compressed data */
-#endif
-
-    ush bi_buf;
-    /* Output buffer. bits are inserted starting at the bottom (least
-     * significant bits).
-     */
-    int bi_valid;
-    /* Number of valid bits in bi_buf.  All bits above the last valid bit
-     * are always zero.
-     */
-
-} FAR deflate_state;
-
-/* Output a byte on the stream.
- * IN assertion: there is enough room in pending_buf.
- */
-#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
-
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
-/* In order to simplify the code, particularly on 16 bit machines, match
- * distances are limited to MAX_DIST instead of WSIZE.
- */
-
-        /* in trees.c */
-void _tr_init         OF((deflate_state *s));
-int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
-ulg  _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
-			  int eof));
-void _tr_align        OF((deflate_state *s));
-void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
-                          int eof));
-void _tr_stored_type_only OF((deflate_state *));
-
-#endif
-/* --- deflate.h */
-
-/* +++ deflate.c */
-/* deflate.c -- compress data using the deflation algorithm
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/*
- *  ALGORITHM
- *
- *      The "deflation" process depends on being able to identify portions
- *      of the input text which are identical to earlier input (within a
- *      sliding window trailing behind the input currently being processed).
- *
- *      The most straightforward technique turns out to be the fastest for
- *      most input files: try all possible matches and select the longest.
- *      The key feature of this algorithm is that insertions into the string
- *      dictionary are very simple and thus fast, and deletions are avoided
- *      completely. Insertions are performed at each input character, whereas
- *      string matches are performed only when the previous match ends. So it
- *      is preferable to spend more time in matches to allow very fast string
- *      insertions and avoid deletions. The matching algorithm for small
- *      strings is inspired from that of Rabin & Karp. A brute force approach
- *      is used to find longer strings when a small match has been found.
- *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
- *      (by Leonid Broukhis).
- *         A previous version of this file used a more sophisticated algorithm
- *      (by Fiala and Greene) which is guaranteed to run in linear amortized
- *      time, but has a larger average cost, uses more memory and is patented.
- *      However the F&G algorithm may be faster for some highly redundant
- *      files if the parameter max_chain_length (described below) is too large.
- *
- *  ACKNOWLEDGEMENTS
- *
- *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
- *      I found it in 'freeze' written by Leonid Broukhis.
- *      Thanks to many people for bug reports and testing.
- *
- *  REFERENCES
- *
- *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
- *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
- *
- *      A description of the Rabin and Karp algorithm is given in the book
- *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
- *
- *      Fiala,E.R., and Greene,D.H.
- *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
- *
- */
-
-/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */
-
-/* #include "deflate.h" */
-
-char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
-/* ===========================================================================
- *  Function prototypes.
- */
-typedef enum {
-    need_more,      /* block not completed, need more input or more output */
-    block_done,     /* block flush performed */
-    finish_started, /* finish started, need only more output at next deflate */
-    finish_done     /* finish done, accept no more input or output */
-} block_state;
-
-typedef block_state (*compress_func) OF((deflate_state *s, int flush));
-/* Compression function. Returns the block state after the call. */
-
-local void fill_window    OF((deflate_state *s));
-local block_state deflate_stored OF((deflate_state *s, int flush));
-local block_state deflate_fast   OF((deflate_state *s, int flush));
-local block_state deflate_slow   OF((deflate_state *s, int flush));
-local void lm_init        OF((deflate_state *s));
-local void putShortMSB    OF((deflate_state *s, uInt b));
-local void flush_pending  OF((z_streamp strm));
-local int read_buf        OF((z_streamp strm, charf *buf, unsigned size));
-#ifdef ASMV
-      void match_init OF((void)); /* asm code initialization */
-      uInt longest_match  OF((deflate_state *s, IPos cur_match));
-#else
-local uInt longest_match  OF((deflate_state *s, IPos cur_match));
-#endif
-
-#ifdef DEBUG_ZLIB
-local  void check_match OF((deflate_state *s, IPos start, IPos match,
-                            int length));
-#endif
-
-/* ===========================================================================
- * Local data
- */
-
-#define NIL 0
-/* Tail of hash chains */
-
-#ifndef TOO_FAR
-#  define TOO_FAR 4096
-#endif
-/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-/* Values for max_lazy_match, good_match and max_chain_length, depending on
- * the desired pack level (0..9). The values given below have been tuned to
- * exclude worst case performance for pathological files. Better values may be
- * found for specific files.
- */
-typedef struct config_s {
-   ush good_length; /* reduce lazy search above this match length */
-   ush max_lazy;    /* do not perform lazy search above this match length */
-   ush nice_length; /* quit search above this match length */
-   ush max_chain;
-   compress_func func;
-} config;
-
-local config configuration_table[10] = {
-/*      good lazy nice chain */
-/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
-/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
-/* 2 */ {4,    5, 16,    8, deflate_fast},
-/* 3 */ {4,    6, 32,   32, deflate_fast},
-
-/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
-/* 5 */ {8,   16, 32,   32, deflate_slow},
-/* 6 */ {8,   16, 128, 128, deflate_slow},
-/* 7 */ {8,   32, 128, 256, deflate_slow},
-/* 8 */ {32, 128, 258, 1024, deflate_slow},
-/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
-
-/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
- * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
- * meaning.
- */
-
-#define EQUAL 0
-/* result of memcmp for equal strings */
-
-#ifndef NO_DUMMY_DECL
-struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
-#endif
-
-/* ===========================================================================
- * Update a hash value with the given input byte
- * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
- *    input characters, so that a running hash key can be computed from the
- *    previous key instead of complete recalculation each time.
- */
-#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
-
-
-/* ===========================================================================
- * Insert string str in the dictionary and set match_head to the previous head
- * of the hash chain (the most recent string with same hash key). Return
- * the previous length of the hash chain.
- * IN  assertion: all calls to to INSERT_STRING are made with consecutive
- *    input characters and the first MIN_MATCH bytes of str are valid
- *    (except for the last MIN_MATCH-1 bytes of the input file).
- */
-#define INSERT_STRING(s, str, match_head) \
-   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
-    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
-    s->head[s->ins_h] = (Pos)(str))
-
-/* ===========================================================================
- * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
- * prev[] will be initialized on the fly.
- */
-#define CLEAR_HASH(s) \
-    s->head[s->hash_size-1] = NIL; \
-    zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
-
-/* ========================================================================= */
-int deflateInit_(strm, level, version, stream_size)
-    z_streamp strm;
-    int level;
-    const char *version;
-    int stream_size;
-{
-    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
-			 Z_DEFAULT_STRATEGY, version, stream_size);
-    /* To do: ignore strm->next_in if we use it as window */
-}
-
-/* ========================================================================= */
-int deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
-		  version, stream_size)
-    z_streamp strm;
-    int  level;
-    int  method;
-    int  windowBits;
-    int  memLevel;
-    int  strategy;
-    const char *version;
-    int stream_size;
-{
-    deflate_state *s;
-    int noheader = 0;
-    static char* my_version = ZLIB_VERSION;
-
-    ushf *overlay;
-    /* We overlay pending_buf and d_buf+l_buf. This works since the average
-     * output size for (length,distance) codes is <= 24 bits.
-     */
-
-    if (version == Z_NULL || version[0] != my_version[0] ||
-        stream_size != sizeof(z_stream)) {
-	return Z_VERSION_ERROR;
-    }
-    if (strm == Z_NULL) return Z_STREAM_ERROR;
-
-    strm->msg = Z_NULL;
-#ifndef NO_ZCFUNCS
-    if (strm->zalloc == Z_NULL) {
-	strm->zalloc = zcalloc;
-	strm->opaque = (voidpf)0;
-    }
-    if (strm->zfree == Z_NULL) strm->zfree = zcfree;
-#endif
-
-    if (level == Z_DEFAULT_COMPRESSION) level = 6;
-
-    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
-        noheader = 1;
-        windowBits = -windowBits;
-    }
-    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
-        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
-	strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-        return Z_STREAM_ERROR;
-    }
-    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
-    if (s == Z_NULL) return Z_MEM_ERROR;
-    strm->state = (struct internal_state FAR *)s;
-    s->strm = strm;
-
-    s->noheader = noheader;
-    s->w_bits = windowBits;
-    s->w_size = 1 << s->w_bits;
-    s->w_mask = s->w_size - 1;
-
-    s->hash_bits = memLevel + 7;
-    s->hash_size = 1 << s->hash_bits;
-    s->hash_mask = s->hash_size - 1;
-    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
-
-    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
-    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
-    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
-
-    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
-
-    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
-    s->pending_buf = (uchf *) overlay;
-    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
-
-    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
-        s->pending_buf == Z_NULL) {
-        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
-        deflateEnd (strm);
-        return Z_MEM_ERROR;
-    }
-    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
-    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
-
-    s->level = level;
-    s->strategy = strategy;
-    s->method = (Byte)method;
-
-    return deflateReset(strm);
-}
-
-/* ========================================================================= */
-int deflateSetDictionary (strm, dictionary, dictLength)
-    z_streamp strm;
-    const Bytef *dictionary;
-    uInt  dictLength;
-{
-    deflate_state *s;
-    uInt length = dictLength;
-    uInt n;
-    IPos hash_head = 0;
-
-    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
-	return Z_STREAM_ERROR;
-
-    s = (deflate_state *) strm->state;
-    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
-
-    strm->adler = adler32(strm->adler, dictionary, dictLength);
-
-    if (length < MIN_MATCH) return Z_OK;
-    if (length > MAX_DIST(s)) {
-	length = MAX_DIST(s);
-#ifndef USE_DICT_HEAD
-	dictionary += dictLength - length; /* use the tail of the dictionary */
-#endif
-    }
-    zmemcpy((charf *)s->window, dictionary, length);
-    s->strstart = length;
-    s->block_start = (long)length;
-
-    /* Insert all strings in the hash table (except for the last two bytes).
-     * s->lookahead stays null, so s->ins_h will be recomputed at the next
-     * call of fill_window.
-     */
-    s->ins_h = s->window[0];
-    UPDATE_HASH(s, s->ins_h, s->window[1]);
-    for (n = 0; n <= length - MIN_MATCH; n++) {
-	INSERT_STRING(s, n, hash_head);
-    }
-    if (hash_head) hash_head = 0;  /* to make compiler happy */
-    return Z_OK;
-}
-
-/* ========================================================================= */
-int deflateReset (strm)
-    z_streamp strm;
-{
-    deflate_state *s;
-    
-    if (strm == Z_NULL || strm->state == Z_NULL ||
-        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
-
-    strm->total_in = strm->total_out = 0;
-    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
-    strm->data_type = Z_UNKNOWN;
-
-    s = (deflate_state *)strm->state;
-    s->pending = 0;
-    s->pending_out = s->pending_buf;
-
-    if (s->noheader < 0) {
-        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
-    }
-    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
-    strm->adler = 1;
-    s->last_flush = Z_NO_FLUSH;
-
-    _tr_init(s);
-    lm_init(s);
-
-    return Z_OK;
-}
-
-/* ========================================================================= */
-int deflateParams(strm, level, strategy)
-    z_streamp strm;
-    int level;
-    int strategy;
-{
-    deflate_state *s;
-    compress_func func;
-    int err = Z_OK;
-
-    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-    s = (deflate_state *) strm->state;
-
-    if (level == Z_DEFAULT_COMPRESSION) {
-	level = 6;
-    }
-    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-	return Z_STREAM_ERROR;
-    }
-    func = configuration_table[s->level].func;
-
-    if (func != configuration_table[level].func && strm->total_in != 0) {
-	/* Flush the last buffer: */
-	err = deflate(strm, Z_PARTIAL_FLUSH);
-    }
-    if (s->level != level) {
-	s->level = level;
-	s->max_lazy_match   = configuration_table[level].max_lazy;
-	s->good_match       = configuration_table[level].good_length;
-	s->nice_match       = configuration_table[level].nice_length;
-	s->max_chain_length = configuration_table[level].max_chain;
-    }
-    s->strategy = strategy;
-    return err;
-}
-
-/* =========================================================================
- * Put a short in the pending buffer. The 16-bit value is put in MSB order.
- * IN assertion: the stream state is correct and there is enough room in
- * pending_buf.
- */
-local void putShortMSB (s, b)
-    deflate_state *s;
-    uInt b;
-{
-    put_byte(s, (Byte)(b >> 8));
-    put_byte(s, (Byte)(b & 0xff));
-}   
-
-/* =========================================================================
- * Flush as much pending output as possible. All deflate() output goes
- * through this function so some applications may wish to modify it
- * to avoid allocating a large strm->next_out buffer and copying into it.
- * (See also read_buf()).
- */
-local void flush_pending(strm)
-    z_streamp strm;
-{
-    deflate_state *s = (deflate_state *) strm->state;
-    unsigned len = s->pending;
-
-    if (len > strm->avail_out) len = strm->avail_out;
-    if (len == 0) return;
-
-    if (strm->next_out != Z_NULL) {
-	zmemcpy(strm->next_out, s->pending_out, len);
-	strm->next_out += len;
-    }
-    s->pending_out += len;
-    strm->total_out += len;
-    strm->avail_out  -= len;
-    s->pending -= len;
-    if (s->pending == 0) {
-        s->pending_out = s->pending_buf;
-    }
-}
-
-/* ========================================================================= */
-int deflate (strm, flush)
-    z_streamp strm;
-    int flush;
-{
-    int old_flush; /* value of flush param for previous deflate call */
-    deflate_state *s;
-
-    if (strm == Z_NULL || strm->state == Z_NULL ||
-	flush > Z_FINISH || flush < 0) {
-        return Z_STREAM_ERROR;
-    }
-    s = (deflate_state *) strm->state;
-
-    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
-	(s->status == FINISH_STATE && flush != Z_FINISH)) {
-        ERR_RETURN(strm, Z_STREAM_ERROR);
-    }
-    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
-
-    s->strm = strm; /* just in case */
-    old_flush = s->last_flush;
-    s->last_flush = flush;
-
-    /* Write the zlib header */
-    if (s->status == INIT_STATE) {
-
-        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
-        uInt level_flags = (s->level-1) >> 1;
-
-        if (level_flags > 3) level_flags = 3;
-        header |= (level_flags << 6);
-	if (s->strstart != 0) header |= PRESET_DICT;
-        header += 31 - (header % 31);
-
-        s->status = BUSY_STATE;
-        putShortMSB(s, header);
-
-	/* Save the adler32 of the preset dictionary: */
-	if (s->strstart != 0) {
-	    putShortMSB(s, (uInt)(strm->adler >> 16));
-	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
-	}
-	strm->adler = 1L;
-    }
-
-    /* Flush as much pending output as possible */
-    if (s->pending != 0) {
-        flush_pending(strm);
-        if (strm->avail_out == 0) {
-	    /* Since avail_out is 0, deflate will be called again with
-	     * more output space, but possibly with both pending and
-	     * avail_in equal to zero. There won't be anything to do,
-	     * but this is not an error situation so make sure we
-	     * return OK instead of BUF_ERROR at next call of deflate:
-             */
-	    s->last_flush = -1;
-	    return Z_OK;
-	}
-
-    /* Make sure there is something to do and avoid duplicate consecutive
-     * flushes. For repeated and useless calls with Z_FINISH, we keep
-     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
-     */
-    } else if (strm->avail_in == 0 && flush <= old_flush &&
-	       flush != Z_FINISH) {
-        ERR_RETURN(strm, Z_BUF_ERROR);
-    }
-
-    /* User must not provide more input after the first FINISH: */
-    if (s->status == FINISH_STATE && strm->avail_in != 0) {
-        ERR_RETURN(strm, Z_BUF_ERROR);
-    }
-
-    /* Start a new block or continue the current one.
-     */
-    if (strm->avail_in != 0 || s->lookahead != 0 ||
-        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
-        block_state bstate;
-
-	bstate = (*(configuration_table[s->level].func))(s, flush);
-
-        if (bstate == finish_started || bstate == finish_done) {
-            s->status = FINISH_STATE;
-        }
-        if (bstate == need_more || bstate == finish_started) {
-	    if (strm->avail_out == 0) {
-	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
-	    }
-	    return Z_OK;
-	    /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
-	     * of deflate should use the same flush parameter to make sure
-	     * that the flush is complete. So we don't have to output an
-	     * empty block here, this will be done at next call. This also
-	     * ensures that for a very small output buffer, we emit at most
-	     * one empty block.
-	     */
-	}
-        if (bstate == block_done) {
-            if (flush == Z_PARTIAL_FLUSH) {
-                _tr_align(s);
-	    } else if (flush == Z_PACKET_FLUSH) {
-		/* Output just the 3-bit `stored' block type value,
-		   but not a zero length. */
-		_tr_stored_type_only(s);
-            } else { /* FULL_FLUSH or SYNC_FLUSH */
-                _tr_stored_block(s, (char*)0, 0L, 0);
-                /* For a full flush, this empty block will be recognized
-                 * as a special marker by inflate_sync().
-                 */
-                if (flush == Z_FULL_FLUSH) {
-                    CLEAR_HASH(s);             /* forget history */
-                }
-            }
-            flush_pending(strm);
-	    if (strm->avail_out == 0) {
-	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
-	      return Z_OK;
-	    }
-        }
-    }
-    Assert(strm->avail_out > 0, "bug2");
-
-    if (flush != Z_FINISH) return Z_OK;
-    if (s->noheader) return Z_STREAM_END;
-
-    /* Write the zlib trailer (adler32) */
-    putShortMSB(s, (uInt)(strm->adler >> 16));
-    putShortMSB(s, (uInt)(strm->adler & 0xffff));
-    flush_pending(strm);
-    /* If avail_out is zero, the application will call deflate again
-     * to flush the rest.
-     */
-    s->noheader = -1; /* write the trailer only once! */
-    return s->pending != 0 ? Z_OK : Z_STREAM_END;
-}
-
-/* ========================================================================= */
-int deflateEnd (strm)
-    z_streamp strm;
-{
-    int status;
-    deflate_state *s;
-
-    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-    s = (deflate_state *) strm->state;
-
-    status = s->status;
-    if (status != INIT_STATE && status != BUSY_STATE &&
-	status != FINISH_STATE) {
-      return Z_STREAM_ERROR;
-    }
-
-    /* Deallocate in reverse order of allocations: */
-    TRY_FREE(strm, s->pending_buf);
-    TRY_FREE(strm, s->head);
-    TRY_FREE(strm, s->prev);
-    TRY_FREE(strm, s->window);
-
-    ZFREE(strm, s);
-    strm->state = Z_NULL;
-
-    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
-}
-
-/* =========================================================================
- * Copy the source state to the destination state.
- */
-int deflateCopy (dest, source)
-    z_streamp dest;
-    z_streamp source;
-{
-    deflate_state *ds;
-    deflate_state *ss;
-    ushf *overlay;
-
-    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL)
-        return Z_STREAM_ERROR;
-    ss = (deflate_state *) source->state;
-
-    *dest = *source;
-
-    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
-    if (ds == Z_NULL) return Z_MEM_ERROR;
-    dest->state = (struct internal_state FAR *) ds;
-    *ds = *ss;
-    ds->strm = dest;
-
-    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
-    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
-    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
-    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
-    ds->pending_buf = (uchf *) overlay;
-
-    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
-        ds->pending_buf == Z_NULL) {
-        deflateEnd (dest);
-        return Z_MEM_ERROR;
-    }
-    /* ??? following zmemcpy doesn't work for 16-bit MSDOS */
-    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
-    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
-    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
-    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
-
-    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
-    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
-    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
-
-    ds->l_desc.dyn_tree = ds->dyn_ltree;
-    ds->d_desc.dyn_tree = ds->dyn_dtree;
-    ds->bl_desc.dyn_tree = ds->bl_tree;
-
-    return Z_OK;
-}
-
-/* ===========================================================================
- * Return the number of bytes of output which are immediately available
- * for output from the decompressor.
- */
-int deflateOutputPending (strm)
-    z_streamp strm;
-{
-    if (strm == Z_NULL || strm->state == Z_NULL) return 0;
-    
-    return ((deflate_state *)(strm->state))->pending;
-}
-
-/* ===========================================================================
- * Read a new buffer from the current input stream, update the adler32
- * and total number of bytes read.  All deflate() input goes through
- * this function so some applications may wish to modify it to avoid
- * allocating a large strm->next_in buffer and copying from it.
- * (See also flush_pending()).
- */
-local int read_buf(strm, buf, size)
-    z_streamp strm;
-    charf *buf;
-    unsigned size;
-{
-    unsigned len = strm->avail_in;
-
-    if (len > size) len = size;
-    if (len == 0) return 0;
-
-    strm->avail_in  -= len;
-
-    if (!((deflate_state *)(strm->state))->noheader) {
-        strm->adler = adler32(strm->adler, strm->next_in, len);
-    }
-    zmemcpy(buf, strm->next_in, len);
-    strm->next_in  += len;
-    strm->total_in += len;
-
-    return (int)len;
-}
-
-/* ===========================================================================
- * Initialize the "longest match" routines for a new zlib stream
- */
-local void lm_init (s)
-    deflate_state *s;
-{
-    s->window_size = (ulg)2L*s->w_size;
-
-    CLEAR_HASH(s);
-
-    /* Set the default configuration parameters:
-     */
-    s->max_lazy_match   = configuration_table[s->level].max_lazy;
-    s->good_match       = configuration_table[s->level].good_length;
-    s->nice_match       = configuration_table[s->level].nice_length;
-    s->max_chain_length = configuration_table[s->level].max_chain;
-
-    s->strstart = 0;
-    s->block_start = 0L;
-    s->lookahead = 0;
-    s->match_length = s->prev_length = MIN_MATCH-1;
-    s->match_available = 0;
-    s->ins_h = 0;
-#ifdef ASMV
-    match_init(); /* initialize the asm code */
-#endif
-}
-
-/* ===========================================================================
- * Set match_start to the longest match starting at the given string and
- * return its length. Matches shorter or equal to prev_length are discarded,
- * in which case the result is equal to prev_length and match_start is
- * garbage.
- * IN assertions: cur_match is the head of the hash chain for the current
- *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
- * OUT assertion: the match length is not greater than s->lookahead.
- */
-#ifndef ASMV
-/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
- * match.S. The code will be functionally equivalent.
- */
-local uInt longest_match(s, cur_match)
-    deflate_state *s;
-    IPos cur_match;                             /* current match */
-{
-    unsigned chain_length = s->max_chain_length;/* max hash chain length */
-    register Bytef *scan = s->window + s->strstart; /* current string */
-    register Bytef *match;                       /* matched string */
-    register int len;                           /* length of current match */
-    int best_len = s->prev_length;              /* best match length so far */
-    int nice_match = s->nice_match;             /* stop if match long enough */
-    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
-        s->strstart - (IPos)MAX_DIST(s) : NIL;
-    /* Stop when cur_match becomes <= limit. To simplify the code,
-     * we prevent matches with the string of window index 0.
-     */
-    Posf *prev = s->prev;
-    uInt wmask = s->w_mask;
-
-#ifdef UNALIGNED_OK
-    /* Compare two bytes at a time. Note: this is not always beneficial.
-     * Try with and without -DUNALIGNED_OK to check.
-     */
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
-    register ush scan_start = *(ushf*)scan;
-    register ush scan_end   = *(ushf*)(scan+best_len-1);
-#else
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
-    register Byte scan_end1  = scan[best_len-1];
-    register Byte scan_end   = scan[best_len];
-#endif
-
-    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
-     * It is easy to get rid of this optimization if necessary.
-     */
-    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
-
-    /* Do not waste too much time if we already have a good match: */
-    if (s->prev_length >= s->good_match) {
-        chain_length >>= 2;
-    }
-    /* Do not look for matches beyond the end of the input. This is necessary
-     * to make deflate deterministic.
-     */
-    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
-
-    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
-
-    do {
-        Assert(cur_match < s->strstart, "no future");
-        match = s->window + cur_match;
-
-        /* Skip to next match if the match length cannot increase
-         * or if the match length is less than 2:
-         */
-#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
-        /* This code assumes sizeof(unsigned short) == 2. Do not use
-         * UNALIGNED_OK if your compiler uses a different size.
-         */
-        if (*(ushf*)(match+best_len-1) != scan_end ||
-            *(ushf*)match != scan_start) continue;
-
-        /* It is not necessary to compare scan[2] and match[2] since they are
-         * always equal when the other bytes match, given that the hash keys
-         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
-         * strstart+3, +5, ... up to strstart+257. We check for insufficient
-         * lookahead only every 4th comparison; the 128th check will be made
-         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
-         * necessary to put more guard bytes at the end of the window, or
-         * to check more often for insufficient lookahead.
-         */
-        Assert(scan[2] == match[2], "scan[2]?");
-        scan++, match++;
-        do {
-        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 scan < strend);
-        /* The funny "do {}" generates better code on most compilers */
-
-        /* Here, scan <= window+strstart+257 */
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-        if (*scan == *match) scan++;
-
-        len = (MAX_MATCH - 1) - (int)(strend-scan);
-        scan = strend - (MAX_MATCH-1);
-
-#else /* UNALIGNED_OK */
-
-        if (match[best_len]   != scan_end  ||
-            match[best_len-1] != scan_end1 ||
-            *match            != *scan     ||
-            *++match          != scan[1])      continue;
-
-        /* The check at best_len-1 can be removed because it will be made
-         * again later. (This heuristic is not always a win.)
-         * It is not necessary to compare scan[2] and match[2] since they
-         * are always equal when the other bytes match, given that
-         * the hash keys are equal and that HASH_BITS >= 8.
-         */
-        scan += 2, match++;
-        Assert(*scan == *match, "match[2]?");
-
-        /* We check for insufficient lookahead only every 8th comparison;
-         * the 256th check will be made at strstart+258.
-         */
-        do {
-        } while (*++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 scan < strend);
-
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-
-        len = MAX_MATCH - (int)(strend - scan);
-        scan = strend - MAX_MATCH;
-
-#endif /* UNALIGNED_OK */
-
-        if (len > best_len) {
-            s->match_start = cur_match;
-            best_len = len;
-            if (len >= nice_match) break;
-#ifdef UNALIGNED_OK
-            scan_end = *(ushf*)(scan+best_len-1);
-#else
-            scan_end1  = scan[best_len-1];
-            scan_end   = scan[best_len];
-#endif
-        }
-    } while ((cur_match = prev[cur_match & wmask]) > limit
-             && --chain_length != 0);
-
-    if ((uInt)best_len <= s->lookahead) return best_len;
-    return s->lookahead;
-}
-#endif /* ASMV */
-
-#ifdef DEBUG_ZLIB
-/* ===========================================================================
- * Check that the match at match_start is indeed a match.
- */
-local void check_match(s, start, match, length)
-    deflate_state *s;
-    IPos start, match;
-    int length;
-{
-    /* check that the match is indeed a match */
-    if (zmemcmp((charf *)s->window + match,
-                (charf *)s->window + start, length) != EQUAL) {
-        fprintf(stderr, " start %u, match %u, length %d\n",
-		start, match, length);
-        do {
-	    fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
-	} while (--length != 0);
-        z_error("invalid match");
-    }
-    if (z_verbose > 1) {
-        fprintf(stderr,"\\[%d,%d]", start-match, length);
-        do { putc(s->window[start++], stderr); } while (--length != 0);
-    }
-}
-#else
-#  define check_match(s, start, match, length)
-#endif
-
-/* ===========================================================================
- * Fill the window when the lookahead becomes insufficient.
- * Updates strstart and lookahead.
- *
- * IN assertion: lookahead < MIN_LOOKAHEAD
- * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
- *    At least one byte has been read, or avail_in == 0; reads are
- *    performed for at least two bytes (required for the zip translate_eol
- *    option -- not supported here).
- */
-local void fill_window(s)
-    deflate_state *s;
-{
-    register unsigned n, m;
-    register Posf *p;
-    unsigned more;    /* Amount of free space at the end of the window. */
-    uInt wsize = s->w_size;
-
-    do {
-        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
-
-        /* Deal with !@#$% 64K limit: */
-        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
-            more = wsize;
-
-        } else if (more == (unsigned)(-1)) {
-            /* Very unlikely, but possible on 16 bit machine if strstart == 0
-             * and lookahead == 1 (input done one byte at time)
-             */
-            more--;
-
-        /* If the window is almost full and there is insufficient lookahead,
-         * move the upper half to the lower one to make room in the upper half.
-         */
-        } else if (s->strstart >= wsize+MAX_DIST(s)) {
-
-            zmemcpy((charf *)s->window, (charf *)s->window+wsize,
-                   (unsigned)wsize);
-            s->match_start -= wsize;
-            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
-            s->block_start -= (long) wsize;
-
-            /* Slide the hash table (could be avoided with 32 bit values
-               at the expense of memory usage). We slide even when level == 0
-               to keep the hash table consistent if we switch back to level > 0
-               later. (Using level 0 permanently is not an optimal usage of
-               zlib, so we don't care about this pathological case.)
-             */
-            n = s->hash_size;
-            p = &s->head[n];
-            do {
-                m = *--p;
-                *p = (Pos)(m >= wsize ? m-wsize : NIL);
-            } while (--n);
-
-            n = wsize;
-            p = &s->prev[n];
-            do {
-                m = *--p;
-                *p = (Pos)(m >= wsize ? m-wsize : NIL);
-                /* If n is not on any hash chain, prev[n] is garbage but
-                 * its value will never be used.
-                 */
-            } while (--n);
-            more += wsize;
-        }
-        if (s->strm->avail_in == 0) return;
-
-        /* If there was no sliding:
-         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
-         *    more == window_size - lookahead - strstart
-         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
-         * => more >= window_size - 2*WSIZE + 2
-         * In the BIG_MEM or MMAP case (not yet supported),
-         *   window_size == input_size + MIN_LOOKAHEAD  &&
-         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
-         * Otherwise, window_size == 2*WSIZE so more >= 2.
-         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
-         */
-        Assert(more >= 2, "more < 2");
-
-        n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
-                     more);
-        s->lookahead += n;
-
-        /* Initialize the hash value now that we have some input: */
-        if (s->lookahead >= MIN_MATCH) {
-            s->ins_h = s->window[s->strstart];
-            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-#if MIN_MATCH != 3
-            Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
-        }
-        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
-         * but this is not important since only literal bytes will be emitted.
-         */
-
-    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
-}
-
-/* ===========================================================================
- * Flush the current block, with given end-of-file flag.
- * IN assertion: strstart is set to the end of the current match.
- */
-#define FLUSH_BLOCK_ONLY(s, eof) { \
-   _tr_flush_block(s, (s->block_start >= 0L ? \
-                   (charf *)&s->window[(unsigned)s->block_start] : \
-                   (charf *)Z_NULL), \
-		(ulg)((long)s->strstart - s->block_start), \
-		(eof)); \
-   s->block_start = s->strstart; \
-   flush_pending(s->strm); \
-   Tracev((stderr,"[FLUSH]")); \
-}
-
-/* Same but force premature exit if necessary. */
-#define FLUSH_BLOCK(s, eof) { \
-   FLUSH_BLOCK_ONLY(s, eof); \
-   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
-}
-
-/* ===========================================================================
- * Copy without compression as much as possible from the input stream, return
- * the current block state.
- * This function does not insert new strings in the dictionary since
- * uncompressible data is probably not useful. This function is used
- * only for the level=0 compression option.
- * NOTE: this function should be optimized to avoid extra copying from
- * window to pending_buf.
- */
-local block_state deflate_stored(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
-     * to pending_buf_size, and each stored block has a 5 byte header:
-     */
-    ulg max_block_size = 0xffff;
-    ulg max_start;
-
-    if (max_block_size > s->pending_buf_size - 5) {
-        max_block_size = s->pending_buf_size - 5;
-    }
-
-    /* Copy as much as possible from input to output: */
-    for (;;) {
-        /* Fill the window as much as possible: */
-        if (s->lookahead <= 1) {
-
-            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
-		   s->block_start >= (long)s->w_size, "slide too late");
-
-            fill_window(s);
-            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
-
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-	Assert(s->block_start >= 0L, "block gone");
-
-	s->strstart += s->lookahead;
-	s->lookahead = 0;
-
-	/* Emit a stored block if pending_buf will be full: */
- 	max_start = s->block_start + max_block_size;
-        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
-	    /* strstart == 0 is possible when wraparound on 16-bit machine */
-	    s->lookahead = (uInt)(s->strstart - max_start);
-	    s->strstart = (uInt)max_start;
-            FLUSH_BLOCK(s, 0);
-	}
-	/* Flush if we may have to slide, otherwise block_start may become
-         * negative and the data will be gone:
-         */
-        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
-            FLUSH_BLOCK(s, 0);
-	}
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-
-/* ===========================================================================
- * Compress as much as possible from the input stream, return the current
- * block state.
- * This function does not perform lazy evaluation of matches and inserts
- * new strings in the dictionary only for unmatched strings or for short
- * matches. It is used only for the fast compression options.
- */
-local block_state deflate_fast(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    IPos hash_head = NIL; /* head of the hash chain */
-    int bflush;           /* set if current block must be flushed */
-
-    for (;;) {
-        /* Make sure that we always have enough lookahead, except
-         * at the end of the input file. We need MAX_MATCH bytes
-         * for the next match, plus MIN_MATCH bytes to insert the
-         * string following the next match.
-         */
-        if (s->lookahead < MIN_LOOKAHEAD) {
-            fill_window(s);
-            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-	        return need_more;
-	    }
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-
-        /* Insert the string window[strstart .. strstart+2] in the
-         * dictionary, and set hash_head to the head of the hash chain:
-         */
-        if (s->lookahead >= MIN_MATCH) {
-            INSERT_STRING(s, s->strstart, hash_head);
-        }
-
-        /* Find the longest match, discarding those <= prev_length.
-         * At this point we have always match_length < MIN_MATCH
-         */
-        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
-            /* To simplify the code, we prevent matches with the string
-             * of window index 0 (in particular we have to avoid a match
-             * of the string with itself at the start of the input file).
-             */
-            if (s->strategy != Z_HUFFMAN_ONLY) {
-                s->match_length = longest_match (s, hash_head);
-            }
-            /* longest_match() sets match_start */
-        }
-        if (s->match_length >= MIN_MATCH) {
-            check_match(s, s->strstart, s->match_start, s->match_length);
-
-            bflush = _tr_tally(s, s->strstart - s->match_start,
-                               s->match_length - MIN_MATCH);
-
-            s->lookahead -= s->match_length;
-
-            /* Insert new strings in the hash table only if the match length
-             * is not too large. This saves time but degrades compression.
-             */
-            if (s->match_length <= s->max_insert_length &&
-                s->lookahead >= MIN_MATCH) {
-                s->match_length--; /* string at strstart already in hash table */
-                do {
-                    s->strstart++;
-                    INSERT_STRING(s, s->strstart, hash_head);
-                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
-                     * always MIN_MATCH bytes ahead.
-                     */
-                } while (--s->match_length != 0);
-                s->strstart++; 
-            } else {
-                s->strstart += s->match_length;
-                s->match_length = 0;
-                s->ins_h = s->window[s->strstart];
-                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-#if MIN_MATCH != 3
-                Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
-                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
-                 * matter since it will be recomputed at next deflate call.
-                 */
-            }
-        } else {
-            /* No match, output a literal byte */
-            Tracevv((stderr,"%c", s->window[s->strstart]));
-            bflush = _tr_tally (s, 0, s->window[s->strstart]);
-            s->lookahead--;
-            s->strstart++; 
-        }
-        if (bflush) FLUSH_BLOCK(s, 0);
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-
-/* ===========================================================================
- * Same as above, but achieves better compression. We use a lazy
- * evaluation for matches: a match is finally adopted only if there is
- * no better match at the next window position.
- */
-local block_state deflate_slow(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    IPos hash_head = NIL;    /* head of hash chain */
-    int bflush;              /* set if current block must be flushed */
-
-    /* Process the input block. */
-    for (;;) {
-        /* Make sure that we always have enough lookahead, except
-         * at the end of the input file. We need MAX_MATCH bytes
-         * for the next match, plus MIN_MATCH bytes to insert the
-         * string following the next match.
-         */
-        if (s->lookahead < MIN_LOOKAHEAD) {
-            fill_window(s);
-            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-	        return need_more;
-	    }
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-
-        /* Insert the string window[strstart .. strstart+2] in the
-         * dictionary, and set hash_head to the head of the hash chain:
-         */
-        if (s->lookahead >= MIN_MATCH) {
-            INSERT_STRING(s, s->strstart, hash_head);
-        }
-
-        /* Find the longest match, discarding those <= prev_length.
-         */
-        s->prev_length = s->match_length, s->prev_match = s->match_start;
-        s->match_length = MIN_MATCH-1;
-
-        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
-            s->strstart - hash_head <= MAX_DIST(s)) {
-            /* To simplify the code, we prevent matches with the string
-             * of window index 0 (in particular we have to avoid a match
-             * of the string with itself at the start of the input file).
-             */
-            if (s->strategy != Z_HUFFMAN_ONLY) {
-                s->match_length = longest_match (s, hash_head);
-            }
-            /* longest_match() sets match_start */
-
-            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
-                 (s->match_length == MIN_MATCH &&
-                  s->strstart - s->match_start > TOO_FAR))) {
-
-                /* If prev_match is also MIN_MATCH, match_start is garbage
-                 * but we will ignore the current match anyway.
-                 */
-                s->match_length = MIN_MATCH-1;
-            }
-        }
-        /* If there was a match at the previous step and the current
-         * match is not better, output the previous match:
-         */
-        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
-            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
-            /* Do not insert strings in hash table beyond this. */
-
-            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
-
-            bflush = _tr_tally(s, s->strstart -1 - s->prev_match,
-                               s->prev_length - MIN_MATCH);
-
-            /* Insert in hash table all strings up to the end of the match.
-             * strstart-1 and strstart are already inserted. If there is not
-             * enough lookahead, the last two strings are not inserted in
-             * the hash table.
-             */
-            s->lookahead -= s->prev_length-1;
-            s->prev_length -= 2;
-            do {
-                if (++s->strstart <= max_insert) {
-                    INSERT_STRING(s, s->strstart, hash_head);
-                }
-            } while (--s->prev_length != 0);
-            s->match_available = 0;
-            s->match_length = MIN_MATCH-1;
-            s->strstart++;
-
-            if (bflush) FLUSH_BLOCK(s, 0);
-
-        } else if (s->match_available) {
-            /* If there was no match at the previous position, output a
-             * single literal. If there was a match but the current match
-             * is longer, truncate the previous match to a single literal.
-             */
-            Tracevv((stderr,"%c", s->window[s->strstart-1]));
-            if (_tr_tally (s, 0, s->window[s->strstart-1])) {
-                FLUSH_BLOCK_ONLY(s, 0);
-            }
-            s->strstart++;
-            s->lookahead--;
-            if (s->strm->avail_out == 0) return need_more;
-        } else {
-            /* There is no previous match to compare with, wait for
-             * the next step to decide.
-             */
-            s->match_available = 1;
-            s->strstart++;
-            s->lookahead--;
-        }
-    }
-    Assert (flush != Z_NO_FLUSH, "no flush?");
-    if (s->match_available) {
-        Tracevv((stderr,"%c", s->window[s->strstart-1]));
-        _tr_tally (s, 0, s->window[s->strstart-1]);
-        s->match_available = 0;
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-/* --- deflate.c */
-
-/* +++ trees.c */
-/* trees.c -- output deflated data using Huffman coding
- * Copyright (C) 1995-1996 Jean-loup Gailly
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/*
- *  ALGORITHM
- *
- *      The "deflation" process uses several Huffman trees. The more
- *      common source values are represented by shorter bit sequences.
- *
- *      Each code tree is stored in a compressed form which is itself
- * a Huffman encoding of the lengths of all the code strings (in
- * ascending order by source values).  The actual code strings are
- * reconstructed from the lengths in the inflate process, as described
- * in the deflate specification.
- *
- *  REFERENCES
- *
- *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
- *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
- *
- *      Storer, James A.
- *          Data Compression:  Methods and Theory, pp. 49-50.
- *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
- *
- *      Sedgewick, R.
- *          Algorithms, p290.
- *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
- */
-
-/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
-
-/* #include "deflate.h" */
-
-#ifdef DEBUG_ZLIB
-#  include <ctype.h>
-#endif
-
-/* ===========================================================================
- * Constants
- */
-
-#define MAX_BL_BITS 7
-/* Bit length codes must not exceed MAX_BL_BITS bits */
-
-#define END_BLOCK 256
-/* end of block literal code */
-
-#define REP_3_6      16
-/* repeat previous bit length 3-6 times (2 bits of repeat count) */
-
-#define REPZ_3_10    17
-/* repeat a zero length 3-10 times  (3 bits of repeat count) */
-
-#define REPZ_11_138  18
-/* repeat a zero length 11-138 times  (7 bits of repeat count) */
-
-local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
-   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
-
-local int extra_dbits[D_CODES] /* extra bits for each distance code */
-   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
-
-local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
-   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
-
-local uch bl_order[BL_CODES]
-   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
-/* The lengths of the bit length codes are sent in order of decreasing
- * probability, to avoid transmitting the lengths for unused bit length codes.
- */
-
-#define Buf_size (8 * 2*sizeof(char))
-/* Number of bits used within bi_buf. (bi_buf might be implemented on
- * more than 16 bits on some systems.)
- */
-
-/* ===========================================================================
- * Local data. These are initialized only once.
- */
-
-local ct_data static_ltree[L_CODES+2];
-/* The static literal tree. Since the bit lengths are imposed, there is no
- * need for the L_CODES extra codes used during heap construction. However
- * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
- * below).
- */
-
-local ct_data static_dtree[D_CODES];
-/* The static distance tree. (Actually a trivial tree since all codes use
- * 5 bits.)
- */
-
-local uch dist_code[512];
-/* distance codes. The first 256 values correspond to the distances
- * 3 .. 258, the last 256 values correspond to the top 8 bits of
- * the 15 bit distances.
- */
-
-local uch length_code[MAX_MATCH-MIN_MATCH+1];
-/* length code for each normalized match length (0 == MIN_MATCH) */
-
-local int base_length[LENGTH_CODES];
-/* First normalized length for each code (0 = MIN_MATCH) */
-
-local int base_dist[D_CODES];
-/* First normalized distance for each code (0 = distance of 1) */
-
-struct static_tree_desc_s {
-    ct_data *static_tree;        /* static tree or NULL */
-    intf    *extra_bits;         /* extra bits for each code or NULL */
-    int     extra_base;          /* base index for extra_bits */
-    int     elems;               /* max number of elements in the tree */
-    int     max_length;          /* max bit length for the codes */
-};
-
-local static_tree_desc  static_l_desc =
-{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
-
-local static_tree_desc  static_d_desc =
-{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
-
-local static_tree_desc  static_bl_desc =
-{(ct_data *)0, extra_blbits, 0,      BL_CODES, MAX_BL_BITS};
-
-/* ===========================================================================
- * Local (static) routines in this file.
- */
-
-local void tr_static_init OF((void));
-local void init_block     OF((deflate_state *s));
-local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
-local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
-local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
-local void build_tree     OF((deflate_state *s, tree_desc *desc));
-local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
-local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
-local int  build_bl_tree  OF((deflate_state *s));
-local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
-                              int blcodes));
-local void compress_block OF((deflate_state *s, ct_data *ltree,
-                              ct_data *dtree));
-local void set_data_type  OF((deflate_state *s));
-local unsigned bi_reverse OF((unsigned value, int length));
-local void bi_windup      OF((deflate_state *s));
-local void bi_flush       OF((deflate_state *s));
-local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
-                              int header));
-
-#ifndef DEBUG_ZLIB
-#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
-   /* Send a code of the given tree. c and tree must not have side effects */
-
-#else /* DEBUG_ZLIB */
-#  define send_code(s, c, tree) \
-     { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
-       send_bits(s, tree[c].Code, tree[c].Len); }
-#endif
-
-#define d_code(dist) \
-   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
-/* Mapping from a distance to a distance code. dist is the distance - 1 and
- * must not have side effects. dist_code[256] and dist_code[257] are never
- * used.
- */
-
-/* ===========================================================================
- * Output a short LSB first on the stream.
- * IN assertion: there is enough room in pendingBuf.
- */
-#define put_short(s, w) { \
-    put_byte(s, (uch)((w) & 0xff)); \
-    put_byte(s, (uch)((ush)(w) >> 8)); \
-}
-
-/* ===========================================================================
- * Send a value on a given number of bits.
- * IN assertion: length <= 16 and value fits in length bits.
- */
-#ifdef DEBUG_ZLIB
-local void send_bits      OF((deflate_state *s, int value, int length));
-
-local void send_bits(s, value, length)
-    deflate_state *s;
-    int value;  /* value to send */
-    int length; /* number of bits */
-{
-    Tracevv((stderr," l %2d v %4x ", length, value));
-    Assert(length > 0 && length <= 15, "invalid length");
-    s->bits_sent += (ulg)length;
-
-    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
-     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
-     * unused bits in value.
-     */
-    if (s->bi_valid > (int)Buf_size - length) {
-        s->bi_buf |= (value << s->bi_valid);
-        put_short(s, s->bi_buf);
-        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
-        s->bi_valid += length - Buf_size;
-    } else {
-        s->bi_buf |= value << s->bi_valid;
-        s->bi_valid += length;
-    }
-}
-#else /* !DEBUG_ZLIB */
-
-#define send_bits(s, value, length) \
-{ int len = length;\
-  if (s->bi_valid > (int)Buf_size - len) {\
-    int val = value;\
-    s->bi_buf |= (val << s->bi_valid);\
-    put_short(s, s->bi_buf);\
-    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
-    s->bi_valid += len - Buf_size;\
-  } else {\
-    s->bi_buf |= (value) << s->bi_valid;\
-    s->bi_valid += len;\
-  }\
-}
-#endif /* DEBUG_ZLIB */
-
-
-#define MAX(a,b) (a >= b ? a : b)
-/* the arguments must not have side effects */
-
-/* ===========================================================================
- * Initialize the various 'constant' tables. In a multi-threaded environment,
- * this function may be called by two threads concurrently, but this is
- * harmless since both invocations do exactly the same thing.
- */
-local void tr_static_init()
-{
-    static int static_init_done = 0;
-    int n;        /* iterates over tree elements */
-    int bits;     /* bit counter */
-    int length;   /* length value */
-    int code;     /* code value */
-    int dist;     /* distance index */
-    ush bl_count[MAX_BITS+1];
-    /* number of codes at each bit length for an optimal tree */
-
-    if (static_init_done) return;
-
-    /* Initialize the mapping length (0..255) -> length code (0..28) */
-    length = 0;
-    for (code = 0; code < LENGTH_CODES-1; code++) {
-        base_length[code] = length;
-        for (n = 0; n < (1<<extra_lbits[code]); n++) {
-            length_code[length++] = (uch)code;
-        }
-    }
-    Assert (length == 256, "tr_static_init: length != 256");
-    /* Note that the length 255 (match length 258) can be represented
-     * in two different ways: code 284 + 5 bits or code 285, so we
-     * overwrite length_code[255] to use the best encoding:
-     */
-    length_code[length-1] = (uch)code;
-
-    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
-    dist = 0;
-    for (code = 0 ; code < 16; code++) {
-        base_dist[code] = dist;
-        for (n = 0; n < (1<<extra_dbits[code]); n++) {
-            dist_code[dist++] = (uch)code;
-        }
-    }
-    Assert (dist == 256, "tr_static_init: dist != 256");
-    dist >>= 7; /* from now on, all distances are divided by 128 */
-    for ( ; code < D_CODES; code++) {
-        base_dist[code] = dist << 7;
-        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
-            dist_code[256 + dist++] = (uch)code;
-        }
-    }
-    Assert (dist == 256, "tr_static_init: 256+dist != 512");
-
-    /* Construct the codes of the static literal tree */
-    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
-    n = 0;
-    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
-    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
-    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
-    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
-    /* Codes 286 and 287 do not exist, but we must include them in the
-     * tree construction to get a canonical Huffman tree (longest code
-     * all ones)
-     */
-    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
-
-    /* The static distance tree is trivial: */
-    for (n = 0; n < D_CODES; n++) {
-        static_dtree[n].Len = 5;
-        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
-    }
-    static_init_done = 1;
-}
-
-/* ===========================================================================
- * Initialize the tree data structures for a new zlib stream.
- */
-void _tr_init(s)
-    deflate_state *s;
-{
-    tr_static_init();
-
-    s->compressed_len = 0L;
-
-    s->l_desc.dyn_tree = s->dyn_ltree;
-    s->l_desc.stat_desc = &static_l_desc;
-
-    s->d_desc.dyn_tree = s->dyn_dtree;
-    s->d_desc.stat_desc = &static_d_desc;
-
-    s->bl_desc.dyn_tree = s->bl_tree;
-    s->bl_desc.stat_desc = &static_bl_desc;
-
-    s->bi_buf = 0;
-    s->bi_valid = 0;
-    s->last_eob_len = 8; /* enough lookahead for inflate */
-#ifdef DEBUG_ZLIB
-    s->bits_sent = 0L;
-#endif
-
-    /* Initialize the first block of the first file: */
-    init_block(s);
-}
-
-/* ===========================================================================
- * Initialize a new block.
- */
-local void init_block(s)
-    deflate_state *s;
-{
-    int n; /* iterates over tree elements */
-
-    /* Initialize the trees. */
-    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
-    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
-    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
-
-    s->dyn_ltree[END_BLOCK].Freq = 1;
-    s->opt_len = s->static_len = 0L;
-    s->last_lit = s->matches = 0;
-}
-
-#define SMALLEST 1
-/* Index within the heap array of least frequent node in the Huffman tree */
-
-
-/* ===========================================================================
- * Remove the smallest element from the heap and recreate the heap with
- * one less element. Updates heap and heap_len.
- */
-#define pqremove(s, tree, top) \
-{\
-    top = s->heap[SMALLEST]; \
-    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
-    pqdownheap(s, tree, SMALLEST); \
-}
-
-/* ===========================================================================
- * Compares to subtrees, using the tree depth as tie breaker when
- * the subtrees have equal frequency. This minimizes the worst case length.
- */
-#define smaller(tree, n, m, depth) \
-   (tree[n].Freq < tree[m].Freq || \
-   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
-
-/* ===========================================================================
- * Restore the heap property by moving down the tree starting at node k,
- * exchanging a node with the smallest of its two sons if necessary, stopping
- * when the heap property is re-established (each father smaller than its
- * two sons).
- */
-local void pqdownheap(s, tree, k)
-    deflate_state *s;
-    ct_data *tree;  /* the tree to restore */
-    int k;               /* node to move down */
-{
-    int v = s->heap[k];
-    int j = k << 1;  /* left son of k */
-    while (j <= s->heap_len) {
-        /* Set j to the smallest of the two sons: */
-        if (j < s->heap_len &&
-            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
-            j++;
-        }
-        /* Exit if v is smaller than both sons */
-        if (smaller(tree, v, s->heap[j], s->depth)) break;
-
-        /* Exchange v with the smallest son */
-        s->heap[k] = s->heap[j];  k = j;
-
-        /* And continue down the tree, setting j to the left son of k */
-        j <<= 1;
-    }
-    s->heap[k] = v;
-}
-
-/* ===========================================================================
- * Compute the optimal bit lengths for a tree and update the total bit length
- * for the current block.
- * IN assertion: the fields freq and dad are set, heap[heap_max] and
- *    above are the tree nodes sorted by increasing frequency.
- * OUT assertions: the field len is set to the optimal bit length, the
- *     array bl_count contains the frequencies for each bit length.
- *     The length opt_len is updated; static_len is also updated if stree is
- *     not null.
- */
-local void gen_bitlen(s, desc)
-    deflate_state *s;
-    tree_desc *desc;    /* the tree descriptor */
-{
-    ct_data *tree  = desc->dyn_tree;
-    int max_code   = desc->max_code;
-    ct_data *stree = desc->stat_desc->static_tree;
-    intf *extra    = desc->stat_desc->extra_bits;
-    int base       = desc->stat_desc->extra_base;
-    int max_length = desc->stat_desc->max_length;
-    int h;              /* heap index */
-    int n, m;           /* iterate over the tree elements */
-    int bits;           /* bit length */
-    int xbits;          /* extra bits */
-    ush f;              /* frequency */
-    int overflow = 0;   /* number of elements with bit length too large */
-
-    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
-
-    /* In a first pass, compute the optimal bit lengths (which may
-     * overflow in the case of the bit length tree).
-     */
-    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
-
-    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
-        n = s->heap[h];
-        bits = tree[tree[n].Dad].Len + 1;
-        if (bits > max_length) bits = max_length, overflow++;
-        tree[n].Len = (ush)bits;
-        /* We overwrite tree[n].Dad which is no longer needed */
-
-        if (n > max_code) continue; /* not a leaf node */
-
-        s->bl_count[bits]++;
-        xbits = 0;
-        if (n >= base) xbits = extra[n-base];
-        f = tree[n].Freq;
-        s->opt_len += (ulg)f * (bits + xbits);
-        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
-    }
-    if (overflow == 0) return;
-
-    Trace((stderr,"\nbit length overflow\n"));
-    /* This happens for example on obj2 and pic of the Calgary corpus */
-
-    /* Find the first bit length which could increase: */
-    do {
-        bits = max_length-1;
-        while (s->bl_count[bits] == 0) bits--;
-        s->bl_count[bits]--;      /* move one leaf down the tree */
-        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
-        s->bl_count[max_length]--;
-        /* The brother of the overflow item also moves one step up,
-         * but this does not affect bl_count[max_length]
-         */
-        overflow -= 2;
-    } while (overflow > 0);
-
-    /* Now recompute all bit lengths, scanning in increasing frequency.
-     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
-     * lengths instead of fixing only the wrong ones. This idea is taken
-     * from 'ar' written by Haruhiko Okumura.)
-     */
-    for (bits = max_length; bits != 0; bits--) {
-        n = s->bl_count[bits];
-        while (n != 0) {
-            m = s->heap[--h];
-            if (m > max_code) continue;
-            if (tree[m].Len != (unsigned) bits) {
-                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
-                s->opt_len += ((long)bits - (long)tree[m].Len)
-                              *(long)tree[m].Freq;
-                tree[m].Len = (ush)bits;
-            }
-            n--;
-        }
-    }
-}
-
-/* ===========================================================================
- * Generate the codes for a given tree and bit counts (which need not be
- * optimal).
- * IN assertion: the array bl_count contains the bit length statistics for
- * the given tree and the field len is set for all tree elements.
- * OUT assertion: the field code is set for all tree elements of non
- *     zero code length.
- */
-local void gen_codes (tree, max_code, bl_count)
-    ct_data *tree;             /* the tree to decorate */
-    int max_code;              /* largest code with non zero frequency */
-    ushf *bl_count;            /* number of codes at each bit length */
-{
-    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
-    ush code = 0;              /* running code value */
-    int bits;                  /* bit index */
-    int n;                     /* code index */
-
-    /* The distribution counts are first used to generate the code values
-     * without bit reversal.
-     */
-    for (bits = 1; bits <= MAX_BITS; bits++) {
-        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
-    }
-    /* Check that the bit counts in bl_count are consistent. The last code
-     * must be all ones.
-     */
-    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
-            "inconsistent bit counts");
-    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
-
-    for (n = 0;  n <= max_code; n++) {
-        int len = tree[n].Len;
-        if (len == 0) continue;
-        /* Now reverse the bits */
-        tree[n].Code = bi_reverse(next_code[len]++, len);
-
-        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
-             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
-    }
-}
-
-/* ===========================================================================
- * Construct one Huffman tree and assigns the code bit strings and lengths.
- * Update the total bit length for the current block.
- * IN assertion: the field freq is set for all tree elements.
- * OUT assertions: the fields len and code are set to the optimal bit length
- *     and corresponding code. The length opt_len is updated; static_len is
- *     also updated if stree is not null. The field max_code is set.
- */
-local void build_tree(s, desc)
-    deflate_state *s;
-    tree_desc *desc; /* the tree descriptor */
-{
-    ct_data *tree   = desc->dyn_tree;
-    ct_data *stree  = desc->stat_desc->static_tree;
-    int elems       = desc->stat_desc->elems;
-    int n, m;          /* iterate over heap elements */
-    int max_code = -1; /* largest code with non zero frequency */
-    int node;          /* new node being created */
-
-    /* Construct the initial heap, with least frequent element in
-     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
-     * heap[0] is not used.
-     */
-    s->heap_len = 0, s->heap_max = HEAP_SIZE;
-
-    for (n = 0; n < elems; n++) {
-        if (tree[n].Freq != 0) {
-            s->heap[++(s->heap_len)] = max_code = n;
-            s->depth[n] = 0;
-        } else {
-            tree[n].Len = 0;
-        }
-    }
-
-    /* The pkzip format requires that at least one distance code exists,
-     * and that at least one bit should be sent even if there is only one
-     * possible code. So to avoid special checks later on we force at least
-     * two codes of non zero frequency.
-     */
-    while (s->heap_len < 2) {
-        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
-        tree[node].Freq = 1;
-        s->depth[node] = 0;
-        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
-        /* node is 0 or 1 so it does not have extra bits */
-    }
-    desc->max_code = max_code;
-
-    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
-     * establish sub-heaps of increasing lengths:
-     */
-    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
-
-    /* Construct the Huffman tree by repeatedly combining the least two
-     * frequent nodes.
-     */
-    node = elems;              /* next internal node of the tree */
-    do {
-        pqremove(s, tree, n);  /* n = node of least frequency */
-        m = s->heap[SMALLEST]; /* m = node of next least frequency */
-
-        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
-        s->heap[--(s->heap_max)] = m;
-
-        /* Create a new node father of n and m */
-        tree[node].Freq = tree[n].Freq + tree[m].Freq;
-        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
-        tree[n].Dad = tree[m].Dad = (ush)node;
-#ifdef DUMP_BL_TREE
-        if (tree == s->bl_tree) {
-            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
-                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
-        }
-#endif
-        /* and insert the new node in the heap */
-        s->heap[SMALLEST] = node++;
-        pqdownheap(s, tree, SMALLEST);
-
-    } while (s->heap_len >= 2);
-
-    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
-
-    /* At this point, the fields freq and dad are set. We can now
-     * generate the bit lengths.
-     */
-    gen_bitlen(s, (tree_desc *)desc);
-
-    /* The field len is now set, we can generate the bit codes */
-    gen_codes ((ct_data *)tree, max_code, s->bl_count);
-}
-
-/* ===========================================================================
- * Scan a literal or distance tree to determine the frequencies of the codes
- * in the bit length tree.
- */
-local void scan_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree;   /* the tree to be scanned */
-    int max_code;    /* and its largest code of non zero frequency */
-{
-    int n;                     /* iterates over all tree elements */
-    int prevlen = -1;          /* last emitted length */
-    int curlen;                /* length of current code */
-    int nextlen = tree[0].Len; /* length of next code */
-    int count = 0;             /* repeat count of the current code */
-    int max_count = 7;         /* max repeat count */
-    int min_count = 4;         /* min repeat count */
-
-    if (nextlen == 0) max_count = 138, min_count = 3;
-    tree[max_code+1].Len = (ush)0xffff; /* guard */
-
-    for (n = 0; n <= max_code; n++) {
-        curlen = nextlen; nextlen = tree[n+1].Len;
-        if (++count < max_count && curlen == nextlen) {
-            continue;
-        } else if (count < min_count) {
-            s->bl_tree[curlen].Freq += count;
-        } else if (curlen != 0) {
-            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
-            s->bl_tree[REP_3_6].Freq++;
-        } else if (count <= 10) {
-            s->bl_tree[REPZ_3_10].Freq++;
-        } else {
-            s->bl_tree[REPZ_11_138].Freq++;
-        }
-        count = 0; prevlen = curlen;
-        if (nextlen == 0) {
-            max_count = 138, min_count = 3;
-        } else if (curlen == nextlen) {
-            max_count = 6, min_count = 3;
-        } else {
-            max_count = 7, min_count = 4;
-        }
-    }
-}
-
-/* ===========================================================================
- * Send a literal or distance tree in compressed form, using the codes in
- * bl_tree.
- */
-local void send_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree; /* the tree to be scanned */
-    int max_code;       /* and its largest code of non zero frequency */
-{
-    int n;                     /* iterates over all tree elements */
-    int prevlen = -1;          /* last emitted length */
-    int curlen;                /* length of current code */
-    int nextlen = tree[0].Len; /* length of next code */
-    int count = 0;             /* repeat count of the current code */
-    int max_count = 7;         /* max repeat count */
-    int min_count = 4;         /* min repeat count */
-
-    /* tree[max_code+1].Len = -1; */  /* guard already set */
-    if (nextlen == 0) max_count = 138, min_count = 3;
-
-    for (n = 0; n <= max_code; n++) {
-        curlen = nextlen; nextlen = tree[n+1].Len;
-        if (++count < max_count && curlen == nextlen) {
-            continue;
-        } else if (count < min_count) {
-            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
-
-        } else if (curlen != 0) {
-            if (curlen != prevlen) {
-                send_code(s, curlen, s->bl_tree); count--;
-            }
-            Assert(count >= 3 && count <= 6, " 3_6?");
-            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
-
-        } else if (count <= 10) {
-            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
-
-        } else {
-            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
-        }
-        count = 0; prevlen = curlen;
-        if (nextlen == 0) {
-            max_count = 138, min_count = 3;
-        } else if (curlen == nextlen) {
-            max_count = 6, min_count = 3;
-        } else {
-            max_count = 7, min_count = 4;
-        }
-    }
-}
-
-/* ===========================================================================
- * Construct the Huffman tree for the bit lengths and return the index in
- * bl_order of the last bit length code to send.
- */
-local int build_bl_tree(s)
-    deflate_state *s;
-{
-    int max_blindex;  /* index of last bit length code of non zero freq */
-
-    /* Determine the bit length frequencies for literal and distance trees */
-    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
-    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
-
-    /* Build the bit length tree: */
-    build_tree(s, (tree_desc *)(&(s->bl_desc)));
-    /* opt_len now includes the length of the tree representations, except
-     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
-     */
-
-    /* Determine the number of bit length codes to send. The pkzip format
-     * requires that at least 4 bit length codes be sent. (appnote.txt says
-     * 3 but the actual value used is 4.)
-     */
-    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
-        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
-    }
-    /* Update opt_len to include the bit length tree and counts */
-    s->opt_len += 3*(max_blindex+1) + 5+5+4;
-    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
-            s->opt_len, s->static_len));
-
-    return max_blindex;
-}
-
-/* ===========================================================================
- * Send the header for a block using dynamic Huffman trees: the counts, the
- * lengths of the bit length codes, the literal tree and the distance tree.
- * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
- */
-local void send_all_trees(s, lcodes, dcodes, blcodes)
-    deflate_state *s;
-    int lcodes, dcodes, blcodes; /* number of codes for each tree */
-{
-    int rank;                    /* index in bl_order */
-
-    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
-    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
-            "too many codes");
-    Tracev((stderr, "\nbl counts: "));
-    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
-    send_bits(s, dcodes-1,   5);
-    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
-    for (rank = 0; rank < blcodes; rank++) {
-        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
-        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
-    }
-    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
-
-    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
-    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
-
-    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
-    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
-}
-
-/* ===========================================================================
- * Send a stored block
- */
-void _tr_stored_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
-{
-    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
-    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
-    s->compressed_len += (stored_len + 4) << 3;
-
-    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
-}
-
-/* Send just the `stored block' type code without any length bytes or data.
- */
-void _tr_stored_type_only(s)
-    deflate_state *s;
-{
-    send_bits(s, (STORED_BLOCK << 1), 3);
-    bi_windup(s);
-    s->compressed_len = (s->compressed_len + 3) & ~7L;
-}
-
-
-/* ===========================================================================
- * Send one empty static block to give enough lookahead for inflate.
- * This takes 10 bits, of which 7 may remain in the bit buffer.
- * The current inflate code requires 9 bits of lookahead. If the
- * last two codes for the previous block (real code plus EOB) were coded
- * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
- * the last real code. In this case we send two empty static blocks instead
- * of one. (There are no problems if the previous block is stored or fixed.)
- * To simplify the code, we assume the worst case of last real code encoded
- * on one bit only.
- */
-void _tr_align(s)
-    deflate_state *s;
-{
-    send_bits(s, STATIC_TREES<<1, 3);
-    send_code(s, END_BLOCK, static_ltree);
-    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
-    bi_flush(s);
-    /* Of the 10 bits for the empty block, we have already sent
-     * (10 - bi_valid) bits. The lookahead for the last real code (before
-     * the EOB of the previous block) was thus at least one plus the length
-     * of the EOB plus what we have just sent of the empty static block.
-     */
-    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
-        send_bits(s, STATIC_TREES<<1, 3);
-        send_code(s, END_BLOCK, static_ltree);
-        s->compressed_len += 10L;
-        bi_flush(s);
-    }
-    s->last_eob_len = 7;
-}
-
-/* ===========================================================================
- * Determine the best encoding for the current block: dynamic trees, static
- * trees or store, and output the encoded block to the zip file. This function
- * returns the total compressed length for the file so far.
- */
-ulg _tr_flush_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block, or NULL if too old */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
-{
-    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
-    int max_blindex = 0;  /* index of last bit length code of non zero freq */
-
-    /* Build the Huffman trees unless a stored block is forced */
-    if (s->level > 0) {
-
-	 /* Check if the file is ascii or binary */
-	if (s->data_type == Z_UNKNOWN) set_data_type(s);
-
-	/* Construct the literal and distance trees */
-	build_tree(s, (tree_desc *)(&(s->l_desc)));
-	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
-		s->static_len));
-
-	build_tree(s, (tree_desc *)(&(s->d_desc)));
-	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
-		s->static_len));
-	/* At this point, opt_len and static_len are the total bit lengths of
-	 * the compressed block data, excluding the tree representations.
-	 */
-
-	/* Build the bit length tree for the above two trees, and get the index
-	 * in bl_order of the last bit length code to send.
-	 */
-	max_blindex = build_bl_tree(s);
-
-	/* Determine the best encoding. Compute first the block length in bytes*/
-	opt_lenb = (s->opt_len+3+7)>>3;
-	static_lenb = (s->static_len+3+7)>>3;
-
-	Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
-		opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
-		s->last_lit));
-
-	if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
-
-    } else {
-        Assert(buf != (char*)0, "lost buf");
-	opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
-    }
-
-    /* If compression failed and this is the first and last block,
-     * and if the .zip file can be seeked (to rewrite the local header),
-     * the whole file is transformed into a stored file:
-     */
-#ifdef STORED_FILE_OK
-#  ifdef FORCE_STORED_FILE
-    if (eof && s->compressed_len == 0L) { /* force stored file */
-#  else
-    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
-#  endif
-        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
-        if (buf == (charf*)0) error ("block vanished");
-
-        copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
-        s->compressed_len = stored_len << 3;
-        s->method = STORED;
-    } else
-#endif /* STORED_FILE_OK */
-
-#ifdef FORCE_STORED
-    if (buf != (char*)0) { /* force stored block */
-#else
-    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
-                       /* 4: two words for the lengths */
-#endif
-        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
-         * Otherwise we can't have processed more than WSIZE input bytes since
-         * the last block flush, because compression would have been
-         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
-         * transform a block into a stored block.
-         */
-        _tr_stored_block(s, buf, stored_len, eof);
-
-#ifdef FORCE_STATIC
-    } else if (static_lenb >= 0) { /* force static trees */
-#else
-    } else if (static_lenb == opt_lenb) {
-#endif
-        send_bits(s, (STATIC_TREES<<1)+eof, 3);
-        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
-        s->compressed_len += 3 + s->static_len;
-    } else {
-        send_bits(s, (DYN_TREES<<1)+eof, 3);
-        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
-                       max_blindex+1);
-        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
-        s->compressed_len += 3 + s->opt_len;
-    }
-    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
-    init_block(s);
-
-    if (eof) {
-        bi_windup(s);
-        s->compressed_len += 7;  /* align on byte boundary */
-    }
-    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
-           s->compressed_len-7*eof));
-
-    return s->compressed_len >> 3;
-}
-
-/* ===========================================================================
- * Save the match info and tally the frequency counts. Return true if
- * the current block must be flushed.
- */
-int _tr_tally (s, dist, lc)
-    deflate_state *s;
-    unsigned dist;  /* distance of matched string */
-    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
-{
-    s->d_buf[s->last_lit] = (ush)dist;
-    s->l_buf[s->last_lit++] = (uch)lc;
-    if (dist == 0) {
-        /* lc is the unmatched char */
-        s->dyn_ltree[lc].Freq++;
-    } else {
-        s->matches++;
-        /* Here, lc is the match length - MIN_MATCH */
-        dist--;             /* dist = match distance - 1 */
-        Assert((ush)dist < (ush)MAX_DIST(s) &&
-               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
-               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
-
-        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
-        s->dyn_dtree[d_code(dist)].Freq++;
-    }
-
-    /* Try to guess if it is profitable to stop the current block here */
-    if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
-        /* Compute an upper bound for the compressed length */
-        ulg out_length = (ulg)s->last_lit*8L;
-        ulg in_length = (ulg)((long)s->strstart - s->block_start);
-        int dcode;
-        for (dcode = 0; dcode < D_CODES; dcode++) {
-            out_length += (ulg)s->dyn_dtree[dcode].Freq *
-                (5L+extra_dbits[dcode]);
-        }
-        out_length >>= 3;
-        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
-               s->last_lit, in_length, out_length,
-               100L - out_length*100L/in_length));
-        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
-    }
-    return (s->last_lit == s->lit_bufsize-1);
-    /* We avoid equality with lit_bufsize because of wraparound at 64K
-     * on 16 bit machines and because stored blocks are restricted to
-     * 64K-1 bytes.
-     */
-}
-
-/* ===========================================================================
- * Send the block data compressed using the given Huffman trees
- */
-local void compress_block(s, ltree, dtree)
-    deflate_state *s;
-    ct_data *ltree; /* literal tree */
-    ct_data *dtree; /* distance tree */
-{
-    unsigned dist;      /* distance of matched string */
-    int lc;             /* match length or unmatched char (if dist == 0) */
-    unsigned lx = 0;    /* running index in l_buf */
-    unsigned code;      /* the code to send */
-    int extra;          /* number of extra bits to send */
-
-    if (s->last_lit != 0) do {
-        dist = s->d_buf[lx];
-        lc = s->l_buf[lx++];
-        if (dist == 0) {
-            send_code(s, lc, ltree); /* send a literal byte */
-            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
-        } else {
-            /* Here, lc is the match length - MIN_MATCH */
-            code = length_code[lc];
-            send_code(s, code+LITERALS+1, ltree); /* send the length code */
-            extra = extra_lbits[code];
-            if (extra != 0) {
-                lc -= base_length[code];
-                send_bits(s, lc, extra);       /* send the extra length bits */
-            }
-            dist--; /* dist is now the match distance - 1 */
-            code = d_code(dist);
-            Assert (code < D_CODES, "bad d_code");
-
-            send_code(s, code, dtree);       /* send the distance code */
-            extra = extra_dbits[code];
-            if (extra != 0) {
-                dist -= base_dist[code];
-                send_bits(s, dist, extra);   /* send the extra distance bits */
-            }
-        } /* literal or match pair ? */
-
-        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
-        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
-
-    } while (lx < s->last_lit);
-
-    send_code(s, END_BLOCK, ltree);
-    s->last_eob_len = ltree[END_BLOCK].Len;
-}
-
-/* ===========================================================================
- * Set the data type to ASCII or BINARY, using a crude approximation:
- * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
- * IN assertion: the fields freq of dyn_ltree are set and the total of all
- * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
- */
-local void set_data_type(s)
-    deflate_state *s;
-{
-    int n = 0;
-    unsigned ascii_freq = 0;
-    unsigned bin_freq = 0;
-    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
-    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
-    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
-    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
-}
-
-/* ===========================================================================
- * Reverse the first len bits of a code, using straightforward code (a faster
- * method would use a table)
- * IN assertion: 1 <= len <= 15
- */
-local unsigned bi_reverse(code, len)
-    unsigned code; /* the value to invert */
-    int len;       /* its bit length */
-{
-    register unsigned res = 0;
-    do {
-        res |= code & 1;
-        code >>= 1, res <<= 1;
-    } while (--len > 0);
-    return res >> 1;
-}
-
-/* ===========================================================================
- * Flush the bit buffer, keeping at most 7 bits in it.
- */
-local void bi_flush(s)
-    deflate_state *s;
-{
-    if (s->bi_valid == 16) {
-        put_short(s, s->bi_buf);
-        s->bi_buf = 0;
-        s->bi_valid = 0;
-    } else if (s->bi_valid >= 8) {
-        put_byte(s, (Byte)s->bi_buf);
-        s->bi_buf >>= 8;
-        s->bi_valid -= 8;
-    }
-}
-
-/* ===========================================================================
- * Flush the bit buffer and align the output on a byte boundary
- */
-local void bi_windup(s)
-    deflate_state *s;
-{
-    if (s->bi_valid > 8) {
-        put_short(s, s->bi_buf);
-    } else if (s->bi_valid > 0) {
-        put_byte(s, (Byte)s->bi_buf);
-    }
-    s->bi_buf = 0;
-    s->bi_valid = 0;
-#ifdef DEBUG_ZLIB
-    s->bits_sent = (s->bits_sent+7) & ~7;
-#endif
-}
-
-/* ===========================================================================
- * Copy a stored block, storing first the length and its
- * one's complement if requested.
- */
-local void copy_block(s, buf, len, header)
-    deflate_state *s;
-    charf    *buf;    /* the input data */
-    unsigned len;     /* its length */
-    int      header;  /* true if block header must be written */
-{
-    bi_windup(s);        /* align on byte boundary */
-    s->last_eob_len = 8; /* enough lookahead for inflate */
-
-    if (header) {
-        put_short(s, (ush)len);   
-        put_short(s, (ush)~len);
-#ifdef DEBUG_ZLIB
-        s->bits_sent += 2*16;
-#endif
-    }
-#ifdef DEBUG_ZLIB
-    s->bits_sent += (ulg)len<<3;
-#endif
-    /* bundle up the put_byte(s, *buf++) calls */
-    zmemcpy(&s->pending_buf[s->pending], buf, len);
-    s->pending += len;
-}
-/* --- trees.c */
-
-/* +++ inflate.c */
-/* inflate.c -- zlib interface to inflate modules
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-
-/* +++ infblock.h */
-/* infblock.h -- header to use infblock.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-struct inflate_blocks_state;
-typedef struct inflate_blocks_state FAR inflate_blocks_statef;
-
-extern inflate_blocks_statef * inflate_blocks_new OF((
-    z_streamp z,
-    check_func c,               /* check function */
-    uInt w));                   /* window size */
-
-extern int inflate_blocks OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));                      /* initial return code */
-
-extern void inflate_blocks_reset OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern int inflate_blocks_free OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern void inflate_set_dictionary OF((
-    inflate_blocks_statef *s,
-    const Bytef *d,  /* dictionary */
-    uInt  n));       /* dictionary length */
-
-extern int inflate_addhistory OF((
-    inflate_blocks_statef *,
-    z_streamp));
-
-extern int inflate_packet_flush OF((
-    inflate_blocks_statef *));
-/* --- infblock.h */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* inflate private state */
-struct internal_state {
-
-  /* mode */
-  enum {
-      METHOD,   /* waiting for method byte */
-      FLAG,     /* waiting for flag byte */
-      DICT4,    /* four dictionary check bytes to go */
-      DICT3,    /* three dictionary check bytes to go */
-      DICT2,    /* two dictionary check bytes to go */
-      DICT1,    /* one dictionary check byte to go */
-      DICT0,    /* waiting for inflateSetDictionary */
-      BLOCKS,   /* decompressing blocks */
-      CHECK4,   /* four check bytes to go */
-      CHECK3,   /* three check bytes to go */
-      CHECK2,   /* two check bytes to go */
-      CHECK1,   /* one check byte to go */
-      DONE,     /* finished check, done */
-      BAD}      /* got an error--stay here */
-    mode;               /* current inflate mode */
-
-  /* mode dependent information */
-  union {
-    uInt method;        /* if FLAGS, method byte */
-    struct {
-      uLong was;                /* computed check value */
-      uLong need;               /* stream check value */
-    } check;            /* if CHECK, check values to compare */
-    uInt marker;        /* if BAD, inflateSync's marker bytes count */
-  } sub;        /* submode */
-
-  /* mode independent information */
-  int  nowrap;          /* flag for no wrapper */
-  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
-  inflate_blocks_statef 
-    *blocks;            /* current inflate_blocks state */
-
-};
-
-
-int inflateReset(z)
-z_streamp z;
-{
-  uLong c;
-
-  if (z == Z_NULL || z->state == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->total_in = z->total_out = 0;
-  z->msg = Z_NULL;
-  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
-  inflate_blocks_reset(z->state->blocks, z, &c);
-  Trace((stderr, "inflate: reset\n"));
-  return Z_OK;
-}
-
-
-int inflateEnd(z)
-z_streamp z;
-{
-  uLong c;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->blocks != Z_NULL)
-    inflate_blocks_free(z->state->blocks, z, &c);
-  ZFREE(z, z->state);
-  z->state = Z_NULL;
-  Trace((stderr, "inflate: end\n"));
-  return Z_OK;
-}
-
-
-int inflateInit2_(z, w, version, stream_size)
-z_streamp z;
-int w;
-const char *version;
-int stream_size;
-{
-  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
-      stream_size != sizeof(z_stream))
-      return Z_VERSION_ERROR;
-
-  /* initialize state */
-  if (z == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->msg = Z_NULL;
-#ifndef NO_ZCFUNCS
-  if (z->zalloc == Z_NULL)
-  {
-    z->zalloc = zcalloc;
-    z->opaque = (voidpf)0;
-  }
-  if (z->zfree == Z_NULL) z->zfree = zcfree;
-#endif
-  if ((z->state = (struct internal_state FAR *)
-       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
-    return Z_MEM_ERROR;
-  z->state->blocks = Z_NULL;
-
-  /* handle undocumented nowrap option (no zlib header or check) */
-  z->state->nowrap = 0;
-  if (w < 0)
-  {
-    w = - w;
-    z->state->nowrap = 1;
-  }
-
-  /* set window size */
-  if (w < 8 || w > 15)
-  {
-    inflateEnd(z);
-    return Z_STREAM_ERROR;
-  }
-  z->state->wbits = (uInt)w;
-
-  /* create inflate_blocks state */
-  if ((z->state->blocks =
-      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
-      == Z_NULL)
-  {
-    inflateEnd(z);
-    return Z_MEM_ERROR;
-  }
-  Trace((stderr, "inflate: allocated\n"));
-
-  /* reset state */
-  inflateReset(z);
-  return Z_OK;
-}
-
-
-int inflateInit_(z, version, stream_size)
-z_streamp z;
-const char *version;
-int stream_size;
-{
-  return inflateInit2_(z, DEF_WBITS, version, stream_size);
-}
-
-
-#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
-#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
-
-int inflate(z, f)
-z_streamp z;
-int f;
-{
-  int r;
-  uInt b;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0)
-    return Z_STREAM_ERROR;
-  r = Z_BUF_ERROR;
-  while (1) switch (z->state->mode)
-  {
-    case METHOD:
-      NEEDBYTE
-      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"unknown compression method";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"invalid window size";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      z->state->mode = FLAG;
-    case FLAG:
-      NEEDBYTE
-      b = NEXTBYTE;
-      if (((z->state->sub.method << 8) + b) % 31)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"incorrect header check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      Trace((stderr, "inflate: zlib header ok\n"));
-      if (!(b & PRESET_DICT))
-      {
-        z->state->mode = BLOCKS;
-	break;
-      }
-      z->state->mode = DICT4;
-    case DICT4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = DICT3;
-    case DICT3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = DICT2;
-    case DICT2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = DICT1;
-    case DICT1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-      z->adler = z->state->sub.check.need;
-      z->state->mode = DICT0;
-      return Z_NEED_DICT;
-    case DICT0:
-      z->state->mode = BAD;
-      z->msg = (char*)"need dictionary";
-      z->state->sub.marker = 0;       /* can try inflateSync */
-      return Z_STREAM_ERROR;
-    case BLOCKS:
-      r = inflate_blocks(z->state->blocks, z, r);
-      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
-	  r = inflate_packet_flush(z->state->blocks);
-      if (r == Z_DATA_ERROR)
-      {
-        z->state->mode = BAD;
-        z->state->sub.marker = 0;       /* can try inflateSync */
-        break;
-      }
-      if (r != Z_STREAM_END)
-        return r;
-      r = Z_OK;
-      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
-      if (z->state->nowrap)
-      {
-        z->state->mode = DONE;
-        break;
-      }
-      z->state->mode = CHECK4;
-    case CHECK4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = CHECK3;
-    case CHECK3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = CHECK2;
-    case CHECK2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = CHECK1;
-    case CHECK1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-
-      if (z->state->sub.check.was != z->state->sub.check.need)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"incorrect data check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      Trace((stderr, "inflate: zlib check ok\n"));
-      z->state->mode = DONE;
-    case DONE:
-      return Z_STREAM_END;
-    case BAD:
-      return Z_DATA_ERROR;
-    default:
-      return Z_STREAM_ERROR;
-  }
-
- empty:
-  if (f != Z_PACKET_FLUSH)
-    return r;
-  z->state->mode = BAD;
-  z->msg = (char *)"need more for packet flush";
-  z->state->sub.marker = 0;       /* can try inflateSync */
-  return Z_DATA_ERROR;
-}
-
-
-int inflateSetDictionary(z, dictionary, dictLength)
-z_streamp z;
-const Bytef *dictionary;
-uInt  dictLength;
-{
-  uInt length = dictLength;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
-    return Z_STREAM_ERROR;
-
-  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
-  z->adler = 1L;
-
-  if (length >= ((uInt)1<<z->state->wbits))
-  {
-    length = (1<<z->state->wbits)-1;
-    dictionary += dictLength - length;
-  }
-  inflate_set_dictionary(z->state->blocks, dictionary, length);
-  z->state->mode = BLOCKS;
-  return Z_OK;
-}
-
-/*
- * This subroutine adds the data at next_in/avail_in to the output history
- * without performing any output.  The output buffer must be "caught up";
- * i.e. no pending output (hence s->read equals s->write), and the state must
- * be BLOCKS (i.e. we should be willing to see the start of a series of
- * BLOCKS).  On exit, the output will also be caught up, and the checksum
- * will have been updated if need be.
- */
-
-int inflateIncomp(z)
-z_stream *z;
-{
-    if (z->state->mode != BLOCKS)
-	return Z_DATA_ERROR;
-    return inflate_addhistory(z->state->blocks, z);
-}
-
-
-int inflateSync(z)
-z_streamp z;
-{
-  uInt n;       /* number of bytes to look at */
-  Bytef *p;     /* pointer to bytes */
-  uInt m;       /* number of marker bytes found in a row */
-  uLong r, w;   /* temporaries to save total_in and total_out */
-
-  /* set up */
-  if (z == Z_NULL || z->state == Z_NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->mode != BAD)
-  {
-    z->state->mode = BAD;
-    z->state->sub.marker = 0;
-  }
-  if ((n = z->avail_in) == 0)
-    return Z_BUF_ERROR;
-  p = z->next_in;
-  m = z->state->sub.marker;
-
-  /* search */
-  while (n && m < 4)
-  {
-    if (*p == (Byte)(m < 2 ? 0 : 0xff))
-      m++;
-    else if (*p)
-      m = 0;
-    else
-      m = 4 - m;
-    p++, n--;
-  }
-
-  /* restore */
-  z->total_in += p - z->next_in;
-  z->next_in = p;
-  z->avail_in = n;
-  z->state->sub.marker = m;
-
-  /* return no joy or set up to restart on a new block */
-  if (m != 4)
-    return Z_DATA_ERROR;
-  r = z->total_in;  w = z->total_out;
-  inflateReset(z);
-  z->total_in = r;  z->total_out = w;
-  z->state->mode = BLOCKS;
-  return Z_OK;
-}
-
-#undef NEEDBYTE
-#undef NEXTBYTE
-/* --- inflate.c */
-
-/* +++ infblock.c */
-/* infblock.c -- interpret and process block types to last block
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "infblock.h" */
-
-/* +++ inftrees.h */
-/* inftrees.h -- header to use inftrees.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* Huffman code lookup table entry--this entry is four bytes for machines
-   that have 16-bit pointers (e.g. PC's in the small or medium model). */
-
-typedef struct inflate_huft_s FAR inflate_huft;
-
-struct inflate_huft_s {
-  union {
-    struct {
-      Byte Exop;        /* number of extra bits or operation */
-      Byte Bits;        /* number of bits in this code or subcode */
-    } what;
-    Bytef *pad;         /* pad structure to a power of 2 (4 bytes for */
-  } word;               /*  16-bit, 8 bytes for 32-bit machines) */
-  union {
-    uInt Base;          /* literal, length base, or distance base */
-    inflate_huft *Next; /* pointer to next level of table */
-  } more;
-};
-
-#ifdef DEBUG_ZLIB
-  extern uInt inflate_hufts;
-#endif
-
-extern int inflate_trees_bits OF((
-    uIntf *,                    /* 19 code lengths */
-    uIntf *,                    /* bits tree desired/actual depth */
-    inflate_huft * FAR *,       /* bits tree result */
-    z_streamp ));               /* for zalloc, zfree functions */
-
-extern int inflate_trees_dynamic OF((
-    uInt,                       /* number of literal/length codes */
-    uInt,                       /* number of distance codes */
-    uIntf *,                    /* that many (total) code lengths */
-    uIntf *,                    /* literal desired/actual bit depth */
-    uIntf *,                    /* distance desired/actual bit depth */
-    inflate_huft * FAR *,       /* literal/length tree result */
-    inflate_huft * FAR *,       /* distance tree result */
-    z_streamp ));               /* for zalloc, zfree functions */
-
-extern int inflate_trees_fixed OF((
-    uIntf *,                    /* literal desired/actual bit depth */
-    uIntf *,                    /* distance desired/actual bit depth */
-    inflate_huft * FAR *,       /* literal/length tree result */
-    inflate_huft * FAR *));     /* distance tree result */
-
-extern int inflate_trees_free OF((
-    inflate_huft *,             /* tables to free */
-    z_streamp ));               /* for zfree function */
-
-/* --- inftrees.h */
-
-/* +++ infcodes.h */
-/* infcodes.h -- header to use infcodes.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-struct inflate_codes_state;
-typedef struct inflate_codes_state FAR inflate_codes_statef;
-
-extern inflate_codes_statef *inflate_codes_new OF((
-    uInt, uInt,
-    inflate_huft *, inflate_huft *,
-    z_streamp ));
-
-extern int inflate_codes OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-extern void inflate_codes_free OF((
-    inflate_codes_statef *,
-    z_streamp ));
-
-/* --- infcodes.h */
-
-/* +++ infutil.h */
-/* infutil.h -- types and macros common to blocks and codes
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-#ifndef _INFUTIL_H
-#define _INFUTIL_H
-
-typedef enum {
-      TYPE,     /* get type bits (3, including end bit) */
-      LENS,     /* get lengths for stored */
-      STORED,   /* processing stored block */
-      TABLE,    /* get table lengths */
-      BTREE,    /* get bit lengths tree for a dynamic block */
-      DTREE,    /* get length, distance trees for a dynamic block */
-      CODES,    /* processing fixed or dynamic block */
-      DRY,      /* output remaining window bytes */
-      DONEB,    /* finished last block, done */
-      BADB}     /* got a data error--stuck here */
-inflate_block_mode;
-
-/* inflate blocks semi-private state */
-struct inflate_blocks_state {
-
-  /* mode */
-  inflate_block_mode  mode;     /* current inflate_block mode */
-
-  /* mode dependent information */
-  union {
-    uInt left;          /* if STORED, bytes left to copy */
-    struct {
-      uInt table;               /* table lengths (14 bits) */
-      uInt index;               /* index into blens (or border) */
-      uIntf *blens;             /* bit lengths of codes */
-      uInt bb;                  /* bit length tree depth */
-      inflate_huft *tb;         /* bit length decoding tree */
-    } trees;            /* if DTREE, decoding info for trees */
-    struct {
-      inflate_huft *tl;
-      inflate_huft *td;         /* trees to free */
-      inflate_codes_statef 
-         *codes;
-    } decode;           /* if CODES, current state */
-  } sub;                /* submode */
-  uInt last;            /* true if this block is the last block */
-
-  /* mode independent information */
-  uInt bitk;            /* bits in bit buffer */
-  uLong bitb;           /* bit buffer */
-  Bytef *window;        /* sliding window */
-  Bytef *end;           /* one byte after sliding window */
-  Bytef *read;          /* window read pointer */
-  Bytef *write;         /* window write pointer */
-  check_func checkfn;   /* check function */
-  uLong check;          /* check on output */
-
-};
-
-
-/* defines for inflate input/output */
-/*   update pointers and return */
-#define UPDBITS {s->bitb=b;s->bitk=k;}
-#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
-#define UPDOUT {s->write=q;}
-#define UPDATE {UPDBITS UPDIN UPDOUT}
-#define LEAVE {UPDATE return inflate_flush(s,z,r);}
-/*   get bytes and bits */
-#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
-#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
-#define NEXTBYTE (n--,*p++)
-#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define DUMPBITS(j) {b>>=(j);k-=(j);}
-/*   output bytes */
-#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
-#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
-#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
-#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
-#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;}
-#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
-/*   load local pointers */
-#define LOAD {LOADIN LOADOUT}
-
-/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
-extern uInt inflate_mask[17];
-
-/* copy as much as possible from the sliding window to the output area */
-extern int inflate_flush OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-#ifndef NO_DUMMY_DECL
-struct internal_state      {int dummy;}; /* for buggy compilers */
-#endif
-
-#endif
-/* --- infutil.h */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* Table for deflate from PKZIP's appnote.txt. */
-local const uInt border[] = { /* Order of the bit length code lengths */
-        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
-/*
-   Notes beyond the 1.93a appnote.txt:
-
-   1. Distance pointers never point before the beginning of the output
-      stream.
-   2. Distance pointers can point back across blocks, up to 32k away.
-   3. There is an implied maximum of 7 bits for the bit length table and
-      15 bits for the actual data.
-   4. If only one code exists, then it is encoded using one bit.  (Zero
-      would be more efficient, but perhaps a little confusing.)  If two
-      codes exist, they are coded using one bit each (0 and 1).
-   5. There is no way of sending zero distance codes--a dummy must be
-      sent if there are none.  (History: a pre 2.0 version of PKZIP would
-      store blocks with no distance codes, but this was discovered to be
-      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
-      zero distance codes, which is sent as one code of zero bits in
-      length.
-   6. There are up to 286 literal/length codes.  Code 256 represents the
-      end-of-block.  Note however that the static length tree defines
-      288 codes just to fill out the Huffman codes.  Codes 286 and 287
-      cannot be used though, since there is no length base or extra bits
-      defined for them.  Similarily, there are up to 30 distance codes.
-      However, static trees define 32 codes (all 5 bits) to fill out the
-      Huffman codes, but the last two had better not show up in the data.
-   7. Unzip can check dynamic Huffman blocks for complete code sets.
-      The exception is that a single code would not be complete (see #4).
-   8. The five bits following the block type is really the number of
-      literal codes sent minus 257.
-   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
-      (1+6+6).  Therefore, to output three times the length, you output
-      three codes (1+1+1), whereas to output four times the same length,
-      you only need two codes (1+3).  Hmm.
-  10. In the tree reconstruction algorithm, Code = Code + Increment
-      only if BitLength(i) is not zero.  (Pretty obvious.)
-  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
-  12. Note: length code 284 can represent 227-258, but length code 285
-      really is 258.  The last length deserves its own, short code
-      since it gets used a lot in very redundant files.  The length
-      258 is special since 258 - 3 (the min match length) is 255.
-  13. The literal/length and distance code bit lengths are read as a
-      single stream of lengths.  It is possible (and advantageous) for
-      a repeat code (16, 17, or 18) to go across the boundary between
-      the two sets of lengths.
- */
-
-
-void inflate_blocks_reset(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  if (s->checkfn != Z_NULL)
-    *c = s->check;
-  if (s->mode == BTREE || s->mode == DTREE)
-    ZFREE(z, s->sub.trees.blens);
-  if (s->mode == CODES)
-  {
-    inflate_codes_free(s->sub.decode.codes, z);
-    inflate_trees_free(s->sub.decode.td, z);
-    inflate_trees_free(s->sub.decode.tl, z);
-  }
-  s->mode = TYPE;
-  s->bitk = 0;
-  s->bitb = 0;
-  s->read = s->write = s->window;
-  if (s->checkfn != Z_NULL)
-    z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0);
-  Trace((stderr, "inflate:   blocks reset\n"));
-}
-
-
-inflate_blocks_statef *inflate_blocks_new(z, c, w)
-z_streamp z;
-check_func c;
-uInt w;
-{
-  inflate_blocks_statef *s;
-
-  if ((s = (inflate_blocks_statef *)ZALLOC
-       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
-    return s;
-  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
-  {
-    ZFREE(z, s);
-    return Z_NULL;
-  }
-  s->end = s->window + w;
-  s->checkfn = c;
-  s->mode = TYPE;
-  Trace((stderr, "inflate:   blocks allocated\n"));
-  inflate_blocks_reset(s, z, &s->check);
-  return s;
-}
-
-
-#ifdef DEBUG_ZLIB
-  extern uInt inflate_hufts;
-#endif
-int inflate_blocks(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt t;               /* temporary storage */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-
-  /* copy input/output information to locals (UPDATE macro restores) */
-  LOAD
-
-  /* process input based on current state */
-  while (1) switch (s->mode)
-  {
-    case TYPE:
-      NEEDBITS(3)
-      t = (uInt)b & 7;
-      s->last = t & 1;
-      switch (t >> 1)
-      {
-        case 0:                         /* stored */
-          Trace((stderr, "inflate:     stored block%s\n",
-                 s->last ? " (last)" : ""));
-          DUMPBITS(3)
-          t = k & 7;                    /* go to byte boundary */
-          DUMPBITS(t)
-          s->mode = LENS;               /* get length of stored block */
-          break;
-        case 1:                         /* fixed */
-          Trace((stderr, "inflate:     fixed codes block%s\n",
-                 s->last ? " (last)" : ""));
-          {
-            uInt bl, bd;
-            inflate_huft *tl, *td;
-
-            inflate_trees_fixed(&bl, &bd, &tl, &td);
-            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
-            if (s->sub.decode.codes == Z_NULL)
-            {
-              r = Z_MEM_ERROR;
-              LEAVE
-            }
-            s->sub.decode.tl = Z_NULL;  /* don't try to free these */
-            s->sub.decode.td = Z_NULL;
-          }
-          DUMPBITS(3)
-          s->mode = CODES;
-          break;
-        case 2:                         /* dynamic */
-          Trace((stderr, "inflate:     dynamic codes block%s\n",
-                 s->last ? " (last)" : ""));
-          DUMPBITS(3)
-          s->mode = TABLE;
-          break;
-        case 3:                         /* illegal */
-          DUMPBITS(3)
-          s->mode = BADB;
-          z->msg = (char*)"invalid block type";
-          r = Z_DATA_ERROR;
-          LEAVE
-      }
-      break;
-    case LENS:
-      NEEDBITS(32)
-      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
-      {
-        s->mode = BADB;
-        z->msg = (char*)"invalid stored block lengths";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-      s->sub.left = (uInt)b & 0xffff;
-      b = k = 0;                      /* dump bits */
-      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
-      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
-      break;
-    case STORED:
-      if (n == 0)
-        LEAVE
-      NEEDOUT
-      t = s->sub.left;
-      if (t > n) t = n;
-      if (t > m) t = m;
-      zmemcpy(q, p, t);
-      p += t;  n -= t;
-      q += t;  m -= t;
-      if ((s->sub.left -= t) != 0)
-        break;
-      Tracev((stderr, "inflate:       stored end, %lu total out\n",
-              z->total_out + (q >= s->read ? q - s->read :
-              (s->end - s->read) + (q - s->window))));
-      s->mode = s->last ? DRY : TYPE;
-      break;
-    case TABLE:
-      NEEDBITS(14)
-      s->sub.trees.table = t = (uInt)b & 0x3fff;
-#ifndef PKZIP_BUG_WORKAROUND
-      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
-      {
-        s->mode = BADB;
-        z->msg = (char*)"too many length or distance symbols";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-#endif
-      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
-      if (t < 19)
-        t = 19;
-      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
-      {
-        r = Z_MEM_ERROR;
-        LEAVE
-      }
-      DUMPBITS(14)
-      s->sub.trees.index = 0;
-      Tracev((stderr, "inflate:       table sizes ok\n"));
-      s->mode = BTREE;
-    case BTREE:
-      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
-      {
-        NEEDBITS(3)
-        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
-        DUMPBITS(3)
-      }
-      while (s->sub.trees.index < 19)
-        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
-      s->sub.trees.bb = 7;
-      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
-                             &s->sub.trees.tb, z);
-      if (t != Z_OK)
-      {
-        ZFREE(z, s->sub.trees.blens);
-        r = t;
-        if (r == Z_DATA_ERROR)
-          s->mode = BADB;
-        LEAVE
-      }
-      s->sub.trees.index = 0;
-      Tracev((stderr, "inflate:       bits tree ok\n"));
-      s->mode = DTREE;
-    case DTREE:
-      while (t = s->sub.trees.table,
-             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
-      {
-        inflate_huft *h;
-        uInt i, j, c;
-
-        t = s->sub.trees.bb;
-        NEEDBITS(t)
-        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
-        t = h->word.what.Bits;
-        c = h->more.Base;
-        if (c < 16)
-        {
-          DUMPBITS(t)
-          s->sub.trees.blens[s->sub.trees.index++] = c;
-        }
-        else /* c == 16..18 */
-        {
-          i = c == 18 ? 7 : c - 14;
-          j = c == 18 ? 11 : 3;
-          NEEDBITS(t + i)
-          DUMPBITS(t)
-          j += (uInt)b & inflate_mask[i];
-          DUMPBITS(i)
-          i = s->sub.trees.index;
-          t = s->sub.trees.table;
-          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
-              (c == 16 && i < 1))
-          {
-            inflate_trees_free(s->sub.trees.tb, z);
-            ZFREE(z, s->sub.trees.blens);
-            s->mode = BADB;
-            z->msg = (char*)"invalid bit length repeat";
-            r = Z_DATA_ERROR;
-            LEAVE
-          }
-          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
-          do {
-            s->sub.trees.blens[i++] = c;
-          } while (--j);
-          s->sub.trees.index = i;
-        }
-      }
-      inflate_trees_free(s->sub.trees.tb, z);
-      s->sub.trees.tb = Z_NULL;
-      {
-        uInt bl, bd;
-        inflate_huft *tl, *td;
-        inflate_codes_statef *c;
-
-        bl = 9;         /* must be <= 9 for lookahead assumptions */
-        bd = 6;         /* must be <= 9 for lookahead assumptions */
-        t = s->sub.trees.table;
-#ifdef DEBUG_ZLIB
-      inflate_hufts = 0;
-#endif
-        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
-                                  s->sub.trees.blens, &bl, &bd, &tl, &td, z);
-        ZFREE(z, s->sub.trees.blens);
-        if (t != Z_OK)
-        {
-          if (t == (uInt)Z_DATA_ERROR)
-            s->mode = BADB;
-          r = t;
-          LEAVE
-        }
-        Tracev((stderr, "inflate:       trees ok, %d * %d bytes used\n",
-              inflate_hufts, sizeof(inflate_huft)));
-        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
-        {
-          inflate_trees_free(td, z);
-          inflate_trees_free(tl, z);
-          r = Z_MEM_ERROR;
-          LEAVE
-        }
-        s->sub.decode.codes = c;
-        s->sub.decode.tl = tl;
-        s->sub.decode.td = td;
-      }
-      s->mode = CODES;
-    case CODES:
-      UPDATE
-      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
-        return inflate_flush(s, z, r);
-      r = Z_OK;
-      inflate_codes_free(s->sub.decode.codes, z);
-      inflate_trees_free(s->sub.decode.td, z);
-      inflate_trees_free(s->sub.decode.tl, z);
-      LOAD
-      Tracev((stderr, "inflate:       codes end, %lu total out\n",
-              z->total_out + (q >= s->read ? q - s->read :
-              (s->end - s->read) + (q - s->window))));
-      if (!s->last)
-      {
-        s->mode = TYPE;
-        break;
-      }
-      if (k > 7)              /* return unused byte, if any */
-      {
-        Assert(k < 16, "inflate_codes grabbed too many bytes")
-        k -= 8;
-        n++;
-        p--;                    /* can always return one */
-      }
-      s->mode = DRY;
-    case DRY:
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      s->mode = DONEB;
-    case DONEB:
-      r = Z_STREAM_END;
-      LEAVE
-    case BADB:
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-}
-
-
-int inflate_blocks_free(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  inflate_blocks_reset(s, z, c);
-  ZFREE(z, s->window);
-  ZFREE(z, s);
-  Trace((stderr, "inflate:   blocks freed\n"));
-  return Z_OK;
-}
-
-
-void inflate_set_dictionary(s, d, n)
-inflate_blocks_statef *s;
-const Bytef *d;
-uInt  n;
-{
-  zmemcpy((charf *)s->window, d, n);
-  s->read = s->write = s->window + n;
-}
-
-/*
- * This subroutine adds the data at next_in/avail_in to the output history
- * without performing any output.  The output buffer must be "caught up";
- * i.e. no pending output (hence s->read equals s->write), and the state must
- * be BLOCKS (i.e. we should be willing to see the start of a series of
- * BLOCKS).  On exit, the output will also be caught up, and the checksum
- * will have been updated if need be.
- */
-int inflate_addhistory(s, z)
-inflate_blocks_statef *s;
-z_stream *z;
-{
-    uLong b;              /* bit buffer */  /* NOT USED HERE */
-    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
-    uInt t;               /* temporary storage */
-    Bytef *p;             /* input data pointer */
-    uInt n;               /* bytes available there */
-    Bytef *q;             /* output window write pointer */
-    uInt m;               /* bytes to end of window or read pointer */
-
-    if (s->read != s->write)
-	return Z_STREAM_ERROR;
-    if (s->mode != TYPE)
-	return Z_DATA_ERROR;
-
-    /* we're ready to rock */
-    LOAD
-    /* while there is input ready, copy to output buffer, moving
-     * pointers as needed.
-     */
-    while (n) {
-	t = n;  /* how many to do */
-	/* is there room until end of buffer? */
-	if (t > m) t = m;
-	/* update check information */
-	if (s->checkfn != Z_NULL)
-	    s->check = (*s->checkfn)(s->check, q, t);
-	zmemcpy(q, p, t);
-	q += t;
-	p += t;
-	n -= t;
-	z->total_out += t;
-	s->read = q;    /* drag read pointer forward */
-/*      WWRAP  */ 	/* expand WWRAP macro by hand to handle s->read */
-	if (q == s->end) {
-	    s->read = q = s->window;
-	    m = WAVAIL;
-	}
-    }
-    UPDATE
-    return Z_OK;
-}
-
-
-/*
- * At the end of a Deflate-compressed PPP packet, we expect to have seen
- * a `stored' block type value but not the (zero) length bytes.
- */
-int inflate_packet_flush(s)
-    inflate_blocks_statef *s;
-{
-    if (s->mode != LENS)
-	return Z_DATA_ERROR;
-    s->mode = TYPE;
-    return Z_OK;
-}
-/* --- infblock.c */
-
-/* +++ inftrees.c */
-/* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-
-char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
-#ifndef NO_DUMMY_DECL
-struct internal_state  {int dummy;}; /* for buggy compilers */
-#endif
-
-/* simplify the use of the inflate_huft type with some defines */
-#define base more.Base
-#define next more.Next
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-
-local int huft_build OF((
-    uIntf *,            /* code lengths in bits */
-    uInt,               /* number of codes */
-    uInt,               /* number of "simple" codes */
-    const uIntf *,      /* list of base values for non-simple codes */
-    const uIntf *,      /* list of extra bits for non-simple codes */
-    inflate_huft * FAR*,/* result: starting table */
-    uIntf *,            /* maximum lookup bits (returns actual) */
-    z_streamp ));       /* for zalloc function */
-
-local voidpf falloc OF((
-    voidpf,             /* opaque pointer (not used) */
-    uInt,               /* number of items */
-    uInt));             /* size of item */
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
-        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
-        /* see note #13 above about 258 */
-local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
-        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
-local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
-        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-        8193, 12289, 16385, 24577};
-local const uInt cpdext[30] = { /* Extra bits for distance codes */
-        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-        12, 12, 13, 13};
-
-/*
-   Huffman code decoding is performed using a multi-level table lookup.
-   The fastest way to decode is to simply build a lookup table whose
-   size is determined by the longest code.  However, the time it takes
-   to build this table can also be a factor if the data being decoded
-   is not very long.  The most common codes are necessarily the
-   shortest codes, so those codes dominate the decoding time, and hence
-   the speed.  The idea is you can have a shorter table that decodes the
-   shorter, more probable codes, and then point to subsidiary tables for
-   the longer codes.  The time it costs to decode the longer codes is
-   then traded against the time it takes to make longer tables.
-
-   This results of this trade are in the variables lbits and dbits
-   below.  lbits is the number of bits the first level table for literal/
-   length codes can decode in one step, and dbits is the same thing for
-   the distance codes.  Subsequent tables are also less than or equal to
-   those sizes.  These values may be adjusted either when all of the
-   codes are shorter than that, in which case the longest code length in
-   bits is used, or when the shortest code is *longer* than the requested
-   table size, in which case the length of the shortest code in bits is
-   used.
-
-   There are two different values for the two tables, since they code a
-   different number of possibilities each.  The literal/length table
-   codes 286 possible values, or in a flat code, a little over eight
-   bits.  The distance table codes 30 possible values, or a little less
-   than five bits, flat.  The optimum values for speed end up being
-   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
-   The optimum values may differ though from machine to machine, and
-   possibly even between compilers.  Your mileage may vary.
- */
-
-
-/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
-#define BMAX 15         /* maximum bit length of any code */
-#define N_MAX 288       /* maximum number of codes in any set */
-
-#ifdef DEBUG_ZLIB
-  uInt inflate_hufts;
-#endif
-
-local int huft_build(b, n, s, d, e, t, m, zs)
-uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
-uInt n;                 /* number of codes (assumed <= N_MAX) */
-uInt s;                 /* number of simple-valued codes (0..s-1) */
-const uIntf *d;         /* list of base values for non-simple codes */
-const uIntf *e;         /* list of extra bits for non-simple codes */
-inflate_huft * FAR *t;  /* result: starting table */
-uIntf *m;               /* maximum lookup bits, returns actual */
-z_streamp zs;           /* for zalloc function */
-/* Given a list of code lengths and a maximum table size, make a set of
-   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
-   if the given code set is incomplete (the tables are still built in this
-   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
-   lengths), or Z_MEM_ERROR if not enough memory. */
-{
-
-  uInt a;                       /* counter for codes of length k */
-  uInt c[BMAX+1];               /* bit length count table */
-  uInt f;                       /* i repeats in table every f entries */
-  int g;                        /* maximum code length */
-  int h;                        /* table level */
-  register uInt i;              /* counter, current code */
-  register uInt j;              /* counter */
-  register int k;               /* number of bits in current code */
-  int l;                        /* bits per table (returned in m) */
-  register uIntf *p;            /* pointer into c[], b[], or v[] */
-  inflate_huft *q;              /* points to current table */
-  struct inflate_huft_s r;      /* table entry for structure assignment */
-  inflate_huft *u[BMAX];        /* table stack */
-  uInt v[N_MAX];                /* values in order of bit length */
-  register int w;               /* bits before this table == (l * h) */
-  uInt x[BMAX+1];               /* bit offsets, then code stack */
-  uIntf *xp;                    /* pointer into x */
-  int y;                        /* number of dummy codes added */
-  uInt z;                       /* number of entries in current table */
-
-
-  /* Generate counts for each bit length */
-  p = c;
-#define C0 *p++ = 0;
-#define C2 C0 C0 C0 C0
-#define C4 C2 C2 C2 C2
-  C4                            /* clear c[]--assume BMAX+1 is 16 */
-  p = b;  i = n;
-  do {
-    c[*p++]++;                  /* assume all entries <= BMAX */
-  } while (--i);
-  if (c[0] == n)                /* null input--all zero length codes */
-  {
-    *t = (inflate_huft *)Z_NULL;
-    *m = 0;
-    return Z_OK;
-  }
-
-
-  /* Find minimum and maximum length, bound *m by those */
-  l = *m;
-  for (j = 1; j <= BMAX; j++)
-    if (c[j])
-      break;
-  k = j;                        /* minimum code length */
-  if ((uInt)l < j)
-    l = j;
-  for (i = BMAX; i; i--)
-    if (c[i])
-      break;
-  g = i;                        /* maximum code length */
-  if ((uInt)l > i)
-    l = i;
-  *m = l;
-
-
-  /* Adjust last length count to fill out codes, if needed */
-  for (y = 1 << j; j < i; j++, y <<= 1)
-    if ((y -= c[j]) < 0)
-      return Z_DATA_ERROR;
-  if ((y -= c[i]) < 0)
-    return Z_DATA_ERROR;
-  c[i] += y;
-
-
-  /* Generate starting offsets into the value table for each length */
-  x[1] = j = 0;
-  p = c + 1;  xp = x + 2;
-  while (--i) {                 /* note that i == g from above */
-    *xp++ = (j += *p++);
-  }
-
-
-  /* Make a table of values in order of bit lengths */
-  p = b;  i = 0;
-  do {
-    if ((j = *p++) != 0)
-      v[x[j]++] = i;
-  } while (++i < n);
-  n = x[g];                   /* set n to length of v */
-
-
-  /* Generate the Huffman codes and for each, make the table entries */
-  x[0] = i = 0;                 /* first Huffman code is zero */
-  p = v;                        /* grab values in bit order */
-  h = -1;                       /* no tables yet--level -1 */
-  w = -l;                       /* bits decoded == (l * h) */
-  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
-  q = (inflate_huft *)Z_NULL;   /* ditto */
-  z = 0;                        /* ditto */
-
-  /* go through the bit lengths (k already is bits in shortest code) */
-  for (; k <= g; k++)
-  {
-    a = c[k];
-    while (a--)
-    {
-      /* here i is the Huffman code of length k bits for value *p */
-      /* make tables up to required level */
-      while (k > w + l)
-      {
-        h++;
-        w += l;                 /* previous table always l bits */
-
-        /* compute minimum size table less than or equal to l bits */
-        z = g - w;
-        z = z > (uInt)l ? l : z;        /* table size upper limit */
-        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
-        {                       /* too few codes for k-w bit table */
-          f -= a + 1;           /* deduct codes from patterns left */
-          xp = c + k;
-          if (j < z)
-            while (++j < z)     /* try smaller tables up to z bits */
-            {
-              if ((f <<= 1) <= *++xp)
-                break;          /* enough codes to use up j bits */
-              f -= *xp;         /* else deduct codes from patterns */
-            }
-        }
-        z = 1 << j;             /* table entries for j-bit table */
-
-        /* allocate and link in new table */
-        if ((q = (inflate_huft *)ZALLOC
-             (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
-        {
-          if (h)
-            inflate_trees_free(u[0], zs);
-          return Z_MEM_ERROR;   /* not enough memory */
-        }
-#ifdef DEBUG_ZLIB
-        inflate_hufts += z + 1;
-#endif
-        *t = q + 1;             /* link to list for huft_free() */
-        *(t = &(q->next)) = Z_NULL;
-        u[h] = ++q;             /* table starts after link */
-
-        /* connect to last table, if there is one */
-        if (h)
-        {
-          x[h] = i;             /* save pattern for backing up */
-          r.bits = (Byte)l;     /* bits to dump before this table */
-          r.exop = (Byte)j;     /* bits in this table */
-          r.next = q;           /* pointer to this table */
-          j = i >> (w - l);     /* (get around Turbo C bug) */
-          u[h-1][j] = r;        /* connect to last table */
-        }
-      }
-
-      /* set up table entry in r */
-      r.bits = (Byte)(k - w);
-      if (p >= v + n)
-        r.exop = 128 + 64;      /* out of values--invalid code */
-      else if (*p < s)
-      {
-        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
-        r.base = *p++;          /* simple code is just the value */
-      }
-      else
-      {
-        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
-        r.base = d[*p++ - s];
-      }
-
-      /* fill code-like entries with r */
-      f = 1 << (k - w);
-      for (j = i >> w; j < z; j += f)
-        q[j] = r;
-
-      /* backwards increment the k-bit code i */
-      for (j = 1 << (k - 1); i & j; j >>= 1)
-        i ^= j;
-      i ^= j;
-
-      /* backup over finished tables */
-      while ((i & ((1 << w) - 1)) != x[h])
-      {
-        h--;                    /* don't need to update q */
-        w -= l;
-      }
-    }
-  }
-
-
-  /* Return Z_BUF_ERROR if we were given an incomplete table */
-  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
-}
-
-
-int inflate_trees_bits(c, bb, tb, z)
-uIntf *c;               /* 19 code lengths */
-uIntf *bb;              /* bits tree desired/actual depth */
-inflate_huft * FAR *tb; /* bits tree result */
-z_streamp z;            /* for zfree function */
-{
-  int r;
-
-  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
-  if (r == Z_DATA_ERROR)
-    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
-  else if (r == Z_BUF_ERROR || *bb == 0)
-  {
-    inflate_trees_free(*tb, z);
-    z->msg = (char*)"incomplete dynamic bit lengths tree";
-    r = Z_DATA_ERROR;
-  }
-  return r;
-}
-
-
-int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
-uInt nl;                /* number of literal/length codes */
-uInt nd;                /* number of distance codes */
-uIntf *c;               /* that many (total) code lengths */
-uIntf *bl;              /* literal desired/actual bit depth */
-uIntf *bd;              /* distance desired/actual bit depth */
-inflate_huft * FAR *tl; /* literal/length tree result */
-inflate_huft * FAR *td; /* distance tree result */
-z_streamp z;            /* for zfree function */
-{
-  int r;
-
-  /* build literal/length tree */
-  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z);
-  if (r != Z_OK || *bl == 0)
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed literal/length tree";
-    else if (r != Z_MEM_ERROR)
-    {
-      inflate_trees_free(*tl, z);
-      z->msg = (char*)"incomplete literal/length tree";
-      r = Z_DATA_ERROR;
-    }
-    return r;
-  }
-
-  /* build distance tree */
-  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z);
-  if (r != Z_OK || (*bd == 0 && nl > 257))
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed distance tree";
-    else if (r == Z_BUF_ERROR) {
-#ifdef PKZIP_BUG_WORKAROUND
-      r = Z_OK;
-    }
-#else
-      inflate_trees_free(*td, z);
-      z->msg = (char*)"incomplete distance tree";
-      r = Z_DATA_ERROR;
-    }
-    else if (r != Z_MEM_ERROR)
-    {
-      z->msg = (char*)"empty distance tree with lengths";
-      r = Z_DATA_ERROR;
-    }
-    inflate_trees_free(*tl, z);
-    return r;
-#endif
-  }
-
-  /* done */
-  return Z_OK;
-}
-
-
-/* build fixed tables only once--keep them here */
-local int fixed_built = 0;
-#define FIXEDH 530      /* number of hufts used by fixed tables */
-local inflate_huft fixed_mem[FIXEDH];
-local uInt fixed_bl;
-local uInt fixed_bd;
-local inflate_huft *fixed_tl;
-local inflate_huft *fixed_td;
-
-
-local voidpf falloc(q, n, s)
-voidpf q;       /* opaque pointer */
-uInt n;         /* number of items */
-uInt s;         /* size of item */
-{
-  Assert(s == sizeof(inflate_huft) && n <= *(intf *)q,
-         "inflate_trees falloc overflow");
-  *(intf *)q -= n+s-s; /* s-s to avoid warning */
-  return (voidpf)(fixed_mem + *(intf *)q);
-}
-
-
-int inflate_trees_fixed(bl, bd, tl, td)
-uIntf *bl;               /* literal desired/actual bit depth */
-uIntf *bd;               /* distance desired/actual bit depth */
-inflate_huft * FAR *tl;  /* literal/length tree result */
-inflate_huft * FAR *td;  /* distance tree result */
-{
-  /* build fixed tables if not already (multiple overlapped executions ok) */
-  if (!fixed_built)
-  {
-    int k;              /* temporary variable */
-    unsigned c[288];    /* length list for huft_build */
-    z_stream z;         /* for falloc function */
-    int f = FIXEDH;     /* number of hufts left in fixed_mem */
-
-    /* set up fake z_stream for memory routines */
-    z.zalloc = falloc;
-    z.zfree = Z_NULL;
-    z.opaque = (voidpf)&f;
-
-    /* literal table */
-    for (k = 0; k < 144; k++)
-      c[k] = 8;
-    for (; k < 256; k++)
-      c[k] = 9;
-    for (; k < 280; k++)
-      c[k] = 7;
-    for (; k < 288; k++)
-      c[k] = 8;
-    fixed_bl = 7;
-    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
-
-    /* distance table */
-    for (k = 0; k < 30; k++)
-      c[k] = 5;
-    fixed_bd = 5;
-    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
-
-    /* done */
-    Assert(f == 0, "invalid build of fixed tables");
-    fixed_built = 1;
-  }
-  *bl = fixed_bl;
-  *bd = fixed_bd;
-  *tl = fixed_tl;
-  *td = fixed_td;
-  return Z_OK;
-}
-
-
-int inflate_trees_free(t, z)
-inflate_huft *t;        /* table to free */
-z_streamp z;            /* for zfree function */
-/* Free the malloc'ed tables built by huft_build(), which makes a linked
-   list of the tables it made, with the links in a dummy first entry of
-   each table. */
-{
-  register inflate_huft *p, *q, *r;
-
-  /* Reverse linked list */
-  p = Z_NULL;
-  q = t;
-  while (q != Z_NULL)
-  {
-    r = (q - 1)->next;
-    (q - 1)->next = p;
-    p = q;
-    q = r;
-  }
-  /* Go through linked list, freeing from the malloced (t[-1]) address. */
-  while (p != Z_NULL)
-  {
-    q = (--p)->next;
-    ZFREE(z,p);
-    p = q;
-  } 
-  return Z_OK;
-}
-/* --- inftrees.c */
-
-/* +++ infcodes.c */
-/* infcodes.c -- process literals and length/distance pairs
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-/* #include "infblock.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-
-/* +++ inffast.h */
-/* inffast.h -- header to use inffast.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-extern int inflate_fast OF((
-    uInt,
-    uInt,
-    inflate_huft *,
-    inflate_huft *,
-    inflate_blocks_statef *,
-    z_streamp ));
-/* --- inffast.h */
-
-/* simplify the use of the inflate_huft type with some defines */
-#define base more.Base
-#define next more.Next
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* inflate codes private state */
-struct inflate_codes_state {
-
-  /* mode */
-  enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-      START,    /* x: set up for LEN */
-      LEN,      /* i: get length/literal/eob next */
-      LENEXT,   /* i: getting length extra (have base) */
-      DIST,     /* i: get distance next */
-      DISTEXT,  /* i: getting distance extra */
-      COPY,     /* o: copying bytes in window, waiting for space */
-      LIT,      /* o: got literal, waiting for output space */
-      WASH,     /* o: got eob, possibly still output waiting */
-      END,      /* x: got eob and all data flushed */
-      BADCODE}  /* x: got error */
-    mode;               /* current inflate_codes mode */
-
-  /* mode dependent information */
-  uInt len;
-  union {
-    struct {
-      inflate_huft *tree;       /* pointer into tree */
-      uInt need;                /* bits needed */
-    } code;             /* if LEN or DIST, where in tree */
-    uInt lit;           /* if LIT, literal */
-    struct {
-      uInt get;                 /* bits to get for extra */
-      uInt dist;                /* distance back to copy from */
-    } copy;             /* if EXT or COPY, where and how much */
-  } sub;                /* submode */
-
-  /* mode independent information */
-  Byte lbits;           /* ltree bits decoded per branch */
-  Byte dbits;           /* dtree bits decoder per branch */
-  inflate_huft *ltree;          /* literal/length/eob tree */
-  inflate_huft *dtree;          /* distance tree */
-
-};
-
-
-inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-z_streamp z;
-{
-  inflate_codes_statef *c;
-
-  if ((c = (inflate_codes_statef *)
-       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
-  {
-    c->mode = START;
-    c->lbits = (Byte)bl;
-    c->dbits = (Byte)bd;
-    c->ltree = tl;
-    c->dtree = td;
-    Tracev((stderr, "inflate:       codes new\n"));
-  }
-  return c;
-}
-
-
-int inflate_codes(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt j;               /* temporary storage */
-  inflate_huft *t;      /* temporary pointer */
-  uInt e;               /* extra bits or operation */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-  Bytef *f;             /* pointer to copy strings from */
-  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
-
-  /* copy input/output information to locals (UPDATE macro restores) */
-  LOAD
-
-  /* process input and output based on current state */
-  while (1) switch (c->mode)
-  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-    case START:         /* x: set up for LEN */
-#ifndef SLOW
-      if (m >= 258 && n >= 10)
-      {
-        UPDATE
-        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
-        LOAD
-        if (r != Z_OK)
-        {
-          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
-          break;
-        }
-      }
-#endif /* !SLOW */
-      c->sub.code.need = c->lbits;
-      c->sub.code.tree = c->ltree;
-      c->mode = LEN;
-    case LEN:           /* i: get length/literal/eob next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e == 0)               /* literal */
-      {
-        c->sub.lit = t->base;
-        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-                 "inflate:         literal '%c'\n" :
-                 "inflate:         literal 0x%02x\n", t->base));
-        c->mode = LIT;
-        break;
-      }
-      if (e & 16)               /* length */
-      {
-        c->sub.copy.get = e & 15;
-        c->len = t->base;
-        c->mode = LENEXT;
-        break;
-      }
-      if ((e & 64) == 0)        /* next table */
-      {
-        c->sub.code.need = e;
-        c->sub.code.tree = t->next;
-        break;
-      }
-      if (e & 32)               /* end of block */
-      {
-        Tracevv((stderr, "inflate:         end of block\n"));
-        c->mode = WASH;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"invalid literal/length code";
-      r = Z_DATA_ERROR;
-      LEAVE
-    case LENEXT:        /* i: getting length extra (have base) */
-      j = c->sub.copy.get;
-      NEEDBITS(j)
-      c->len += (uInt)b & inflate_mask[j];
-      DUMPBITS(j)
-      c->sub.code.need = c->dbits;
-      c->sub.code.tree = c->dtree;
-      Tracevv((stderr, "inflate:         length %u\n", c->len));
-      c->mode = DIST;
-    case DIST:          /* i: get distance next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e & 16)               /* distance */
-      {
-        c->sub.copy.get = e & 15;
-        c->sub.copy.dist = t->base;
-        c->mode = DISTEXT;
-        break;
-      }
-      if ((e & 64) == 0)        /* next table */
-      {
-        c->sub.code.need = e;
-        c->sub.code.tree = t->next;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"invalid distance code";
-      r = Z_DATA_ERROR;
-      LEAVE
-    case DISTEXT:       /* i: getting distance extra */
-      j = c->sub.copy.get;
-      NEEDBITS(j)
-      c->sub.copy.dist += (uInt)b & inflate_mask[j];
-      DUMPBITS(j)
-      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
-      c->mode = COPY;
-    case COPY:          /* o: copying bytes in window, waiting for space */
-#ifndef __TURBOC__ /* Turbo C bug for following expression */
-      f = (uInt)(q - s->window) < c->sub.copy.dist ?
-          s->end - (c->sub.copy.dist - (q - s->window)) :
-          q - c->sub.copy.dist;
-#else
-      f = q - c->sub.copy.dist;
-      if ((uInt)(q - s->window) < c->sub.copy.dist)
-        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
-#endif
-      while (c->len)
-      {
-        NEEDOUT
-        OUTBYTE(*f++)
-        if (f == s->end)
-          f = s->window;
-        c->len--;
-      }
-      c->mode = START;
-      break;
-    case LIT:           /* o: got literal, waiting for output space */
-      NEEDOUT
-      OUTBYTE(c->sub.lit)
-      c->mode = START;
-      break;
-    case WASH:          /* o: got eob, possibly more output */
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      c->mode = END;
-    case END:
-      r = Z_STREAM_END;
-      LEAVE
-    case BADCODE:       /* x: got error */
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-}
-
-
-void inflate_codes_free(c, z)
-inflate_codes_statef *c;
-z_streamp z;
-{
-  ZFREE(z, c);
-  Tracev((stderr, "inflate:       codes free\n"));
-}
-/* --- infcodes.c */
-
-/* +++ infutil.c */
-/* inflate_util.c -- data and routines common to blocks and codes
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "infblock.h" */
-/* #include "inftrees.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* And'ing with mask[n] masks the lower n bits */
-uInt inflate_mask[17] = {
-    0x0000,
-    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-
-/* copy as much as possible from the sliding window to the output area */
-int inflate_flush(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt n;
-  Bytef *p;
-  Bytef *q;
-
-  /* local copies of source and destination pointers */
-  p = z->next_out;
-  q = s->read;
-
-  /* compute number of bytes to copy as far as end of window */
-  n = (uInt)((q <= s->write ? s->write : s->end) - q);
-  if (n > z->avail_out) n = z->avail_out;
-  if (n && r == Z_BUF_ERROR) r = Z_OK;
-
-  /* update counters */
-  z->avail_out -= n;
-  z->total_out += n;
-
-  /* update check information */
-  if (s->checkfn != Z_NULL)
-    z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-  /* copy as far as end of window */
-  if (p != Z_NULL) {
-    zmemcpy(p, q, n);
-    p += n;
-  }
-  q += n;
-
-  /* see if more to copy at beginning of window */
-  if (q == s->end)
-  {
-    /* wrap pointers */
-    q = s->window;
-    if (s->write == s->end)
-      s->write = s->window;
-
-    /* compute bytes to copy */
-    n = (uInt)(s->write - q);
-    if (n > z->avail_out) n = z->avail_out;
-    if (n && r == Z_BUF_ERROR) r = Z_OK;
-
-    /* update counters */
-    z->avail_out -= n;
-    z->total_out += n;
-
-    /* update check information */
-    if (s->checkfn != Z_NULL)
-      z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-    /* copy */
-    if (p != Z_NULL) {
-      zmemcpy(p, q, n);
-      p += n;
-    }
-    q += n;
-  }
-
-  /* update pointers */
-  z->next_out = p;
-  s->read = q;
-
-  /* done */
-  return r;
-}
-/* --- infutil.c */
-
-/* +++ inffast.c */
-/* inffast.c -- process literals and length/distance pairs fast
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-/* #include "infblock.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-/* #include "inffast.h" */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* simplify the use of the inflate_huft type with some defines */
-#define base more.Base
-#define next more.Next
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* macros for bit input with no checking and for returning unused bytes */
-#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
-
-/* Called with number of bytes left to write in window at least 258
-   (the maximum string length) and number of input bytes available
-   at least ten.  The ten bytes are six bytes for the longest length/
-   distance pair plus four bytes for overloading the bit buffer. */
-
-int inflate_fast(bl, bd, tl, td, s, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-inflate_blocks_statef *s;
-z_streamp z;
-{
-  inflate_huft *t;      /* temporary pointer */
-  uInt e;               /* extra bits or operation */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-  uInt ml;              /* mask for literal/length tree */
-  uInt md;              /* mask for distance tree */
-  uInt c;               /* bytes to copy */
-  uInt d;               /* distance back to copy from */
-  Bytef *r;             /* copy source pointer */
-
-  /* load input, output, bit values */
-  LOAD
-
-  /* initialize masks */
-  ml = inflate_mask[bl];
-  md = inflate_mask[bd];
-
-  /* do until not enough input or output space for fast loop */
-  do {                          /* assume called with m >= 258 && n >= 10 */
-    /* get literal/length code */
-    GRABBITS(20)                /* max bits for literal/length code */
-    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
-    {
-      DUMPBITS(t->bits)
-      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-                "inflate:         * literal '%c'\n" :
-                "inflate:         * literal 0x%02x\n", t->base));
-      *q++ = (Byte)t->base;
-      m--;
-      continue;
-    }
-    do {
-      DUMPBITS(t->bits)
-      if (e & 16)
-      {
-        /* get extra bits for length */
-        e &= 15;
-        c = t->base + ((uInt)b & inflate_mask[e]);
-        DUMPBITS(e)
-        Tracevv((stderr, "inflate:         * length %u\n", c));
-
-        /* decode distance base of block to copy */
-        GRABBITS(15);           /* max bits for distance code */
-        e = (t = td + ((uInt)b & md))->exop;
-        do {
-          DUMPBITS(t->bits)
-          if (e & 16)
-          {
-            /* get extra bits to add to distance base */
-            e &= 15;
-            GRABBITS(e)         /* get extra bits (up to 13) */
-            d = t->base + ((uInt)b & inflate_mask[e]);
-            DUMPBITS(e)
-            Tracevv((stderr, "inflate:         * distance %u\n", d));
-
-            /* do the copy */
-            m -= c;
-            if ((uInt)(q - s->window) >= d)     /* offset before dest */
-            {                                   /*  just copy */
-              r = q - d;
-              *q++ = *r++;  c--;        /* minimum count is three, */
-              *q++ = *r++;  c--;        /*  so unroll loop a little */
-            }
-            else                        /* else offset after destination */
-            {
-              e = d - (uInt)(q - s->window); /* bytes from offset to end */
-              r = s->end - e;           /* pointer to offset */
-              if (c > e)                /* if source crosses, */
-              {
-                c -= e;                 /* copy to end of window */
-                do {
-                  *q++ = *r++;
-                } while (--e);
-                r = s->window;          /* copy rest from start of window */
-              }
-            }
-            do {                        /* copy all or what's left */
-              *q++ = *r++;
-            } while (--c);
-            break;
-          }
-          else if ((e & 64) == 0)
-            e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
-          else
-          {
-            z->msg = (char*)"invalid distance code";
-            UNGRAB
-            UPDATE
-            return Z_DATA_ERROR;
-          }
-        } while (1);
-        break;
-      }
-      if ((e & 64) == 0)
-      {
-        if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
-        {
-          DUMPBITS(t->bits)
-          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-                    "inflate:         * literal '%c'\n" :
-                    "inflate:         * literal 0x%02x\n", t->base));
-          *q++ = (Byte)t->base;
-          m--;
-          break;
-        }
-      }
-      else if (e & 32)
-      {
-        Tracevv((stderr, "inflate:         * end of block\n"));
-        UNGRAB
-        UPDATE
-        return Z_STREAM_END;
-      }
-      else
-      {
-        z->msg = (char*)"invalid literal/length code";
-        UNGRAB
-        UPDATE
-        return Z_DATA_ERROR;
-      }
-    } while (1);
-  } while (m >= 258 && n >= 10);
-
-  /* not enough input or output--restore pointers and return */
-  UNGRAB
-  UPDATE
-  return Z_OK;
-}
-/* --- inffast.c */
-
-/* +++ zutil.c */
-/* zutil.c -- target dependent utility functions for the compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */
-
-/* #include "zutil.h" */
-
-#ifndef NO_DUMMY_DECL
-struct internal_state      {int dummy;}; /* for buggy compilers */
-#endif
-
-#ifndef STDC
-extern void exit OF((int));
-#endif
-
-const char *z_errmsg[10] = {
-"need dictionary",     /* Z_NEED_DICT       2  */
-"stream end",          /* Z_STREAM_END      1  */
-"",                    /* Z_OK              0  */
-"file error",          /* Z_ERRNO         (-1) */
-"stream error",        /* Z_STREAM_ERROR  (-2) */
-"data error",          /* Z_DATA_ERROR    (-3) */
-"insufficient memory", /* Z_MEM_ERROR     (-4) */
-"buffer error",        /* Z_BUF_ERROR     (-5) */
-"incompatible version",/* Z_VERSION_ERROR (-6) */
-""};
-
-
-const char *zlibVersion()
-{
-    return ZLIB_VERSION;
-}
-
-#ifdef DEBUG_ZLIB
-void z_error (m)
-    char *m;
-{
-    fprintf(stderr, "%s\n", m);
-    exit(1);
-}
-#endif
-
-#ifndef HAVE_MEMCPY
-
-void zmemcpy(dest, source, len)
-    Bytef* dest;
-    Bytef* source;
-    uInt  len;
-{
-    if (len == 0) return;
-    do {
-        *dest++ = *source++; /* ??? to be unrolled */
-    } while (--len != 0);
-}
-
-int zmemcmp(s1, s2, len)
-    Bytef* s1;
-    Bytef* s2;
-    uInt  len;
-{
-    uInt j;
-
-    for (j = 0; j < len; j++) {
-        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
-    }
-    return 0;
-}
-
-void zmemzero(dest, len)
-    Bytef* dest;
-    uInt  len;
-{
-    if (len == 0) return;
-    do {
-        *dest++ = 0;  /* ??? to be unrolled */
-    } while (--len != 0);
-}
-#endif
-
-#ifdef __TURBOC__
-#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
-/* Small and medium model in Turbo C are for now limited to near allocation
- * with reduced MAX_WBITS and MAX_MEM_LEVEL
- */
-#  define MY_ZCALLOC
-
-/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
- * and farmalloc(64K) returns a pointer with an offset of 8, so we
- * must fix the pointer. Warning: the pointer must be put back to its
- * original form in order to free it, use zcfree().
- */
-
-#define MAX_PTR 10
-/* 10*64K = 640K */
-
-local int next_ptr = 0;
-
-typedef struct ptr_table_s {
-    voidpf org_ptr;
-    voidpf new_ptr;
-} ptr_table;
-
-local ptr_table table[MAX_PTR];
-/* This table is used to remember the original form of pointers
- * to large buffers (64K). Such pointers are normalized with a zero offset.
- * Since MSDOS is not a preemptive multitasking OS, this table is not
- * protected from concurrent access. This hack doesn't work anyway on
- * a protected system like OS/2. Use Microsoft C instead.
- */
-
-voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-{
-    voidpf buf = opaque; /* just to make some compilers happy */
-    ulg bsize = (ulg)items*size;
-
-    /* If we allocate less than 65520 bytes, we assume that farmalloc
-     * will return a usable pointer which doesn't have to be normalized.
-     */
-    if (bsize < 65520L) {
-        buf = farmalloc(bsize);
-        if (*(ush*)&buf != 0) return buf;
-    } else {
-        buf = farmalloc(bsize + 16L);
-    }
-    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
-    table[next_ptr].org_ptr = buf;
-
-    /* Normalize the pointer to seg:0 */
-    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
-    *(ush*)&buf = 0;
-    table[next_ptr++].new_ptr = buf;
-    return buf;
-}
-
-void  zcfree (voidpf opaque, voidpf ptr)
-{
-    int n;
-    if (*(ush*)&ptr != 0) { /* object < 64K */
-        farfree(ptr);
-        return;
-    }
-    /* Find the original pointer */
-    for (n = 0; n < next_ptr; n++) {
-        if (ptr != table[n].new_ptr) continue;
-
-        farfree(table[n].org_ptr);
-        while (++n < next_ptr) {
-            table[n-1] = table[n];
-        }
-        next_ptr--;
-        return;
-    }
-    ptr = opaque; /* just to make some compilers happy */
-    Assert(0, "zcfree: ptr not found");
-}
-#endif
-#endif /* __TURBOC__ */
-
-
-#if defined(M_I86) && !defined(__32BIT__)
-/* Microsoft C in 16-bit mode */
-
-#  define MY_ZCALLOC
-
-#if (!defined(_MSC_VER) || (_MSC_VER < 600))
-#  define _halloc  halloc
-#  define _hfree   hfree
-#endif
-
-voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-{
-    if (opaque) opaque = 0; /* to make compiler happy */
-    return _halloc((long)items, size);
-}
-
-void  zcfree (voidpf opaque, voidpf ptr)
-{
-    if (opaque) opaque = 0; /* to make compiler happy */
-    _hfree(ptr);
-}
-
-#endif /* MSC */
-
-
-#ifndef MY_ZCALLOC /* Any system without a special alloc function */
-
-#ifndef STDC
-extern voidp  calloc OF((uInt items, uInt size));
-extern void   free   OF((voidpf ptr));
-#endif
-
-voidpf zcalloc (opaque, items, size)
-    voidpf opaque;
-    unsigned items;
-    unsigned size;
-{
-    if (opaque) items += size - size; /* make compiler happy */
-    return (voidpf)calloc(items, size);
-}
-
-void  zcfree (opaque, ptr)
-    voidpf opaque;
-    voidpf ptr;
-{
-    free(ptr);
-    if (opaque) return; /* make compiler happy */
-}
-
-#endif /* MY_ZCALLOC */
-/* --- zutil.c */
-
-/* +++ adler32.c */
-/* adler32.c -- compute the Adler-32 checksum of a data stream
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */
-
-/* #include "zlib.h" */
-
-#define BASE 65521L /* largest prime smaller than 65536 */
-#define NMAX 5552
-/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
-
-#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
-#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
-#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
-#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
-#define DO16(buf)   DO8(buf,0); DO8(buf,8);
-
-/* ========================================================================= */
-uLong adler32(adler, buf, len)
-    uLong adler;
-    const Bytef *buf;
-    uInt len;
-{
-    unsigned long s1 = adler & 0xffff;
-    unsigned long s2 = (adler >> 16) & 0xffff;
-    int k;
-
-    if (buf == Z_NULL) return 1L;
-
-    while (len > 0) {
-        k = len < NMAX ? len : NMAX;
-        len -= k;
-        while (k >= 16) {
-            DO16(buf);
-	    buf += 16;
-            k -= 16;
-        }
-        if (k != 0) do {
-            s1 += *buf++;
-	    s2 += s1;
-        } while (--k);
-        s1 %= BASE;
-        s2 %= BASE;
-    }
-    return (s2 << 16) | s1;
-}
-/* --- adler32.c */
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/zlib.h linux/fs/jffs2/zlib.h
--- v2.5.2/linux/fs/jffs2/zlib.h	Fri Sep 14 14:04:07 2001
+++ linux/fs/jffs2/zlib.h	Wed Dec 31 16:00:00 1969
@@ -1,1010 +0,0 @@
-/*	$Id: zlib.h,v 1.2 1997/12/23 10:47:44 paulus Exp $	*/
-
-/*
- * This file is derived from zlib.h and zconf.h from the zlib-1.0.4
- * distribution by Jean-loup Gailly and Mark Adler, with some additions
- * by Paul Mackerras to aid in implementing Deflate compression and
- * decompression for PPP packets.
- */
-
-/*
- *  ==FILEVERSION 971127==
- *
- * This marker is used by the Linux installation script to determine
- * whether an up-to-date version of this file is already installed.
- */
-
-
-/* +++ zlib.h */
-/* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.0.4, Jul 24th, 1996.
-
-  Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  gzip@prep.ai.mit.edu    madler@alumni.caltech.edu
-
-
-  The data format used by the zlib library is described by RFCs (Request for
-  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
-  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
-*/
-
-#ifndef _ZLIB_H
-#define _ZLIB_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* +++ zconf.h */
-/* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */
-
-#ifndef _ZCONF_H
-#define _ZCONF_H
-
-/*
- * If you *really* need a unique prefix for all types and library functions,
- * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
- */
-#ifdef Z_PREFIX
-#  define deflateInit_	z_deflateInit_
-#  define deflate	z_deflate
-#  define deflateEnd	z_deflateEnd
-#  define inflateInit_ 	z_inflateInit_
-#  define inflate	z_inflate
-#  define inflateEnd	z_inflateEnd
-#  define deflateInit2_	z_deflateInit2_
-#  define deflateSetDictionary z_deflateSetDictionary
-#  define deflateCopy	z_deflateCopy
-#  define deflateReset	z_deflateReset
-#  define deflateParams	z_deflateParams
-#  define inflateInit2_	z_inflateInit2_
-#  define inflateSetDictionary z_inflateSetDictionary
-#  define inflateSync	z_inflateSync
-#  define inflateReset	z_inflateReset
-#  define compress	z_compress
-#  define uncompress	z_uncompress
-#  define adler32	z_adler32
-#  define crc32		z_crc32
-#  define get_crc_table z_get_crc_table
-
-#  define Byte		z_Byte
-#  define uInt		z_uInt
-#  define uLong		z_uLong
-#  define Bytef	        z_Bytef
-#  define charf		z_charf
-#  define intf		z_intf
-#  define uIntf		z_uIntf
-#  define uLongf	z_uLongf
-#  define voidpf	z_voidpf
-#  define voidp		z_voidp
-#endif
-
-#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
-#  define WIN32
-#endif
-#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
-#  ifndef __32BIT__
-#    define __32BIT__
-#  endif
-#endif
-#if defined(__MSDOS__) && !defined(MSDOS)
-#  define MSDOS
-#endif
-
-/*
- * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
- * than 64k bytes at a time (needed on systems with 16-bit int).
- */
-#if defined(MSDOS) && !defined(__32BIT__)
-#  define MAXSEG_64K
-#endif
-#ifdef MSDOS
-#  define UNALIGNED_OK
-#endif
-
-#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
-#  define STDC
-#endif
-#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC)
-#  define STDC
-#endif
-
-#ifndef STDC
-#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
-#    define const
-#  endif
-#endif
-
-/* Some Mac compilers merge all .h files incorrectly: */
-#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
-#  define NO_DUMMY_DECL
-#endif
-
-/* Maximum value for memLevel in deflateInit2 */
-#ifndef MAX_MEM_LEVEL
-#  ifdef MAXSEG_64K
-#    define MAX_MEM_LEVEL 8
-#  else
-#    define MAX_MEM_LEVEL 9
-#  endif
-#endif
-
-/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
-#ifndef MAX_WBITS
-#  define MAX_WBITS   15 /* 32K LZ77 window */
-#endif
-
-/* The memory requirements for deflate are (in bytes):
-            1 << (windowBits+2)   +  1 << (memLevel+9)
- that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
- plus a few kilobytes for small objects. For example, if you want to reduce
- the default memory requirements from 256K to 128K, compile with
-     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
- Of course this will generally degrade compression (there's no free lunch).
-
-   The memory requirements for inflate are (in bytes) 1 << windowBits
- that is, 32K for windowBits=15 (default value) plus a few kilobytes
- for small objects.
-*/
-
-                        /* Type declarations */
-
-#ifndef OF /* function prototypes */
-#  ifdef STDC
-#    define OF(args)  args
-#  else
-#    define OF(args)  ()
-#  endif
-#endif
-
-/* The following definitions for FAR are needed only for MSDOS mixed
- * model programming (small or medium model with some far allocations).
- * This was tested only with MSC; for other MSDOS compilers you may have
- * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
- * just define FAR to be empty.
- */
-#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
-   /* MSC small or medium model */
-#  define SMALL_MEDIUM
-#  ifdef _MSC_VER
-#    define FAR __far
-#  else
-#    define FAR far
-#  endif
-#endif
-#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
-#  ifndef __32BIT__
-#    define SMALL_MEDIUM
-#    define FAR __far
-#  endif
-#endif
-#ifndef FAR
-#   define FAR
-#endif
-
-typedef unsigned char  Byte;  /* 8 bits */
-typedef unsigned int   uInt;  /* 16 bits or more */
-typedef unsigned long  uLong; /* 32 bits or more */
-
-#if defined(__BORLANDC__) && defined(SMALL_MEDIUM)
-   /* Borland C/C++ ignores FAR inside typedef */
-#  define Bytef Byte FAR
-#else
-   typedef Byte  FAR Bytef;
-#endif
-typedef char  FAR charf;
-typedef int   FAR intf;
-typedef uInt  FAR uIntf;
-typedef uLong FAR uLongf;
-
-#ifdef STDC
-   typedef void FAR *voidpf;
-   typedef void     *voidp;
-#else
-   typedef Byte FAR *voidpf;
-   typedef Byte     *voidp;
-#endif
-
-
-/* Compile with -DZLIB_DLL for Windows DLL support */
-#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL)
-#  include <windows.h>
-#  define EXPORT  WINAPI
-#else
-#  define EXPORT
-#endif
-
-#endif /* _ZCONF_H */
-/* --- zconf.h */
-
-#define ZLIB_VERSION "1.0.4P"
-
-/* 
-     The 'zlib' compression library provides in-memory compression and
-  decompression functions, including integrity checks of the uncompressed
-  data.  This version of the library supports only one compression method
-  (deflation) but other algorithms may be added later and will have the same
-  stream interface.
-
-     For compression the application must provide the output buffer and
-  may optionally provide the input buffer for optimization. For decompression,
-  the application must provide the input buffer and may optionally provide
-  the output buffer for optimization.
-
-     Compression can be done in a single step if the buffers are large
-  enough (for example if an input file is mmap'ed), or can be done by
-  repeated calls of the compression function.  In the latter case, the
-  application must provide more input and/or consume the output
-  (providing more output space) before each call.
-
-     The library does not install any signal handler. It is recommended to
-  add at least a handler for SIGSEGV when decompressing; the library checks
-  the consistency of the input data whenever possible but may go nuts
-  for some forms of corrupted input.
-*/
-
-typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
-
-struct internal_state;
-
-typedef struct z_stream_s {
-    Bytef    *next_in;  /* next input byte */
-    uInt     avail_in;  /* number of bytes available at next_in */
-    uLong    total_in;  /* total nb of input bytes read so far */
-
-    Bytef    *next_out; /* next output byte should be put there */
-    uInt     avail_out; /* remaining free space at next_out */
-    uLong    total_out; /* total nb of bytes output so far */
-
-    char     *msg;      /* last error message, NULL if no error */
-    struct internal_state FAR *state; /* not visible by applications */
-
-    alloc_func zalloc;  /* used to allocate the internal state */
-    free_func  zfree;   /* used to free the internal state */
-    voidpf     opaque;  /* private data object passed to zalloc and zfree */
-
-    int     data_type;  /* best guess about the data type: ascii or binary */
-    uLong   adler;      /* adler32 value of the uncompressed data */
-    uLong   reserved;   /* reserved for future use */
-} z_stream;
-
-typedef z_stream FAR *z_streamp;
-
-/*
-   The application must update next_in and avail_in when avail_in has
-   dropped to zero. It must update next_out and avail_out when avail_out
-   has dropped to zero. The application must initialize zalloc, zfree and
-   opaque before calling the init function. All other fields are set by the
-   compression library and must not be updated by the application.
-
-   The opaque value provided by the application will be passed as the first
-   parameter for calls of zalloc and zfree. This can be useful for custom
-   memory management. The compression library attaches no meaning to the
-   opaque value.
-
-   zalloc must return Z_NULL if there is not enough memory for the object.
-   On 16-bit systems, the functions zalloc and zfree must be able to allocate
-   exactly 65536 bytes, but will not be required to allocate more than this
-   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
-   pointers returned by zalloc for objects of exactly 65536 bytes *must*
-   have their offset normalized to zero. The default allocation function
-   provided by this library ensures this (see zutil.c). To reduce memory
-   requirements and avoid any allocation of 64K objects, at the expense of
-   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
-
-   The fields total_in and total_out can be used for statistics or
-   progress reports. After compression, total_in holds the total size of
-   the uncompressed data and may be saved for use in the decompressor
-   (particularly if the decompressor wants to decompress everything in
-   a single step).
-*/
-
-                        /* constants */
-
-#define Z_NO_FLUSH      0
-#define Z_PARTIAL_FLUSH 1
-#define Z_PACKET_FLUSH	2
-#define Z_SYNC_FLUSH    3
-#define Z_FULL_FLUSH    4
-#define Z_FINISH        5
-/* Allowed flush values; see deflate() below for details */
-
-#define Z_OK            0
-#define Z_STREAM_END    1
-#define Z_NEED_DICT     2
-#define Z_ERRNO        (-1)
-#define Z_STREAM_ERROR (-2)
-#define Z_DATA_ERROR   (-3)
-#define Z_MEM_ERROR    (-4)
-#define Z_BUF_ERROR    (-5)
-#define Z_VERSION_ERROR (-6)
-/* Return codes for the compression/decompression functions. Negative
- * values are errors, positive values are used for special but normal events.
- */
-
-#define Z_NO_COMPRESSION         0
-#define Z_BEST_SPEED             1
-#define Z_BEST_COMPRESSION       9
-#define Z_DEFAULT_COMPRESSION  (-1)
-/* compression levels */
-
-#define Z_FILTERED            1
-#define Z_HUFFMAN_ONLY        2
-#define Z_DEFAULT_STRATEGY    0
-/* compression strategy; see deflateInit2() below for details */
-
-#define Z_BINARY   0
-#define Z_ASCII    1
-#define Z_UNKNOWN  2
-/* Possible values of the data_type field */
-
-#define Z_DEFLATED   8
-/* The deflate compression method (the only one supported in this version) */
-
-#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
-
-#define zlib_version zlibVersion()
-/* for compatibility with versions < 1.0.2 */
-
-                        /* basic functions */
-
-extern const char * EXPORT zlibVersion OF((void));
-/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
-   If the first character differs, the library code actually used is
-   not compatible with the zlib.h header file used by the application.
-   This check is automatically made by deflateInit and inflateInit.
- */
-
-/* 
-extern int EXPORT deflateInit OF((z_streamp strm, int level));
-
-     Initializes the internal stream state for compression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.
-   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
-   use default allocation functions.
-
-     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
-   1 gives best speed, 9 gives best compression, 0 gives no compression at
-   all (the input data is simply copied a block at a time).
-   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
-   compression (currently equivalent to level 6).
-
-     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
-   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
-   with the version assumed by the caller (ZLIB_VERSION).
-   msg is set to null if there is no error message.  deflateInit does not
-   perform any compression: this will be done by deflate().
-*/
-
-
-extern int EXPORT deflate OF((z_streamp strm, int flush));
-/*
-  Performs one or both of the following actions:
-
-  - Compress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in and avail_in are updated and
-    processing will resume at this point for the next call of deflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly. This action is forced if the parameter flush is non zero.
-    Forcing flush frequently degrades the compression ratio, so this parameter
-    should be set only when necessary (in interactive applications).
-    Some output may be provided even if flush is not set.
-
-  Before the call of deflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating avail_in or avail_out accordingly; avail_out
-  should never be zero before the call. The application can consume the
-  compressed output when it wants, for example when the output buffer is full
-  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
-  and with zero avail_out, it must be called again after making room in the
-  output buffer because there might be more output pending.
-
-    If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
-  block is terminated and flushed to the output buffer so that the
-  decompressor can get all input data available so far. For method 9, a future
-  variant on method 8, the current block will be flushed but not terminated.
-  Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
-  output is byte aligned (the compressor can clear its internal bit buffer)
-  and the current block is always terminated; this can be useful if the
-  compressor has to be restarted from scratch after an interruption (in which
-  case the internal state of the compressor may be lost).
-    If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
-  special marker is output and the compression dictionary is discarded; this
-  is useful to allow the decompressor to synchronize if one compressed block
-  has been damaged (see inflateSync below).  Flushing degrades compression and
-  so should be used only when necessary.  Using Z_FULL_FLUSH too often can
-  seriously degrade the compression. If deflate returns with avail_out == 0,
-  this function must be called again with the same value of the flush
-  parameter and more output space (updated avail_out), until the flush is
-  complete (deflate returns with non-zero avail_out).
-
-    If the parameter flush is set to Z_PACKET_FLUSH, the compression
-  block is terminated, and a zero-length stored block is output,
-  omitting the length bytes (the effect of this is that the 3-bit type
-  code 000 for a stored block is output, and the output is then
-  byte-aligned).  This is designed for use at the end of a PPP packet.
-
-    If the parameter flush is set to Z_FINISH, pending input is processed,
-  pending output is flushed and deflate returns with Z_STREAM_END if there
-  was enough output space; if deflate returns with Z_OK, this function must be
-  called again with Z_FINISH and more output space (updated avail_out) but no
-  more input data, until it returns with Z_STREAM_END or an error. After
-  deflate has returned Z_STREAM_END, the only possible operations on the
-  stream are deflateReset or deflateEnd.
-  
-    Z_FINISH can be used immediately after deflateInit if all the compression
-  is to be done in a single step. In this case, avail_out must be at least
-  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
-  Z_STREAM_END, then it must be called again as described above.
-
-    deflate() may update data_type if it can make a good guess about
-  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
-  binary. This field is only for information purposes and does not affect
-  the compression algorithm in any manner.
-
-    deflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if all input has been
-  consumed and all output has been produced (only when flush is set to
-  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
-  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
-*/
-
-
-extern int EXPORT deflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
-   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
-   prematurely (some input or output was discarded). In the error case,
-   msg may be set but then points to a static string (which must not be
-   deallocated).
-*/
-
-
-/* 
-extern int EXPORT inflateInit OF((z_streamp strm));
-
-     Initializes the internal stream state for decompression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.  If
-   zalloc and zfree are set to Z_NULL, inflateInit updates them to use default
-   allocation functions.
-
-     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_VERSION_ERROR if the zlib library version is incompatible
-   with the version assumed by the caller.  msg is set to null if there is no
-   error message. inflateInit does not perform any decompression: this will be
-   done by inflate().
-*/
-
-
-extern int EXPORT inflate OF((z_streamp strm, int flush));
-/*
-  Performs one or both of the following actions:
-
-  - Decompress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in is updated and processing
-    will resume at this point for the next call of inflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly.  inflate() provides as much output as possible, until there
-    is no more input data or no more space in the output buffer (see below
-    about the flush parameter).
-
-  Before the call of inflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating the next_* and avail_* values accordingly.
-  The application can consume the uncompressed output when it wants, for
-  example when the output buffer is full (avail_out == 0), or after each
-  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
-  must be called again after making room in the output buffer because there
-  might be more output pending.
-
-    If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
-  inflate flushes as much output as possible to the output buffer. The
-  flushing behavior of inflate is not specified for values of the flush
-  parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
-  current implementation actually flushes as much output as possible
-  anyway.  For Z_PACKET_FLUSH, inflate checks that once all the input data
-  has been consumed, it is expecting to see the length field of a stored
-  block; if not, it returns Z_DATA_ERROR.
-
-    inflate() should normally be called until it returns Z_STREAM_END or an
-  error. However if all decompression is to be performed in a single step
-  (a single call of inflate), the parameter flush should be set to
-  Z_FINISH. In this case all pending input is processed and all pending
-  output is flushed; avail_out must be large enough to hold all the
-  uncompressed data. (The size of the uncompressed data may have been saved
-  by the compressor for this purpose.) The next operation on this stream must
-  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
-  is never required, but can be used to inform inflate that a faster routine
-  may be used for the single inflate() call.
-
-    inflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if the end of the
-  compressed data has been reached and all uncompressed output has been
-  produced, Z_NEED_DICT if a preset dictionary is needed at this point (see
-  inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted,
-  Z_STREAM_ERROR if the stream structure was inconsistent (for example if
-  next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
-  Z_BUF_ERROR if no progress is possible or if there was not enough room in
-  the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the
-  application may then call inflateSync to look for a good compression block.
-  In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the
-  dictionary chosen by the compressor.
-*/
-
-
-extern int EXPORT inflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
-   was inconsistent. In the error case, msg may be set but then points to a
-   static string (which must not be deallocated).
-*/
-
-                        /* Advanced functions */
-
-/*
-    The following functions are needed only in some special applications.
-*/
-
-/*   
-extern int EXPORT deflateInit2 OF((z_streamp strm,
-                                   int  level,
-                                   int  method,
-                                   int  windowBits,
-                                   int  memLevel,
-                                   int  strategy));
-
-     This is another version of deflateInit with more compression options. The
-   fields next_in, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The method parameter is the compression method. It must be Z_DEFLATED in
-   this version of the library. (Method 9 will allow a 64K history buffer and
-   partial block flushes.)
-
-     The windowBits parameter is the base two logarithm of the window size
-   (the size of the history buffer).  It should be in the range 8..15 for this
-   version of the library (the value 16 will be allowed for method 9). Larger
-   values of this parameter result in better compression at the expense of
-   memory usage. The default value is 15 if deflateInit is used instead.
-
-     The memLevel parameter specifies how much memory should be allocated
-   for the internal compression state. memLevel=1 uses minimum memory but
-   is slow and reduces compression ratio; memLevel=9 uses maximum memory
-   for optimal speed. The default value is 8. See zconf.h for total memory
-   usage as a function of windowBits and memLevel.
-
-     The strategy parameter is used to tune the compression algorithm. Use the
-   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
-   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
-   string match).  Filtered data consists mostly of small values with a
-   somewhat random distribution. In this case, the compression algorithm is
-   tuned to compress them better. The effect of Z_FILTERED is to force more
-   Huffman coding and less string matching; it is somewhat intermediate
-   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
-   the compression ratio but not the correctness of the compressed output even
-   if it is not set appropriately.
-
-     If next_in is not null, the library will use this buffer to hold also
-   some history information; the buffer must either hold the entire input
-   data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
-   is null, the library will allocate its own history buffer (and leave next_in
-   null). next_out need not be provided here but must be provided by the
-   application for the next call of deflate().
-
-     If the history buffer is provided by the application, next_in must
-   must never be changed by the application since the compressor maintains
-   information inside this buffer from call to call; the application
-   must provide more input only by increasing avail_in. next_in is always
-   reset by the library in this case.
-
-      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
-   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
-   an invalid method). msg is set to null if there is no error message.
-   deflateInit2 does not perform any compression: this will be done by
-   deflate(). 
-*/
-                            
-extern int EXPORT deflateSetDictionary OF((z_streamp strm,
-                                           const Bytef *dictionary,
-				           uInt  dictLength));
-/*
-     Initializes the compression dictionary (history buffer) from the given
-   byte sequence without producing any compressed output. This function must
-   be called immediately after deflateInit or deflateInit2, before any call
-   of deflate. The compressor and decompressor must use exactly the same
-   dictionary (see inflateSetDictionary).
-     The dictionary should consist of strings (byte sequences) that are likely
-   to be encountered later in the data to be compressed, with the most commonly
-   used strings preferably put towards the end of the dictionary. Using a
-   dictionary is most useful when the data to be compressed is short and
-   can be predicted with good accuracy; the data can then be compressed better
-   than with the default empty dictionary. In this version of the library,
-   only the last 32K bytes of the dictionary are used.
-     Upon return of this function, strm->adler is set to the Adler32 value
-   of the dictionary; the decompressor may later use this value to determine
-   which dictionary has been used by the compressor. (The Adler32 value
-   applies to the whole dictionary even if only a subset of the dictionary is
-   actually used by the compressor.)
-
-     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state
-   is inconsistent (for example if deflate has already been called for this
-   stream). deflateSetDictionary does not perform any compression: this will
-   be done by deflate(). 
-*/
-
-extern int EXPORT deflateCopy OF((z_streamp dest,
-                                  z_streamp source));
-/*
-     Sets the destination stream as a complete copy of the source stream.  If
-   the source stream is using an application-supplied history buffer, a new
-   buffer is allocated for the destination stream.  The compressed output
-   buffer is always application-supplied. It's the responsibility of the
-   application to provide the correct values of next_out and avail_out for the
-   next call of deflate.
-
-     This function can be useful when several compression strategies will be
-   tried, for example when there are several ways of pre-processing the input
-   data with a filter. The streams that will be discarded should then be freed
-   by calling deflateEnd.  Note that deflateCopy duplicates the internal
-   compression state which can be quite large, so this strategy is slow and
-   can consume lots of memory.
-
-     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
-   (such as zalloc being NULL). msg is left unchanged in both source and
-   destination.
-*/
-
-extern int EXPORT deflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to deflateEnd followed by deflateInit,
-   but does not free and reallocate all the internal compression state.
-   The stream will keep the same compression level and any other attributes
-   that may have been set by deflateInit2.
-
-      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy));
-/*
-     Dynamically update the compression level and compression strategy.
-   This can be used to switch between compression and straight copy of
-   the input data, or to switch to a different kind of input data requiring
-   a different strategy. If the compression level is changed, the input
-   available so far is compressed with the old level (and may be flushed);
-   the new level will take effect only at the next call of deflate().
-
-     Before the call of deflateParams, the stream state must be set as for
-   a call of deflate(), since the currently available input may have to
-   be compressed and flushed. In particular, strm->avail_out must be non-zero.
-
-     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
-   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
-   if strm->avail_out was zero.
-*/
-
-extern int EXPORT deflateOutputPending OF((z_streamp strm));
-/*
-     Returns the number of bytes of output which are immediately
-   available from the compressor (i.e. without any further input
-   or flush).
-*/
-
-/*   
-extern int EXPORT inflateInit2 OF((z_streamp strm,
-                                   int  windowBits));
-
-     This is another version of inflateInit with more compression options. The
-   fields next_out, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The windowBits parameter is the base two logarithm of the maximum window
-   size (the size of the history buffer).  It should be in the range 8..15 for
-   this version of the library (the value 16 will be allowed soon). The
-   default value is 15 if inflateInit is used instead. If a compressed stream
-   with a larger window size is given as input, inflate() will return with
-   the error code Z_DATA_ERROR instead of trying to allocate a larger window.
-
-     If next_out is not null, the library will use this buffer for the history
-   buffer; the buffer must either be large enough to hold the entire output
-   data, or have at least 1<<windowBits bytes.  If next_out is null, the
-   library will allocate its own buffer (and leave next_out null). next_in
-   need not be provided here but must be provided by the application for the
-   next call of inflate().
-
-     If the history buffer is provided by the application, next_out must
-   never be changed by the application since the decompressor maintains
-   history information inside this buffer from call to call; the application
-   can only reset next_out to the beginning of the history buffer when
-   avail_out is zero and all output has been consumed.
-
-      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
-   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
-   windowBits < 8). msg is set to null if there is no error message.
-   inflateInit2 does not perform any decompression: this will be done by
-   inflate().
-*/
-
-extern int EXPORT inflateSetDictionary OF((z_streamp strm,
-				           const Bytef *dictionary,
-					   uInt  dictLength));
-/*
-     Initializes the decompression dictionary (history buffer) from the given
-   uncompressed byte sequence. This function must be called immediately after
-   a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen
-   by the compressor can be determined from the Adler32 value returned by this
-   call of inflate. The compressor and decompressor must use exactly the same
-   dictionary (see deflateSetDictionary).
-
-     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
-   expected one (incorrect Adler32 value). inflateSetDictionary does not
-   perform any decompression: this will be done by subsequent calls of
-   inflate().
-*/
-
-extern int EXPORT inflateSync OF((z_streamp strm));
-/* 
-    Skips invalid compressed data until the special marker (see deflate()
-  above) can be found, or until all available input is skipped. No output
-  is provided.
-
-    inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
-  if no more input was provided, Z_DATA_ERROR if no marker has been found,
-  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
-  case, the application may save the current current value of total_in which
-  indicates where valid compressed data was found. In the error case, the
-  application may repeatedly call inflateSync, providing more input each time,
-  until success or end of the input data.
-*/
-
-extern int EXPORT inflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to inflateEnd followed by inflateInit,
-   but does not free and reallocate all the internal decompression state.
-   The stream will keep attributes that may have been set by inflateInit2.
-
-      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-extern int inflateIncomp OF((z_stream *strm));
-/*
-     This function adds the data at next_in (avail_in bytes) to the output
-   history without performing any output.  There must be no pending output,
-   and the decompressor must be expecting to see the start of a block.
-   Calling this function is equivalent to decompressing a stored block
-   containing the data at next_in (except that the data is not output).
-*/
-
-                        /* utility functions */
-
-/*
-     The following utility functions are implemented on top of the
-   basic stream-oriented functions. To simplify the interface, some
-   default options are assumed (compression level, window size,
-   standard memory allocation functions). The source code of these
-   utility functions can easily be modified if you need special options.
-*/
-
-extern int EXPORT compress OF((Bytef *dest,   uLongf *destLen,
-			       const Bytef *source, uLong sourceLen));
-/*
-     Compresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be at least 0.1% larger than
-   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
-   compressed buffer.
-     This function can be used to compress a whole file at once if the
-   input file is mmap'ed.
-     compress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer.
-*/
-
-extern int EXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
-				 const Bytef *source, uLong sourceLen));
-/*
-     Decompresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be large enough to hold the
-   entire uncompressed data. (The size of the uncompressed data must have
-   been saved previously by the compressor and transmitted to the decompressor
-   by some mechanism outside the scope of this compression library.)
-   Upon exit, destLen is the actual size of the compressed buffer.
-     This function can be used to decompress a whole file at once if the
-   input file is mmap'ed.
-
-     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer, or Z_DATA_ERROR if the input data was corrupted.
-*/
-
-
-typedef voidp gzFile;
-
-extern gzFile EXPORT gzopen  OF((const char *path, const char *mode));
-/*
-     Opens a gzip (.gz) file for reading or writing. The mode parameter
-   is as in fopen ("rb" or "wb") but can also include a compression level
-   ("wb9").  gzopen can be used to read a file which is not in gzip format;
-   in this case gzread will directly read from the file without decompression.
-     gzopen returns NULL if the file could not be opened or if there was
-   insufficient memory to allocate the (de)compression state; errno
-   can be checked to distinguish the two cases (if errno is zero, the
-   zlib error is Z_MEM_ERROR).
-*/
-
-extern gzFile EXPORT gzdopen  OF((int fd, const char *mode));
-/*
-     gzdopen() associates a gzFile with the file descriptor fd.  File
-   descriptors are obtained from calls like open, dup, creat, pipe or
-   fileno (in the file has been previously opened with fopen).
-   The mode parameter is as in gzopen.
-     The next call of gzclose on the returned gzFile will also close the
-   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
-   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
-     gzdopen returns NULL if there was insufficient memory to allocate
-   the (de)compression state.
-*/
-
-extern int EXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
-/*
-     Reads the given number of uncompressed bytes from the compressed file.
-   If the input file was not in gzip format, gzread copies the given number
-   of bytes into the buffer.
-     gzread returns the number of uncompressed bytes actually read (0 for
-   end of file, -1 for error). */
-
-extern int EXPORT    gzwrite OF((gzFile file, const voidp buf, unsigned len));
-/*
-     Writes the given number of uncompressed bytes into the compressed file.
-   gzwrite returns the number of uncompressed bytes actually written
-   (0 in case of error).
-*/
-
-extern int EXPORT    gzflush OF((gzFile file, int flush));
-/*
-     Flushes all pending output into the compressed file. The parameter
-   flush is as in the deflate() function. The return value is the zlib
-   error number (see function gzerror below). gzflush returns Z_OK if
-   the flush parameter is Z_FINISH and all output could be flushed.
-     gzflush should be called only when strictly necessary because it can
-   degrade compression.
-*/
-
-extern int EXPORT    gzclose OF((gzFile file));
-/*
-     Flushes all pending output if necessary, closes the compressed file
-   and deallocates all the (de)compression state. The return value is the zlib
-   error number (see function gzerror below).
-*/
-
-extern const char * EXPORT gzerror OF((gzFile file, int *errnum));
-/*
-     Returns the error message for the last error which occurred on the
-   given compressed file. errnum is set to zlib error number. If an
-   error occurred in the file system and not in the compression library,
-   errnum is set to Z_ERRNO and the application may consult errno
-   to get the exact error code.
-*/
-
-                        /* checksum functions */
-
-/*
-     These functions are not related to compression but are exported
-   anyway because they might be useful in applications using the
-   compression library.
-*/
-
-extern uLong EXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
-
-/*
-     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
-   return the updated checksum. If buf is NULL, this function returns
-   the required initial value for the checksum.
-   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
-   much faster. Usage example:
-
-     uLong adler = adler32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       adler = adler32(adler, buffer, length);
-     }
-     if (adler != original_adler) error();
-*/
-
-extern uLong EXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
-/*
-     Update a running crc with the bytes buf[0..len-1] and return the updated
-   crc. If buf is NULL, this function returns the required initial value
-   for the crc. Pre- and post-conditioning (one's complement) is performed
-   within this function so it shouldn't be done by the application.
-   Usage example:
-
-     uLong crc = crc32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       crc = crc32(crc, buffer, length);
-     }
-     if (crc != original_crc) error();
-*/
-
-
-                        /* various hacks, don't look :) */
-
-/* deflateInit and inflateInit are macros to allow checking the zlib version
- * and the compiler's view of z_stream:
- */
-extern int EXPORT deflateInit_ OF((z_streamp strm, int level,
-			           const char *version, int stream_size));
-extern int EXPORT inflateInit_ OF((z_streamp strm,
-				   const char *version, int stream_size));
-extern int EXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
-				    int windowBits, int memLevel, int strategy,
-				    const char *version, int stream_size));
-extern int EXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
-				    const char *version, int stream_size));
-#define deflateInit(strm, level) \
-        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit(strm) \
-        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
-#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
-        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
-		      (strategy),           ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit2(strm, windowBits) \
-        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
-
-#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
-    struct internal_state {int dummy;}; /* hack for buggy compilers */
-#endif
-
-uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZLIB_H */
-/* --- zlib.h */
diff -u --recursive --new-file v2.5.2/linux/fs/lockd/svc.c linux/fs/lockd/svc.c
--- v2.5.2/linux/fs/lockd/svc.c	Sun Oct 21 10:32:33 2001
+++ linux/fs/lockd/svc.c	Mon Jan 28 15:11:45 2002
@@ -304,7 +304,7 @@
 	 * Wait for the lockd process to exit, but since we're holding
 	 * the lockd semaphore, we can't wait around forever ...
 	 */
-	current->sigpending = 0;
+	current->work.sigpending = 0;
 	interruptible_sleep_on_timeout(&lockd_exit, HZ);
 	if (nlmsvc_pid) {
 		printk(KERN_WARNING 
diff -u --recursive --new-file v2.5.2/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c
--- v2.5.2/linux/fs/minix/bitmap.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/minix/bitmap.c	Wed Jan 23 15:32:20 2002
@@ -261,6 +261,7 @@
 	inode->i_ino = j;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_blocks = inode->i_blksize = 0;
+	memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u));
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
 
diff -u --recursive --new-file v2.5.2/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.5.2/linux/fs/minix/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/minix/inode.c	Wed Jan 23 15:32:20 2002
@@ -75,7 +75,51 @@
 	return;
 }
 
+static kmem_cache_t * minix_inode_cachep;
+
+static struct inode *minix_alloc_inode(struct super_block *sb)
+{
+	struct minix_inode_info *ei;
+	ei = (struct minix_inode_info *)kmem_cache_alloc(minix_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void minix_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(minix_inode_cachep, minix_i(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct minix_inode_info *ei = (struct minix_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	minix_inode_cachep = kmem_cache_create("minix_inode_cache",
+					     sizeof(struct minix_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (minix_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(minix_inode_cachep))
+		printk(KERN_INFO "minix_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations minix_sops = {
+	alloc_inode:	minix_alloc_inode,
+	destroy_inode:	minix_destroy_inode,
 	read_inode:	minix_read_inode,
 	write_inode:	minix_write_inode,
 	delete_inode:	minix_delete_inode,
@@ -344,6 +388,7 @@
 {
 	struct buffer_head * bh;
 	struct minix_inode * raw_inode;
+	struct minix_inode_info *minix_inode = minix_i(inode);
 	int i;
 
 	raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -359,7 +404,7 @@
 	inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time;
 	inode->i_blocks = inode->i_blksize = 0;
 	for (i = 0; i < 9; i++)
-		inode->u.minix_i.u.i1_data[i] = raw_inode->i_zone[i];
+		minix_inode->u.i1_data[i] = raw_inode->i_zone[i];
 	minix_set_inode(inode, raw_inode->i_zone[0]);
 	brelse(bh);
 }
@@ -371,6 +416,7 @@
 {
 	struct buffer_head * bh;
 	struct minix2_inode * raw_inode;
+	struct minix_inode_info *minix_inode = minix_i(inode);
 	int i;
 
 	raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -388,7 +434,7 @@
 	inode->i_ctime = raw_inode->i_ctime;
 	inode->i_blocks = inode->i_blksize = 0;
 	for (i = 0; i < 10; i++)
-		inode->u.minix_i.u.i2_data[i] = raw_inode->i_zone[i];
+		minix_inode->u.i2_data[i] = raw_inode->i_zone[i];
 	minix_set_inode(inode, raw_inode->i_zone[0]);
 	brelse(bh);
 }
@@ -411,6 +457,7 @@
 {
 	struct buffer_head * bh;
 	struct minix_inode * raw_inode;
+	struct minix_inode_info *minix_inode = minix_i(inode);
 	int i;
 
 	raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -425,7 +472,7 @@
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 		raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
 	else for (i = 0; i < 9; i++)
-		raw_inode->i_zone[i] = inode->u.minix_i.u.i1_data[i];
+		raw_inode->i_zone[i] = minix_inode->u.i1_data[i];
 	mark_buffer_dirty(bh);
 	return bh;
 }
@@ -437,6 +484,7 @@
 {
 	struct buffer_head * bh;
 	struct minix2_inode * raw_inode;
+	struct minix_inode_info *minix_inode = minix_i(inode);
 	int i;
 
 	raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -453,7 +501,7 @@
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 		raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
 	else for (i = 0; i < 10; i++)
-		raw_inode->i_zone[i] = inode->u.minix_i.u.i2_data[i];
+		raw_inode->i_zone[i] = minix_inode->u.i2_data[i];
 	mark_buffer_dirty(bh);
 	return bh;
 }
@@ -514,12 +562,23 @@
 
 static int __init init_minix_fs(void)
 {
-        return register_filesystem(&minix_fs_type);
+	int err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&minix_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_minix_fs(void)
 {
         unregister_filesystem(&minix_fs_type);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/minix/itree_v1.c linux/fs/minix/itree_v1.c
--- v2.5.2/linux/fs/minix/itree_v1.c	Fri Sep  7 09:45:51 2001
+++ linux/fs/minix/itree_v1.c	Wed Jan 23 15:32:20 2002
@@ -19,7 +19,7 @@
 
 static inline block_t *i_data(struct inode *inode)
 {
-	return (block_t *)inode->u.minix_i.u.i1_data;
+	return (block_t *)minix_i(inode)->u.i1_data;
 }
 
 static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
diff -u --recursive --new-file v2.5.2/linux/fs/minix/itree_v2.c linux/fs/minix/itree_v2.c
--- v2.5.2/linux/fs/minix/itree_v2.c	Fri Sep  7 09:45:51 2001
+++ linux/fs/minix/itree_v2.c	Wed Jan 23 15:32:20 2002
@@ -19,7 +19,7 @@
 
 static inline block_t *i_data(struct inode *inode)
 {
-	return (block_t *)inode->u.minix_i.u.i2_data;
+	return (block_t *)minix_i(inode)->u.i2_data;
 }
 
 static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
diff -u --recursive --new-file v2.5.2/linux/fs/msdos/msdosfs_syms.c linux/fs/msdos/msdosfs_syms.c
--- v2.5.2/linux/fs/msdos/msdosfs_syms.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/msdos/msdosfs_syms.c	Wed Jan 16 10:20:23 2002
@@ -23,7 +23,6 @@
 EXPORT_SYMBOL(msdos_rename);
 EXPORT_SYMBOL(msdos_rmdir);
 EXPORT_SYMBOL(msdos_unlink);
-EXPORT_SYMBOL(msdos_read_super);
 EXPORT_SYMBOL(msdos_put_super);
 
 static DECLARE_FSTYPE_DEV(msdos_fs_type, "msdos", msdos_read_super);
diff -u --recursive --new-file v2.5.2/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.5.2/linux/fs/msdos/namei.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/msdos/namei.c	Mon Jan 28 13:20:44 2002
@@ -12,10 +12,6 @@
 
 #include <linux/sched.h>
 #include <linux/msdos_fs.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-
-#include <asm/uaccess.h>
 
 #define MSDOS_DEBUG 0
 #define PRINTK(x)
@@ -589,7 +585,15 @@
 
 	MSDOS_SB(sb)->options.isvfat = 0;
 	res = fat_read_super(sb, data, silent, &msdos_dir_inode_operations);
-	if (res)
-		sb->s_root->d_op = &msdos_dentry_operations;
+	if (IS_ERR(res))
+		return NULL;
+	if (res == NULL) {
+		if (!silent)
+			printk(KERN_INFO "VFS: Can't find a valid"
+			       " MSDOS filesystem on dev %s.\n", sb->s_id);
+		return NULL;
+	}
+
+	sb->s_root->d_op = &msdos_dentry_operations;
 	return res;
 }
diff -u --recursive --new-file v2.5.2/linux/fs/namei.c linux/fs/namei.c
--- v2.5.2/linux/fs/namei.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/namei.c	Tue Jan 15 13:53:51 2002
@@ -339,7 +339,7 @@
 		goto loop;
 	if (current->total_link_count >= 40)
 		goto loop;
-	if (current->need_resched) {
+	if (need_resched()) {
 		current->state = TASK_RUNNING;
 		schedule();
 	}
diff -u --recursive --new-file v2.5.2/linux/fs/namespace.c linux/fs/namespace.c
--- v2.5.2/linux/fs/namespace.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/namespace.c	Wed Jan 23 15:32:20 2002
@@ -38,7 +38,7 @@
 	return tmp & hash_mask;
 }
 
-struct vfsmount *alloc_vfsmnt(void)
+struct vfsmount *alloc_vfsmnt(char *name)
 {
 	struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL); 
 	if (mnt) {
@@ -48,6 +48,14 @@
 		INIT_LIST_HEAD(&mnt->mnt_child);
 		INIT_LIST_HEAD(&mnt->mnt_mounts);
 		INIT_LIST_HEAD(&mnt->mnt_list);
+		if (name) {
+			int size = strlen(name)+1;
+			char * newname = kmalloc(size, GFP_KERNEL);
+			if (newname) {
+				memcpy(newname, name, size);
+				mnt->mnt_devname = newname;
+			}
+		}
 	}
 	return mnt;
 }
@@ -59,18 +67,6 @@
 	kmem_cache_free(mnt_cache, mnt);
 }
 
-void set_devname(struct vfsmount *mnt, const char *name)
-{
-	if (name) {
-		int size = strlen(name)+1;
-		char * newname = kmalloc(size, GFP_KERNEL);
-		if (newname) {
-			memcpy(newname, name, size);
-			mnt->mnt_devname = newname;
-		}
-	}
-}
-
 struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
 {
 	struct list_head * head = mount_hashtable + hash(mnt, dentry);
@@ -138,11 +134,10 @@
 clone_mnt(struct vfsmount *old, struct dentry *root)
 {
 	struct super_block *sb = old->mnt_sb;
-	struct vfsmount *mnt = alloc_vfsmnt();
+	struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname);
 
 	if (mnt) {
 		mnt->mnt_flags = old->mnt_flags;
-		set_devname(mnt, old->mnt_devname);
 		atomic_inc(&sb->s_active);
 		mnt->mnt_sb = sb;
 		mnt->mnt_root = dget(root);
diff -u --recursive --new-file v2.5.2/linux/fs/ncpfs/Config.help linux/fs/ncpfs/Config.help
--- v2.5.2/linux/fs/ncpfs/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/fs/ncpfs/Config.help	Fri Jan 25 16:03:57 2002
@@ -0,0 +1,59 @@
+CONFIG_NCPFS_PACKET_SIGNING
+  NCP allows packets to be signed for stronger security. If you want
+  security, say Y.  Normal users can leave it off.  To be able to use
+  packet signing you must use ncpfs > 2.0.12.
+
+CONFIG_NCPFS_IOCTL_LOCKING
+  Allows locking of records on remote volumes.  Say N unless you have
+  special applications which are able to utilize this locking scheme.
+
+CONFIG_NCPFS_STRONG
+  Allows manipulation of files flagged as Delete or Rename Inhibit.
+  To use this feature you must mount volumes with the ncpmount
+  parameter "-s" (ncpfs-2.0.12 and newer).  Say Y unless you are not
+  mounting volumes with -f 444.
+
+CONFIG_NCPFS_NFS_NS
+  Allows you to utilize NFS namespace on NetWare servers.  It brings
+  you case sensitive filenames.  Say Y.  You can disable it at
+  mount-time with the `-N nfs' parameter of ncpmount.
+
+CONFIG_NCPFS_OS2_NS
+  Allows you to utilize OS2/LONG namespace on NetWare servers.
+  Filenames in this namespace are limited to 255 characters, they are
+  case insensitive, and case in names is preserved.  Say Y.  You can
+  disable it at mount time with the -N os2 parameter of ncpmount.
+
+CONFIG_NCPFS_SMALLDOS
+  If you say Y here, every filename on a NetWare server volume using
+  the OS2/LONG namespace and created under DOS or on a volume using
+  DOS namespace will be converted to lowercase characters.
+  Saying N here will give you these filenames in uppercase.
+
+  This is only a cosmetic option since the OS2/LONG namespace is case
+  insensitive. The only major reason for this option is backward
+  compatibility when moving from DOS to OS2/LONG namespace support.
+  Long filenames (created by Win95) will not be affected.
+
+  This option does not solve the problem that filenames appear
+  differently under Linux and under Windows, since Windows does an
+  additional conversions on the client side. You can achieve similar
+  effects by saying Y to "Allow using of Native Language Support"
+  below.
+
+CONFIG_NCPFS_NLS
+  Allows you to use codepages and I/O charsets for file name
+  translation between the server file system and input/output. This
+  may be useful, if you want to access the server with other operating
+  systems, e.g. Windows 95. See also NLS for more Information.
+
+  To select codepages and I/O charsets use ncpfs-2.2.0.13 or newer.
+
+CONFIG_NCPFS_EXTRAS
+  This enables the use of symbolic links and an execute permission
+  bit on NCPFS. The file server need not have long name space or NFS
+  name space loaded for these to work.
+
+  To use the new attributes, it is recommended to use the flags
+  '-f 600 -d 755' on the ncpmount command line.
+
diff -u --recursive --new-file v2.5.2/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.5.2/linux/fs/ncpfs/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/ncpfs/inode.c	Wed Jan 23 15:32:20 2002
@@ -36,8 +36,54 @@
 static void ncp_put_super(struct super_block *);
 static int  ncp_statfs(struct super_block *, struct statfs *);
 
+static kmem_cache_t * ncp_inode_cachep;
+
+static struct inode *ncp_alloc_inode(struct super_block *sb)
+{
+	struct ncp_inode_info *ei;
+	ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void ncp_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		init_MUTEX(&ei->open_sem);
+		inode_init_once(&ei->vfs_inode);
+	}
+}
+ 
+static int init_inodecache(void)
+{
+	ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
+					     sizeof(struct ncp_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (ncp_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(ncp_inode_cachep))
+		printk(KERN_INFO "ncp_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations ncp_sops =
 {
+	alloc_inode:	ncp_alloc_inode,
+	destroy_inode:	ncp_destroy_inode,
 	put_inode:	force_delete,
 	delete_inode:	ncp_delete_inode,
 	put_super:	ncp_put_super,
@@ -61,6 +107,8 @@
 
 #ifdef CONFIG_NCPFS_STRONG
 	NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
+#else
+	NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
 #endif
 	NCP_FINFO(inode)->access = nwinfo->access;
 	NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle;
@@ -216,7 +264,6 @@
 
 	inode = new_inode(sb);
 	if (inode) {
-		init_MUTEX(&NCP_FINFO(inode)->open_sem);
 		atomic_set(&NCP_FINFO(inode)->opened, info->opened);
 
 		inode->i_ino = info->ino;
@@ -707,19 +754,31 @@
 
 static int __init init_ncp_fs(void)
 {
+	int err;
 	DPRINTK("ncpfs: init_module called\n");
 
 #ifdef DEBUG_NCP_MALLOC
 	ncp_malloced = 0;
 	ncp_current_malloced = 0;
 #endif
-	return register_filesystem(&ncp_fs_type);
+	err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&ncp_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_ncp_fs(void)
 {
 	DPRINTK("ncpfs: cleanup_module called\n");
 	unregister_filesystem(&ncp_fs_type);
+	destroy_inodecache();
 #ifdef DEBUG_NCP_MALLOC
 	PRINTK("ncp_malloced: %d\n", ncp_malloced);
 	PRINTK("ncp_current_malloced: %d\n", ncp_current_malloced);
diff -u --recursive --new-file v2.5.2/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.5.2/linux/fs/nfs/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/nfs/inode.c	Mon Jan 21 15:37:32 2002
@@ -45,6 +45,8 @@
 void nfs_zap_caches(struct inode *);
 static void nfs_invalidate_inode(struct inode *);
 
+static struct inode *nfs_alloc_inode(struct super_block *sb);
+static void nfs_destroy_inode(struct inode *);
 static void nfs_read_inode(struct inode *);
 static void nfs_write_inode(struct inode *,int);
 static void nfs_delete_inode(struct inode *);
@@ -55,6 +57,8 @@
 static int  nfs_show_options(struct seq_file *, struct vfsmount *);
 
 static struct super_operations nfs_sops = { 
+	alloc_inode:	nfs_alloc_inode,
+	destroy_inode:	nfs_destroy_inode,
 	read_inode:	nfs_read_inode,
 	write_inode:	nfs_write_inode,
 	delete_inode:	nfs_delete_inode,
@@ -94,26 +98,11 @@
 
 /*
  * The "read_inode" function doesn't actually do anything:
- * the real data is filled in later in nfs_fhget. Here we
- * just mark the cache times invalid, and zero out i_mode
- * (the latter makes "nfs_refresh_inode" do the right thing
- * wrt pipe inodes)
+ * the real data is filled in later in nfs_fhget.
  */
 static void
 nfs_read_inode(struct inode * inode)
 {
-	inode->i_blksize = inode->i_sb->s_blocksize;
-	inode->i_mode = 0;
-	inode->i_rdev = NODEV;
-	/* We can't support UPDATE_ATIME(), since the server will reset it */
-	inode->i_flags |= S_NOATIME;
-	INIT_LIST_HEAD(&inode->u.nfs_i.read);
-	INIT_LIST_HEAD(&inode->u.nfs_i.dirty);
-	INIT_LIST_HEAD(&inode->u.nfs_i.commit);
-	INIT_LIST_HEAD(&inode->u.nfs_i.writeback);
-	NFS_CACHEINV(inode);
-	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
-	NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 }
 
 static void
@@ -623,39 +612,6 @@
 	nfs_zap_caches(inode);
 }
 
-/*
- * Fill in inode information from the fattr.
- */
-static void
-nfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
-{
-	/*
-	 * Check whether the mode has been set, as we only want to
-	 * do this once. (We don't allow inodes to change types.)
-	 */
-	if (inode->i_mode == 0) {
-		NFS_FILEID(inode) = fattr->fileid;
-		NFS_FSID(inode) = fattr->fsid;
-		inode->i_mode = fattr->mode;
-		/* Why so? Because we want revalidate for devices/FIFOs, and
-		 * that's precisely what we have in nfs_file_inode_operations.
-		 */
-		inode->i_op = &nfs_file_inode_operations;
-		if (S_ISREG(inode->i_mode)) {
-			inode->i_fop = &nfs_file_operations;
-			inode->i_data.a_ops = &nfs_file_aops;
-		} else if (S_ISDIR(inode->i_mode)) {
-			inode->i_op = &nfs_dir_inode_operations;
-			inode->i_fop = &nfs_dir_operations;
-		} else if (S_ISLNK(inode->i_mode))
-			inode->i_op = &nfs_symlink_inode_operations;
-		else
-			init_special_inode(inode, inode->i_mode, fattr->rdev);
-		memcpy(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh));
-	}
-	nfs_refresh_inode(inode, fattr);
-}
-
 struct nfs_find_desc {
 	struct nfs_fh		*fh;
 	struct nfs_fattr	*fattr;
@@ -678,7 +634,7 @@
 		return 0;
 	if (NFS_FILEID(inode) != fattr->fileid)
 		return 0;
-	if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0)
+	if (memcmp(NFS_FH(inode), fh, sizeof(struct nfs_fh)) != 0)
 		return 0;
 	/* Force an attribute cache update if inode->i_count == 0 */
 	if (!atomic_read(&inode->i_count))
@@ -700,7 +656,7 @@
 		return 1;
 
 	/* Has the filehandle changed? If so is the old one stale? */
-	if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 &&
+	if (memcmp(NFS_FH(inode), fh, sizeof(struct nfs_fh)) != 0 &&
 	    __nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE)
 		return 1;
 
@@ -749,7 +705,65 @@
 	if (!(inode = iget4(sb, ino, nfs_find_actor, &desc)))
 		goto out_no_inode;
 
-	nfs_fill_inode(inode, fh, fattr);
+	if (NFS_NEW(inode)) {
+		__u64		new_size, new_mtime;
+		loff_t		new_isize;
+		time_t		new_atime;
+
+		/* We can't support UPDATE_ATIME(), since the server will reset it */
+		NFS_FLAGS(inode) &= ~NFS_INO_NEW;
+		NFS_FILEID(inode) = fattr->fileid;
+		NFS_FSID(inode) = fattr->fsid;
+		memcpy(NFS_FH(inode), fh, sizeof(struct nfs_fh));
+		inode->i_flags |= S_NOATIME;
+		inode->i_mode = fattr->mode;
+		/* Why so? Because we want revalidate for devices/FIFOs, and
+		 * that's precisely what we have in nfs_file_inode_operations.
+		 */
+		inode->i_op = &nfs_file_inode_operations;
+		if (S_ISREG(inode->i_mode)) {
+			inode->i_fop = &nfs_file_operations;
+			inode->i_data.a_ops = &nfs_file_aops;
+		} else if (S_ISDIR(inode->i_mode)) {
+			inode->i_op = &nfs_dir_inode_operations;
+			inode->i_fop = &nfs_dir_operations;
+		} else if (S_ISLNK(inode->i_mode))
+			inode->i_op = &nfs_symlink_inode_operations;
+		else
+			init_special_inode(inode, inode->i_mode, fattr->rdev);
+
+		new_mtime = fattr->mtime;
+		new_size = fattr->size;
+		new_isize = nfs_size_to_loff_t(fattr->size);
+		new_atime = nfs_time_to_secs(fattr->atime);
+
+		NFS_READTIME(inode) = jiffies;
+		NFS_CACHE_CTIME(inode) = fattr->ctime;
+		inode->i_ctime = nfs_time_to_secs(fattr->ctime);
+		inode->i_atime = new_atime;
+		NFS_CACHE_MTIME(inode) = new_mtime;
+		inode->i_mtime = nfs_time_to_secs(new_mtime);
+		NFS_CACHE_ISIZE(inode) = new_size;
+		inode->i_size = new_isize;
+		inode->i_mode = fattr->mode;
+		inode->i_nlink = fattr->nlink;
+		inode->i_uid = fattr->uid;
+		inode->i_gid = fattr->gid;
+		if (fattr->valid & NFS_ATTR_FATTR_V3) {
+			/*
+			 * report the blocks in 512byte units
+			 */
+			inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
+			inode->i_blksize = inode->i_sb->s_blocksize;
+		} else {
+			inode->i_blocks = fattr->du.nfs2.blocks;
+			inode->i_blksize = fattr->du.nfs2.blocksize;
+		}
+		NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+		NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
+		memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+	} else
+		nfs_refresh_inode(inode, fattr);
 	dprintk("NFS: __nfs_fhget(%s/%Ld ct=%d)\n",
 		inode->i_sb->s_id,
 		(long long)NFS_FILEID(inode),
@@ -1152,6 +1166,64 @@
 extern int nfs_init_writepagecache(void);
 extern int nfs_destroy_writepagecache(void);
 
+static kmem_cache_t * nfs_inode_cachep;
+
+static struct inode *nfs_alloc_inode(struct super_block *sb)
+{
+	struct nfs_inode *nfsi;
+	nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, SLAB_KERNEL);
+	if (!nfsi)
+		return NULL;
+	nfsi->flags = NFS_INO_NEW;
+	/* do we need the next 4 lines? */
+	nfsi->hash_next = NULL;
+	nfsi->hash_prev = NULL;
+	nfsi->nextscan = 0;
+	nfsi->mm_cred = NULL;
+	return &nfsi->vfs_inode;
+}
+
+static void nfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(nfs_inode_cachep, NFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct nfs_inode *nfsi = (struct nfs_inode *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		inode_init_once(&nfsi->vfs_inode);
+		INIT_LIST_HEAD(&nfsi->read);
+		INIT_LIST_HEAD(&nfsi->dirty);
+		INIT_LIST_HEAD(&nfsi->commit);
+		INIT_LIST_HEAD(&nfsi->writeback);
+		nfsi->nread = 0;
+		nfsi->ndirty = 0;
+		nfsi->ncommit = 0;
+		nfsi->npages = 0;
+	}
+}
+ 
+int nfs_init_inodecache(void)
+{
+	nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
+					     sizeof(struct nfs_inode),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (nfs_inode_cachep == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void nfs_destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(nfs_inode_cachep))
+		printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n");
+}
+
 /*
  * Initialize NFS
  */
@@ -1161,26 +1233,45 @@
 
 	err = nfs_init_nfspagecache();
 	if (err)
-		return err;
+		goto out4;
+
+	err = nfs_init_inodecache();
+	if (err)
+		goto out3;
 
 	err = nfs_init_readpagecache();
 	if (err)
-		return err;
+		goto out2;
 
 	err = nfs_init_writepagecache();
 	if (err)
-		return err;
+		goto out1;
 
 #ifdef CONFIG_PROC_FS
 	rpc_proc_register(&nfs_rpcstat);
 #endif
-        return register_filesystem(&nfs_fs_type);
+        err = register_filesystem(&nfs_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	rpc_proc_unregister("nfs");
+	nfs_destroy_writepagecache();
+out1:
+	nfs_destroy_readpagecache();
+out2:
+	nfs_destroy_inodecache();
+out3:
+	nfs_destroy_nfspagecache();
+out4:
+	return err;
 }
 
 static void __exit exit_nfs_fs(void)
 {
 	nfs_destroy_writepagecache();
 	nfs_destroy_readpagecache();
+	nfs_destroy_inodecache();
 	nfs_destroy_nfspagecache();
 #ifdef CONFIG_PROC_FS
 	rpc_proc_unregister("nfs");
diff -u --recursive --new-file v2.5.2/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.5.2/linux/fs/nfs/read.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/nfs/read.c	Mon Jan 21 15:37:32 2002
@@ -156,10 +156,11 @@
 nfs_mark_request_read(struct nfs_page *req)
 {
 	struct inode *inode = req->wb_inode;
+	struct nfs_inode *nfsi = NFS_I(inode);
 
 	spin_lock(&nfs_wreq_lock);
-	nfs_list_add_request(req, &inode->u.nfs_i.read);
-	inode->u.nfs_i.nread++;
+	nfs_list_add_request(req, &nfsi->read);
+	nfsi->nread++;
 	__nfs_add_lru(&NFS_SERVER(inode)->lru_read, req);
 	spin_unlock(&nfs_wreq_lock);
 }
@@ -167,6 +168,7 @@
 static int
 nfs_readpage_async(struct file *file, struct inode *inode, struct page *page)
 {
+	struct nfs_inode *nfsi = NFS_I(inode);
 	struct nfs_page	*new;
 
 	new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE);
@@ -174,7 +176,7 @@
 		return PTR_ERR(new);
 	nfs_mark_request_read(new);
 
-	if (inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages ||
+	if (nfsi->nread >= NFS_SERVER(inode)->rpages ||
 	    page_index(page) == (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)
 		nfs_pagein_inode(inode, 0, 0);
 	return 0;
@@ -318,13 +320,13 @@
 int
 nfs_scan_lru_read_timeout(struct nfs_server *server, struct list_head *dst)
 {
-	struct inode *inode;
+	struct nfs_inode *nfsi;
 	int npages;
 
 	npages = nfs_scan_lru_timeout(&server->lru_read, dst, server->rpages);
 	if (npages) {
-		inode = nfs_list_entry(dst->next)->wb_inode;
-		inode->u.nfs_i.nread -= npages;
+		nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
+		nfsi->nread -= npages;
 	}
 	return npages;
 }
@@ -341,13 +343,13 @@
 int
 nfs_scan_lru_read(struct nfs_server *server, struct list_head *dst)
 {
-	struct inode *inode;
+	struct nfs_inode *nfsi;
 	int npages;
 
 	npages = nfs_scan_lru(&server->lru_read, dst, server->rpages);
 	if (npages) {
-		inode = nfs_list_entry(dst->next)->wb_inode;
-		inode->u.nfs_i.nread -= npages;
+		nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
+		nfsi->nread -= npages;
 	}
 	return npages;
 }
@@ -365,10 +367,11 @@
 static int
 nfs_scan_read(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
 {
+	struct nfs_inode *nfsi = NFS_I(inode);
 	int	res;
-	res = nfs_scan_list(&inode->u.nfs_i.read, dst, NULL, idx_start, npages);
-	inode->u.nfs_i.nread -= res;
-	if ((inode->u.nfs_i.nread == 0) != list_empty(&inode->u.nfs_i.read))
+	res = nfs_scan_list(&nfsi->read, dst, NULL, idx_start, npages);
+	nfsi->nread -= res;
+	if ((nfsi->nread == 0) != list_empty(&nfsi->read))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.nread.\n");
 	return res;
 }
diff -u --recursive --new-file v2.5.2/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.5.2/linux/fs/nfs/write.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/nfs/write.c	Mon Jan 21 15:37:32 2002
@@ -315,14 +315,15 @@
 static inline void
 nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
 {
+	struct nfs_inode *nfsi = NFS_I(inode);
 	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))
+	if (list_empty(&nfsi->writeback))
 		igrab(inode);
-	inode->u.nfs_i.npages++;
-	list_add(&req->wb_hash, &inode->u.nfs_i.writeback);
+	nfsi->npages++;
+	list_add(&req->wb_hash, &nfsi->writeback);
 	req->wb_count++;
 }
 
@@ -332,6 +333,7 @@
 static inline void
 nfs_inode_remove_request(struct nfs_page *req)
 {
+	struct nfs_inode *nfsi;
 	struct inode *inode;
 	spin_lock(&nfs_wreq_lock);
 	if (list_empty(&req->wb_hash)) {
@@ -343,10 +345,11 @@
 	inode = req->wb_inode;
 	list_del(&req->wb_hash);
 	INIT_LIST_HEAD(&req->wb_hash);
-	inode->u.nfs_i.npages--;
-	if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback))
+	nfsi = NFS_I(inode);
+	nfsi->npages--;
+	if ((nfsi->npages == 0) != list_empty(&nfsi->writeback))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n");
-	if (list_empty(&inode->u.nfs_i.writeback)) {
+	if (list_empty(&nfsi->writeback)) {
 		spin_unlock(&nfs_wreq_lock);
 		iput(inode);
 	} else
@@ -360,9 +363,10 @@
 static inline struct nfs_page *
 _nfs_find_request(struct inode *inode, struct page *page)
 {
+	struct nfs_inode *nfsi = NFS_I(inode);
 	struct list_head	*head, *next;
 
-	head = &inode->u.nfs_i.writeback;
+	head = &nfsi->writeback;
 	next = head->next;
 	while (next != head) {
 		struct nfs_page *req = nfs_inode_wb_entry(next);
@@ -393,10 +397,11 @@
 nfs_mark_request_dirty(struct nfs_page *req)
 {
 	struct inode *inode = req->wb_inode;
+	struct nfs_inode *nfsi = NFS_I(inode);
 
 	spin_lock(&nfs_wreq_lock);
-	nfs_list_add_request(req, &inode->u.nfs_i.dirty);
-	inode->u.nfs_i.ndirty++;
+	nfs_list_add_request(req, &nfsi->dirty);
+	nfsi->ndirty++;
 	__nfs_del_lru(req);
 	__nfs_add_lru(&NFS_SERVER(inode)->lru_dirty, req);
 	spin_unlock(&nfs_wreq_lock);
@@ -409,8 +414,8 @@
 static inline int
 nfs_dirty_request(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_inode;
-	return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty;
+	struct nfs_inode *nfsi = NFS_I(req->wb_inode);
+	return !list_empty(&req->wb_list) && req->wb_list_head == &nfsi->dirty;
 }
 
 #ifdef CONFIG_NFS_V3
@@ -421,10 +426,11 @@
 nfs_mark_request_commit(struct nfs_page *req)
 {
 	struct inode *inode = req->wb_inode;
+	struct nfs_inode *nfsi = NFS_I(inode);
 
 	spin_lock(&nfs_wreq_lock);
-	nfs_list_add_request(req, &inode->u.nfs_i.commit);
-	inode->u.nfs_i.ncommit++;
+	nfs_list_add_request(req, &nfsi->commit);
+	nfsi->ncommit++;
 	__nfs_del_lru(req);
 	__nfs_add_lru(&NFS_SERVER(inode)->lru_commit, req);
 	spin_unlock(&nfs_wreq_lock);
@@ -440,6 +446,7 @@
 static int
 nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages)
 {
+	struct nfs_inode *nfsi = NFS_I(inode);
 	struct list_head	*p, *head;
 	unsigned long		idx_end;
 	unsigned int		res = 0;
@@ -451,7 +458,7 @@
 		idx_end = idx_start + npages - 1;
 
 	spin_lock(&nfs_wreq_lock);
-	head = &inode->u.nfs_i.writeback;
+	head = &nfsi->writeback;
 	p = head->next;
 	while (p != head) {
 		unsigned long pg_idx;
@@ -494,13 +501,13 @@
 int
 nfs_scan_lru_dirty_timeout(struct nfs_server *server, struct list_head *dst)
 {
-	struct inode *inode;
+	struct nfs_inode *nfsi;
 	int npages;
 
 	npages = nfs_scan_lru_timeout(&server->lru_dirty, dst, server->wpages);
 	if (npages) {
-		inode = nfs_list_entry(dst->next)->wb_inode;
-		inode->u.nfs_i.ndirty -= npages;
+		nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
+		nfsi->ndirty -= npages;
 	}
 	return npages;
 }
@@ -517,13 +524,13 @@
 int
 nfs_scan_lru_dirty(struct nfs_server *server, struct list_head *dst)
 {
-	struct inode *inode;
+	struct nfs_inode *nfsi;
 	int npages;
 
 	npages = nfs_scan_lru(&server->lru_dirty, dst, server->wpages);
 	if (npages) {
-		inode = nfs_list_entry(dst->next)->wb_inode;
-		inode->u.nfs_i.ndirty -= npages;
+		nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
+		nfsi->ndirty -= npages;
 	}
 	return npages;
 }
@@ -542,10 +549,11 @@
 static int
 nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
 {
+	struct nfs_inode *nfsi = NFS_I(inode);
 	int	res;
-	res = nfs_scan_list(&inode->u.nfs_i.dirty, dst, file, idx_start, npages);
-	inode->u.nfs_i.ndirty -= res;
-	if ((inode->u.nfs_i.ndirty == 0) != list_empty(&inode->u.nfs_i.dirty))
+	res = nfs_scan_list(&nfsi->dirty, dst, file, idx_start, npages);
+	nfsi->ndirty -= res;
+	if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n");
 	return res;
 }
@@ -565,14 +573,14 @@
 int
 nfs_scan_lru_commit_timeout(struct nfs_server *server, struct list_head *dst)
 {
-	struct inode *inode;
+	struct nfs_inode *nfsi;
 	int npages;
 
 	npages = nfs_scan_lru_timeout(&server->lru_commit, dst, 1);
 	if (npages) {
-		inode = nfs_list_entry(dst->next)->wb_inode;
-		npages += nfs_scan_list(&inode->u.nfs_i.commit, dst, NULL, 0, 0);
-		inode->u.nfs_i.ncommit -= npages;
+		nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
+		npages += nfs_scan_list(&nfsi->commit, dst, NULL, 0, 0);
+		nfsi->ncommit -= npages;
 	}
 	return npages;
 }
@@ -592,14 +600,14 @@
 int
 nfs_scan_lru_commit(struct nfs_server *server, struct list_head *dst)
 {
-	struct inode *inode;
+	struct nfs_inode *nfsi;
 	int npages;
 
 	npages = nfs_scan_lru(&server->lru_commit, dst, 1);
 	if (npages) {
-		inode = nfs_list_entry(dst->next)->wb_inode;
-		npages += nfs_scan_list(&inode->u.nfs_i.commit, dst, NULL, 0, 0);
-		inode->u.nfs_i.ncommit -= npages;
+		nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
+		npages += nfs_scan_list(&nfsi->commit, dst, NULL, 0, 0);
+		nfsi->ncommit -= npages;
 	}
 	return npages;
 }
@@ -618,10 +626,11 @@
 static int
 nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
 {
+	struct nfs_inode *nfsi = NFS_I(inode);
 	int	res;
-	res = nfs_scan_list(&inode->u.nfs_i.commit, dst, file, idx_start, npages);
-	inode->u.nfs_i.ncommit -= res;
-	if ((inode->u.nfs_i.ncommit == 0) != list_empty(&inode->u.nfs_i.commit))
+	res = nfs_scan_list(&nfsi->commit, dst, file, idx_start, npages);
+	nfsi->ncommit -= res;
+	if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
 	return res;
 }
@@ -738,7 +747,7 @@
 {
 	unsigned int	dirty, wpages;
 
-	dirty  = inode->u.nfs_i.ndirty;
+	dirty  = NFS_I(inode)->ndirty;
 	wpages = NFS_SERVER(inode)->wpages;
 #ifdef CONFIG_NFS_V3
 	if (NFS_PROTO(inode)->version == 2) {
@@ -889,6 +898,7 @@
 static int
 nfs_flush_one(struct list_head *head, struct inode *inode, int how)
 {
+	struct nfs_inode *nfsi = NFS_I(inode);
 	struct rpc_clnt 	*clnt = NFS_CLIENT(inode);
 	struct nfs_write_data	*data;
 	struct rpc_task		*task;
@@ -913,7 +923,7 @@
 	if (nfsvers < 3)
 		data->args.stable = NFS_FILE_SYNC;
 	else if (stable) {
-		if (!inode->u.nfs_i.ncommit)
+		if (!nfsi->ncommit)
 			data->args.stable = NFS_FILE_SYNC;
 		else
 			data->args.stable = NFS_DATA_SYNC;
diff -u --recursive --new-file v2.5.2/linux/fs/nfsd/export.c linux/fs/nfsd/export.c
--- v2.5.2/linux/fs/nfsd/export.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/nfsd/export.c	Mon Jan 28 15:11:45 2002
@@ -468,7 +468,7 @@
 		return 0;
 	}
 
-	current->sigpending = 0;
+	current->work.sigpending = 0;
 	want_lock++;
 	while (hash_count || hash_lock) {
 		interruptible_sleep_on(&hash_wait);
diff -u --recursive --new-file v2.5.2/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c
--- v2.5.2/linux/fs/nfsd/nfssvc.c	Wed Oct 17 14:16:34 2001
+++ linux/fs/nfsd/nfssvc.c	Wed Jan 23 15:28:39 2002
@@ -99,7 +99,7 @@
 		if (error < 0)
 			goto failure;
 #endif
-		get_fast_time(&nfssvc_boot);		/* record boot time */
+		do_gettimeofday(&nfssvc_boot);		/* record boot time */
 	} else
 		nfsd_serv->sv_nrthreads++;
 	nrservs -= (nfsd_serv->sv_nrthreads-1);
diff -u --recursive --new-file v2.5.2/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.5.2/linux/fs/nfsd/vfs.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/nfsd/vfs.c	Tue Jan 15 10:52:11 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/fs/nls/Config.help linux/fs/nls/Config.help
--- v2.5.2/linux/fs/nls/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls/Config.help	Fri Jan 25 16:03:58 2002
@@ -0,0 +1,351 @@
+CONFIG_NLS_DEFAULT
+  The default NLS used when mounting file system. Note, that this is
+  the NLS used by your console, not the NLS used by a specific file
+  system (if different) to store data (filenames) on a disk.
+  Currently, the valid values are:
+  big5, cp437, cp737, cp775, cp850, cp852, cp855, cp857, cp860, cp861,
+  cp862, cp863, cp864, cp865, cp866, cp869, cp874, cp932, cp936,
+  cp949, cp950, cp1251, cp1255, euc-jp, euc-kr, gb2312, iso8859-1,
+  iso8859-2, iso8859-3, iso8859-4, iso8859-5, iso8859-6, iso8859-7,
+  iso8859-8, iso8859-9, iso8859-13, iso8859-14, iso8859-15,
+  koi8-r, koi8-ru, koi8-u, sjis, tis-620, utf8.
+  If you specify a wrong value, it will use the built-in NLS;
+  compatible with iso8859-1.
+
+  If unsure, specify it as "iso8859-1".
+
+CONFIG_NLS_CODEPAGE_437
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored
+  in so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage that is used in
+  the United States and parts of Canada. This is recommended.
+
+CONFIG_NLS_CODEPAGE_737
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored
+  in so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage that is used for
+  Greek. If unsure, say N.
+
+CONFIG_NLS_CODEPAGE_775
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored
+  in so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage that is used
+  for the Baltic Rim Languages (Latvian and Lithuanian). If unsure,
+  say N.
+
+CONFIG_NLS_CODEPAGE_850
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage that is used for
+  much of Europe -- United Kingdom, Germany, Spain, Italy, and [add
+  more countries here]. It has some characters useful to many European
+  languages that are not part of the US codepage 437.
+
+  If unsure, say Y.
+
+CONFIG_NLS_CODEPAGE_852
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the Latin 2 codepage used by DOS
+  for much of Central and Eastern Europe. It has all the required
+  characters for these languages: Albanian, Croatian, Czech, English,
+  Finnish, Hungarian, Irish, German, Polish, Romanian, Serbian (Latin
+  transcription), Slovak, Slovenian, and Sorbian.
+
+CONFIG_NLS_CODEPAGE_855
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Cyrillic.
+
+CONFIG_NLS_CODEPAGE_857
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Turkish.
+
+CONFIG_NLS_CODEPAGE_860
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Portuguese.
+
+CONFIG_NLS_CODEPAGE_861
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Icelandic.
+
+CONFIG_NLS_CODEPAGE_862
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Hebrew.
+
+CONFIG_NLS_CODEPAGE_863
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Canadian
+  French.
+
+CONFIG_NLS_CODEPAGE_864
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Arabic.
+
+CONFIG_NLS_CODEPAGE_865
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for the Nordic
+  European countries.
+
+CONFIG_NLS_CODEPAGE_866
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for
+  Cyrillic/Russian.
+
+CONFIG_NLS_CODEPAGE_869
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Greek.
+
+CONFIG_NLS_CODEPAGE_874
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Thai.
+
+CONFIG_NLS_CODEPAGE_1251
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Russian and
+  Bulgarian and Belarusian.
+
+CONFIG_NLS_CODEPAGE_932
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Shift-JIS
+  or EUC-JP. To use EUC-JP, you can use 'euc-jp' as mount option or
+  NLS Default value during kernel configuration, instead of 'cp932'.
+
+CONFIG_NLS_CODEPAGE_936
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Simplified
+  Chinese(GBK).
+
+CONFIG_NLS_CODEPAGE_949
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for UHC.
+
+CONFIG_NLS_CODEPAGE_950
+  The Microsoft FAT file system family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  DOS/Windows partitions correctly. This does apply to the filenames
+  only, not to the file contents. You can include several codepages;
+  say Y here if you want to include the DOS codepage for Traditional
+  Chinese(Big5).
+
+CONFIG_NLS_ISO8859_1
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 1 character
+  set, which covers most West European languages such as Albanian,
+  Catalan, Danish, Dutch, English, Faeroese, Finnish, French, German,
+  Galician, Irish, Icelandic, Italian, Norwegian, Portuguese, Spanish,
+  and Swedish. It is also the default for the US. If unsure, say Y.
+
+CONFIG_NLS_ISO8859_2
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 2 character
+  set, which works for most Latin-written Slavic and Central European
+  languages: Czech, German, Hungarian, Polish, Rumanian, Croatian,
+  Slovak, Slovene.
+
+CONFIG_NLS_ISO8859_3
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 3 character
+  set, which is popular with authors of Esperanto, Galician, Maltese,
+  and Turkish.
+
+CONFIG_NLS_ISO8859_4
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 4 character
+  set which introduces letters for Estonian, Latvian, and
+  Lithuanian. It is an incomplete predecessor of Latin 7.
+
+CONFIG_NLS_ISO8859_5
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for ISO8859-5, a Cyrillic
+  character set with which you can type Bulgarian, Belarusian,
+  Macedonian, Russian, Serbian, and Ukrainian. Note that the charset
+  KOI8-R is preferred in Russia.
+
+CONFIG_NLS_ISO8859_6
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for ISO8859-6, the Arabic
+  character set.
+
+CONFIG_NLS_ISO8859_7
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for ISO8859-7, the Modern
+  Greek character set.
+
+CONFIG_NLS_ISO8859_8
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for ISO8859-8, the Hebrew
+  character set.
+
+CONFIG_NLS_ISO8859_9
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 5 character
+  set, and it replaces the rarely needed Icelandic letters in Latin 1
+  with the Turkish ones. Useful in Turkey.
+
+CONFIG_NLS_ISO8859_13
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 7 character
+  set, which supports modern Baltic languages including Latvian
+  and Lithuanian.
+
+CONFIG_NLS_ISO8859_14
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 8 character
+  set, which adds the last accented vowels for Welsh (aka Cymraeg)
+  (and Manx Gaelic) that were missing in Latin 1.
+  <http://linux.speech.cymru.org/> has further information.
+
+CONFIG_NLS_ISO8859_15
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 9 character
+  set, which covers most West European languages such as Albanian,
+  Catalan, Danish, Dutch, English, Estonian, Faeroese, Finnish,
+  French, German, Galician, Irish, Icelandic, Italian, Norwegian,
+  Portuguese, Spanish, and Swedish. Latin 9 is an update to
+  Latin 1 (ISO 8859-1) that removes a handful of rarely used
+  characters and instead adds support for Estonian, corrects the
+  support for French and Finnish, and adds the new Euro character.
+  If unsure, say Y.
+
+CONFIG_NLS_KOI8_R
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the preferred Russian
+  character set.
+
+CONFIG_NLS_KOI8_U
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the preferred Ukrainian
+  (koi8-u) and Belarusian (koi8-ru) character sets.
+
+CONFIG_NLS_UTF8
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CD-ROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the UTF-8 encoding of
+  the Unicode/ISO9646 universal character set.
+
diff -u --recursive --new-file v2.5.2/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- v2.5.2/linux/fs/ntfs/fs.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/ntfs/fs.c	Mon Jan 28 13:20:35 2002
@@ -68,7 +68,7 @@
 	int error;
 	ntfs_io io;
 	ntfs_attribute *attr;
-	ntfs_inode *ino = NTFS_LINO2NINO(filp->f_dentry->d_inode);
+	ntfs_inode *ino = NTFS_I(filp->f_dentry->d_inode);
 
 	/* Inode is not properly initialized. */
 	if (!ino)
@@ -107,7 +107,7 @@
 {
 	int err;
 	struct inode *vfs_ino = filp->f_dentry->d_inode;
-	ntfs_inode *ntfs_ino = NTFS_LINO2NINO(vfs_ino);
+	ntfs_inode *ntfs_ino = NTFS_I(vfs_ino);
 	ntfs_attribute *data;
 	ntfs_io io;
 	struct ntfs_getuser_update_vm_s param;
@@ -296,7 +296,7 @@
 		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Looking for next "
 				"file using ntfs_getdir_unsorted(), f_pos "
 				"0x%Lx.\n", (loff_t)(cb.ph << 16) | cb.pl);
-		err = ntfs_getdir_unsorted(NTFS_LINO2NINO(dir), &cb.ph, &cb.pl,
+		err = ntfs_getdir_unsorted(NTFS_I(dir), &cb.ph, &cb.pl,
 				ntfs_printcb, &cb);
 	} while (!err && !cb.ret_code && cb.ph < 0x7fff);
 	filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl;
@@ -541,7 +541,7 @@
 	/* ntfs_getdir will place the directory entry into item, and the first
 	 * long long is the MFT record number. */
 	walk.type = BY_NAME;
-	walk.dir = NTFS_LINO2NINO(dir);
+	walk.dir = NTFS_I(dir);
 	walk.result = item;
 	if (ntfs_getdir_byname(&walk))
 		res = iget(dir->i_sb, NTFS_GETU32(item));
@@ -582,8 +582,10 @@
 	}
 	ntfs_debug(DEBUG_OTHER, "ntfs_create %s\n", d->d_name.name);
 	vol = NTFS_INO2VOL(dir);
-	ino = NTFS_LINO2NINO(r);
-	error = ntfs_alloc_file(NTFS_LINO2NINO(dir), ino, (char*)d->d_name.name,
+	ino = NTFS_I(r);
+	ino->u.index.recordsize = 0;
+	ino->u.index.clusters_per_record = 0;
+	error = ntfs_alloc_file(NTFS_I(dir), ino, (char*)d->d_name.name,
 				d->d_name.len);
 	if (error) {
 		ntfs_error("ntfs_alloc_file FAILED: error = %i", error);
@@ -595,7 +597,7 @@
 	error = ntfs_update_inode(ino);
 	if (error)
 		goto fail;
-	error = ntfs_update_inode(NTFS_LINO2NINO(dir));
+	error = ntfs_update_inode(NTFS_I(dir));
 	if (error)
 		goto fail;
 	r->i_uid = vol->uid;
@@ -643,8 +645,8 @@
 	if (!r)
 		goto out;
 	vol = NTFS_INO2VOL(dir);
-	ino = NTFS_LINO2NINO(r);
-	error = ntfs_mkdir(NTFS_LINO2NINO(dir), d->d_name.name, d->d_name.len,
+	ino = NTFS_I(r);
+	error = ntfs_mkdir(NTFS_I(dir), d->d_name.name, d->d_name.len,
 			   ino);
 	if (error)
 		goto out;
@@ -710,9 +712,9 @@
 	case FILE_Mft:
 		if (!vol->mft_ino || ((vol->ino_flags & 1) == 0))
 			goto sys_file_error;
-		ntfs_memcpy(&inode->u.ntfs_i, vol->mft_ino, sizeof(ntfs_inode));
+		ntfs_memcpy(NTFS_I(inode), vol->mft_ino, sizeof(ntfs_inode));
 		ino = vol->mft_ino;
-		vol->mft_ino = &inode->u.ntfs_i;
+		vol->mft_ino = NTFS_I(inode);
 		vol->ino_flags &= ~1;
 		ntfs_free(ino);
 		ino = vol->mft_ino;
@@ -721,9 +723,9 @@
 	case FILE_MftMirr:
 		if (!vol->mftmirr || ((vol->ino_flags & 2) == 0))
 			goto sys_file_error;
-		ntfs_memcpy(&inode->u.ntfs_i, vol->mftmirr, sizeof(ntfs_inode));
+		ntfs_memcpy(NTFS_I(inode), vol->mftmirr, sizeof(ntfs_inode));
 		ino = vol->mftmirr;
-		vol->mftmirr = &inode->u.ntfs_i;
+		vol->mftmirr = NTFS_I(inode);
 		vol->ino_flags &= ~2;
 		ntfs_free(ino);
 		ino = vol->mftmirr;
@@ -732,9 +734,9 @@
 	case FILE_BitMap:
 		if (!vol->bitmap || ((vol->ino_flags & 4) == 0))
 			goto sys_file_error;
-		ntfs_memcpy(&inode->u.ntfs_i, vol->bitmap, sizeof(ntfs_inode));
+		ntfs_memcpy(NTFS_I(inode), vol->bitmap, sizeof(ntfs_inode));
 		ino = vol->bitmap;
-		vol->bitmap = &inode->u.ntfs_i;
+		vol->bitmap = NTFS_I(inode);
 		vol->ino_flags &= ~4;
 		ntfs_free(ino);
 		ino = vol->bitmap;
@@ -746,10 +748,10 @@
 		ntfs_debug(DEBUG_OTHER, "Opening system file %i!\n",
 				inode->i_ino);
 	default:
-		ino = &inode->u.ntfs_i;
-		if (!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode),
-								inode->i_ino))
-		{
+		ino = NTFS_I(inode);
+		ino->u.index.recordsize = 0;
+		ino->u.index.clusters_per_record = 0;
+		if (ntfs_init_inode(ino, NTFS_INO2VOL(inode), inode->i_ino)) {
 			ntfs_debug(DEBUG_OTHER, "NTFS: Error loading inode "
 					"0x%x\n", (unsigned int)inode->i_ino);
 			return;
@@ -803,7 +805,7 @@
 {
 	lock_kernel();
 	ntfs_debug(DEBUG_LINUX, "ntfs_write_inode 0x%x\n", ino->i_ino);
-	ntfs_update_inode(NTFS_LINO2NINO(ino));
+	ntfs_update_inode(NTFS_I(ino));
 	unlock_kernel();
 }
 #endif
@@ -823,7 +825,7 @@
 	case FILE_Mft:
 		if (vol->mft_ino && ((vol->ino_flags & 1) == 0)) {
 			ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
-			ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
+			ntfs_memcpy(ino, NTFS_I(inode), sizeof(ntfs_inode));
 			vol->mft_ino = ino;
 			vol->ino_flags |= 1;
 			goto unl_out;
@@ -832,7 +834,7 @@
 	case FILE_MftMirr:
 		if (vol->mftmirr && ((vol->ino_flags & 2) == 0)) {
 			ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
-			ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
+			ntfs_memcpy(ino, NTFS_I(inode), sizeof(ntfs_inode));
 			vol->mftmirr = ino;
 			vol->ino_flags |= 2;
 			goto unl_out;
@@ -841,7 +843,7 @@
 	case FILE_BitMap:
 		if (vol->bitmap && ((vol->ino_flags & 4) == 0)) {
 			ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
-			ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
+			ntfs_memcpy(ino, NTFS_I(inode), sizeof(ntfs_inode));
 			vol->bitmap = ino;
 			vol->ino_flags |= 4;
 			goto unl_out;
@@ -850,7 +852,7 @@
 	default:
 		/* Nothing. Just clear the inode and exit. */
 	}
-	ntfs_clear_inode(&inode->u.ntfs_i);
+	ntfs_clear_inode(NTFS_I(inode));
 unl_out:
 	unlock_kernel();
 	return;
@@ -914,7 +916,51 @@
 }
 
 /* Define the super block operation that are implemented */
+
+static kmem_cache_t * ntfs_inode_cachep;
+
+static struct inode *__ntfs_alloc_inode(struct super_block *sb)
+{
+	struct ntfs_i *ei;
+	ei = (struct ntfs_i *)kmem_cache_alloc(ntfs_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void ntfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(ntfs_inode_cachep, ntfs_i(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct ntfs_i *ei = (struct ntfs_i *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	ntfs_inode_cachep = kmem_cache_create("ntfs_inode_cache",
+					     sizeof(struct ntfs_i),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (ntfs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(ntfs_inode_cachep))
+		printk(KERN_INFO "ntfs_inode_cache: not all structures were freed\n");
+}
 static struct super_operations ntfs_super_operations = {
+	alloc_inode:	__ntfs_alloc_inode,
+	destroy_inode:	ntfs_destroy_inode,
 	read_inode:	ntfs_read_inode,
 #ifdef CONFIG_NTFS_RW
 	write_inode:	ntfs_write_inode,
@@ -1112,6 +1158,7 @@
 
 static int __init init_ntfs_fs(void)
 {
+	int err;
 	/* Comment this if you trust klogd. There are reasons not to trust it */
 #if defined(DEBUG) && !defined(MODULE)
 	console_verbose();
@@ -1131,8 +1178,18 @@
 			"]\n");
 	SYSCTL(1);
 	ntfs_debug(DEBUG_OTHER, "registering %s\n", ntfs_fs_type.name);
-	/* Add this filesystem to the kernel table of filesystems. */
-	return register_filesystem(&ntfs_fs_type);
+	err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&ntfs_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	SYSCTL(0);
+	return err;
 }
 
 static void __exit exit_ntfs_fs(void)
@@ -1140,6 +1197,7 @@
 	SYSCTL(0);
 	ntfs_debug(DEBUG_OTHER, "unregistering %s\n", ntfs_fs_type.name);
 	unregister_filesystem(&ntfs_fs_type);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/ntfs/macros.h linux/fs/ntfs/macros.h
--- v2.5.2/linux/fs/ntfs/macros.h	Sat Sep  8 12:24:40 2001
+++ linux/fs/ntfs/macros.h	Mon Jan 28 13:20:35 2002
@@ -14,17 +14,14 @@
 #define NTFS_SB(vol)		((struct super_block*)(vol)->sb)
 #define NTFS_SB2VOL(sb)         (&(sb)->u.ntfs_sb)
 #define NTFS_INO2VOL(ino)	(&((ino)->i_sb->u.ntfs_sb))
-#define NTFS_LINO2NINO(ino)     ((struct ntfs_inode_info*)(&((ino)->u.ntfs_i)))
+static inline struct ntfs_i *ntfs_i(struct inode *inode)
+{
+	return list_entry(inode, struct ntfs_i, vfs_inode);
+}
+#define NTFS_I(ino)     (&ntfs_i(ino)->n)
 static inline struct inode *VFS_I(struct ntfs_inode_info *ntfs_ino)
 {
-	struct inode *i = (struct inode*)((char*)ntfs_ino -
-			((char*)&(((struct inode*)NULL)->u.ntfs_i) -
-			(char*)NULL));
-#ifdef DEBUG
-	if ((char*)NTFS_LINO2NINO(i) != (char*)ntfs_ino)
-		BUG();
-#endif
-	return i;
+	return &list_entry(ntfs_ino, struct ntfs_i, n)->vfs_inode;
 }
 
 #define IS_MAGIC(a,b)		(*(int*)(a) == *(int*)(b))
diff -u --recursive --new-file v2.5.2/linux/fs/ntfs/unistr.c linux/fs/ntfs/unistr.c
--- v2.5.2/linux/fs/ntfs/unistr.c	Tue Aug 28 06:57:18 2001
+++ linux/fs/ntfs/unistr.c	Mon Jan 28 13:20:35 2002
@@ -20,6 +20,7 @@
  */
 
 #include <linux/string.h>
+#include <linux/fs.h>
 #include <asm/byteorder.h>
 
 #include "unistr.h"
diff -u --recursive --new-file v2.5.2/linux/fs/open.c linux/fs/open.c
--- v2.5.2/linux/fs/open.c	Fri Oct 12 13:48:42 2001
+++ linux/fs/open.c	Tue Jan 15 11:07:01 2002
@@ -772,6 +772,44 @@
 	return error;
 }
 
+static inline void __put_unused_fd(struct files_struct *files, unsigned int fd)
+{
+	__FD_CLR(fd, files->open_fds);
+	if (fd < files->next_fd)
+		files->next_fd = fd;
+}
+
+void put_unused_fd(unsigned int fd)
+{
+	struct files_struct *files = current->files;
+	write_lock(&files->file_lock);
+	__put_unused_fd(files, fd);
+	write_unlock(&files->file_lock);
+}
+
+/*
+ * Install a file pointer in the fd array.  
+ *
+ * The VFS is full of places where we drop the files lock between
+ * setting the open_fds bitmap and installing the file in the file
+ * array.  At any such point, we are vulnerable to a dup2() race
+ * installing a file in the array before us.  We need to detect this and
+ * fput() the struct file we are about to overwrite in this case.
+ *
+ * It should never happen - if we allow dup2() do it, _really_ bad things
+ * will follow.
+ */
+
+void fd_install(unsigned int fd, struct file * file)
+{
+	struct files_struct *files = current->files;
+	write_lock(&files->file_lock);
+	if (unlikely(files->fd[fd] != NULL))
+		BUG();
+	files->fd[fd] = file;
+	write_unlock(&files->file_lock);
+}
+
 asmlinkage long sys_open(const char * filename, int flags, int mode)
 {
 	char * tmp;
diff -u --recursive --new-file v2.5.2/linux/fs/partitions/Config.help linux/fs/partitions/Config.help
--- v2.5.2/linux/fs/partitions/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/fs/partitions/Config.help	Fri Jan 25 16:03:56 2002
@@ -0,0 +1,144 @@
+CONFIG_PARTITION_ADVANCED
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned under an operating system running on a different
+  architecture than your Linux system.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about foreign partitioning schemes.
+
+  If unsure, say N.
+
+CONFIG_ACORN_PARTITION
+  Support hard disks partitioned under Acorn operating systems.
+
+CONFIG_ACORN_PARTITION_ADFS
+  The Acorn Disc Filing System is the standard file system of the
+  RiscOS operating system which runs on Acorn's ARM-based Risc PC
+  systems and the Acorn Archimedes range of machines.  If you say
+  `Y' here, Linux will support disk partitions created under ADFS.
+
+CONFIG_ACORN_PARTITION_POWERTEC
+  Support reading partition tables created on Acorn machines using
+  the PowerTec SCSI drive.
+
+CONFIG_ACORN_PARTITION_RISCIX
+  Once upon a time, there was a native Unix port for the Acorn series
+  of machines called RISCiX.  If you say 'Y' here, Linux will be able
+  to read disks partitioned under RISCiX.
+
+CONFIG_ACORN_PARTITION_ICS
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned using the ICS interface on Acorn machines.
+
+CONFIG_OSF_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned on an Alpha machine.
+
+CONFIG_MAC_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned on a Macintosh.
+
+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.
+  They are also known as "Dynamic Disks".
+
+  Windows 2000 introduced the concept of Dynamic Disks to get around
+  the limitations of the PC's partitioning scheme.  The Logical Disk
+  Manager allows the user to repartion a disk and create spanned,
+  mirrored, striped or RAID volumes, all without the need for
+  rebooting.
+
+  Normal partitions are now called Basic Disks under Windows 2000 and
+  XP.
+
+  Technical documentation to accompany this driver is available from:
+  <http://linux-ntfs.sf.net/ldm/>.
+
+  If unsure, say N.
+
+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
+  report a bug.
+
+  If unsure, say N.
+
+CONFIG_MSDOS_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned on an x86 PC (not necessarily by DOS).
+
+CONFIG_AMIGA_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned under AmigaOS.
+
+CONFIG_ATARI_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned under the Atari OS.
+
+CONFIG_BSD_DISKLABEL
+  FreeBSD uses its own hard disk partition scheme on your PC. It
+  requires only one entry in the primary partition table of your disk
+  and manages it similarly to DOS extended partitions, putting in its
+  first sector a new partition table in BSD disklabel format. Saying Y
+  here allows you to read these disklabels and further mount FreeBSD
+  partitions from within Linux if you have also said Y to "UFS
+  file system support", above. If you don't know what all this is
+  about, say N.
+
+CONFIG_MINIX_SUBPARTITION
+  Minix 2.0.0/2.0.2 subpartition table support for Linux.
+  Say Y here if you want to mount and use Minix 2.0.0/2.0.2
+  subpartitions.
+
+CONFIG_SUN_PARTITION
+  Like most systems, SunOS uses its own hard disk partition table
+  format, incompatible with all others. Saying Y here allows you to
+  read these partition tables and further mount SunOS partitions from
+  within Linux if you have also said Y to "UFS file system support",
+  above. This is mainly used to carry data from a SPARC under SunOS to
+  your Linux box via a removable medium like magneto-optical or ZIP
+  drives; note however that a good portable way to transport files and
+  directories between unixes (and even other operating systems) is
+  given by the tar program ("man tar" or preferably "info tar"). If
+  you don't know what all this is about, say N.
+
+CONFIG_SOLARIS_X86_PARTITION
+  Like most systems, Solaris x86 uses its own hard disk partition
+  table format, incompatible with all others. Saying Y here allows you
+  to read these partition tables and further mount Solaris x86
+  partitions from within Linux if you have also said Y to "UFS
+  file system support", above.
+
+CONFIG_SGI_PARTITION
+  Say Y here if you would like to be able to read the hard disk
+  partition table format used by SGI machines.
+
+CONFIG_ULTRIX_PARTITION
+  Say Y here if you would like to be able to read the hard disk
+  partition table format used by DEC (now Compaq) Ultrix machines.
+  Otherwise, say N.
+
+CONFIG_IBM_PARTITION
+  Say Y here if you would like to be able to read the hard disk
+  partition table format used by IBM DASD disks operating under CMS.
+  Otherwise, say N.
+
+CONFIG_UNIXWARE_DISKLABEL
+  Like some systems, UnixWare uses its own slice table inside a
+  partition (VTOC - Virtual Table of Contents). Its format is
+  incompatible with all other OSes. Saying Y here allows you to read
+  VTOC and further mount UnixWare partitions read-only from within
+  Linux if you have also said Y to "UFS file system support" or
+  "System V and Coherent file system support", above.
+
+  This is mainly used to carry data from a UnixWare box to your
+  Linux box via a removable medium like magneto-optical, ZIP or
+  removable IDE drives. Note, however, that a good portable way to
+  transport files and directories between unixes (and even other
+  operating systems) is given by the tar program ("man tar" or
+  preferably "info tar").
+
+  If you don't know what all this is about, say N.
+
diff -u --recursive --new-file v2.5.2/linux/fs/partitions/Makefile linux/fs/partitions/Makefile
--- v2.5.2/linux/fs/partitions/Makefile	Thu Jul 26 16:30:04 2001
+++ linux/fs/partitions/Makefile	Tue Jan 15 11:27:47 2002
@@ -9,7 +9,7 @@
 
 O_TARGET := partitions.o
 
-export-objs := check.o ibm.o
+export-objs := check.o ibm.o msdos.o
 
 obj-y := check.o
 
diff -u --recursive --new-file v2.5.2/linux/fs/partitions/msdos.c linux/fs/partitions/msdos.c
--- v2.5.2/linux/fs/partitions/msdos.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/partitions/msdos.c	Tue Jan 15 11:27:47 2002
@@ -29,7 +29,13 @@
 
 #ifdef CONFIG_BLK_DEV_IDE
 #include <linux/ide.h>	/* IDE xlate */
-#endif /* CONFIG_BLK_DEV_IDE */
+#elif defined(CONFIG_BLK_DEV_IDE_MODULE)
+#include <linux/module.h>
+
+int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *);
+EXPORT_SYMBOL(ide_xlate_1024_hook);
+#define ide_xlate_1024 ide_xlate_1024_hook
+#endif
 
 #include <asm/system.h>
 
@@ -468,7 +474,7 @@
  */
 static int handle_ide_mess(struct block_device *bdev)
 {
-#ifdef CONFIG_BLK_DEV_IDE
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	Sector sect;
 	unsigned char *data;
 	kdev_t dev = to_kdev_t(bdev->bd_dev);
@@ -476,6 +482,10 @@
 	int heads = 0;
 	struct partition *p;
 	int i;
+#ifdef CONFIG_BLK_DEV_IDE_MODULE
+	if (!ide_xlate_1024)
+		return 1;
+#endif
 	/*
 	 * The i386 partition handling programs very often
 	 * make partitions end on cylinder boundaries.
@@ -537,7 +547,7 @@
 	/* Flush the cache */
 	invalidate_bdev(bdev, 1);
 	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
 	return 1;
 }
  
diff -u --recursive --new-file v2.5.2/linux/fs/pipe.c linux/fs/pipe.c
--- v2.5.2/linux/fs/pipe.c	Fri Sep 28 18:03:48 2001
+++ linux/fs/pipe.c	Fri Jan 18 16:00:26 2002
@@ -608,16 +608,18 @@
 
 static struct super_block * pipefs_read_super(struct super_block *sb, void *data, int silent)
 {
-	struct inode *root = new_inode(sb);
+	struct inode *root;
+
+	sb->s_blocksize = 1024;
+	sb->s_blocksize_bits = 10;
+	sb->s_magic = PIPEFS_MAGIC;
+	sb->s_op	= &pipefs_ops;
+	root = new_inode(sb);
 	if (!root)
 		return NULL;
 	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
 	root->i_uid = root->i_gid = 0;
 	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
-	sb->s_blocksize = 1024;
-	sb->s_blocksize_bits = 10;
-	sb->s_magic = PIPEFS_MAGIC;
-	sb->s_op	= &pipefs_ops;
 	sb->s_root = d_alloc(NULL, &(const struct qstr) { "pipe:", 5, 0 });
 	if (!sb->s_root) {
 		iput(root);
diff -u --recursive --new-file v2.5.2/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.5.2/linux/fs/proc/array.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/proc/array.c	Tue Jan 15 11:07:01 2002
@@ -70,6 +70,7 @@
 #include <linux/smp.h>
 #include <linux/signal.h>
 #include <linux/highmem.h>
+#include <linux/file.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/fs/proc/generic.c linux/fs/proc/generic.c
--- v2.5.2/linux/fs/proc/generic.c	Fri Sep  7 10:53:59 2001
+++ linux/fs/proc/generic.c	Tue Jan 29 21:15:47 2002
@@ -16,6 +16,7 @@
 #include <linux/stat.h>
 #define __NO_VERSION__
 #include <linux/module.h>
+#include <linux/smp_lock.h>
 #include <asm/bitops.h>
 
 static ssize_t proc_file_read(struct file * file, char * buf,
@@ -140,22 +141,30 @@
 static loff_t
 proc_file_lseek(struct file * file, loff_t offset, int orig)
 {
+    lock_kernel();
+
     switch (orig) {
     case 0:
 	if (offset < 0)
-	    return -EINVAL;    
+	    goto out;
 	file->f_pos = offset;
+	unlock_kernel();
 	return(file->f_pos);
     case 1:
 	if (offset + file->f_pos < 0)
-	    return -EINVAL;    
+	    goto out;
 	file->f_pos += offset;
+	unlock_kernel();
 	return(file->f_pos);
     case 2:
-	return(-EINVAL);
+	goto out;
     default:
-	return(-EINVAL);
+	goto out;
     }
+
+out:
+    unlock_kernel();
+    return -EINVAL;
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/fs/qnx4/bitmap.c linux/fs/qnx4/bitmap.c
--- v2.5.2/linux/fs/qnx4/bitmap.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/qnx4/bitmap.c	Mon Jan 21 15:37:32 2002
@@ -142,13 +142,13 @@
 
 static void qnx4_clear_inode(struct inode *inode)
 {
-	struct qnx4_inode_info *qnx4_ino = &inode->u.qnx4_i;
-
-	memset(qnx4_ino->i_reserved, 0, sizeof qnx4_ino->i_reserved);
-	qnx4_ino->i_size = 0;
-	qnx4_ino->i_num_xtnts = 0;
-	qnx4_ino->i_mode = 0;
-	qnx4_ino->i_status = 0;
+	struct qnx4_inode_entry *qnx4_ino = qnx4_raw_inode(inode);
+	/* What for? */
+	memset(qnx4_ino->di_fname, 0, sizeof qnx4_ino->di_fname);
+	qnx4_ino->di_size = 0;
+	qnx4_ino->di_num_xtnts = 0;
+	qnx4_ino->di_mode = 0;
+	qnx4_ino->di_status = 0;
 }
 
 void qnx4_free_inode(struct inode *inode)
diff -u --recursive --new-file v2.5.2/linux/fs/qnx4/fsync.c linux/fs/qnx4/fsync.c
--- v2.5.2/linux/fs/qnx4/fsync.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/qnx4/fsync.c	Mon Jan 21 15:37:32 2002
@@ -90,7 +90,7 @@
 
 	for (i = 0; i < 7; i++) {
 		rc = sync_block(inode,
-				(unsigned short *) inode->u.qnx4_i.i_first_xtnt.xtnt_blk + i, wait);
+				(unsigned short *) qnx4_raw_inode(inode)->di_first_xtnt.xtnt_blk + i, wait);
 		if (rc > 0)
 			break;
 		if (rc)
diff -u --recursive --new-file v2.5.2/linux/fs/qnx4/inode.c linux/fs/qnx4/inode.c
--- v2.5.2/linux/fs/qnx4/inode.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/qnx4/inode.c	Mon Jan 21 15:37:32 2002
@@ -121,12 +121,16 @@
 
 static struct super_block *qnx4_read_super(struct super_block *, void *, int);
 static void qnx4_put_super(struct super_block *sb);
+static struct inode *qnx4_alloc_inode(struct super_block *sb);
+static void qnx4_destroy_inode(struct inode *inode);
 static void qnx4_read_inode(struct inode *);
 static int qnx4_remount(struct super_block *sb, int *flags, char *data);
 static int qnx4_statfs(struct super_block *, struct statfs *);
 
 static struct super_operations qnx4_sops =
 {
+	alloc_inode:	qnx4_alloc_inode,
+	destroy_inode:	qnx4_destroy_inode,
 	read_inode:	qnx4_read_inode,
 #ifdef CONFIG_QNX4FS_RW
 	write_inode:	qnx4_write_inode,
@@ -227,16 +231,16 @@
 	unsigned long block = 0;
 	struct buffer_head *bh = 0;
 	struct qnx4_xblk *xblk = 0;
-	struct qnx4_inode_info *qnx4_inode = &inode->u.qnx4_i;
-	qnx4_nxtnt_t nxtnt = le16_to_cpu(qnx4_inode->i_num_xtnts);
+	struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode);
+	qnx4_nxtnt_t nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts);
 
-	if ( iblock < le32_to_cpu(qnx4_inode->i_first_xtnt.xtnt_size) ) {
+	if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) {
 		// iblock is in the first extent. This is easy.
-		block = le32_to_cpu(qnx4_inode->i_first_xtnt.xtnt_blk) + iblock - 1;
+		block = le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_blk) + iblock - 1;
 	} else {
 		// iblock is beyond first extent. We have to follow the extent chain.
-		i_xblk = le32_to_cpu(qnx4_inode->i_xblk);
-		offset = iblock - le32_to_cpu(qnx4_inode->i_first_xtnt.xtnt_size);
+		i_xblk = le32_to_cpu(qnx4_inode->di_xblk);
+		offset = iblock - le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size);
 		ix = 0;
 		while ( --nxtnt > 0 ) {
 			if ( ix == 0 ) {
@@ -417,10 +421,12 @@
 {
 	return block_read_full_page(page,qnx4_get_block);
 }
-static int qnx4_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+static int qnx4_prepare_write(struct file *file, struct page *page,
+			      unsigned from, unsigned to)
 {
-	return cont_prepare_write(page,from,to,qnx4_get_block,
-		&page->mapping->host->u.qnx4_i.mmu_private);
+	struct qnx4_inode_info *qnx4_inode = qnx4_i(page->mapping->host);
+	return cont_prepare_write(page, from, to, qnx4_get_block,
+				  &qnx4_inode->mmu_private);
 }
 static int qnx4_bmap(struct address_space *mapping, long block)
 {
@@ -441,6 +447,7 @@
 	struct qnx4_inode_entry *raw_inode;
 	int block, ino;
 	struct super_block *sb = inode->i_sb;
+	struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode);
 
 	ino = inode->i_ino;
 	inode->i_mode = 0;
@@ -472,35 +479,92 @@
 	inode->i_blocks  = le32_to_cpu(raw_inode->di_first_xtnt.xtnt_size);
 	inode->i_blksize = QNX4_DIR_ENTRY_SIZE;
 
-	memcpy(&inode->u.qnx4_i, (struct qnx4_inode_info *) raw_inode, QNX4_DIR_ENTRY_SIZE);
+	memcpy(qnx4_inode, raw_inode, QNX4_DIR_ENTRY_SIZE);
 	if (S_ISREG(inode->i_mode)) {
 		inode->i_op = &qnx4_file_inode_operations;
 		inode->i_fop = &qnx4_file_operations;
 		inode->i_mapping->a_ops = &qnx4_aops;
-		inode->u.qnx4_i.mmu_private = inode->i_size;
+		qnx4_i(inode)->mmu_private = inode->i_size;
 	} else if (S_ISDIR(inode->i_mode)) {
 		inode->i_op = &qnx4_dir_inode_operations;
 		inode->i_fop = &qnx4_dir_operations;
 	} else if (S_ISLNK(inode->i_mode)) {
 		inode->i_op = &page_symlink_inode_operations;
 		inode->i_mapping->a_ops = &qnx4_aops;
-		inode->u.qnx4_i.mmu_private = inode->i_size;
+		qnx4_i(inode)->mmu_private = inode->i_size;
 	} else
 		printk("qnx4: bad inode %d on dev %s\n",ino,sb->s_id);
 	brelse(bh);
 }
 
+static kmem_cache_t *qnx4_inode_cachep;
+
+static struct inode *qnx4_alloc_inode(struct super_block *sb)
+{
+	struct qnx4_inode_info *ei;
+	ei = kmem_cache_alloc(qnx4_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void qnx4_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode));
+}
+
+static void init_once(void *foo, kmem_cache_t * cachep,
+		      unsigned long flags)
+{
+	struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+	qnx4_inode_cachep = kmem_cache_create("qnx4_inode_cache",
+					     sizeof(struct qnx4_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (qnx4_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(qnx4_inode_cachep))
+		printk(KERN_INFO
+		       "qnx4_inode_cache: not all structures were freed\n");
+}
+
 static DECLARE_FSTYPE_DEV(qnx4_fs_type, "qnx4", qnx4_read_super);
 
 static int __init init_qnx4_fs(void)
 {
+	int err;
+
+	err = init_inodecache();
+	if (err)
+		return err;
+
+	err = register_filesystem(&qnx4_fs_type);
+	if (err) {
+		destroy_inodecache();
+		return err;
+	}
+
 	printk("QNX4 filesystem 0.2.2 registered.\n");
-	return register_filesystem(&qnx4_fs_type);
+	return 0;
 }
 
 static void __exit exit_qnx4_fs(void)
 {
 	unregister_filesystem(&qnx4_fs_type);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/read_write.c linux/fs/read_write.c
--- v2.5.2/linux/fs/read_write.c	Sun Aug  5 13:12:41 2001
+++ linux/fs/read_write.c	Tue Jan 29 21:22:41 2002
@@ -28,16 +28,18 @@
 loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
 {
 	long long retval;
+	struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
 
+	down(&inode->i_sem);
 	switch (origin) {
 		case 2:
-			offset += file->f_dentry->d_inode->i_size;
+			offset += inode->i_size;
 			break;
 		case 1:
 			offset += file->f_pos;
 	}
 	retval = -EINVAL;
-	if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
+	if (offset>=0 && offset<=inode->i_sb->s_maxbytes) {
 		if (offset != file->f_pos) {
 			file->f_pos = offset;
 			file->f_reada = 0;
@@ -45,6 +47,7 @@
 		}
 		retval = offset;
 	}
+	up(&inode->i_sem);
 	return retval;
 }
 
@@ -57,6 +60,7 @@
 {
 	long long retval;
 
+	lock_kernel();
 	switch (origin) {
 		case 2:
 			offset += file->f_dentry->d_inode->i_size;
@@ -73,21 +77,18 @@
 		}
 		retval = offset;
 	}
+	unlock_kernel();
 	return retval;
 }
 
 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
 {
 	loff_t (*fn)(struct file *, loff_t, int);
-	loff_t retval;
 
 	fn = default_llseek;
 	if (file->f_op && file->f_op->llseek)
 		fn = file->f_op->llseek;
-	lock_kernel();
-	retval = fn(file, offset, origin);
-	unlock_kernel();
-	return retval;
+	return fn(file, offset, origin);
 }
 
 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/Makefile linux/fs/reiserfs/Makefile
--- v2.5.2/linux/fs/reiserfs/Makefile	Wed Nov 21 09:56:28 2001
+++ linux/fs/reiserfs/Makefile	Tue Jan 29 10:47:05 2002
@@ -9,7 +9,7 @@
 
 O_TARGET := reiserfs.o
 obj-y   := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o super.o prints.o objectid.o \
-lbalance.o ibalance.o stree.o hashes.o buffer2.o tail_conversion.o journal.o resize.o tail_conversion.o version.o item_ops.o ioctl.o procfs.o
+lbalance.o ibalance.o stree.o hashes.o buffer2.o tail_conversion.o journal.o resize.o tail_conversion.o item_ops.o ioctl.o procfs.o
 
 obj-m   := $(O_TARGET)
 
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/bitmap.c linux/fs/reiserfs/bitmap.c
--- v2.5.2/linux/fs/reiserfs/bitmap.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/bitmap.c	Tue Jan 29 10:47:05 2002
@@ -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
@@ -382,16 +402,18 @@
       goto free_and_return ;
     }
     search_start = new_block ;
-    if (search_start >= reiserfs_get_journal_block(s) &&
-        search_start < (reiserfs_get_journal_block(s) + JOURNAL_BLOCK_COUNT)) {
-	reiserfs_warning("vs-4130: reiserfs_new_blocknrs: trying to allocate log block %lu\n",
-			 search_start) ;
-	search_start++ ;
-	amount_needed++ ;
-	continue ;
-    }
-       
 
+
+    /* make sure the block is not of journal or reserved area */
+    if (is_block_in_log_or_reserved_area(s, search_start)) {
+      reiserfs_warning("vs-4130: reiserfs_new_blocknrs: trying to allocate log block %lu\n",
+		       search_start) ;
+      search_start++ ;
+      amount_needed++ ;
+      continue ;
+    }
+    
+    
     reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[i], 1) ;
 
     RFALSE( buffer_locked (SB_AP_BITMAP (s)[i]) || 
@@ -466,6 +488,7 @@
 				unsigned long      * free_blocknrs,
 				unsigned long        search_start)
 {
+  struct reiserfs_inode_info *ei = REISERFS_I(p_s_inode);
   int ret=0, blks_gotten=0;
   unsigned long border = 0;
   unsigned long bstart = 0;
@@ -488,12 +511,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 +521,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
@@ -550,13 +567,13 @@
     }
 
   /* take a block off the prealloc list and return it -Hans */
-  if (p_s_inode->u.reiserfs_i.i_prealloc_count > 0) {
-    p_s_inode->u.reiserfs_i.i_prealloc_count--;
-    *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block++;
+  if (ei->i_prealloc_count > 0) {
+    ei->i_prealloc_count--;
+    *free_blocknrs = ei->i_prealloc_block++;
 
     /* if no more preallocated blocks, remove inode from list */
-    if (! p_s_inode->u.reiserfs_i.i_prealloc_count) {
-      list_del(&p_s_inode->u.reiserfs_i.i_prealloc_list);
+    if (! ei->i_prealloc_count) {
+      list_del_init(&ei->i_prealloc_list);
     }
     
     return ret;
@@ -567,8 +584,8 @@
   /* this uses the last preallocated block as the search_start.  discard
   ** prealloc does not zero out this number.
   */
-  if (search_start <= p_s_inode->u.reiserfs_i.i_prealloc_block) {
-    search_start = p_s_inode->u.reiserfs_i.i_prealloc_block;
+  if (search_start <= ei->i_prealloc_block) {
+    search_start = ei->i_prealloc_block;
   }
   
   /* doing the compare again forces search_start to be >= the border,
@@ -588,6 +605,7 @@
   *free_blocknrs = 0;
   blks = PREALLOCATION_SIZE-1;
   for (blks_gotten=0; blks_gotten<PREALLOCATION_SIZE; blks_gotten++) {
+
     ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
 				   1/*amount_needed*/, 
 				   0/*for root reserved*/,
@@ -611,18 +629,18 @@
     }
 #endif
     if (blks_gotten==0) {
-      p_s_inode->u.reiserfs_i.i_prealloc_block = *free_blocknrs;
+      ei->i_prealloc_block = *free_blocknrs;
     }
     search_start = *free_blocknrs; 
     *free_blocknrs = 0;
   }
-  p_s_inode->u.reiserfs_i.i_prealloc_count = blks;
-  *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block;
-  p_s_inode->u.reiserfs_i.i_prealloc_block++;
+  ei->i_prealloc_count = blks;
+  *free_blocknrs = ei->i_prealloc_block;
+  ei->i_prealloc_block++;
 
   /* if inode has preallocated blocks, link him to list */
-  if (p_s_inode->u.reiserfs_i.i_prealloc_count) {
-    list_add(&p_s_inode->u.reiserfs_i.i_prealloc_list,
+  if (ei->i_prealloc_count) {
+    list_add(&ei->i_prealloc_list,
 	     &SB_JOURNAL(th->t_super)->j_prealloc_list);
   } 
   /* we did actually manage to get 1 block */
@@ -657,42 +675,45 @@
 // analog. You should be able to tell which portion by looking at the
 // ext2 code and comparing. 
 static void __discard_prealloc (struct reiserfs_transaction_handle * th,
-				struct inode * inode)
+				struct reiserfs_inode_info *ei)
 {
-  while (inode->u.reiserfs_i.i_prealloc_count > 0) {
-    reiserfs_free_block(th,inode->u.reiserfs_i.i_prealloc_block);
-    inode->u.reiserfs_i.i_prealloc_block++;
-    inode->u.reiserfs_i.i_prealloc_count --;
+  unsigned long save = ei->i_prealloc_block ;
+  while (ei->i_prealloc_count > 0) {
+    reiserfs_free_prealloc_block(th,ei->i_prealloc_block);
+    ei->i_prealloc_block++;
+    ei->i_prealloc_count --;
   }
-  list_del (&(inode->u.reiserfs_i.i_prealloc_list));
+  ei->i_prealloc_block = save;
+  list_del_init(&(ei->i_prealloc_list));
 }
 
 
 void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th, 
 				struct inode * inode)
 {
+  struct reiserfs_inode_info *ei = REISERFS_I(inode);
 #ifdef CONFIG_REISERFS_CHECK
-  if (inode->u.reiserfs_i.i_prealloc_count < 0)
+  if (ei->i_prealloc_count < 0)
      reiserfs_warning("zam-4001:" __FUNCTION__ ": inode has negative prealloc blocks count.\n");
 #endif  
-    if (inode->u.reiserfs_i.i_prealloc_count > 0) {
-    __discard_prealloc(th, inode);
+    if (ei->i_prealloc_count > 0) {
+    __discard_prealloc(th, ei);
   }
       }
 
 void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
 {
   struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
-  struct inode * inode;
   
   while (!list_empty(plist)) {
-    inode = list_entry(plist->next, struct inode, u.reiserfs_i.i_prealloc_list);
+	struct reiserfs_inode_info *ei;
+	ei = list_entry(plist->next, struct reiserfs_inode_info, i_prealloc_list);
 #ifdef CONFIG_REISERFS_CHECK
-    if (!inode->u.reiserfs_i.i_prealloc_count) {
-      reiserfs_warning("zam-4001:" __FUNCTION__ ": inode is in prealloc list but has no preallocated blocks.\n");
-    }
-#endif    
-    __discard_prealloc(th, inode);
+	if (!ei->i_prealloc_count) {
+		reiserfs_warning("zam-4001:" __FUNCTION__ ": inode is in prealloc list but has no preallocated blocks.\n");
+	}
+#endif
+	__discard_prealloc(th, ei);
     }
 }
 #endif
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/buffer2.c linux/fs/reiserfs/buffer2.c
--- v2.5.2/linux/fs/reiserfs/buffer2.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/buffer2.c	Tue Jan 29 10:47:05 2002
@@ -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
@@ -61,7 +48,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) 
 {
     struct buffer_head  *result;
@@ -73,275 +59,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(struct super_block *sb, int n_block)
-{
-    return sb_getblk(sb, n_block);
-}
-
-#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, n_new_blocknumber);
-  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
-      yield();
-    }
-
-#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, n_new_blocknumber);
-  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 -u --recursive --new-file v2.5.2/linux/fs/reiserfs/dir.c linux/fs/reiserfs/dir.c
--- v2.5.2/linux/fs/reiserfs/dir.c	Tue Oct 30 15:11:34 2001
+++ linux/fs/reiserfs/dir.c	Tue Jan 29 10:47:05 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/fs/reiserfs/do_balan.c linux/fs/reiserfs/do_balan.c
--- v2.5.2/linux/fs/reiserfs/do_balan.c	Fri Nov  9 14:18:25 2001
+++ linux/fs/reiserfs/do_balan.c	Tue Jan 29 10:47:05 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/fs/reiserfs/file.c linux/fs/reiserfs/file.c
--- v2.5.2/linux/fs/reiserfs/file.c	Fri Oct 12 14:20:42 2001
+++ linux/fs/reiserfs/file.c	Tue Jan 29 10:47:10 2002
@@ -33,9 +33,9 @@
 
     /* fast out for when nothing needs to be done */
     if ((atomic_read(&inode->i_count) > 1 ||
-         !inode->u.reiserfs_i.i_pack_on_close || 
+	!(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) || 
          !tail_has_to_be_packed(inode))       && 
-	inode->u.reiserfs_i.i_prealloc_count <= 0) {
+	REISERFS_I(inode)->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 &&
+	(REISERFS_I(inode)->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,30 @@
 	/* 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 ;
+
+	/* fill in hole pointers in the expanding truncate case. */
+        if (attr->ia_size > inode->i_size) {
+	    error = generic_cont_expand(inode, attr->ia_size) ;
+	    if (REISERFS_I(inode)->i_prealloc_count > 0) {
+		struct reiserfs_transaction_handle th ;
+		/* we're changing at most 2 bitmaps, inode + super */
+		journal_begin(&th, inode->i_sb, 4) ;
+		reiserfs_discard_prealloc (&th, inode);
+		journal_end(&th, inode->i_sb, 4) ;
+	    }
+	    if (error)
+	        return error ;
+	}
     }
+
+    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 -u --recursive --new-file v2.5.2/linux/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c
--- v2.5.2/linux/fs/reiserfs/fix_node.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/fix_node.c	Tue Jan 29 10:47:05 2002
@@ -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, *p_n_blocknr);
+    p_s_new_bh = sb_getblk(p_s_sb, *p_n_blocknr);
     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 -u --recursive --new-file v2.5.2/linux/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c
--- v2.5.2/linux/fs/reiserfs/inode.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/inode.c	Tue Jan 29 10:47:10 2002
@@ -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, sector_t 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 */
 	;
@@ -69,12 +73,12 @@
 
 /* take base of inode_key (it comes from inode always) (dirid, objectid) and version from an inode, set
    offset and type of key */
-void make_cpu_key (struct cpu_key * key, const struct inode * inode, loff_t offset,
+void make_cpu_key (struct cpu_key * key, 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);
 }
 
 
@@ -101,9 +105,9 @@
 }
 
 static void add_to_flushlist(struct inode *inode, struct buffer_head *bh) {
-    struct inode *jinode = &(SB_JOURNAL(inode->i_sb)->j_dummy_inode) ;
+    struct list_head *list = &(SB_JOURNAL(inode->i_sb)->j_dirty_buffers) ;
 
-    buffer_insert_inode_queue(bh, jinode) ;
+    buffer_insert_list(bh, list) ;
 }
 
 //
@@ -213,9 +217,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;
 
@@ -267,7 +271,9 @@
 	pathrelse (&path);
         if (p)
             kunmap(bh_result->b_page) ;
-	if ((args & GET_BLOCK_NO_HOLE)) {
+	// We do not return -ENOENT if there is a hole but page is uptodate, because it means
+	// That there is some MMAPED data associated with it that is yet to be written to disk.
+	if ((args & GET_BLOCK_NO_HOLE) && !Page_Uptodate(bh_result->b_page) ) {
 	    return -ENOENT ;
 	}
         return 0 ;
@@ -286,9 +292,13 @@
 	ret = 0 ;
 	if (blocknr) {
 		map_bh(bh_result, inode->i_sb, blocknr);
-	} else if ((args & GET_BLOCK_NO_HOLE)) {
+	} else 
+	    // We do not return -ENOENT if there is a hole but page is uptodate, because it means
+	    // That there is some MMAPED data associated with it that is yet to  be written to disk.
+	    if ((args & GET_BLOCK_NO_HOLE) && !Page_Uptodate(bh_result->b_page) ) {
 	    ret = -ENOENT ;
-	}
+	    }
+
 	pathrelse (&path);
         if (p)
             kunmap(bh_result->b_page) ;
@@ -311,6 +321,16 @@
     */
     if (buffer_uptodate(bh_result)) {
         goto finished ;
+    } else 
+	/*
+	** grab_tail_page can trigger calls to reiserfs_get_block on up to date
+	** pages without any buffers.  If the page is up to date, we don't want
+	** read old data off disk.  Set the up to date bit on the buffer instead
+	** and jump to the end
+	*/
+	    if (Page_Uptodate(bh_result->b_page)) {
+		mark_buffer_uptodate(bh_result, 1);
+		goto finished ;
     }
 
     // read file tail into part of page
@@ -535,7 +555,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();
@@ -559,7 +579,7 @@
 	return ret;
     }
 
-    inode->u.reiserfs_i.i_pack_on_close = 1 ;
+    REISERFS_I(inode)->i_flags |= i_pack_on_close_mask ;
 
     windex = push_journal_writer("reiserfs_get_block") ;
   
@@ -808,8 +828,7 @@
 	/* inserting indirect pointers for a hole can take a 
 	** long time.  reschedule if needed
 	*/
-	if (current->need_resched)
-	    schedule() ;
+	cond_resched();
 
 	retval = search_for_position_by_key (inode->i_sb, &key, &path);
 	if (retval == IO_ERROR) {
@@ -818,7 +837,7 @@
 	}
 	if (retval == POSITION_FOUND) {
 	    reiserfs_warning ("vs-825: reiserfs_get_block: "
-			      "%k should not be found\n", &key);
+			      "%K should not be found\n", &key);
 	    retval = -EEXIST;
 	    if (allocated_block_nr)
 	        reiserfs_free_block (&th, allocated_block_nr);
@@ -869,13 +888,12 @@
     copy_key (INODE_PKEY (inode), &(ih->ih_key));
     inode->i_blksize = PAGE_SIZE;
 
-    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
-
     if (stat_data_v1 (ih)) {
 	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);
@@ -899,7 +917,7 @@
 	}
 
         rdev = sd_v1_rdev(sd);
-	inode->u.reiserfs_i.i_first_direct_byte = sd_v1_first_direct_byte(sd);
+	REISERFS_I(inode)->i_first_direct_byte = sd_v1_first_direct_byte(sd);
     } else {
 	// new stat data found, but object may have old items
 	// (directories and symlinks)
@@ -924,13 +942,18 @@
             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);
+	REISERFS_I(inode)->i_first_direct_byte = 0;
     }
-
+    REISERFS_I(inode)->i_flags = 0;
+    REISERFS_I(inode)->i_prealloc_block = 0;
+    REISERFS_I(inode)->i_prealloc_count = 0;
+    REISERFS_I(inode)->i_trans_id = 0;
+    REISERFS_I(inode)->i_trans_index = 0;
     /* nopack = 0, by default */
-    inode->u.reiserfs_i.nopack = 0;
+    REISERFS_I(inode)->i_flags &= ~i_nopack_mask;
 
     pathrelse (path);
     if (S_ISREG (inode->i_mode)) {
@@ -994,7 +1017,7 @@
         set_sd_v1_blocks(sd_v1, inode->i_blocks );
 
     // Sigh. i_first_direct_byte is back
-    set_sd_v1_first_direct_byte(sd_v1, inode->u.reiserfs_i.i_first_direct_byte);
+    set_sd_v1_first_direct_byte(sd_v1, REISERFS_I(inode)->i_first_direct_byte);
 }
 
 
@@ -1110,7 +1133,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;
@@ -1133,6 +1156,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 */
 
 }
@@ -1157,7 +1204,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;
@@ -1298,26 +1345,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)
 {
@@ -1332,7 +1359,7 @@
    containing "." and ".." entries */
 static int reiserfs_new_directory (struct reiserfs_transaction_handle *th, 
 				   struct item_head * ih, struct path * path,
-				   const struct inode * dir)
+				   struct inode * dir)
 {
     struct super_block * sb = th->t_super;
     char empty_dir [EMPTY_DIR_SIZE];
@@ -1340,20 +1367,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, 
@@ -1389,12 +1416,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);
@@ -1420,7 +1447,7 @@
    directory) or reiserfs_new_symlink (to insert symlink body if new
    object is symlink) or nothing (if new object is regular file) */
 struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th,
-				   const struct inode * dir, int mode, 
+				   struct inode * dir, int mode, 
 				   const char * symname, 
 				   int i_size, /* 0 for regular, EMTRY_DIR_SIZE for dirs,
 						  strlen (symname) for symlinks)*/
@@ -1465,13 +1492,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 */
@@ -1502,14 +1529,25 @@
     inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
     inode->i_size = i_size;
     inode->i_blocks = (inode->i_size + 511) >> 9;
-    inode->u.reiserfs_i.i_first_direct_byte = S_ISLNK(mode) ? 1 : 
+    REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 : 
       U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
 
-    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
+    REISERFS_I(inode)->i_flags = 0;
+    REISERFS_I(inode)->i_prealloc_block = 0;
+    REISERFS_I(inode)->i_prealloc_count = 0;
+    REISERFS_I(inode)->i_trans_id = 0;
+    REISERFS_I(inode)->i_trans_index = 0;
 
-    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
@@ -1521,10 +1559,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) {
@@ -1684,12 +1726,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) ;
@@ -1729,6 +1782,7 @@
     int bytes_copied = 0 ;
     int copy_size ;
 
+    kmap(bh_result->b_page) ;
 start_over:
     lock_kernel() ;
     journal_begin(&th, inode->i_sb, jbegin_count) ;
@@ -1801,10 +1855,8 @@
 
     /* this is where we fill in holes in the file. */
     if (use_get_block) {
-        kmap(bh_result->b_page) ;
 	retval = reiserfs_get_block(inode, block, bh_result, 
 	                            GET_BLOCK_CREATE | GET_BLOCK_NO_ISEM) ;
-        kunmap(bh_result->b_page) ;
 	if (!retval) {
 	    if (!buffer_mapped(bh_result) || bh_result->b_blocknr == 0) {
 	        /* get_block failed to find a mapped unformatted node. */
@@ -1813,6 +1865,7 @@
 	    }
 	}
     }
+    kunmap(bh_result->b_page) ;
     return retval ;
 }
 
@@ -1989,7 +2042,7 @@
     /* we test for O_SYNC here so we can commit the transaction
     ** for any packed tails the file might have had
     */
-    if (f->f_flags & O_SYNC) {
+    if (f && (f->f_flags & O_SYNC)) {
 	lock_kernel() ;
  	reiserfs_commit_for_inode(inode) ;
 	unlock_kernel();
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/ioctl.c linux/fs/reiserfs/ioctl.c
--- v2.5.2/linux/fs/reiserfs/ioctl.c	Sat Sep  8 12:05:32 2001
+++ linux/fs/reiserfs/ioctl.c	Tue Jan 29 10:47:05 2002
@@ -46,7 +46,7 @@
         return -EINVAL ;
     }
     /* ioctl already done */
-    if (inode->u.reiserfs_i.nopack) {
+    if (REISERFS_I(inode)->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;
+	REISERFS_I(inode)->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;
+    REISERFS_I(inode)->i_flags |= i_nopack_mask;
     kunmap(page) ; /* mapped by prepare_write */
 
 out_unlock:
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c
--- v2.5.2/linux/fs/reiserfs/journal.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/journal.c	Tue Jan 29 10:47:10 2002
@@ -92,6 +92,9 @@
 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 journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks);
+static int release_journal_dev( struct super_block *super,
+				struct reiserfs_journal *journal );
 
 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 *)) ;
@@ -670,7 +673,7 @@
   atomic_set(&(jl->j_commit_flushing), 1) ; 
 
 
-  if (jl->j_len > JOURNAL_TRANS_MAX) {
+  if (jl->j_len > SB_JOURNAL_TRANS_MAX(s)) {
     reiserfs_panic(s, "journal-512: flush_commit_list: length is %lu, list number %d\n", jl->j_len, jl - SB_JOURNAL_LIST(s)) ;
     return 0 ;
   }
@@ -684,8 +687,8 @@
 retry:
   count = 0 ;
   for (i = 0 ; atomic_read(&(jl->j_commit_left)) > 1 && i < (jl->j_len + 1) ; i++) {  /* everything but commit_bh */
-    bn = reiserfs_get_journal_block(s) + (jl->j_start+i) % JOURNAL_BLOCK_COUNT;
-    tbh = sb_get_hash_table(s, bn) ;
+    bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + (jl->j_start+i) %  SB_ONDISK_JOURNAL_SIZE(s);
+    tbh = get_hash_table(SB_JOURNAL_DEV(s), bn, s->s_blocksize) ;
 
 /* kill this sanity check */
 if (count > (orig_commit_left + 2)) {
@@ -713,8 +716,8 @@
   if (count > 0) {
     for (i = 0 ; atomic_read(&(jl->j_commit_left)) > 1 && 
                  i < (jl->j_len + 1) ; i++) {  /* everything but commit_bh */
-      bn = reiserfs_get_journal_block(s) + (jl->j_start + i) % JOURNAL_BLOCK_COUNT  ;
-      tbh = sb_get_hash_table(s, bn) ;
+      bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + (jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s) ;
+      tbh = get_hash_table(SB_JOURNAL_DEV(s), bn, s->s_blocksize) ;
 
       wait_on_buffer(tbh) ;
       if (!buffer_uptodate(tbh)) {
@@ -928,7 +931,7 @@
   atomic_set(&(jl->j_flushing), 1) ;
 
   count = 0 ;
-  if (j_len_saved > JOURNAL_TRANS_MAX) {
+  if (j_len_saved > SB_JOURNAL_TRANS_MAX(s)) {
     reiserfs_panic(s, "journal-715: flush_journal_list, length is %lu, list number %d\n", j_len_saved, jl - SB_JOURNAL_LIST(s)) ;
     atomic_dec(&(jl->j_flushing)) ;
     return 0 ;
@@ -1085,7 +1088,7 @@
   ** being flushed
   */
   if (flushall) {
-    update_journal_header_block(s, (jl->j_start + jl->j_len + 2) % JOURNAL_BLOCK_COUNT, jl->j_trans_id) ;
+    update_journal_header_block(s, (jl->j_start + jl->j_len + 2) % SB_ONDISK_JOURNAL_SIZE(s), jl->j_trans_id) ;
   }
   remove_all_from_journal_list(s, jl, 0) ;
   jl->j_len = 0 ;
@@ -1342,6 +1345,7 @@
   wake_up(&reiserfs_commit_thread_wait) ;
   sleep_on(&reiserfs_commit_thread_done) ;
 
+  release_journal_dev( p_s_sb, SB_JOURNAL( p_s_sb ) );
   free_journal_ram(p_s_sb) ;
 
   return 0 ;
@@ -1365,7 +1369,7 @@
 			               struct reiserfs_journal_commit *commit) {
   if (le32_to_cpu(commit->j_trans_id) != le32_to_cpu(desc->j_trans_id) || 
       le32_to_cpu(commit->j_len) != le32_to_cpu(desc->j_len) || 
-      le32_to_cpu(commit->j_len) > JOURNAL_TRANS_MAX || 
+      le32_to_cpu(commit->j_len) > SB_JOURNAL_TRANS_MAX(p_s_sb) || 
       le32_to_cpu(commit->j_len) <= 0 
   ) {
     return 1 ;
@@ -1401,10 +1405,12 @@
 		     *newest_mount_id) ;
       return -1 ;
     }
-    offset = d_bh->b_blocknr - reiserfs_get_journal_block(p_s_sb) ;
+    offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) ;
 
     /* ok, we have a journal description block, lets see if the transaction was valid */
-    c_bh = sb_bread(p_s_sb, reiserfs_get_journal_block(p_s_sb) + ((offset + le32_to_cpu(desc->j_len) + 1) % JOURNAL_BLOCK_COUNT)) ;
+    c_bh = bread(SB_JOURNAL_DEV(p_s_sb), SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+		 ((offset + le32_to_cpu(desc->j_len) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)), 
+		 p_s_sb->s_blocksize) ;
     if (!c_bh)
       return 0 ;
     commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
@@ -1412,7 +1418,7 @@
       reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, 
                      "journal_transaction_is_valid, commit offset %ld had bad "
 		     "time %d or length %d\n", 
-		     c_bh->b_blocknr - reiserfs_get_journal_block(p_s_sb),
+		     c_bh->b_blocknr -  SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
 		     le32_to_cpu(commit->j_trans_id), 
 		     le32_to_cpu(commit->j_len));
       brelse(c_bh) ;
@@ -1426,7 +1432,7 @@
     brelse(c_bh) ;
     reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1006: found valid "
                    "transaction start offset %lu, len %d id %d\n", 
-		   d_bh->b_blocknr - reiserfs_get_journal_block(p_s_sb), 
+		   d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), 
 		   le32_to_cpu(desc->j_len), le32_to_cpu(desc->j_trans_id)) ;
     return 1 ;
   } else {
@@ -1458,19 +1464,19 @@
   unsigned long trans_offset ;
   int i;
 
-  d_bh = sb_bread(p_s_sb, cur_dblock) ;
+  d_bh = bread(SB_JOURNAL_DEV(p_s_sb), cur_dblock, p_s_sb->s_blocksize) ;
   if (!d_bh)
     return 1 ;
   desc = (struct reiserfs_journal_desc *)d_bh->b_data ;
-  trans_offset = d_bh->b_blocknr - reiserfs_get_journal_block(p_s_sb) ;
+  trans_offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) ;
   reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1037: "
                  "journal_read_transaction, offset %lu, len %d mount_id %d\n", 
-		 d_bh->b_blocknr - reiserfs_get_journal_block(p_s_sb), 
+		 d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), 
 		 le32_to_cpu(desc->j_len), le32_to_cpu(desc->j_mount_id)) ;
   if (le32_to_cpu(desc->j_trans_id) < oldest_trans_id) {
     reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1039: "
                    "journal_read_trans skipping because %lu is too old\n", 
-		   cur_dblock - reiserfs_get_journal_block(p_s_sb)) ;
+		   cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)) ;
     brelse(d_bh) ;
     return 1 ;
   }
@@ -1482,7 +1488,9 @@
     brelse(d_bh) ;
     return 1 ;
   }
-  c_bh = sb_bread(p_s_sb, reiserfs_get_journal_block(p_s_sb) + ((trans_offset + le32_to_cpu(desc->j_len) + 1) % JOURNAL_BLOCK_COUNT)) ;
+  c_bh = bread(SB_JOURNAL_DEV(p_s_sb), SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+		((trans_offset + le32_to_cpu(desc->j_len) + 1) % 
+		 SB_ONDISK_JOURNAL_SIZE(p_s_sb)), p_s_sb->s_blocksize) ;
   if (!c_bh) {
     brelse(d_bh) ;
     return 1 ;
@@ -1491,7 +1499,7 @@
   if (journal_compare_desc_commit(p_s_sb, desc, commit)) {
     reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal_read_transaction, "
                    "commit offset %ld had bad time %d or length %d\n", 
-		   c_bh->b_blocknr - reiserfs_get_journal_block(p_s_sb), 
+		   c_bh->b_blocknr -  SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), 
 		   le32_to_cpu(commit->j_trans_id), le32_to_cpu(commit->j_len));
     brelse(c_bh) ;
     brelse(d_bh) ;
@@ -1511,14 +1519,14 @@
   }
   /* get all the buffer heads */
   for(i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) {
-    log_blocks[i] = sb_getblk(p_s_sb, reiserfs_get_journal_block(p_s_sb) + (trans_offset + 1 + i) % JOURNAL_BLOCK_COUNT);
+    log_blocks[i] =  getblk(SB_JOURNAL_DEV(p_s_sb),  SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + (trans_offset + 1 + i) % SB_ONDISK_JOURNAL_SIZE(p_s_sb), p_s_sb->s_blocksize);
     if (i < JOURNAL_TRANS_HALF) {
       real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(desc->j_realblock[i])) ;
     } else {
       real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(commit->j_realblock[i - JOURNAL_TRANS_HALF])) ;
     }
-    if (real_blocks[i]->b_blocknr >= reiserfs_get_journal_block(p_s_sb) &&
-        real_blocks[i]->b_blocknr < (reiserfs_get_journal_block(p_s_sb)+JOURNAL_BLOCK_COUNT)) {
+    /* make sure we don't try to replay onto log or reserved area */
+    if (is_block_in_log_or_reserved_area(p_s_sb, real_blocks[i]->b_blocknr)) {
       reiserfs_warning("journal-1204: REPLAY FAILURE fsck required! Trying to replay onto a log block\n") ;
       brelse_array(log_blocks, i) ;
       brelse_array(real_blocks, i) ;
@@ -1565,13 +1573,13 @@
     }
     brelse(real_blocks[i]) ;
   }
-  cur_dblock = reiserfs_get_journal_block(p_s_sb) + ((trans_offset + le32_to_cpu(desc->j_len) + 2) % JOURNAL_BLOCK_COUNT) ;
+  cur_dblock =  SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + ((trans_offset + le32_to_cpu(desc->j_len) + 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)) ;
   reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1095: setting journal "
                  "start to offset %ld\n", 
-		 cur_dblock - reiserfs_get_journal_block(p_s_sb)) ;
+		 cur_dblock -  SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)) ;
   
   /* init starting values for the first transaction, in case this is the last transaction to be replayed. */
-  SB_JOURNAL(p_s_sb)->j_start = cur_dblock - reiserfs_get_journal_block(p_s_sb) ;
+  SB_JOURNAL(p_s_sb)->j_start = cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) ;
   SB_JOURNAL(p_s_sb)->j_last_flush_trans_id = trans_id ;
   SB_JOURNAL(p_s_sb)->j_trans_id = trans_id + 1;
   brelse(c_bh) ;
@@ -1607,25 +1615,27 @@
   int continue_replay = 1 ;
   int ret ;
 
-  cur_dblock = reiserfs_get_journal_block(p_s_sb) ;
-  printk("reiserfs: checking transaction log (device %s) ...\n", p_s_sb->s_id) ;
+  cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) ;
+  printk("reiserfs: checking transaction log (%s) for (%s)\n",
+	 bdevname(SB_JOURNAL_DEV(p_s_sb)), p_s_sb->s_id) ;
   start = CURRENT_TIME ;
 
   /* step 1, read in the journal header block.  Check the transaction it says 
   ** is the first unflushed, and if that transaction is not valid, 
   ** replay is done
   */
-  SB_JOURNAL(p_s_sb)->j_header_bh = sb_bread(p_s_sb, 
-                                          reiserfs_get_journal_block(p_s_sb) + 
-					  JOURNAL_BLOCK_COUNT) ;
+  SB_JOURNAL(p_s_sb)->j_header_bh = bread (SB_JOURNAL_DEV(p_s_sb),
+					   SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + 
+					   SB_ONDISK_JOURNAL_SIZE(p_s_sb),
+					   p_s_sb->s_blocksize) ;
   if (!SB_JOURNAL(p_s_sb)->j_header_bh) {
     return 1 ;
   }
   jh = (struct reiserfs_journal_header *)(SB_JOURNAL(p_s_sb)->j_header_bh->b_data) ;
   if (le32_to_cpu(jh->j_first_unflushed_offset) >= 0 && 
-      le32_to_cpu(jh->j_first_unflushed_offset) < JOURNAL_BLOCK_COUNT &&
+      le32_to_cpu(jh->j_first_unflushed_offset) < SB_ONDISK_JOURNAL_SIZE(p_s_sb) && 
       le32_to_cpu(jh->j_last_flush_trans_id) > 0) {
-    last_flush_start = reiserfs_get_journal_block(p_s_sb) + 
+    last_flush_start = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + 
                        le32_to_cpu(jh->j_first_unflushed_offset) ;
     last_flush_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) ;
     reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1153: found in "
@@ -1638,7 +1648,7 @@
     ** there is nothing more we can do, and it makes no sense to read 
     ** through the whole log.
     */
-    d_bh = sb_bread(p_s_sb, reiserfs_get_journal_block(p_s_sb) + le32_to_cpu(jh->j_first_unflushed_offset)) ;
+    d_bh = bread(SB_JOURNAL_DEV(p_s_sb), SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + le32_to_cpu(jh->j_first_unflushed_offset), p_s_sb->s_blocksize) ;
     ret = journal_transaction_is_valid(p_s_sb, d_bh, NULL, NULL) ;
     if (!ret) {
       continue_replay = 0 ;
@@ -1657,8 +1667,8 @@
   /* ok, there are transactions that need to be replayed.  start with the first log block, find
   ** all the valid transactions, and pick out the oldest.
   */
-  while(continue_replay && cur_dblock < (reiserfs_get_journal_block(p_s_sb) + JOURNAL_BLOCK_COUNT)) {
-    d_bh = sb_bread(p_s_sb, cur_dblock) ;
+  while(continue_replay && cur_dblock < (SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(p_s_sb))) {
+    d_bh = bread(SB_JOURNAL_DEV(p_s_sb), cur_dblock, p_s_sb->s_blocksize) ;
     ret = journal_transaction_is_valid(p_s_sb, d_bh, &oldest_invalid_trans_id, &newest_mount_id) ;
     if (ret == 1) {
       desc = (struct reiserfs_journal_desc *)d_bh->b_data ;
@@ -1668,7 +1678,7 @@
 	newest_mount_id = le32_to_cpu(desc->j_mount_id) ;
 	reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1179: Setting "
 	               "oldest_start to offset %lu, trans_id %lu\n", 
-		       oldest_start - reiserfs_get_journal_block(p_s_sb), 
+		       oldest_start - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), 
 		       oldest_trans_id) ;
       } else if (oldest_trans_id > le32_to_cpu(desc->j_trans_id)) { 
         /* one we just read was older */
@@ -1676,7 +1686,7 @@
 	oldest_start = d_bh->b_blocknr ;
 	reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1180: Resetting "
 	               "oldest_start to offset %lu, trans_id %lu\n", 
-			oldest_start - reiserfs_get_journal_block(p_s_sb), 
+			oldest_start - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), 
 			oldest_trans_id) ;
       }
       if (newest_mount_id < le32_to_cpu(desc->j_mount_id)) {
@@ -1694,13 +1704,13 @@
   /* 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)  {
     reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1206: Starting replay "
                    "from offset %lu, trans_id %lu\n", 
-		   cur_dblock - reiserfs_get_journal_block(p_s_sb), 
+		   cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), 
 		   oldest_trans_id) ;
 
   }
@@ -1712,8 +1722,10 @@
     } else if (ret != 0) {
       break ;
     }
-    cur_dblock = reiserfs_get_journal_block(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start ;
+    cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start ;
     replay_count++ ;
+   if (cur_dblock == oldest_start)
+        break;
   }
 
   if (oldest_trans_id == 0) {
@@ -1844,7 +1856,7 @@
       break ;
     }
     wake_up(&reiserfs_commit_thread_done) ;
-    interruptible_sleep_on_timeout(&reiserfs_commit_thread_wait, 5) ;
+    interruptible_sleep_on_timeout(&reiserfs_commit_thread_wait, 5 * HZ) ;
   }
   unlock_kernel() ;
   wake_up(&reiserfs_commit_thread_done) ;
@@ -1859,11 +1871,106 @@
   }
 }
 
+static int release_journal_dev( struct super_block *super,
+				struct reiserfs_journal *journal )
+{
+    int result;
+    
+    result = 0;
+	
+    if( journal -> j_dev_bd != NULL ) {
+	result = blkdev_put( journal -> j_dev_bd, BDEV_FS );
+	journal -> j_dev_bd = NULL;
+    }
+    if( journal -> j_dev_file != NULL ) {
+	result = filp_close( journal -> j_dev_file, NULL );
+	journal -> j_dev_file = NULL;
+    }
+    if( result != 0 ) {
+	reiserfs_warning("sh-457: release_journal_dev: Cannot release journal device: %i", result );
+    }
+    return result;
+}
+
+static int journal_init_dev( struct super_block *super, 
+			     struct reiserfs_journal *journal, 
+			     const char *jdev_name )
+{
+	int result;
+	kdev_t jdev;
+
+	result = 0;
+
+	journal -> j_dev_bd = NULL;
+	journal -> j_dev_file = NULL;
+	jdev = SB_JOURNAL_DEV( super ) = 
+      		SB_ONDISK_JOURNAL_DEVICE( super ) ?
+		to_kdev_t(SB_ONDISK_JOURNAL_DEVICE( super )) : super -> s_dev;	
+	/* there is no "jdev" option and journal is on separate device */
+	if( ( !jdev_name || !jdev_name[ 0 ] ) && 
+	    SB_ONDISK_JOURNAL_DEVICE( super ) ) {
+		journal -> j_dev_bd = bdget( kdev_t_to_nr( jdev ) );
+		if( journal -> j_dev_bd )
+			result = blkdev_get( journal -> j_dev_bd, 
+					     FMODE_READ | FMODE_WRITE, 0, 
+					     BDEV_FS );
+		else
+			result = -ENOMEM;
+		if( result != 0 )
+			printk( "sh-458: journal_init_dev: cannot init journal device\n '%s': %i", 
+				kdevname( jdev ), result );
+
+		return result;
+	}
+
+	/* no "jdev" option and journal is on the host device */
+	if( !jdev_name || !jdev_name[ 0 ] )
+		return 0;
+	journal -> j_dev_file = filp_open( jdev_name, 0, 0 );
+	if( !IS_ERR( journal -> j_dev_file ) ) {
+		struct inode *jdev_inode;
+
+		jdev_inode = journal -> j_dev_file -> f_dentry -> d_inode;
+		journal -> j_dev_bd = jdev_inode -> i_bdev;
+		if( !S_ISBLK( jdev_inode -> i_mode ) ) {
+			printk( "journal_init_dev: '%s' is not a block device", jdev_name );
+			result = -ENOTBLK;
+		} else if( journal -> j_dev_file -> f_vfsmnt -> mnt_flags & MNT_NODEV) {
+			printk( "journal_init_dev: Cannot use devices on '%s'", jdev_name );
+			result = -EACCES;
+		} else if( jdev_inode -> i_bdev == NULL ) {
+			printk( "journal_init_dev: bdev unintialized for '%s'", jdev_name );
+			result = -ENOMEM;
+		} else if( ( result = blkdev_get( jdev_inode -> i_bdev, 
+						  FMODE_READ | FMODE_WRITE,
+						  0, BDEV_FS ) ) != 0 ) {
+			printk( "journal_init_dev: Cannot load device '%s': %i", jdev_name,
+			     result );
+		} else
+			/* ok */
+			SB_JOURNAL_DEV( super ) = 
+				to_kdev_t( jdev_inode -> i_bdev -> bd_dev );
+	} else {
+		result = PTR_ERR( journal -> j_dev_file );
+		journal -> j_dev_file = NULL;
+		printk( "journal_init_dev: Cannot open '%s': %i", jdev_name, result );
+	}
+	if( result != 0 ) {
+		release_journal_dev( super, journal );
+	}
+	printk( "journal_init_dev: journal device: %s", kdevname( SB_JOURNAL_DEV( super ) ) );
+	return result;
+}
+
 /*
 ** must be called once on fs mount.  calls journal_read for you
 */
-int journal_init(struct super_block *p_s_sb) {
-  int num_cnodes = JOURNAL_BLOCK_COUNT * 2 ;
+int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_format) {
+    int num_cnodes = SB_ONDISK_JOURNAL_SIZE(p_s_sb) * 2 ;
+    struct buffer_head *bhjh;
+    struct reiserfs_super_block * rs;
+    struct reiserfs_journal_header *jh;
+    struct reiserfs_journal *journal;
 
   if (sizeof(struct reiserfs_journal_commit) != 4096 ||
       sizeof(struct reiserfs_journal_desc) != 4096
@@ -1872,19 +1979,107 @@
         sizeof(struct reiserfs_journal_desc)) ;
     return 1 ;
   }
-  /* sanity check to make sure they don't overflow the journal */
-  if (JOURNAL_BLOCK_COUNT > reiserfs_get_journal_orig_size(p_s_sb)) {
-    printk("journal-1393: current JOURNAL_BLOCK_COUNT (%d) is too big.  This FS was created with a journal size of %lu blocks\n",
-            JOURNAL_BLOCK_COUNT, reiserfs_get_journal_orig_size(p_s_sb)) ;
+
+    journal = SB_JOURNAL(p_s_sb) = vmalloc(sizeof (struct reiserfs_journal)) ;
+    if (!journal) {
+	printk("journal-1256: unable to get memory for journal structure\n") ;
     return 1 ;
   }
-  SB_JOURNAL(p_s_sb) = vmalloc(sizeof (struct reiserfs_journal)) ;
+    memset(journal, 0, sizeof(struct reiserfs_journal)) ;
 
-  if (!SB_JOURNAL(p_s_sb)) {
-    printk("journal-1256: unable to get memory for journal structure\n") ;
+    /* reserved for journal area support */
+    SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) = (old_format ?
+					     REISERFS_OLD_DISK_OFFSET_IN_BYTES / p_s_sb->s_blocksize +
+					     SB_BMAP_NR(p_s_sb) + 1 :
+					     REISERFS_DISK_OFFSET_IN_BYTES / p_s_sb->s_blocksize + 2); 
+    
+    if( journal_init_dev( p_s_sb, journal, j_dev_name ) != 0 ) {
+      printk( "sh-462: unable to initialize jornal device\n");
+      return 1;
+    }
+
+     rs = SB_DISK_SUPER_BLOCK(p_s_sb);
+     
+     /* read journal header */
+     bhjh = bread (SB_JOURNAL_DEV(p_s_sb),
+		   SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(p_s_sb),
+		   SB_BLOCKSIZE(p_s_sb));
+     if (!bhjh) {
+	 printk("sh-459: unable to read  journal header\n") ;
+	 return 1 ;
+     }
+     jh = (struct reiserfs_journal_header *)(bhjh->b_data);
+     
+     /* make sure that journal matches to the super block */
+     if (is_reiserfs_jr(rs) && (jh->jh_journal.jp_journal_magic != sb_jp_journal_magic(rs))) {
+	 char jname[ 32 ];
+	 char fname[ 32 ];
+	 
+	 strcpy( jname, kdevname( SB_JOURNAL_DEV(p_s_sb) ) );
+	 strcpy( fname, kdevname( p_s_sb->s_dev ) );
+	 printk("sh-460: journal header magic %x (device %s) does not match "
+		"to magic found in super block %x (device %s)\n",
+		jh->jh_journal.jp_journal_magic, jname,
+		sb_jp_journal_magic(rs), fname);
+	 brelse (bhjh);
     return 1 ;
   }
-  memset(SB_JOURNAL(p_s_sb), 0, sizeof(struct reiserfs_journal)) ;
+     
+  SB_JOURNAL_TRANS_MAX(p_s_sb)      = le32_to_cpu (jh->jh_journal.jp_journal_trans_max);
+  SB_JOURNAL_MAX_BATCH(p_s_sb)      = le32_to_cpu (jh->jh_journal.jp_journal_max_batch);
+  SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age);
+  SB_JOURNAL_MAX_TRANS_AGE(p_s_sb)  = JOURNAL_MAX_TRANS_AGE;
+
+  if (SB_JOURNAL_TRANS_MAX(p_s_sb)) {
+    /* make sure these parameters are available, assign it if they are not */
+    __u32 initial = SB_JOURNAL_TRANS_MAX(p_s_sb);
+    __u32 ratio = 1;
+    
+    if (p_s_sb->s_blocksize < 4096)
+      ratio = 4096 / p_s_sb->s_blocksize;
+    
+    if (SB_ONDISK_JOURNAL_SIZE(p_s_sb)/SB_JOURNAL_TRANS_MAX(p_s_sb) < JOURNAL_MIN_RATIO)
+      SB_JOURNAL_TRANS_MAX(p_s_sb) = SB_ONDISK_JOURNAL_SIZE(p_s_sb) / JOURNAL_MIN_RATIO;
+    if (SB_JOURNAL_TRANS_MAX(p_s_sb) > JOURNAL_TRANS_MAX_DEFAULT / ratio)
+      SB_JOURNAL_TRANS_MAX(p_s_sb) = JOURNAL_TRANS_MAX_DEFAULT / ratio;
+    if (SB_JOURNAL_TRANS_MAX(p_s_sb) < JOURNAL_TRANS_MIN_DEFAULT / ratio)
+      SB_JOURNAL_TRANS_MAX(p_s_sb) = JOURNAL_TRANS_MIN_DEFAULT / ratio;
+    
+    if (SB_JOURNAL_TRANS_MAX(p_s_sb) != initial)
+      printk ("sh-461: journal_init: wrong transaction max size (%u). Changed to %u\n",
+	      initial, SB_JOURNAL_TRANS_MAX(p_s_sb));
+
+    SB_JOURNAL_MAX_BATCH(p_s_sb) = SB_JOURNAL_TRANS_MAX(p_s_sb)*
+      JOURNAL_MAX_BATCH_DEFAULT/JOURNAL_TRANS_MAX_DEFAULT;
+  }  
+  
+  if (!SB_JOURNAL_TRANS_MAX(p_s_sb)) {
+    /*we have the file system was created by old version of mkreiserfs 
+      so this field contains zero value */
+    SB_JOURNAL_TRANS_MAX(p_s_sb)      = JOURNAL_TRANS_MAX_DEFAULT ;
+    SB_JOURNAL_MAX_BATCH(p_s_sb)      = JOURNAL_MAX_BATCH_DEFAULT ;  
+    SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = JOURNAL_MAX_COMMIT_AGE ;
+    
+    /* for blocksize >= 4096 - max transaction size is 1024. For block size < 4096
+       trans max size is decreased proportionally */
+    if (p_s_sb->s_blocksize < 4096) {
+      SB_JOURNAL_TRANS_MAX(p_s_sb) /= (4096 / p_s_sb->s_blocksize) ;
+      SB_JOURNAL_MAX_BATCH(p_s_sb) = (SB_JOURNAL_TRANS_MAX(p_s_sb)) * 9 / 10 ;
+    }
+  }
+  printk ("Reiserfs journal params: device %s, size %u, "
+	  "journal first block %u, max trans len %u, max batch %u, "
+	  "max commit age %u, max trans age %u\n",
+	  kdevname( SB_JOURNAL_DEV(p_s_sb) ),
+	  SB_ONDISK_JOURNAL_SIZE(p_s_sb),
+	  SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+	  SB_JOURNAL_TRANS_MAX(p_s_sb),
+	  SB_JOURNAL_MAX_BATCH(p_s_sb),
+	  SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb),
+	  SB_JOURNAL_MAX_TRANS_AGE(p_s_sb));
+
+  brelse (bhjh);
+     
 
   SB_JOURNAL(p_s_sb)->j_list_bitmap_index = 0 ;
   SB_JOURNAL_LIST_INDEX(p_s_sb) = -10000 ; /* make sure flush_old_commits does not try to flush a list while replay is on */
@@ -1897,7 +2092,7 @@
   memset(journal_writers, 0, sizeof(char *) * 512) ; /* debug code */
 
   INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ;
-  INIT_LIST_HEAD(&(SB_JOURNAL(p_s_sb)->j_dummy_inode.i_dirty_buffers)) ;
+  INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_dirty_buffers) ;
   reiserfs_allocate_list_bitmaps(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_bitmap, 
                                  SB_BMAP_NR(p_s_sb)) ;
   allocate_bitmap_nodes(p_s_sb) ;
@@ -1948,6 +2143,7 @@
                   CLONE_FS | CLONE_FILES | CLONE_VM) ;
   }
   return 0 ;
+
 }
 
 /*
@@ -1960,10 +2156,10 @@
   if (reiserfs_dont_log(th->t_super)) 
     return 0 ;
   if ( SB_JOURNAL(th->t_super)->j_must_wait > 0 ||
-       (SB_JOURNAL(th->t_super)->j_len_alloc + new_alloc) >= JOURNAL_MAX_BATCH || 
+       (SB_JOURNAL(th->t_super)->j_len_alloc + new_alloc) >= SB_JOURNAL_MAX_BATCH(th->t_super) || 
        atomic_read(&(SB_JOURNAL(th->t_super)->j_jlock)) ||
-      (now - SB_JOURNAL(th->t_super)->j_trans_start_time) > JOURNAL_MAX_TRANS_AGE ||
-       SB_JOURNAL(th->t_super)->j_cnode_free < (JOURNAL_TRANS_MAX * 3)) { 
+      (now - SB_JOURNAL(th->t_super)->j_trans_start_time) > SB_JOURNAL_MAX_TRANS_AGE(th->t_super) ||
+       SB_JOURNAL(th->t_super)->j_cnode_free < (SB_JOURNAL_TRANS_MAX(th->t_super) * 3)) { 
     return 1 ;
   }
   return 0 ;
@@ -2030,13 +2226,12 @@
   ** we don't sleep if there aren't other writers
   */
 
-
   if (  (!join && SB_JOURNAL(p_s_sb)->j_must_wait > 0) ||
-     ( !join && (SB_JOURNAL(p_s_sb)->j_len_alloc + nblocks + 2) >= JOURNAL_MAX_BATCH) || 
+     ( !join && (SB_JOURNAL(p_s_sb)->j_len_alloc + nblocks + 2) >= SB_JOURNAL_MAX_BATCH(p_s_sb)) || 
      (!join && atomic_read(&(SB_JOURNAL(p_s_sb)->j_wcount)) > 0 && SB_JOURNAL(p_s_sb)->j_trans_start_time > 0 && 
-      (now - SB_JOURNAL(p_s_sb)->j_trans_start_time) > JOURNAL_MAX_TRANS_AGE) ||
+      (now - SB_JOURNAL(p_s_sb)->j_trans_start_time) > SB_JOURNAL_MAX_TRANS_AGE(p_s_sb)) ||
      (!join && atomic_read(&(SB_JOURNAL(p_s_sb)->j_jlock)) ) ||
-     (!join && SB_JOURNAL(p_s_sb)->j_cnode_free < (JOURNAL_TRANS_MAX * 3))) {
+     (!join && SB_JOURNAL(p_s_sb)->j_cnode_free < (SB_JOURNAL_TRANS_MAX(p_s_sb) * 3))) {
 
     unlock_journal(p_s_sb) ; /* allow others to finish this transaction */
 
@@ -2080,7 +2275,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) ;
 }
 
@@ -2146,7 +2341,7 @@
   /* this error means I've screwed up, and we've overflowed the transaction.  
   ** Nothing can be done here, except make the FS readonly or panic.
   */ 
-  if (SB_JOURNAL(p_s_sb)->j_len >= JOURNAL_TRANS_MAX) { 
+  if (SB_JOURNAL(p_s_sb)->j_len >= SB_JOURNAL_TRANS_MAX(p_s_sb)) { 
     reiserfs_panic(th->t_super, "journal-1413: journal_mark_dirty: j_len (%lu) is too big\n", SB_JOURNAL(p_s_sb)->j_len) ;
   }
 
@@ -2235,7 +2430,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;
@@ -2333,20 +2528,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 ;
 }
 
@@ -2396,7 +2577,7 @@
   /* starting with oldest, loop until we get to the start */
   i = (SB_JOURNAL_LIST_INDEX(p_s_sb) + 1) % JOURNAL_LIST_COUNT ;
   while(i != start) {
-    if (SB_JOURNAL_LIST(p_s_sb)[i].j_len > 0 && ((now - SB_JOURNAL_LIST(p_s_sb)[i].j_timestamp) > JOURNAL_MAX_COMMIT_AGE ||
+    if (SB_JOURNAL_LIST(p_s_sb)[i].j_len > 0 && ((now - SB_JOURNAL_LIST(p_s_sb)[i].j_timestamp) > SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) ||
        immediate)) {
       /* we have to check again to be sure the current transaction did not change */
       if (i != SB_JOURNAL_LIST_INDEX(p_s_sb))  {
@@ -2412,7 +2593,7 @@
   if (!immediate && atomic_read(&(SB_JOURNAL(p_s_sb)->j_wcount)) <= 0 &&  
      SB_JOURNAL(p_s_sb)->j_trans_start_time > 0 && 
      SB_JOURNAL(p_s_sb)->j_len > 0 && 
-     (now - SB_JOURNAL(p_s_sb)->j_trans_start_time) > JOURNAL_MAX_TRANS_AGE) {
+     (now - SB_JOURNAL(p_s_sb)->j_trans_start_time) > SB_JOURNAL_MAX_TRANS_AGE(p_s_sb)) {
     journal_join(&th, p_s_sb, 1) ;
     reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
     journal_mark_dirty(&th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
@@ -2504,21 +2685,21 @@
 
   /* deal with old transactions where we are the last writers */
   now = CURRENT_TIME ;
-  if ((now - SB_JOURNAL(p_s_sb)->j_trans_start_time) > JOURNAL_MAX_TRANS_AGE) {
+  if ((now - SB_JOURNAL(p_s_sb)->j_trans_start_time) > SB_JOURNAL_MAX_TRANS_AGE(p_s_sb)) {
     commit_now = 1 ;
     SB_JOURNAL(p_s_sb)->j_next_async_flush = 1 ;
   }
   /* don't batch when someone is waiting on j_join_wait */
   /* don't batch when syncing the commit or flushing the whole trans */
   if (!(SB_JOURNAL(p_s_sb)->j_must_wait > 0) && !(atomic_read(&(SB_JOURNAL(p_s_sb)->j_jlock))) && !flush && !commit_now && 
-      (SB_JOURNAL(p_s_sb)->j_len < JOURNAL_MAX_BATCH)  && 
-      SB_JOURNAL(p_s_sb)->j_len_alloc < JOURNAL_MAX_BATCH && SB_JOURNAL(p_s_sb)->j_cnode_free > (JOURNAL_TRANS_MAX * 3)) {
+      (SB_JOURNAL(p_s_sb)->j_len < SB_JOURNAL_MAX_BATCH(p_s_sb))  && 
+      SB_JOURNAL(p_s_sb)->j_len_alloc < SB_JOURNAL_MAX_BATCH(p_s_sb) && SB_JOURNAL(p_s_sb)->j_cnode_free > (SB_JOURNAL_TRANS_MAX(p_s_sb) * 3)) {
     SB_JOURNAL(p_s_sb)->j_bcount++ ;
     unlock_journal(p_s_sb) ;
     return 0 ;
   }
 
-  if (SB_JOURNAL(p_s_sb)->j_start > JOURNAL_BLOCK_COUNT) {
+  if (SB_JOURNAL(p_s_sb)->j_start > SB_ONDISK_JOURNAL_SIZE(p_s_sb)) {
     reiserfs_panic(p_s_sb, "journal-003: journal_end: j_start (%ld) is too high\n", SB_JOURNAL(p_s_sb)->j_start) ;
   }
   return 1 ;
@@ -2613,14 +2794,14 @@
 
 void reiserfs_update_inode_transaction(struct inode *inode) {
   
-  inode->u.reiserfs_i.i_trans_index = SB_JOURNAL_LIST_INDEX(inode->i_sb);
+  REISERFS_I(inode)->i_trans_index = SB_JOURNAL_LIST_INDEX(inode->i_sb);
 
-  inode->u.reiserfs_i.i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
+  REISERFS_I(inode)->i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
 }
 
 static int reiserfs_inode_in_this_transaction(struct inode *inode) {
-  if (inode->u.reiserfs_i.i_trans_id == SB_JOURNAL(inode->i_sb)->j_trans_id || 
-      inode->u.reiserfs_i.i_trans_id == 0) {
+  if (REISERFS_I(inode)->i_trans_id == SB_JOURNAL(inode->i_sb)->j_trans_id || 
+      REISERFS_I(inode)->i_trans_id == 0) {
     return 1; 
   } 
   return 0 ;
@@ -2631,14 +2812,14 @@
   struct reiserfs_transaction_handle th ;
   struct super_block *sb = inode->i_sb ;
 
-  jl = SB_JOURNAL_LIST(sb) + inode->u.reiserfs_i.i_trans_index ;
+  jl = SB_JOURNAL_LIST(sb) + REISERFS_I(inode)->i_trans_index ;
 
   /* is it from the current transaction, or from an unknown transaction? */
   if (reiserfs_inode_in_this_transaction(inode)) {
     journal_join(&th, sb, 1) ;
     reiserfs_update_inode_transaction(inode) ;
     journal_end_sync(&th, sb, 1) ;
-  } else if (jl->j_trans_id == inode->u.reiserfs_i.i_trans_id) {
+  } else if (jl->j_trans_id == REISERFS_I(inode)->i_trans_id) {
     flush_commit_list(sb, jl, 1) ;
   }
   /* if the transaction id does not match, this list is long since flushed
@@ -2760,7 +2941,7 @@
   
   rs = SB_DISK_SUPER_BLOCK(p_s_sb) ;
   /* setup description block */
-  d_bh = sb_getblk(p_s_sb, reiserfs_get_journal_block(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start) ; 
+  d_bh = getblk(SB_JOURNAL_DEV(p_s_sb), SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start, p_s_sb->s_blocksize) ; 
   mark_buffer_uptodate(d_bh, 1) ;
   desc = (struct reiserfs_journal_desc *)(d_bh)->b_data ;
   memset(desc, 0, sizeof(struct reiserfs_journal_desc)) ;
@@ -2768,8 +2949,9 @@
   desc->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ;
 
   /* setup commit block.  Don't write (keep it clean too) this one until after everyone else is written */
-  c_bh = sb_getblk(p_s_sb,  reiserfs_get_journal_block(p_s_sb) + 
-  				        ((SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL(p_s_sb)->j_len + 1) % JOURNAL_BLOCK_COUNT)) ;
+  c_bh =  getblk(SB_JOURNAL_DEV(p_s_sb), SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + 
+		 ((SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL(p_s_sb)->j_len + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)), 
+		 p_s_sb->s_blocksize) ;
   commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
   memset(commit, 0, sizeof(struct reiserfs_journal_commit)) ;
   commit->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ;
@@ -2812,8 +2994,10 @@
         last_cn->next = jl_cn ;
       }
       last_cn = jl_cn ;
-      if (cn->bh->b_blocknr >= reiserfs_get_journal_block(p_s_sb) &&
-          cn->bh->b_blocknr < (reiserfs_get_journal_block(p_s_sb) + JOURNAL_BLOCK_COUNT)) {
+      /* make sure the block we are trying to log is not a block 
+         of journal or reserved area */
+
+      if (is_block_in_log_or_reserved_area(p_s_sb, cn->bh->b_blocknr)) {
         reiserfs_panic(p_s_sb, "journal-2332: Trying to log block %lu, which is a log block\n", cn->bh->b_blocknr) ;
       }
       jl_cn->blocknr = cn->bh->b_blocknr ; 
@@ -2857,8 +3041,9 @@
     /* copy all the real blocks into log area.  dirty log blocks */
     if (test_bit(BH_JDirty, &cn->bh->b_state)) {
       struct buffer_head *tmp_bh ;
-      tmp_bh = sb_getblk(p_s_sb, reiserfs_get_journal_block(p_s_sb) + 
-		     ((cur_write_start + jindex) % JOURNAL_BLOCK_COUNT)) ;
+      tmp_bh =  getblk(SB_JOURNAL_DEV(p_s_sb), SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + 
+		       ((cur_write_start + jindex) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)), 
+		       p_s_sb->s_blocksize) ;
       mark_buffer_uptodate(tmp_bh, 1) ;
       memcpy(tmp_bh->b_data, cn->bh->b_data, cn->bh->b_size) ;  
       jindex++ ;
@@ -2902,7 +3087,7 @@
   SB_JOURNAL_LIST_INDEX(p_s_sb) = jindex ;
 
   /* write any buffers that must hit disk before this commit is done */
-  fsync_inode_buffers(&(SB_JOURNAL(p_s_sb)->j_dummy_inode)) ;
+  fsync_buffers_list(&(SB_JOURNAL(p_s_sb)->j_dirty_buffers)) ;
 
   /* honor the flush and async wishes from the caller */
   if (flush) {
@@ -2919,7 +3104,7 @@
 
   /* reset journal values for the next transaction */
   old_start = SB_JOURNAL(p_s_sb)->j_start ;
-  SB_JOURNAL(p_s_sb)->j_start = (SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL(p_s_sb)->j_len + 2) % JOURNAL_BLOCK_COUNT;
+  SB_JOURNAL(p_s_sb)->j_start = (SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL(p_s_sb)->j_len + 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb);
   atomic_set(&(SB_JOURNAL(p_s_sb)->j_wcount), 0) ;
   SB_JOURNAL(p_s_sb)->j_bcount = 0 ;
   SB_JOURNAL(p_s_sb)->j_last = NULL ;
@@ -2940,12 +3125,12 @@
   for (i = 0 ; i < JOURNAL_LIST_COUNT ; i++) {
     jindex = i ;
     if (SB_JOURNAL_LIST(p_s_sb)[jindex].j_len > 0 && SB_JOURNAL(p_s_sb)->j_start <= SB_JOURNAL_LIST(p_s_sb)[jindex].j_start) {
-      if ((SB_JOURNAL(p_s_sb)->j_start + JOURNAL_TRANS_MAX + 1) >= SB_JOURNAL_LIST(p_s_sb)[jindex].j_start) {
+      if ((SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL_TRANS_MAX(p_s_sb) + 1) >= SB_JOURNAL_LIST(p_s_sb)[jindex].j_start) {
 	flush_journal_list(p_s_sb, SB_JOURNAL_LIST(p_s_sb) + jindex, 1) ; 
       }
     } else if (SB_JOURNAL_LIST(p_s_sb)[jindex].j_len > 0 && 
-              (SB_JOURNAL(p_s_sb)->j_start + JOURNAL_TRANS_MAX + 1) > JOURNAL_BLOCK_COUNT) {
-      if (((SB_JOURNAL(p_s_sb)->j_start + JOURNAL_TRANS_MAX + 1) % JOURNAL_BLOCK_COUNT) >= 
+              (SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL_TRANS_MAX(p_s_sb) + 1) > SB_ONDISK_JOURNAL_SIZE(p_s_sb)) {
+      if (((SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL_TRANS_MAX(p_s_sb) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)) >= 
             SB_JOURNAL_LIST(p_s_sb)[jindex].j_start) {
 	flush_journal_list(p_s_sb, SB_JOURNAL_LIST(p_s_sb) + jindex, 1 ) ; 
       }
@@ -2953,7 +3138,7 @@
     /* this check should always be run, to send old lists to disk */
     if (SB_JOURNAL_LIST(p_s_sb)[jindex].j_len > 0 && 
               SB_JOURNAL_LIST(p_s_sb)[jindex].j_timestamp < 
-	      (CURRENT_TIME - (JOURNAL_MAX_TRANS_AGE * 4))) {
+	      (CURRENT_TIME - (SB_JOURNAL_MAX_TRANS_AGE(p_s_sb) * 4))) {
 	flush_journal_list(p_s_sb, SB_JOURNAL_LIST(p_s_sb) + jindex, 1 ) ; 
     }
   }
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/lbalance.c linux/fs/reiserfs/lbalance.c
--- v2.5.2/linux/fs/reiserfs/lbalance.c	Tue Oct 30 15:11:34 2001
+++ linux/fs/reiserfs/lbalance.c	Tue Jan 29 10:47:05 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/fs/reiserfs/namei.c linux/fs/reiserfs/namei.c
--- v2.5.2/linux/fs/reiserfs/namei.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/namei.c	Tue Jan 29 10:47:05 2002
@@ -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));
@@ -320,9 +309,10 @@
 
     while (1) {
 	retval = search_by_entry_key (dir->i_sb, &key_to_search, path_to_entry, de);
-	if (retval == IO_ERROR)
-	    // FIXME: still has to be dealt with
-	    reiserfs_panic (dir->i_sb, "zam-7001: io error in " __FUNCTION__ "\n");
+	if (retval == IO_ERROR) {
+	    reiserfs_warning ("zam-7001: io error in " __FUNCTION__ "\n");
+	    return IO_ERROR;
+	}
 
 	/* compare names for all entries having given hash value */
 	retval = linear_search_in_dir_item (&key_to_search, de, name, namelen);
@@ -347,7 +337,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 +363,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 +507,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 +563,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 +618,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 +697,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 +754,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 +780,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 +788,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 +804,6 @@
 	retval = -ENOENT;
 	goto end_unlink;
     }
-    inode = dentry->d_inode;
 
     reiserfs_update_inode_transaction(inode) ;
     reiserfs_update_inode_transaction(dir) ;
@@ -834,6 +834,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 +859,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;
@@ -872,7 +876,7 @@
     }
 
     item_len = ROUND_UP (strlen (symname));
-    if (item_len > MAX_ITEM_LEN (dir->i_sb->s_blocksize)) {
+    if (item_len > MAX_DIRECT_ITEM_LEN (dir->i_sb->s_blocksize)) {
 	iput(inode) ;
 	return -ENAMETOOLONG;
     }
@@ -932,7 +936,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,21 +1036,26 @@
  * 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);
     INITIALIZE_PATH (new_entry_path);
     INITIALIZE_PATH (dot_dot_entry_path);
-    struct item_head new_entry_ih, old_entry_ih ;
+    struct item_head new_entry_ih, old_entry_ih, dot_dot_ih ;
     struct reiserfs_dir_entry old_de, new_de, dot_dot_de;
     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 +1105,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) ;
@@ -1123,6 +1132,8 @@
 
 	copy_item_head(&old_entry_ih, get_ih(&old_entry_path)) ;
 
+	reiserfs_prepare_for_journal(old_inode->i_sb, old_de.de_bh, 1) ;
+
 	// look for new name by reiserfs_find_entry
 	new_de.de_gen_number_bit_string = 0;
 	retval = reiserfs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, 
@@ -1137,6 +1148,7 @@
 	if (S_ISDIR(old_inode->i_mode)) {
 	    if (search_by_entry_key (new_dir->i_sb, &dot_dot_de.de_entry_key, &dot_dot_entry_path, &dot_dot_de) != NAME_FOUND)
 		BUG ();
+	    copy_item_head(&dot_dot_ih, get_ih(&dot_dot_entry_path)) ;
 	    // node containing ".." gets into transaction
 	    reiserfs_prepare_for_journal(old_inode->i_sb, dot_dot_de.de_bh, 1) ;
 	}
@@ -1153,28 +1165,32 @@
 	** of the above checks could have scheduled.  We have to be
 	** sure our items haven't been shifted by another process.
 	*/
-	if (!entry_points_to_object(new_dentry->d_name.name, 
+	if (item_moved(&new_entry_ih, &new_entry_path) ||
+	    !entry_points_to_object(new_dentry->d_name.name, 
 	                            new_dentry->d_name.len,
 				    &new_de, new_inode) ||
-	    item_moved(&new_entry_ih, &new_entry_path) ||
 	    item_moved(&old_entry_ih, &old_entry_path) || 
 	    !entry_points_to_object (old_dentry->d_name.name, 
 	                             old_dentry->d_name.len,
 				     &old_de, old_inode)) {
 	    reiserfs_restore_prepared_buffer (old_inode->i_sb, new_de.de_bh);
+	    reiserfs_restore_prepared_buffer (old_inode->i_sb, old_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);
-	    yield();
-#endif
 	    continue;
 	}
+	if (S_ISDIR(old_inode->i_mode)) {
+	    if ( item_moved(&dot_dot_ih, &dot_dot_entry_path) ||
+		!entry_points_to_object ( "..", 2, &dot_dot_de, old_dir) ) {
+		reiserfs_restore_prepared_buffer (old_inode->i_sb, old_de.de_bh);
+		reiserfs_restore_prepared_buffer (old_inode->i_sb, new_de.de_bh);
+		reiserfs_restore_prepared_buffer (old_inode->i_sb, dot_dot_de.de_bh);
+		continue;
+	    }
+	}
 
 	RFALSE( S_ISDIR(old_inode->i_mode) && 
-		(!entry_points_to_object ("..", 2, &dot_dot_de, old_dir) || 
-		 !reiserfs_buffer_prepared(dot_dot_de.de_bh)), "" );
+		 !reiserfs_buffer_prepared(dot_dot_de.de_bh), "" );
 
 	break;
     }
@@ -1187,35 +1203,32 @@
     journal_mark_dirty (&th, old_dir->i_sb, new_de.de_bh);
 
     mark_de_hidden (old_de.de_deh + old_de.de_entry_num);
+    journal_mark_dirty (&th, old_dir->i_sb, old_de.de_bh);
     old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
     new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
 
     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
@@ -1226,18 +1239,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 -u --recursive --new-file v2.5.2/linux/fs/reiserfs/objectid.c linux/fs/reiserfs/objectid.c
--- v2.5.2/linux/fs/reiserfs/objectid.c	Fri Nov  9 14:18:25 2001
+++ linux/fs/reiserfs/objectid.c	Tue Jan 29 10:47:05 2002
@@ -5,9 +5,10 @@
 #include <linux/config.h>
 #include <linux/string.h>
 #include <linux/locks.h>
+#include <linux/random.h>
 #include <linux/sched.h>
 #include <linux/reiserfs_fs.h>
-
+#include <linux/reiserfs_fs_sb.h>
 
 // find where objectid map starts
 #define objectid_map(s,rs) (old_format_only (s) ? \
@@ -145,7 +146,7 @@
 	    }
 
             /* JDM comparing two little-endian values for equality -- safe */
-	if (rs->s_oid_cursize == rs->s_oid_maxsize) {
+	if (sb_oid_cursize(rs) == sb_oid_maxsize(rs)) {
 		/* objectid map must be expanded, but there is no space */
 		PROC_INFO_INC( s, leaked_oid );
 		return;
@@ -162,16 +163,16 @@
 	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);
 }
 
 
 int reiserfs_convert_objectid_map_v1(struct super_block *s) {
     struct reiserfs_super_block *disk_sb = SB_DISK_SUPER_BLOCK (s);
-    int cur_size = le16_to_cpu(disk_sb->s_oid_cursize) ;
+    int cur_size = sb_oid_cursize(disk_sb);
     int new_size = (s->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2 ;
-    int old_max = le16_to_cpu(disk_sb->s_oid_maxsize) ;
+    int old_max = sb_oid_maxsize(disk_sb);
     struct reiserfs_super_block_v1 *disk_sb_v1 ;
     __u32 *objectid_map, *new_objectid_map ;
     int i ;
@@ -185,7 +186,7 @@
 	** map 
 	*/
 	objectid_map[new_size - 1] = objectid_map[cur_size - 1] ;
-	disk_sb->s_oid_cursize = cpu_to_le16(new_size) ;
+	set_sb_oid_cursize(disk_sb,new_size) ;
     }
     /* move the smaller objectid map past the end of the new super */
     for (i = new_size - 1 ; i >= 0 ; i--) {
@@ -194,7 +195,11 @@
 
 
     /* set the max size so we don't overflow later */
-    disk_sb->s_oid_maxsize = cpu_to_le16(new_size) ;
+    set_sb_oid_maxsize(disk_sb,new_size) ;
+
+    /* Zero out label and generate random UUID */
+    memset(disk_sb->s_label, 0, sizeof(disk_sb->s_label)) ;
+    generate_random_uuid(disk_sb->s_uuid);
 
     /* finally, zero out the unused chunk of the new super */
     memset(disk_sb->s_unused, 0, sizeof(disk_sb->s_unused)) ;
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/prints.c linux/fs/reiserfs/prints.c
--- v2.5.2/linux/fs/reiserfs/prints.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/prints.c	Tue Jan 29 10:47:05 2002
@@ -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",
@@ -485,12 +485,13 @@
     char *version;
     
 
-    if (strncmp (rs->s_magic,  REISERFS_SUPER_MAGIC_STRING,
-                 strlen ( REISERFS_SUPER_MAGIC_STRING)) == 0) {
+    if (is_reiserfs_3_5(rs)) {
         version = "3.5";
-    } else if( strncmp (rs->s_magic,  REISER2FS_SUPER_MAGIC_STRING,
-                        strlen ( REISER2FS_SUPER_MAGIC_STRING)) == 0) {
+    } else if (is_reiserfs_3_6(rs)) {
         version = "3.6";
+    } else if (is_reiserfs_jr(rs)) {
+      version = ((sb_version(rs) == REISERFS_VERSION_2) ?
+ 		 "3.6" : "3.5");  
     } else {
 	return 1;
     }
@@ -505,27 +506,25 @@
     // someone stores reiserfs super block in some data block ;)
 //    skipped = (bh->b_blocknr * bh->b_size) / sb_blocksize(rs);
     skipped = bh->b_blocknr;
-    data_blocks = sb_block_count(rs) - skipped - 1 -
-                  sb_bmap_nr(rs) - (sb_orig_journal_size(rs) + 1) -
-                  sb_free_blocks(rs);
-    printk ("Busy blocks (skipped %d, bitmaps - %d, journal blocks - %d\n"
-	    "1 super blocks, %d data blocks\n", 
-	    skipped, sb_bmap_nr(rs), 
-	    (sb_orig_journal_size(rs) + 1), data_blocks);
+    data_blocks = sb_block_count(rs) - skipped - 1 - sb_bmap_nr(rs) -
+	    (!is_reiserfs_jr(rs) ? sb_jp_journal_size(rs) + 1 : sb_reserved_for_journal(rs)) -	    
+	    sb_free_blocks(rs);
+    printk ("Busy blocks (skipped %d, bitmaps - %d, journal (or reserved) blocks - %d\n"
+	    "1 super block, %d data blocks\n", 
+	    skipped, sb_bmap_nr(rs), (!is_reiserfs_jr(rs) ? (sb_jp_journal_size(rs) + 1) :
+				      sb_reserved_for_journal(rs)) , data_blocks);
     printk ("Root block %u\n", sb_root_block(rs));
-    printk ("Journal block (first) %d\n", sb_journal_block(rs));
-    printk ("Journal dev %d\n", sb_journal_dev(rs));
-    printk ("Journal orig size %d\n", sb_orig_journal_size(rs));
-    printk ("Filesystem state %s\n", 
-	    (sb_state(rs) == REISERFS_VALID_FS) ? "VALID" : "ERROR");
+    printk ("Journal block (first) %d\n", sb_jp_journal_1st_block(rs));
+    printk ("Journal dev %d\n", sb_jp_journal_dev(rs));
+    printk ("Journal orig size %d\n", sb_jp_journal_size(rs));
+    printk ("FS state %d\n", sb_fs_state(rs));
     printk ("Hash function \"%s\"\n",
             sb_hash_function_code(rs) == TEA_HASH ? "tea" :
 	    ( sb_hash_function_code(rs) == YURA_HASH ? "rupasov" : (sb_hash_function_code(rs) == R5_HASH ? "r5" : "unknown")));
-
+    
     printk ("Tree height %d\n", sb_tree_height(rs));
     return 0;
 }
-
 
 static int print_desc_block (struct buffer_head * bh)
 {
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/procfs.c linux/fs/reiserfs/procfs.c
--- v2.5.2/linux/fs/reiserfs/procfs.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/procfs.c	Tue Jan 29 10:47:05 2002
@@ -15,6 +15,7 @@
 #include <linux/sched.h>
 #include <asm/uaccess.h>
 #include <linux/reiserfs_fs.h>
+#include <linux/reiserfs_fs_sb.h>
 #include <linux/smp_lock.h>
 #include <linux/locks.h>
 #include <linux/init.h>
@@ -76,12 +77,21 @@
 {
 	int len = 0;
 	struct super_block *sb;
+	char *format;
     
-	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	sb = procinfo_prologue( to_kdev_t((int)data) );
 	if( sb == NULL )
 		return -ENOENT;
+	if ( sb->u.reiserfs_sb.s_properties & (1 << REISERFS_3_6) ) {
+		format = "3.6";
+	} else if ( sb->u.reiserfs_sb.s_properties & (1 << REISERFS_3_5) ) {
+		format = "3.5";
+	} else {
+		format = "unknown";
+	}
+
 	len += sprintf( &buffer[ len ], "%s format\twith checks %s\n",
-			old_format_only( sb ) ? "old" : "new",
+			format,
 #if defined( CONFIG_REISERFS_CHECK )
 			"on"
 #else
@@ -96,15 +106,6 @@
 				     int count, int *eof, void *data )
 {
 	int len = 0;
-    
-	len += sprintf( &buffer[ len ], "%s [%s]\n", 
-			reiserfs_get_version_string(),
-#if defined( CONFIG_REISERFS_FS_MODULE )
-			"as module"
-#else
-			"built into kernel"
-#endif
-			);
 	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
 }
 
@@ -116,8 +117,8 @@
 
 #define D2C( x ) le16_to_cpu( x )
 #define D4C( x ) le32_to_cpu( x )
-#define DF( x ) D2C( rs -> x )
-#define DFL( x ) D4C( rs -> x )
+#define DF( x ) D2C( rs -> s_v1.x )
+#define DFL( x ) D4C( rs -> s_v1.x )
 
 #define objectid_map( s, rs ) (old_format_only (s) ?				\
                          (__u32 *)((struct reiserfs_super_block_v1 *)rs + 1) :	\
@@ -125,6 +126,8 @@
 #define MAP( i ) D4C( objectid_map( sb, rs )[ i ] )
 
 #define DJF( x ) le32_to_cpu( rs -> x )
+#define DJV( x ) le32_to_cpu( s_v1 -> x )
+#define DJP( x ) le32_to_cpu( jp -> x ) 
 #define JF( x ) ( r -> s_journal -> x )
 
 int reiserfs_super_in_proc( char *buffer, char **start, off_t offset,
@@ -134,7 +137,7 @@
 	struct reiserfs_sb_info *r;
 	int len = 0;
     
-	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	sb = procinfo_prologue( to_kdev_t((int)data) );
 	if( sb == NULL )
 		return -ENOENT;
 	r = &sb->u.reiserfs_sb;
@@ -179,7 +182,7 @@
 			dont_have_tails( sb ) ? "NO_TAILS " : "TAILS ",
 			replay_only( sb ) ? "REPLAY_ONLY " : "",
 			reiserfs_dont_log( sb ) ? "DONT_LOG " : "LOG ",
-			old_format_only( sb ) ? "CONV " : "",
+			convert_reiserfs( sb ) ? "CONV " : "",
 
 			atomic_read( &r -> s_generation_counter ),
 			SF( s_kmallocs ),
@@ -214,7 +217,7 @@
 	int len = 0;
 	int level;
 	
-	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	sb = procinfo_prologue( to_kdev_t((int)data) );
 	if( sb == NULL )
 		return -ENOENT;
 	r = &sb->u.reiserfs_sb;
@@ -293,7 +296,7 @@
 	struct reiserfs_sb_info *r = &sb->u.reiserfs_sb;
 	int len = 0;
     
-	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	sb = procinfo_prologue( to_kdev_t((int)data) );
 	if( sb == NULL )
 		return -ENOENT;
 	r = &sb->u.reiserfs_sb;
@@ -334,7 +337,7 @@
 	int hash_code;
 	int len = 0;
     
-	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	sb = procinfo_prologue( to_kdev_t((int)data) );
 	if( sb == NULL )
 		return -ENOENT;
 	sb_info = &sb->u.reiserfs_sb;
@@ -348,12 +351,14 @@
 			"blocksize: \t%i\n"
 			"oid_maxsize: \t%i\n"
 			"oid_cursize: \t%i\n"
-			"state: \t%i\n"
-			"magic: \t%12.12s\n"
+			"umount_state: \t%i\n"
+			"magic: \t%10.10s\n"
+			"fs_state: \t%i\n"
 			"hash: \t%s\n"
 			"tree_height: \t%i\n"
 			"bmap_nr: \t%i\n"
-			"version: \t%i\n",
+			"version: \t%i\n"
+			"reserved_for_journal: \t%i\n",
 
 			DFL( s_block_count ),
 			DFL( s_free_blocks ),
@@ -361,15 +366,17 @@
 			DF( s_blocksize ),
 			DF( s_oid_maxsize ),
 			DF( s_oid_cursize ),
-			DF( s_state ),
-			rs -> s_magic,
+			DF( s_umount_state ),
+			rs -> s_v1.s_magic,
+			DF( s_fs_state ),
 			hash_code == TEA_HASH ? "tea" :
 			( hash_code == YURA_HASH ) ? "rupasov" :
 			( hash_code == R5_HASH ) ? "r5" :
 			( hash_code == UNSET_HASH ) ? "unset" : "unknown",
 			DF( s_tree_height ),
 			DF( s_bmap_nr ),
-			DF( s_version ) );
+			DF( s_version ),
+			DF (s_reserved_for_journal));
 
 	procinfo_epilogue( sb );
 	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
@@ -387,12 +394,12 @@
 	int len = 0;
 	int exact;
     
-	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	sb = procinfo_prologue( to_kdev_t((int)data) );
 	if( sb == NULL )
 		return -ENOENT;
 	sb_info = &sb->u.reiserfs_sb;
 	rs = sb_info -> s_rs;
-	mapsize = le16_to_cpu( rs -> s_oid_cursize );
+	mapsize = le16_to_cpu( rs -> s_v1.s_oid_cursize );
 	total_used = 0;
 
 	for( i = 0 ; i < mapsize ; ++i ) {
@@ -423,7 +430,7 @@
 	}
 	len += sprintf( &buffer[ len ], "total: \t%i [%i/%i] used: %lu [%s]\n", 
 			i, 
-			mapsize, le16_to_cpu( rs -> s_oid_maxsize ),
+			mapsize, le16_to_cpu( rs -> s_v1.s_oid_maxsize ),
 			total_used, exact ? "exact" : "estimation" );
 
 	procinfo_epilogue( sb );
@@ -436,25 +443,28 @@
 	struct super_block *sb;
 	struct reiserfs_sb_info *r;
 	struct reiserfs_super_block *rs;
+	struct journal_params *jp;	
 	int len = 0;
     
-	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	sb = procinfo_prologue( to_kdev_t((int)data) );
 	if( sb == NULL )
 		return -ENOENT;
 	r = &sb->u.reiserfs_sb;
 	rs = r -> s_rs;
+	jp = &rs->s_v1.s_journal;
 
 	len += sprintf( &buffer[ len ], 
 			/* on-disk fields */
-			"s_journal_block: \t%i\n"
-			"s_journal_dev: \t%s[%x]\n"
-			"s_orig_journal_size: \t%i\n"
-			"s_journal_trans_max: \t%i\n"
-			"s_journal_block_count: \t%i\n"
-			"s_journal_max_batch: \t%i\n"
-			"s_journal_max_commit_age: \t%i\n"
-			"s_journal_max_trans_age: \t%i\n"
+ 			"jp_journal_1st_block: \t%i\n"
+ 			"jp_journal_dev: \t%s[%x]\n"
+ 			"jp_journal_size: \t%i\n"
+ 			"jp_journal_trans_max: \t%i\n"
+ 			"jp_journal_magic: \t%i\n"
+ 			"jp_journal_max_batch: \t%i\n"
+ 			"jp_journal_max_commit_age: \t%i\n"
+ 			"jp_journal_max_trans_age: \t%i\n"
 			/* incore fields */
+			"j_1st_reserved_block: \t%i\n"	  
 			"j_state: \t%i\n"			
 			"j_trans_id: \t%lu\n"
 			"j_mount_id: \t%lu\n"
@@ -490,16 +500,17 @@
 			"prepare: \t%12lu\n"
 			"prepare_retry: \t%12lu\n",
 
-			DJF( s_journal_block ),
-			DJF( s_journal_dev ) == 0 ? "none" : bdevname( DJF( s_journal_dev ) ), 
-			DJF( s_journal_dev ),
-			DJF( s_orig_journal_size ),
-			DJF( s_journal_trans_max ),
-			DJF( s_journal_block_count ),
-			DJF( s_journal_max_batch ),
-			DJF( s_journal_max_commit_age ),
-			DJF( s_journal_max_trans_age ),
-			
+                        DJP( jp_journal_1st_block ),
+                        DJP( jp_journal_dev ) == 0 ? "none" : bdevname(to_kdev_t(DJP( jp_journal_dev ))),
+                        DJP( jp_journal_dev ),
+                        DJP( jp_journal_size ),
+                        DJP( jp_journal_trans_max ),
+                        DJP( jp_journal_magic ),
+                        DJP( jp_journal_max_batch ),
+                        DJP( jp_journal_max_commit_age ),
+                        DJP( jp_journal_max_trans_age ),
+
+			JF( j_1st_reserved_block ),			
 			JF( j_state ),			
 			JF( j_trans_id ),
 			JF( j_mount_id ),
@@ -578,7 +589,7 @@
 {
 	return ( sb->u.reiserfs_sb.procdir ) ? create_proc_read_entry
 		( name, 0, sb->u.reiserfs_sb.procdir, func, 
-		  ( void * ) ( int ) sb -> s_dev ) : NULL;
+		  ( void * ) kdev_t_to_nr( sb -> s_dev ) ) : NULL;
 }
 
 void reiserfs_proc_unregister( struct super_block *sb, const char *name )
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/resize.c linux/fs/reiserfs/resize.c
--- v2.5.2/linux/fs/reiserfs/resize.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/resize.c	Tue Jan 29 10:47:05 2002
@@ -111,8 +111,8 @@
 	    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, i * s->s_blocksize * 8);
-		memset(bitmap[i]->b_data, 0, sb->s_blocksize);
+		bitmap[i] = sb_getblk(s, i * s->s_blocksize * 8);
+		memset(bitmap[i]->b_data, 0, sb_blocksize(sb));
 		reiserfs_test_and_set_le_bit(0, bitmap[i]->b_data);
 
 		mark_buffer_dirty(bitmap[i]) ;
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c
--- v2.5.2/linux/fs/reiserfs/stree.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/stree.c	Tue Jan 29 10:47:05 2002
@@ -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, blocknr);
+    bh = sb_getblk (s, blocknr);
   
     if (!buffer_uptodate (bh)) {
 	ll_rw_block (READA, 1, &bh);
@@ -726,7 +726,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 ) {
@@ -916,7 +920,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 ... */
@@ -991,10 +995,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) ) {
 
@@ -1019,13 +1019,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;
 
 
@@ -1098,8 +1096,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 ;
@@ -1109,69 +1107,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 = sb_get_hash_table(p_s_sb, get_block_num(p_n_unfm_pointer,0));
-
-		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
@@ -1181,27 +1133,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);
-		yield();
-	    }
 	    /* 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 );
@@ -1386,8 +1317,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);
@@ -1401,13 +1332,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;
 	}
@@ -1427,7 +1358,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;
@@ -1444,15 +1375,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 ) )
       {
@@ -1489,7 +1411,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 || (REISERFS_I(p_s_inode)->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));
@@ -1654,7 +1576,7 @@
 	    /* we delete first part of tail which was stored in direct
                item(s) */
 	    // FIXME: this is to keep 3.5 happy
-	    p_s_inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;
+	    REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX;
 	    p_s_inode->i_blocks -= p_s_sb->s_blocksize / 512;
 	}
     }
@@ -1691,7 +1613,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 ;
+	REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask ;
     }
     return n_ret_value;
 }
@@ -1700,14 +1622,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);    
 }
 
 
@@ -1780,6 +1702,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);
 
@@ -1816,7 +1739,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 -u --recursive --new-file v2.5.2/linux/fs/reiserfs/super.c linux/fs/reiserfs/super.c
--- v2.5.2/linux/fs/reiserfs/super.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/super.c	Tue Jan 29 10:47:10 2002
@@ -24,8 +24,39 @@
 #define REISERFS_OLD_BLOCKSIZE 4096
 #define REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ 20
 
-char reiserfs_super_magic_string[] = REISERFS_SUPER_MAGIC_STRING;
-char reiser2fs_super_magic_string[] = REISER2FS_SUPER_MAGIC_STRING;
+const char reiserfs_3_5_magic_string[] = REISERFS_SUPER_MAGIC_STRING;
+const char reiserfs_3_6_magic_string[] = REISER2FS_SUPER_MAGIC_STRING;
+const char reiserfs_jr_magic_string[] = REISER2FS_JR_SUPER_MAGIC_STRING;
+
+int is_reiserfs_3_5 (struct reiserfs_super_block * rs)
+{
+  return !strncmp (rs->s_v1.s_magic, reiserfs_3_5_magic_string,
+		   strlen (reiserfs_3_5_magic_string));
+}
+
+
+int is_reiserfs_3_6 (struct reiserfs_super_block * rs)
+{
+  return !strncmp (rs->s_v1.s_magic, reiserfs_3_6_magic_string,
+ 		   strlen (reiserfs_3_6_magic_string));
+}
+
+
+int is_reiserfs_jr (struct reiserfs_super_block * rs)
+{
+  return !strncmp (rs->s_v1.s_magic, reiserfs_jr_magic_string,
+ 		   strlen (reiserfs_jr_magic_string));
+}
+
+
+static int is_any_reiserfs_magic_string (struct reiserfs_super_block * rs)
+{
+  return (is_reiserfs_3_5 (rs) || is_reiserfs_3_6 (rs) ||
+	  is_reiserfs_jr (rs));
+}
+
+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,
@@ -34,7 +65,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 ;
@@ -53,7 +84,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 ;
@@ -74,6 +105,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) {
+            REISERFS_I(inode) -> 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 {
+            REISERFS_I(inode) -> 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);
+        printk ("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 && 
+	    ( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ),
+	    "saved link already exists for truncated inode %lx",
+	    ( long ) inode -> i_ino );
+    RFALSE( !truncate && 
+	    ( REISERFS_I(inode) -> 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 )
+	    REISERFS_I(inode) -> i_flags |= i_link_saved_truncate_mask;
+	else
+	    REISERFS_I(inode) -> 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 && 
+          ( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ) ) ||
+        ( !truncate && 
+          ( REISERFS_I(inode) -> i_flags & i_link_saved_unlink_mask ) ) )
+	reiserfs_delete_solid_item (&th, &key);
+    if (!truncate) {
+	reiserfs_release_objectid (&th, inode->i_ino);
+	REISERFS_I(inode) -> i_flags &= ~i_link_saved_unlink_mask;
+    } else
+	REISERFS_I(inode) -> 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
@@ -81,7 +353,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 ;
@@ -90,7 +362,7 @@
   if (!(s->s_flags & MS_RDONLY)) {
     journal_begin(&th, s, 10) ;
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
-    set_sb_state( SB_DISK_SUPER_BLOCK(s), s->u.reiserfs_sb.s_mount_state );
+    set_sb_umount_state( SB_DISK_SUPER_BLOCK(s), s->u.reiserfs_sb.s_mount_state );
     journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
   }
 
@@ -124,8 +396,74 @@
   return;
 }
 
+static kmem_cache_t * reiserfs_inode_cachep;
+
+static struct inode *reiserfs_alloc_inode(struct super_block *sb)
+{
+	struct reiserfs_inode_info *ei;
+	ei = (struct reiserfs_inode_info *)kmem_cache_alloc(reiserfs_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void reiserfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		INIT_LIST_HEAD(&ei->i_prealloc_list) ;
+		inode_init_once(&ei->vfs_inode);
+	}
+}
+ 
+static int init_inodecache(void)
+{
+	reiserfs_inode_cachep = kmem_cache_create("reiser_inode_cache",
+					     sizeof(struct reiserfs_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (reiserfs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(reiserfs_inode_cachep))
+		printk(KERN_INFO "reiserfs_inode_cache: not all structures were freed\n");
+}
+
+/* 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 = 
 {
+  alloc_inode: reiserfs_alloc_inode,
+  destroy_inode: reiserfs_destroy_inode,
   read_inode: reiserfs_read_inode,
   read_inode2: reiserfs_read_inode2,
   write_inode: reiserfs_write_inode,
@@ -144,7 +482,7 @@
 };
 
 /* this was (ext2)parse_options */
-static int parse_options (char * options, unsigned long * mount_options, unsigned long * blocks)
+static int parse_options (char * options, unsigned long * mount_options, unsigned long * blocks, char **jdev_name)
 {
     char * this_char;
     char * value;
@@ -211,6 +549,13 @@
 	  	printk("reiserfs: hash option requires a value\n");
 		return 0 ;
 	    }
+	} else if (!strcmp (this_char, "jdev")) {
+	    if (value && *value && jdev_name) {
+		    *jdev_name = value;
+	    } else {
+		    printk("reiserfs: jdev option requires a value\n");
+		    return 0 ;
+	    }
 	} else {
 	    printk ("reiserfs: Unrecognized mount option %s\n", this_char);
 	    return 0;
@@ -232,7 +577,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 ;
@@ -240,8 +585,7 @@
   unsigned long mount_options;
 
   rs = SB_DISK_SUPER_BLOCK (s);
-
-  if (!parse_options(data, &mount_options, &blocks))
+  if (!parse_options(data, &mount_options, &blocks, NULL))
   	return 0;
 
   if(blocks) {
@@ -257,26 +601,26 @@
   
   if (*flags & MS_RDONLY) {
     /* try to remount file system with read-only permissions */
-    if (sb_state(rs) == REISERFS_VALID_FS || s->u.reiserfs_sb.s_mount_state != REISERFS_VALID_FS) {
+    if (sb_umount_state(rs) == REISERFS_VALID_FS || s->u.reiserfs_sb.s_mount_state != REISERFS_VALID_FS) {
       return 0;
     }
 
     journal_begin(&th, s, 10) ;
     /* Mounting a rw partition read-only. */
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
-    set_sb_state( rs, s->u.reiserfs_sb.s_mount_state );
+    set_sb_umount_state( rs, s->u.reiserfs_sb.s_mount_state );
     journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
     s->s_dirt = 0;
   } else {
-    s->u.reiserfs_sb.s_mount_state = sb_state(rs) ;
+    s->u.reiserfs_sb.s_mount_state = sb_umount_state(rs) ;
     s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
     journal_begin(&th, s, 10) ;
 
     /* Mount a partition which is read-only, read-write */
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
-    s->u.reiserfs_sb.s_mount_state = sb_state(rs);
+    s->u.reiserfs_sb.s_mount_state = sb_umount_state(rs);
     s->s_flags &= ~MS_RDONLY;
-    set_sb_state( rs, REISERFS_ERROR_FS );
+    set_sb_umount_state( rs, REISERFS_ERROR_FS );
     /* mark_buffer_dirty (SB_BUFFER_WITH_SB (s), 1); */
     journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
     s->s_dirt = 0;
@@ -285,6 +629,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;
 }
 
@@ -364,17 +712,14 @@
 
     bh = sb_bread (s, offset / s->s_blocksize);
     if (!bh) {
-      printk ("read_super_block: "
-              "bread failed (dev %s, block %d, size %d)\n",
+      printk ("sh-2006: read_super_block: "
+              "bread failed (dev %s, block %lu, size %lu)\n",
               s->s_id, offset / s->s_blocksize, s->s_blocksize);
       return 1;
     }
  
     rs = (struct reiserfs_super_block *)bh->b_data;
-    if (!is_reiserfs_magic_string (rs)) {
-      printk ("read_super_block: "
-              "can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
-              s->s_id, bh->b_blocknr, s->s_blocksize);
+    if (!is_any_reiserfs_magic_string (rs)) {
       brelse (bh);
       return 1;
     }
@@ -385,39 +730,48 @@
     brelse (bh);
     
     sb_set_blocksize (s, sb_blocksize(rs));
-
+    
     bh = reiserfs_bread (s, offset / s->s_blocksize);
     if (!bh) {
-	printk("read_super_block: "
-                "bread failed (dev %s, block %d, size %d)\n",
+	printk("sh-2007: read_super_block: "
+                "bread failed (dev %s, block %lu, size %lu)\n",
                 s->s_id, offset / s->s_blocksize, s->s_blocksize);
 	return 1;
     }
     
     rs = (struct reiserfs_super_block *)bh->b_data;
-    if (!is_reiserfs_magic_string (rs) || sb_blocksize(rs) != s->s_blocksize) {
-	printk ("read_super_block: "
-		"can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
+    if (sb_blocksize(rs) != s->s_blocksize) {
+	printk ("sh-2011: read_super_block: "
+		"can't find a reiserfs filesystem on (dev %s, block %lu, size %lu)\n",
 		s->s_id, bh->b_blocknr, s->s_blocksize);
 	brelse (bh);
-	printk ("read_super_block: can't find a reiserfs filesystem on dev %s.\n", s->s_id);
 	return 1;
     }
-    /* must check to be sure we haven't pulled an old format super out
-    ** of the old format's log.  This is a kludge of a check, but it
-    ** will work.  If block we've just read in is inside the
-    ** journal for that super, it can't be valid.  
-    */
-    if (bh->b_blocknr >= sb_journal_block(rs) && 
-	bh->b_blocknr < (sb_journal_block(rs) + JOURNAL_BLOCK_COUNT)) {
-	brelse(bh) ;
-	printk("super-459: read_super_block: "
-	       "super found at block %lu is within its own log. "
-	       "It must not be of this format type.\n", bh->b_blocknr) ;
-	return 1 ;
-    }
+
     SB_BUFFER_WITH_SB (s) = bh;
     SB_DISK_SUPER_BLOCK (s) = rs;
+
+    if (is_reiserfs_jr (rs)) {
+	/* magic is of non-standard journal filesystem, look at s_version to
+	   find which format is in use */
+	if (sb_version(rs) == REISERFS_VERSION_2)
+	  printk ("read_super_block: found reiserfs format \"3.6\" "
+		  "with non-standard journal\n");
+	else if (sb_version(rs) == REISERFS_VERSION_1)
+	  printk ("read_super_block: found reiserfs format \"3.5\" "
+		  "with non-standard journal\n");
+	else {
+	  printk ("sh-2012: read_super_block: found unknown format \"%u\" "
+	            "of reiserfs with non-standard magic\n", sb_version(rs));
+	return 1;
+	}
+    }
+    else
+      /* s_version of standard format may contain incorrect information,
+	 so we just look at the magic string */
+      printk ("found reiserfs format \"%s\" with standard journal\n",
+	      is_reiserfs_3_5 (rs) ? "3.5" : "3.6");
+
     s->s_op = &reiserfs_sops;
 
     /* new format is limited by the 32 bit wide i_blocks field, want to
@@ -602,7 +956,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;
@@ -612,11 +966,12 @@
     unsigned long blocks;
     int jinit_done = 0 ;
     struct reiserfs_iget4_args args ;
-
+    struct reiserfs_super_block * rs;
+    char *jdev_name;
 
     memset (&s->u.reiserfs_sb, 0, sizeof (struct reiserfs_sb_info));
-
-    if (parse_options ((char *) data, &(s->u.reiserfs_sb.s_mount_opt), &blocks) == 0) {
+    jdev_name = NULL;
+    if (parse_options ((char *) data, &(s->u.reiserfs_sb.s_mount_opt), &blocks, &jdev_name) == 0) {
 	return NULL;
     }
 
@@ -627,17 +982,15 @@
 
     size = block_size(s->s_dev);
     sb_set_blocksize(s, size);
-
-    /* read block (64-th 1k block), which can contain reiserfs super block */
-    if (read_super_block (s, REISERFS_DISK_OFFSET_IN_BYTES)) {
-	// try old format (undistributed bitmap, super block in 8-th 1k block of a device)
-	sb_set_blocksize(s, size);
-	if (read_super_block (s, REISERFS_OLD_DISK_OFFSET_IN_BYTES)) 
-	    goto error;
-	else
-	    old_format = 1;
+    
+    /* try old format (undistributed bitmap, super block in 8-th 1k block of a device) */
+    if (!read_super_block (s, REISERFS_OLD_DISK_OFFSET_IN_BYTES)) 
+      old_format = 1;
+    /* try new format (64-th 1k block), which can contain reiserfs super block */
+    else if (read_super_block (s, REISERFS_DISK_OFFSET_IN_BYTES)) {
+      printk("sh-2021: reiserfs_read_super: can not find reiserfs on %s\n", s->s_id);
+      goto error;    
     }
-
     s->u.reiserfs_sb.s_mount_state = SB_REISERFS_STATE(s);
     s->u.reiserfs_sb.s_mount_state = REISERFS_VALID_FS ;
 
@@ -651,8 +1004,8 @@
 #endif
 
     // set_device_ro(s->s_dev, 1) ;
-    if (journal_init(s)) {
-	printk("reiserfs_read_super: unable to initialize journal space\n") ;
+    if( journal_init(s, jdev_name, old_format) ) {
+	printk("sh-2022: reiserfs_read_super: unable to initialize journal space\n") ;
 	goto error ;
     } else {
 	jinit_done = 1 ; /* once this is set, journal_release must be called
@@ -692,54 +1045,56 @@
       goto error ;
     }
 
+    rs = SB_DISK_SUPER_BLOCK (s);
+    if (is_reiserfs_3_5 (rs) || (is_reiserfs_jr (rs) && SB_VERSION (s) == REISERFS_VERSION_1))
+	set_bit(REISERFS_3_5, &(s->u.reiserfs_sb.s_properties));
+    else
+	set_bit(REISERFS_3_6, &(s->u.reiserfs_sb.s_properties));
+    
     if (!(s->s_flags & MS_RDONLY)) {
-	struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
-        int old_magic;
-
-      old_magic = strncmp (rs->s_magic,  REISER2FS_SUPER_MAGIC_STRING,
-                           strlen ( REISER2FS_SUPER_MAGIC_STRING));
-	if( old_magic && le16_to_cpu(rs->s_version) != 0 ) {
-	  dput(s->s_root) ;
-	  s->s_root = NULL ;
-	  reiserfs_warning("reiserfs: wrong version/magic combination in the super-block\n") ;
-	  goto error ;
-	}
 
 	journal_begin(&th, s, 1) ;
 	reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
 
-        set_sb_state( rs, REISERFS_ERROR_FS );
-
-        if ( old_magic ) {
-	    // filesystem created under 3.5.x found
-	    if (!old_format_only (s)) {
-		reiserfs_warning("reiserfs: converting 3.5.x filesystem to the new format\n") ;
-		// after this 3.5.x will not be able to mount this partition
-		memcpy (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING, 
-			sizeof (REISER2FS_SUPER_MAGIC_STRING));
-
-		reiserfs_convert_objectid_map_v1(s) ;
-	    } else {
-		reiserfs_warning("reiserfs: using 3.5.x disk format\n") ;
-	    }
-	} else {
-	    // new format found
-	    set_bit (REISERFS_CONVERT, &(s->u.reiserfs_sb.s_mount_opt));
+        set_sb_umount_state( rs, REISERFS_ERROR_FS );
+	set_sb_fs_state (rs, 0);
+	
+	if (old_format_only(s)) {
+	  /* filesystem of format 3.5 either with standard or non-standard
+	     journal */       
+	  if (convert_reiserfs (s)) {
+	    /* and -o conv is given */ 
+	    reiserfs_warning ("reiserfs: converting 3.5 filesystem to the 3.6 format\n") ;
+	    
+	    if (is_reiserfs_3_5 (rs))
+	      /* put magic string of 3.6 format. 2.2 will not be able to
+		 mount this filesystem anymore */
+	      memcpy (rs->s_v1.s_magic, reiserfs_3_6_magic_string, 
+		      sizeof (reiserfs_3_6_magic_string));
+	    
+	    set_sb_version(rs,REISERFS_VERSION_2);
+	    reiserfs_convert_objectid_map_v1(s) ;
+	    set_bit(REISERFS_3_6, &(s->u.reiserfs_sb.s_properties));
+	    clear_bit(REISERFS_3_5, &(s->u.reiserfs_sb.s_properties));
+	  } else {
+	    reiserfs_warning("reiserfs: using 3.5.x disk format\n") ;
+	  }
 	}
 
-	// mark hash in super block: it could be unset. overwrite should be ok
-        set_sb_hash_function_code( rs, function2code(s->u.reiserfs_sb.s_hash_function ) );
-
 	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);
-	if (strncmp (rs->s_magic,  REISER2FS_SUPER_MAGIC_STRING, 
-		     strlen ( REISER2FS_SUPER_MAGIC_STRING))) {
+	if ( old_format_only(s) ) {
 	    reiserfs_warning("reiserfs: using 3.5.x disk format\n") ;
 	}
     }
+    // mark hash in super block: it could be unset. overwrite should be ok
+    set_sb_hash_function_code( rs, function2code(s->u.reiserfs_sb.s_hash_function ) );
 
     reiserfs_proc_info_init( s );
     reiserfs_proc_register( s, "version", reiserfs_version_in_proc );
@@ -751,7 +1106,6 @@
     reiserfs_proc_register( s, "journal", reiserfs_journal_in_proc );
     init_waitqueue_head (&(s->u.reiserfs_sb.s_wait));
 
-    printk("%s\n", reiserfs_get_version_string()) ;
     return s;
 
  error:
@@ -780,7 +1134,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);
   
@@ -803,12 +1157,25 @@
 //
 static int __init init_reiserfs_fs (void)
 {
+	int err = init_inodecache();
+	if (err)
+		goto out1;
 	reiserfs_proc_info_global_init();
 	reiserfs_proc_register_global( "version", 
 				       reiserfs_global_version_in_proc );
-        return register_filesystem(&reiserfs_fs_type);
+        err = register_filesystem(&reiserfs_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	reiserfs_proc_unregister_global( "version" );
+	reiserfs_proc_info_global_done();
+	destroy_inodecache();
+out1:
+	return err;
 }
 
+
 MODULE_DESCRIPTION("ReiserFS journaled filesystem");
 MODULE_AUTHOR("Hans Reiser <reiser@namesys.com>");
 MODULE_LICENSE("GPL");
@@ -822,6 +1189,7 @@
 	reiserfs_proc_unregister_global( "version" );
 	reiserfs_proc_info_global_done();
         unregister_filesystem(&reiserfs_fs_type);
+	destroy_inodecache();
 }
 
 module_init(init_reiserfs_fs) ;
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/tail_conversion.c linux/fs/reiserfs/tail_conversion.c
--- v2.5.2/linux/fs/reiserfs/tail_conversion.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/tail_conversion.c	Tue Jan 29 10:47:05 2002
@@ -125,7 +125,7 @@
 	memset(page_address(unbh->b_page) + pgoff, 0, n_blk_size - total_tail) ;
     }
 
-    inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;
+    REISERFS_I(inode)->i_first_direct_byte = U32_MAX;
 
     return 0;
 }
@@ -241,7 +241,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.
@@ -285,7 +285,7 @@
 
     /* we store position of first direct item in the in-core inode */
     //mark_file_with_tail (p_s_inode, pos1 + 1);
-    p_s_inode->u.reiserfs_i.i_first_direct_byte = pos1 + 1;
+    REISERFS_I(p_s_inode)->i_first_direct_byte = pos1 + 1;
 
     return n_block_size - round_tail_len;
 }
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/version.c linux/fs/reiserfs/version.c
--- v2.5.2/linux/fs/reiserfs/version.c	Mon Jan 15 12:42:32 2001
+++ linux/fs/reiserfs/version.c	Wed Dec 31 16:00:00 1969
@@ -1,7 +0,0 @@
-/*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
- */
-
-char *reiserfs_get_version_string(void) {
-  return "ReiserFS version 3.6.25" ;
-}
diff -u --recursive --new-file v2.5.2/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.5.2/linux/fs/smbfs/dir.c	Tue Oct  2 17:03:34 2001
+++ linux/fs/smbfs/dir.c	Mon Jan 28 13:20:34 2002
@@ -228,7 +228,7 @@
 	lock_kernel();
 	server = server_from_dentry(dentry);
 	if (server->opt.protocol < SMB_PROTOCOL_LANMAN2) {
-		unsigned long age = jiffies - dir->u.smbfs_i.oldmtime;
+		unsigned long age = jiffies - SMB_I(dir)->oldmtime;
 		if (age > 2*HZ)
 			smb_invalid_dir_cache(dir);
 	}
@@ -454,9 +454,10 @@
 		goto out_no_inode;
 
 	if (have_id) {
-		inode->u.smbfs_i.fileid = fileid;
-		inode->u.smbfs_i.access = SMB_O_RDWR;
-		inode->u.smbfs_i.open = server->generation;
+		struct smb_inode_info *ei = SMB_I(inode);
+		ei->fileid = fileid;
+		ei->access = SMB_O_RDWR;
+		ei->open = server->generation;
 	}
 	d_instantiate(dentry, inode);
 out:
diff -u --recursive --new-file v2.5.2/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.5.2/linux/fs/smbfs/file.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/smbfs/file.c	Mon Jan 28 13:20:34 2002
@@ -43,7 +43,7 @@
 	 *       (should be ok with writepage_sync)
 	 */
 	smb_lock_server(server);
-	result = smb_proc_flush(server, dentry->d_inode->u.smbfs_i.fileid);
+	result = smb_proc_flush(server, SMB_I(dentry->d_inode)->fileid);
 	smb_unlock_server(server);
 	return result;
 }
@@ -126,7 +126,7 @@
 
 	offset += page->index << PAGE_CACHE_SHIFT;
 	VERBOSE("file ino=%ld, fileid=%d, count=%d@%ld, wsize=%d\n",
-		inode->i_ino, inode->u.smbfs_i.fileid, count, offset, wsize);
+		inode->i_ino, SMB_I(inode)->fileid, count, offset, wsize);
 
 	do {
 		if (count < wsize)
@@ -152,7 +152,7 @@
 		 * Update the inode now rather than waiting for a refresh.
 		 */
 		inode->i_mtime = inode->i_atime = CURRENT_TIME;
-		inode->u.smbfs_i.flags |= SMB_F_LOCALWRITE;
+		SMB_I(inode)->flags |= SMB_F_LOCALWRITE;
 		if (offset > inode->i_size)
 			inode->i_size = offset;
 	} while (count);
@@ -337,7 +337,7 @@
 	result = smb_open(dentry, smb_mode);
 	if (result)
 		goto out;
-	inode->u.smbfs_i.openers++;
+	SMB_I(inode)->openers++;
 out:
 	unlock_kernel();
 	return 0;
@@ -347,7 +347,7 @@
 smb_file_release(struct inode *inode, struct file * file)
 {
 	lock_kernel();
-	if (!--inode->u.smbfs_i.openers) {
+	if (!--SMB_I(inode)->openers) {
 		/* We must flush any dirty pages now as we won't be able to
 		   write anything after close. mmap can trigger this.
 		   "openers" should perhaps include mmap'ers ... */
diff -u --recursive --new-file v2.5.2/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.5.2/linux/fs/smbfs/inode.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/smbfs/inode.c	Mon Jan 28 13:20:34 2002
@@ -49,8 +49,52 @@
 static int  smb_statfs(struct super_block *, struct statfs *);
 static int  smb_show_options(struct seq_file *, struct vfsmount *);
 
+static kmem_cache_t *smb_inode_cachep;
+
+static struct inode *smb_alloc_inode(struct super_block *sb)
+{
+	struct smb_inode_info *ei;
+	ei = (struct smb_inode_info *)kmem_cache_alloc(smb_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void smb_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(smb_inode_cachep, SMB_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct smb_inode_info *ei = (struct smb_inode_info *) foo;
+	unsigned long flagmask = SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR;
+
+	if ((flags & flagmask) == SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	smb_inode_cachep = kmem_cache_create("smb_inode_cache",
+					     sizeof(struct smb_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (smb_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(smb_inode_cachep))
+		printk(KERN_INFO "smb_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations smb_sops =
 {
+	alloc_inode:	smb_alloc_inode,
+	destroy_inode:	smb_destroy_inode,
 	put_inode:	force_delete,
 	delete_inode:	smb_delete_inode,
 	put_super:	smb_put_super,
@@ -71,7 +115,12 @@
 	if (!result)
 		return result;
 	result->i_ino = fattr->f_ino;
-	memset(&(result->u.smbfs_i), 0, sizeof(result->u.smbfs_i));
+	SMB_I(result)->open = 0;
+	SMB_I(result)->fileid = 0;
+	SMB_I(result)->access = 0;
+	SMB_I(result)->flags = 0;
+	SMB_I(result)->closed = 0;
+	SMB_I(result)->openers = 0;
 	smb_set_inode_attr(result, fattr);
 	if (S_ISREG(result->i_mode)) {
 		result->i_op = &smb_file_inode_operations;
@@ -105,7 +154,7 @@
 	fattr->f_blksize= inode->i_blksize;
 	fattr->f_blocks	= inode->i_blocks;
 
-	fattr->attr	= inode->u.smbfs_i.attr;
+	fattr->attr	= SMB_I(inode)->attr;
 	/*
 	 * Keep the attributes in sync with the inode permissions.
 	 */
@@ -122,6 +171,8 @@
 void
 smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
 {
+	struct smb_inode_info *ei = SMB_I(inode);
+
 	/*
 	 * A size change should have a different mtime, or same mtime
 	 * but different size.
@@ -140,11 +191,12 @@
 	inode->i_size	= fattr->f_size;
 	inode->i_mtime	= fattr->f_mtime;
 	inode->i_atime	= fattr->f_atime;
-	inode->u.smbfs_i.attr = fattr->attr;
+	ei->attr = fattr->attr;
+
 	/*
 	 * Update the "last time refreshed" field for revalidation.
 	 */
-	inode->u.smbfs_i.oldmtime = jiffies;
+	ei->oldmtime = jiffies;
 
 	if (inode->i_mtime != last_time || inode->i_size != last_sz) {
 		VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n",
@@ -237,9 +289,9 @@
 	/*
 	 * Check whether we've recently refreshed the inode.
 	 */
-	if (time_before(jiffies, inode->u.smbfs_i.oldmtime + SMB_MAX_AGE(s))) {
+	if (time_before(jiffies, SMB_I(inode)->oldmtime + SMB_MAX_AGE(s))) {
 		VERBOSE("up-to-date, ino=%ld, jiffies=%lu, oldtime=%lu\n",
-			inode->i_ino, jiffies, inode->u.smbfs_i.oldmtime);
+			inode->i_ino, jiffies, SMB_I(inode)->oldmtime);
 		goto out;
 	}
 
@@ -579,8 +631,8 @@
 		error = smb_open(dentry, O_WRONLY);
 		if (error)
 			goto out;
-		error = smb_proc_trunc(server, inode->u.smbfs_i.fileid,
-					 attr->ia_size);
+		error = smb_proc_trunc(server, SMB_I(inode)->fileid,
+				       attr->ia_size);
 		if (error)
 			goto out;
 		error = vmtruncate(inode, attr->ia_size);
@@ -658,6 +710,7 @@
 
 static int __init init_smb_fs(void)
 {
+	int err;
 	DEBUG1("registering ...\n");
 
 #ifdef DEBUG_SMB_MALLOC
@@ -666,13 +719,24 @@
 	smb_current_vmalloced = 0;
 #endif
 
-	return register_filesystem(&smb_fs_type);
+	err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&smb_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_smb_fs(void)
 {
 	DEBUG1("unregistering ...\n");
 	unregister_filesystem(&smb_fs_type);
+	destroy_inodecache();
 #ifdef DEBUG_SMB_MALLOC
 	printk(KERN_DEBUG "smb_malloced: %d\n", smb_malloced);
 	printk(KERN_DEBUG "smb_current_kmalloced: %d\n",smb_current_kmalloced);
diff -u --recursive --new-file v2.5.2/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.5.2/linux/fs/smbfs/proc.c	Sun Oct  7 16:47:43 2001
+++ linux/fs/smbfs/proc.c	Mon Jan 28 13:20:34 2002
@@ -940,6 +940,7 @@
 smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
 {
 	struct inode *ino = dentry->d_inode;
+	struct smb_inode_info *ei = SMB_I(ino);
 	int mode, read_write = 0x42, read_only = 0x40;
 	int res;
 	char *p;
@@ -990,12 +991,12 @@
 	}
 	/* We should now have data in vwv[0..6]. */
 
-	ino->u.smbfs_i.fileid = WVAL(server->packet, smb_vwv0);
-	ino->u.smbfs_i.attr   = WVAL(server->packet, smb_vwv1);
+	ei->fileid = WVAL(server->packet, smb_vwv0);
+	ei->attr   = WVAL(server->packet, smb_vwv1);
 	/* smb_vwv2 has mtime */
 	/* smb_vwv4 has size  */
-	ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK);
-	ino->u.smbfs_i.open = server->generation;
+	ei->access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK);
+	ei->open = server->generation;
 
 out:
 	return res;
@@ -1010,6 +1011,7 @@
 {
 	struct inode *inode = dentry->d_inode;
 	int result;
+	__u16 access;
 
 	result = -ENOENT;
 	if (!inode) {
@@ -1040,11 +1042,10 @@
 	 * Check whether the access is compatible with the desired mode.
 	 */
 	result = 0;
-	if (inode->u.smbfs_i.access != wish && 
-	    inode->u.smbfs_i.access != SMB_O_RDWR)
-	{
+	access = SMB_I(inode)->access;
+	if (access != wish && access != SMB_O_RDWR) {
 		PARANOIA("%s/%s access denied, access=%x, wish=%x\n",
-			 DENTRY_PATH(dentry), inode->u.smbfs_i.access, wish);
+			 DENTRY_PATH(dentry), access, wish);
 		result = -EACCES;
 	}
 out:
@@ -1073,6 +1074,7 @@
 static int 
 smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino)
 {
+	struct smb_inode_info *ei = SMB_I(ino);
 	int result = 0;
 	if (smb_is_open(ino))
 	{
@@ -1080,7 +1082,7 @@
 		 * We clear the open flag in advance, in case another
  		 * process observes the value while we block below.
 		 */
-		ino->u.smbfs_i.open = 0;
+		ei->open = 0;
 
 		/*
 		 * Kludge alert: SMB timestamps are accurate only to
@@ -1096,22 +1098,21 @@
 		 * update the time stamps to sync mtime and atime.
 		 */
 		if ((server->opt.protocol >= SMB_PROTOCOL_LANMAN2) &&
-		    !(ino->u.smbfs_i.access == SMB_O_RDONLY))
+		    !(ei->access == SMB_O_RDONLY))
 		{
 			struct smb_fattr fattr;
 			smb_get_inode_attr(ino, &fattr);
 			smb_proc_setattr_ext(server, ino, &fattr);
 		}
 
-		result = smb_proc_close(server, ino->u.smbfs_i.fileid,
-						ino->i_mtime);
+		result = smb_proc_close(server, ei->fileid, ino->i_mtime);
 		/*
 		 * Force a revalidation after closing ... some servers
 		 * don't post the size until the file has been closed.
 		 */
 		if (server->opt.protocol < SMB_PROTOCOL_NT1)
-			ino->u.smbfs_i.oldmtime = 0;
-		ino->u.smbfs_i.closed = jiffies;
+			ei->oldmtime = 0;
+		ei->closed = jiffies;
 	}
 	return result;
 }
@@ -1160,7 +1161,7 @@
 	smb_lock_server(server);
 	smb_setup_header(server, SMBread, 5, 0);
 	buf = server->packet;
-	WSET(buf, smb_vwv0, inode->u.smbfs_i.fileid);
+	WSET(buf, smb_vwv0, SMB_I(inode)->fileid);
 	WSET(buf, smb_vwv1, count);
 	DSET(buf, smb_vwv2, offset);
 	WSET(buf, smb_vwv4, 0);
@@ -1193,7 +1194,7 @@
 
 out:
 	VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",
-		inode->i_ino, inode->u.smbfs_i.fileid, count, result);
+		inode->i_ino, SMB_I(inode)->fileid, count, result);
 	smb_unlock_server(server);
 	return result;
 }
@@ -1204,10 +1205,10 @@
 	struct smb_sb_info *server = server_from_inode(inode);
 	int result;
 	__u8 *p;
-	__u16 fileid = inode->u.smbfs_i.fileid;
+	__u16 fileid = SMB_I(inode)->fileid;
 
 	VERBOSE("ino=%ld, fileid=%d, count=%d@%ld, packet_size=%d\n",
-		inode->i_ino, inode->u.smbfs_i.fileid, count, offset,
+		inode->i_ino, SMB_I(inode)->fileid, count, offset,
 		server->packet_size);
 
 	smb_lock_server(server);
@@ -2291,10 +2292,10 @@
 	 */
 	if (server->mnt->flags & SMB_MOUNT_WIN95 &&
 	    inode &&
-	    inode->u.smbfs_i.flags & SMB_F_LOCALWRITE &&
+	    SMB_I(inode)->flags & SMB_F_LOCALWRITE &&
 	    smb_is_open(inode))
 	{
-		__u16 fileid = inode->u.smbfs_i.fileid;
+		__u16 fileid = SMB_I(inode)->fileid;
 		fattr->f_size = smb_proc_seek(server, fileid, 2, 0);
 	}
 
@@ -2395,7 +2396,7 @@
 
       retry:
 	smb_setup_header(server, SMBsetattrE, 7, 0);
-	WSET(server->packet, smb_vwv0, inode->u.smbfs_i.fileid);
+	WSET(server->packet, smb_vwv0, SMB_I(inode)->fileid);
 	/* We don't change the creation time */
 	WSET(server->packet, smb_vwv1, 0);
 	WSET(server->packet, smb_vwv2, 0);
@@ -2511,8 +2512,7 @@
 	/* setting the time on a Win95 server fails (tridge) */
 	if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 && 
 	    !(server->mnt->flags & SMB_MOUNT_WIN95)) {
-		if (smb_is_open(inode) &&
-		    inode->u.smbfs_i.access != SMB_O_RDONLY)
+		if (smb_is_open(inode) && SMB_I(inode)->access != SMB_O_RDONLY)
 			result = smb_proc_setattr_ext(server, inode, fattr);
 		else
 			result = smb_proc_setattr_trans2(server, dentry, fattr);
diff -u --recursive --new-file v2.5.2/linux/fs/super.c linux/fs/super.c
--- v2.5.2/linux/fs/super.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/super.c	Wed Jan 23 15:32:20 2002
@@ -408,9 +408,8 @@
 		put_anon_dev(dev);
 }
 
-struct vfsmount *alloc_vfsmnt(void);
+struct vfsmount *alloc_vfsmnt(char *name);
 void free_vfsmnt(struct vfsmount *mnt);
-void set_devname(struct vfsmount *mnt, const char *name);
 
 static inline struct super_block * find_super(kdev_t dev)
 {
@@ -790,10 +789,9 @@
 	if (!type)
 		return ERR_PTR(-ENODEV);
 
-	mnt = alloc_vfsmnt();
+	mnt = alloc_vfsmnt(name);
 	if (!mnt)
 		goto out;
-	set_devname(mnt, name);
 	if (type->fs_flags & FS_REQUIRES_DEV)
 		sb = get_sb_bdev(type, flags, name, data);
 	else if (type->fs_flags & FS_SINGLE)
diff -u --recursive --new-file v2.5.2/linux/fs/sysv/ChangeLog linux/fs/sysv/ChangeLog
--- v2.5.2/linux/fs/sysv/ChangeLog	Mon Jan 14 18:25:11 2002
+++ linux/fs/sysv/ChangeLog	Thu Jan 24 22:05:04 2002
@@ -1,3 +1,37 @@
+2002-01-24  David S. Miller  <davem@redhat.com>
+
+	* inode.c: Include linux/init.h
+
+Mon Jan 21 2001  Alexander Viro  <viro@math.psu.edu>
+	* ialloc.c (sysv_new_inode): zero SYSV_I(inode)->i_data out.
+	* i_vnode renamed to vfs_inode.  Sorry, but let's keep that
+	  consistent.
+
+Sat Jan 19 2001  Christoph Hellwig  <hch@infradead.org>
+
+	* include/linux/sysv_fs.h (SYSV_I): Get fs-private inode data using
+		list_entry() instead of inode->u.
+	* include/linux/sysv_fs_i.h: Add 'struct inode  i_vnode' field to
+		sysv_inode_info structure.
+	* inode.c: Include <linux/slab.h>, implement alloc_inode/destroy_inode
+		sop methods, add infrastructure for per-fs inode slab cache.
+	* super.c (init_sysv_fs): Initialize inode cache, recover properly
+		in the case of failed register_filesystem for V7.
+	(exit_sysv_fs): Destroy inode cache.
+
+Sat Jan 19 2001  Christoph Hellwig  <hch@infradead.org>
+
+	* include/linux/sysv_fs.h: Include <linux/sysv_fs_i.h>, declare SYSV_I().
+	* dir.c (sysv_find_entry): Use SYSV_I() instead of ->u.sysv_i to
+		access fs-private inode data.
+	* ialloc.c (sysv_new_inode): Likewise.
+	* inode.c (sysv_read_inode): Likewise.
+	(sysv_update_inode): Likewise.
+	* itree.c (get_branch): Likewise.
+	(sysv_truncate): Likewise.
+	* symlink.c (sysv_readlink): Likewise.
+	(sysv_follow_link): Likewise.
+
 Fri Jan  4 2001  Alexander Viro  <viro@math.psu.edu>
 
 	* ialloc.c (sysv_free_inode): Use sb->s_id instead of bdevname().
diff -u --recursive --new-file v2.5.2/linux/fs/sysv/dir.c linux/fs/sysv/dir.c
--- v2.5.2/linux/fs/sysv/dir.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/sysv/dir.c	Wed Jan 23 15:32:19 2002
@@ -145,7 +145,7 @@
 
 	*res_page = NULL;
 
-	start = dir->u.sysv_i.i_dir_start_lookup;
+	start = SYSV_I(dir)->i_dir_start_lookup;
 	if (start >= npages)
 		start = 0;
 	n = start;
@@ -174,7 +174,7 @@
 	return NULL;
 
 found:
-	dir->u.sysv_i.i_dir_start_lookup = n;
+	SYSV_I(dir)->i_dir_start_lookup = n;
 	*res_page = page;
 	return de;
 }
diff -u --recursive --new-file v2.5.2/linux/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c
--- v2.5.2/linux/fs/sysv/ialloc.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/sysv/ialloc.c	Wed Jan 23 15:32:19 2002
@@ -165,7 +165,8 @@
 	inode->i_ino = fs16_to_cpu(sb, ino);
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_blocks = inode->i_blksize = 0;
-	inode->u.sysv_i.i_dir_start_lookup = 0;
+	memset(SYSV_I(inode)->i_data, 0, sizeof(SYSV_I(inode)->i_data));
+	SYSV_I(inode)->i_dir_start_lookup = 0;
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
 
diff -u --recursive --new-file v2.5.2/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.5.2/linux/fs/sysv/inode.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/sysv/inode.c	Thu Jan 24 22:05:04 2002
@@ -26,6 +26,8 @@
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
 #include <linux/highuid.h>
+#include <linux/slab.h>
+#include <linux/init.h>
 #include <asm/byteorder.h>
 
 /* This is only called on sync() and umount(), when s_dirt=1. */
@@ -144,6 +146,7 @@
 	struct super_block * sb = inode->i_sb;
 	struct buffer_head * bh;
 	struct sysv_inode * raw_inode;
+	struct sysv_inode_info * si;
 	unsigned int block, ino;
 	dev_t rdev = 0;
 
@@ -169,13 +172,15 @@
 	inode->i_mtime = fs32_to_cpu(sb, raw_inode->i_mtime);
 	inode->i_ctime = fs32_to_cpu(sb, raw_inode->i_ctime);
 	inode->i_blocks = inode->i_blksize = 0;
+
+	si = SYSV_I(inode);
 	for (block = 0; block < 10+1+1+1; block++)
 		read3byte(sb, &raw_inode->i_a.i_addb[3*block],
-			(unsigned char*)&inode->u.sysv_i.i_data[block]);
+			(unsigned char*)&si->i_data[block]);
 	brelse(bh);
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-		rdev = (u16)fs32_to_cpu(sb, inode->u.sysv_i.i_data[0]);
-	inode->u.sysv_i.i_dir_start_lookup = 0;
+		rdev = (u16)fs32_to_cpu(sb, si->i_data[0]);
+	si->i_dir_start_lookup = 0;
 	sysv_set_inode(inode, rdev);
 	return;
 
@@ -189,6 +194,7 @@
 	struct super_block * sb = inode->i_sb;
 	struct buffer_head * bh;
 	struct sysv_inode * raw_inode;
+	struct sysv_inode_info * si;
 	unsigned int ino, block;
 
 	ino = inode->i_ino;
@@ -211,11 +217,12 @@
 	raw_inode->i_atime = cpu_to_fs32(sb, inode->i_atime);
 	raw_inode->i_mtime = cpu_to_fs32(sb, inode->i_mtime);
 	raw_inode->i_ctime = cpu_to_fs32(sb, inode->i_ctime);
+
+	si = SYSV_I(inode);
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-		inode->u.sysv_i.i_data[0] = 
-			cpu_to_fs32(sb, kdev_t_to_nr(inode->i_rdev));
+		si->i_data[0] = cpu_to_fs32(sb, kdev_t_to_nr(inode->i_rdev));
 	for (block = 0; block < 10+1+1+1; block++)
-		write3byte(sb, (unsigned char*)&inode->u.sysv_i.i_data[block],
+		write3byte(sb, (unsigned char*)&si->i_data[block],
 			&raw_inode->i_a.i_addb[3*block]);
 	mark_buffer_dirty(bh);
 	return bh;
@@ -260,7 +267,35 @@
 	unlock_kernel();
 }
 
+static kmem_cache_t *sysv_inode_cachep;
+
+static struct inode *sysv_alloc_inode(struct super_block *sb)
+{
+	struct sysv_inode_info *si;
+
+	si = kmem_cache_alloc(sysv_inode_cachep, SLAB_KERNEL);
+	if (!si)
+		return NULL;
+	return &si->vfs_inode;
+}
+
+static void sysv_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(sysv_inode_cachep, SYSV_I(inode));
+}
+
+static void init_once(void *p, kmem_cache_t *cachep, unsigned long flags)
+{
+	struct sysv_inode_info *si = (struct sysv_inode_info *)p;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+			SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&si->vfs_inode);
+}
+
 struct super_operations sysv_sops = {
+	alloc_inode:	sysv_alloc_inode,
+	destroy_inode:	sysv_destroy_inode,
 	read_inode:	sysv_read_inode,
 	write_inode:	sysv_write_inode,
 	delete_inode:	sysv_delete_inode,
@@ -268,3 +303,18 @@
 	write_super:	sysv_write_super,
 	statfs:		sysv_statfs,
 };
+
+int __init sysv_init_icache(void)
+{
+	sysv_inode_cachep = kmem_cache_create("sysv_inode_cache",
+			sizeof(struct sysv_inode_info), 0,
+			SLAB_HWCACHE_ALIGN, init_once, NULL);
+	if (!sysv_inode_cachep)
+		return -ENOMEM;
+	return 0;
+}
+
+void sysv_destroy_icache(void)
+{
+	kmem_cache_destroy(sysv_inode_cachep);
+}
diff -u --recursive --new-file v2.5.2/linux/fs/sysv/itree.c linux/fs/sysv/itree.c
--- v2.5.2/linux/fs/sysv/itree.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/sysv/itree.c	Wed Jan 23 15:32:19 2002
@@ -91,7 +91,7 @@
 	struct buffer_head *bh;
 
 	*err = 0;
-	add_chain (chain, NULL, inode->u.sysv_i.i_data + *offsets);
+	add_chain (chain, NULL, SYSV_I(inode)->i_data + *offsets);
 	if (!p->key)
 		goto no_block;
 	while (--depth) {
@@ -348,7 +348,7 @@
 
 void sysv_truncate (struct inode * inode)
 {
-	u32 *i_data = inode->u.sysv_i.i_data;
+	u32 *i_data = SYSV_I(inode)->i_data;
 	int offsets[DEPTH];
 	Indirect chain[DEPTH];
 	Indirect *partial;
diff -u --recursive --new-file v2.5.2/linux/fs/sysv/super.c linux/fs/sysv/super.c
--- v2.5.2/linux/fs/sysv/super.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/sysv/super.c	Wed Jan 23 15:32:20 2002
@@ -479,18 +479,37 @@
 static DECLARE_FSTYPE_DEV(sysv_fs_type, "sysv", sysv_read_super);
 static DECLARE_FSTYPE_DEV(v7_fs_type, "v7", v7_read_super);
 
+extern int sysv_init_icache(void) __init;
+extern void sysv_destroy_icache(void);
+
 static int __init init_sysv_fs(void)
 {
-	int err = register_filesystem(&sysv_fs_type);
-	if (!err)
-		err = register_filesystem(&v7_fs_type);
-	return err;
+	int error;
+
+	error = sysv_init_icache();
+	if (error)
+		goto out;
+	error = register_filesystem(&sysv_fs_type);
+	if (error)
+		goto destroy_icache;
+	error = register_filesystem(&v7_fs_type);
+	if (error)
+		goto unregister;
+	return 0;
+
+unregister:
+	unregister_filesystem(&sysv_fs_type);
+destroy_icache:
+	sysv_destroy_icache();
+out:
+	return error;
 }
 
 static void __exit exit_sysv_fs(void)
 {
 	unregister_filesystem(&sysv_fs_type);
 	unregister_filesystem(&v7_fs_type);
+	sysv_destroy_icache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/sysv/symlink.c linux/fs/sysv/symlink.c
--- v2.5.2/linux/fs/sysv/symlink.c	Sun Sep  2 10:34:36 2001
+++ linux/fs/sysv/symlink.c	Wed Jan 23 15:32:19 2002
@@ -6,16 +6,17 @@
  */
 
 #include <linux/fs.h>
+#include <linux/sysv_fs.h>
 
 static int sysv_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
-	char *s = (char *)dentry->d_inode->u.sysv_i.i_data;
+	char *s = (char *)SYSV_I(dentry->d_inode)->i_data;
 	return vfs_readlink(dentry, buffer, buflen, s);
 }
 
 static int sysv_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char *s = (char *)dentry->d_inode->u.sysv_i.i_data;
+	char *s = (char *)SYSV_I(dentry->d_inode)->i_data;
 	return vfs_follow_link(nd, s);
 }
 
diff -u --recursive --new-file v2.5.2/linux/fs/udf/ialloc.c linux/fs/udf/ialloc.c
--- v2.5.2/linux/fs/udf/ialloc.c	Thu Oct 11 08:59:24 2001
+++ linux/fs/udf/ialloc.c	Wed Jan 23 15:32:20 2002
@@ -95,6 +95,11 @@
 	}
 	lock_super(sb);
 
+	UDF_I_UNIQUE(inode) = 0;
+	UDF_I_LENEXTENTS(inode) = 0;
+	UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
+	UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
+	UDF_I_STRAT4096(inode) = 0;
 	if (UDF_SB_LVIDBH(sb))
 	{
 		struct LogicalVolHeaderDesc *lvhd;
diff -u --recursive --new-file v2.5.2/linux/fs/udf/inode.c linux/fs/udf/inode.c
--- v2.5.2/linux/fs/udf/inode.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/udf/inode.c	Wed Jan 23 15:32:20 2002
@@ -945,7 +945,6 @@
 	 *      i_nlink = 1
 	 *      i_op = NULL;
 	 */
-
 	inode->i_blksize = PAGE_SIZE;
 
 	bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
@@ -1042,6 +1041,16 @@
 		UDF_I_STRAT4096(inode) = 1;
 
 	UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICB_FLAG_ALLOC_MASK;
+	UDF_I_UMTIME(inode) = 0;
+	UDF_I_UCTIME(inode) = 0;
+	UDF_I_CRTIME(inode) = 0;
+	UDF_I_UCRTIME(inode) = 0;
+	UDF_I_UNIQUE(inode) = 0;
+	UDF_I_LENEATTR(inode) = 0;
+	UDF_I_LENEXTENTS(inode) = 0;
+	UDF_I_LENALLOC(inode) = 0;
+	UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
+	UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
 	if (fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY)
 		UDF_I_EXTENDED_FE(inode) = 1;
 	else if (fe->descTag.tagIdent == TID_FILE_ENTRY)
@@ -1069,9 +1078,6 @@
 
 	inode->i_mode = udf_convert_permissions(fe);
 	inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
-
-	UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
-	UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
 
 	if (UDF_I_EXTENDED_FE(inode) == 0)
 	{
diff -u --recursive --new-file v2.5.2/linux/fs/udf/super.c linux/fs/udf/super.c
--- v2.5.2/linux/fs/udf/super.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/udf/super.c	Wed Jan 23 15:32:20 2002
@@ -98,8 +98,52 @@
 /* UDF filesystem type */
 static DECLARE_FSTYPE_DEV(udf_fstype, "udf", udf_read_super);
 
+static kmem_cache_t * udf_inode_cachep;
+
+static struct inode *udf_alloc_inode(struct super_block *sb)
+{
+	struct udf_inode_info *ei;
+	ei = (struct udf_inode_info *)kmem_cache_alloc(udf_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void udf_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(udf_inode_cachep, UDF_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct udf_inode_info *ei = (struct udf_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	udf_inode_cachep = kmem_cache_create("udf_inode_cache",
+					     sizeof(struct udf_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (udf_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(udf_inode_cachep))
+		printk(KERN_INFO "udf_inode_cache: not all structures were freed\n");
+}
+
 /* Superblock operations */
 static struct super_operations udf_sb_ops = {
+	alloc_inode:		udf_alloc_inode,
+	destroy_inode:		udf_destroy_inode,
 	read_inode:		udf_read_inode,
 	write_inode:		udf_write_inode,
 	put_inode:		udf_put_inode,
@@ -130,14 +174,26 @@
 
 static int __init init_udf_fs(void)
 {
+	int err;
 	printk(KERN_NOTICE "udf: registering filesystem\n");
-	return register_filesystem(&udf_fstype);
+	err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&udf_fstype);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_udf_fs(void)
 {
 	printk(KERN_NOTICE "udf: unregistering filesystem\n");
 	unregister_filesystem(&udf_fstype);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/udf/udf_i.h linux/fs/udf/udf_i.h
--- v2.5.2/linux/fs/udf/udf_i.h	Mon Jul  2 14:10:02 2001
+++ linux/fs/udf/udf_i.h	Wed Jan 23 15:32:20 2002
@@ -1,7 +1,11 @@
 #ifndef __LINUX_UDF_I_H
 #define __LINUX_UDF_I_H
 
-#define UDF_I(X)			(&((X)->u.udf_i))
+#include <linux/udf_fs_i.h>
+static inline struct udf_inode_info *UDF_I(struct inode *inode)
+{
+	return list_entry(inode, struct udf_inode_info, vfs_inode);
+}
 
 #define UDF_I_LOCATION(X)	( UDF_I(X)->i_location )
 #define UDF_I_LENEATTR(X)	( UDF_I(X)->i_lenEAttr )
diff -u --recursive --new-file v2.5.2/linux/fs/ufs/balloc.c linux/fs/ufs/balloc.c
--- v2.5.2/linux/fs/ufs/balloc.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/ufs/balloc.c	Mon Jan 21 15:37:32 2002
@@ -271,7 +271,7 @@
 			unlock_super (sb);
 			return (unsigned)-1;
 		}
-		if (fragment < inode->u.ufs_i.i_lastfrag) {
+		if (fragment < UFS_I(inode)->i_lastfrag) {
 			UFSD(("EXIT (ALREADY ALLOCATED)\n"))
 			unlock_super (sb);
 			return 0;
@@ -310,7 +310,7 @@
 			*p = cpu_to_fs32(sb, result);
 			*err = 0;
 			inode->i_blocks += count << uspi->s_nspfshift;
-			inode->u.ufs_i.i_lastfrag = max_t(u32, inode->u.ufs_i.i_lastfrag, fragment + count);
+			UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
 			NULLIFY_FRAGMENTS
 		}
 		unlock_super(sb);
@@ -325,7 +325,7 @@
 	if (result) {
 		*err = 0;
 		inode->i_blocks += count << uspi->s_nspfshift;
-		inode->u.ufs_i.i_lastfrag = max_t(u32, inode->u.ufs_i.i_lastfrag, fragment + count);
+		UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
 		NULLIFY_FRAGMENTS
 		unlock_super(sb);
 		UFSD(("EXIT, result %u\n", result))
@@ -378,7 +378,7 @@
 		*p = cpu_to_fs32(sb, result);
 		*err = 0;
 		inode->i_blocks += count << uspi->s_nspfshift;
-		inode->u.ufs_i.i_lastfrag = max_t(u32, inode->u.ufs_i.i_lastfrag, fragment + count);
+		UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
 		NULLIFY_FRAGMENTS
 		unlock_super(sb);
 		if (newcount < request)
diff -u --recursive --new-file v2.5.2/linux/fs/ufs/file.c linux/fs/ufs/file.c
--- v2.5.2/linux/fs/ufs/file.c	Sun Aug 12 17:37:53 2001
+++ linux/fs/ufs/file.c	Tue Jan 29 21:15:47 2002
@@ -47,6 +47,8 @@
 	long long retval;
 	struct inode *inode = file->f_dentry->d_inode;
 
+	lock_kernel();
+
 	switch (origin) {
 		case 2:
 			offset += inode->i_size;
@@ -64,6 +66,7 @@
 		}
 		retval = offset;
 	}
+	unlock_kernel();
 	return retval;
 }
 
diff -u --recursive --new-file v2.5.2/linux/fs/ufs/ialloc.c linux/fs/ufs/ialloc.c
--- v2.5.2/linux/fs/ufs/ialloc.c	Mon Nov 19 14:55:46 2001
+++ linux/fs/ufs/ialloc.c	Mon Jan 21 15:37:32 2002
@@ -142,7 +142,7 @@
  * For other inodes, search forward from the parent directory's block
  * group to find a free inode.
  */
-struct inode * ufs_new_inode (const struct inode * dir,	int mode)
+struct inode * ufs_new_inode(struct inode * dir, int mode)
 {
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
@@ -151,6 +151,7 @@
 	struct ufs_cylinder_group * ucg;
 	struct inode * inode;
 	unsigned cg, bit, i, j, start;
+	struct ufs_inode_info *ufsi;
 
 	UFSD(("ENTER\n"))
 	
@@ -161,6 +162,7 @@
 	inode = new_inode(sb);
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
+	ufsi = UFS_I(inode);
 	uspi = sb->u.ufs_sb.s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 
@@ -261,8 +263,13 @@
 	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size (for stat), not the fs block size */
 	inode->i_blocks = 0;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-	inode->u.ufs_i.i_flags = dir->u.ufs_i.i_flags;
-	inode->u.ufs_i.i_lastfrag = 0;
+	ufsi->i_flags = UFS_I(dir)->i_flags;
+	ufsi->i_lastfrag = 0;
+	ufsi->i_gen = 0;
+	ufsi->i_shadow = 0;
+	ufsi->i_osync = 0;
+	ufsi->i_oeftflag = 0;
+	memset(&ufsi->i_u1, 0, sizeof(ufsi->i_u1));
 
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
diff -u --recursive --new-file v2.5.2/linux/fs/ufs/inode.c linux/fs/ufs/inode.c
--- v2.5.2/linux/fs/ufs/inode.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/ufs/inode.c	Mon Jan 21 15:37:32 2002
@@ -84,6 +84,7 @@
 
 int ufs_frag_map(struct inode *inode, int frag)
 {
+	struct ufs_inode_info *ufsi = UFS_I(inode);
 	struct super_block *sb = inode->i_sb;
 	struct ufs_sb_private_info *uspi = sb->u.ufs_sb.s_uspi;
 	int mask = uspi->s_apbmask>>uspi->s_fpbshift;
@@ -99,7 +100,7 @@
 	p = offsets;
 
 	lock_kernel();
-	block = inode->u.ufs_i.i_u1.i_data[*p++];
+	block = ufsi->i_u1.i_data[*p++];
 	if (!block)
 		goto out;
 	while (--depth) {
@@ -124,6 +125,7 @@
 	unsigned int fragment, unsigned int new_fragment,
 	unsigned int required, int *err, int metadata, long *phys, int *new)
 {
+	struct ufs_inode_info *ufsi = UFS_I(inode);
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct buffer_head * result;
@@ -138,12 +140,12 @@
 	uspi = sb->u.ufs_sb.s_uspi;
 	block = ufs_fragstoblks (fragment);
 	blockoff = ufs_fragnum (fragment);
-	p = inode->u.ufs_i.i_u1.i_data + block;
+	p = ufsi->i_u1.i_data + block;
 	goal = 0;
 
 repeat:
 	tmp = fs32_to_cpu(sb, *p);
-	lastfrag = inode->u.ufs_i.i_lastfrag;
+	lastfrag = ufsi->i_lastfrag;
 	if (tmp && fragment < lastfrag) {
 		if (metadata) {
 			result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
@@ -169,19 +171,19 @@
 		 * We must reallocate last allocated block
 		 */
 		if (lastblockoff) {
-			p2 = inode->u.ufs_i.i_u1.i_data + lastblock;
+			p2 = ufsi->i_u1.i_data + lastblock;
 			tmp = ufs_new_fragments (inode, p2, lastfrag, 
 				fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff, err);
 			if (!tmp) {
-				if (lastfrag != inode->u.ufs_i.i_lastfrag)
+				if (lastfrag != ufsi->i_lastfrag)
 					goto repeat;
 				else
 					return NULL;
 			}
-			lastfrag = inode->u.ufs_i.i_lastfrag;
+			lastfrag = ufsi->i_lastfrag;
 			
 		}
-		goal = fs32_to_cpu(sb, inode->u.ufs_i.i_u1.i_data[lastblock]) + uspi->s_fpb;
+		goal = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock]) + uspi->s_fpb;
 		tmp = ufs_new_fragments (inode, p, fragment - blockoff, 
 			goal, required + blockoff, err);
 	}
@@ -196,14 +198,14 @@
 	 * We will allocate new block before last allocated block
 	 */
 	else /* (lastblock > block) */ {
-		if (lastblock && (tmp = fs32_to_cpu(sb, inode->u.ufs_i.i_u1.i_data[lastblock-1])))
+		if (lastblock && (tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock-1])))
 			goal = tmp + uspi->s_fpb;
 		tmp = ufs_new_fragments (inode, p, fragment - blockoff, 
 			goal, uspi->s_fpb, err);
 	}
 	if (!tmp) {
 		if ((!blockoff && *p) || 
-		    (blockoff && lastfrag != inode->u.ufs_i.i_lastfrag))
+		    (blockoff && lastfrag != ufsi->i_lastfrag))
 			goto repeat;
 		*err = -ENOSPC;
 		return NULL;
@@ -470,6 +472,7 @@
 
 void ufs_read_inode (struct inode * inode)
 {
+	struct ufs_inode_info *ufsi = UFS_I(inode);
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct ufs_inode * ufs_inode;	
@@ -517,24 +520,23 @@
 	inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks);
 	inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size (for stat) */
 	inode->i_version = ++event;
-
-	inode->u.ufs_i.i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags);
-	inode->u.ufs_i.i_gen = fs32_to_cpu(sb, ufs_inode->ui_gen);
-	inode->u.ufs_i.i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
-	inode->u.ufs_i.i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
-	inode->u.ufs_i.i_lastfrag = (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
+	ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags);
+	ufsi->i_gen = fs32_to_cpu(sb, ufs_inode->ui_gen);
+	ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
+	ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
+	ufsi->i_lastfrag = (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
 	
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 		;
 	else if (inode->i_blocks) {
 		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
-			inode->u.ufs_i.i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i];
+			ufsi->i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i];
 	}
 	else {
 		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
-			inode->u.ufs_i.i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i];
+			ufsi->i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i];
 	}
-
+	ufsi->i_osync = 0;
 
 	if (S_ISREG(inode->i_mode)) {
 		inode->i_op = &ufs_file_inode_operations;
@@ -566,6 +568,7 @@
 
 static int ufs_update_inode(struct inode * inode, int do_sync)
 {
+	struct ufs_inode_info *ufsi = UFS_I(inode);
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct buffer_head * bh;
@@ -606,23 +609,23 @@
 	ufs_inode->ui_mtime.tv_sec = cpu_to_fs32(sb, inode->i_mtime);
 	ufs_inode->ui_mtime.tv_usec = 0;
 	ufs_inode->ui_blocks = cpu_to_fs32(sb, inode->i_blocks);
-	ufs_inode->ui_flags = cpu_to_fs32(sb, inode->u.ufs_i.i_flags);
-	ufs_inode->ui_gen = cpu_to_fs32(sb, inode->u.ufs_i.i_gen);
+	ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags);
+	ufs_inode->ui_gen = cpu_to_fs32(sb, ufsi->i_gen);
 
 	if ((flags & UFS_UID_MASK) == UFS_UID_EFT) {
-		ufs_inode->ui_u3.ui_sun.ui_shadow = cpu_to_fs32(sb, inode->u.ufs_i.i_shadow);
-		ufs_inode->ui_u3.ui_sun.ui_oeftflag = cpu_to_fs32(sb, inode->u.ufs_i.i_oeftflag);
+		ufs_inode->ui_u3.ui_sun.ui_shadow = cpu_to_fs32(sb, ufsi->i_shadow);
+		ufs_inode->ui_u3.ui_sun.ui_oeftflag = cpu_to_fs32(sb, ufsi->i_oeftflag);
 	}
 
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 		ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, kdev_t_to_nr(inode->i_rdev));
 	else if (inode->i_blocks) {
 		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
-			ufs_inode->ui_u2.ui_addr.ui_db[i] = inode->u.ufs_i.i_u1.i_data[i];
+			ufs_inode->ui_u2.ui_addr.ui_db[i] = ufsi->i_u1.i_data[i];
 	}
 	else {
 		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
-			ufs_inode->ui_u2.ui_symlink[i] = inode->u.ufs_i.i_u1.i_symlink[i];
+			ufs_inode->ui_u2.ui_symlink[i] = ufsi->i_u1.i_symlink[i];
 	}
 
 	if (!inode->i_nlink)
@@ -653,7 +656,7 @@
 
 void ufs_delete_inode (struct inode * inode)
 {
-	/*inode->u.ufs_i.i_dtime = CURRENT_TIME;*/
+	/*UFS_I(inode)->i_dtime = CURRENT_TIME;*/
 	lock_kernel();
 	mark_inode_dirty(inode);
 	ufs_update_inode(inode, IS_SYNC(inode));
diff -u --recursive --new-file v2.5.2/linux/fs/ufs/namei.c linux/fs/ufs/namei.c
--- v2.5.2/linux/fs/ufs/namei.c	Sat Oct 20 19:14:42 2001
+++ linux/fs/ufs/namei.c	Mon Jan 21 15:37:32 2002
@@ -138,7 +138,7 @@
 	} else {
 		/* fast symlink */
 		inode->i_op = &ufs_fast_symlink_inode_operations;
-		memcpy((char*)&inode->u.ufs_i.i_u1.i_data,symname,l);
+		memcpy((char*)&UFS_I(inode)->i_u1.i_data,symname,l);
 		inode->i_size = l-1;
 	}
 	mark_inode_dirty(inode);
diff -u --recursive --new-file v2.5.2/linux/fs/ufs/super.c linux/fs/ufs/super.c
--- v2.5.2/linux/fs/ufs/super.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/ufs/super.c	Mon Jan 28 13:29:48 2002
@@ -652,13 +652,15 @@
 	uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask);
 	uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift);
 
-	if (uspi->s_bsize != 4096 && uspi->s_bsize != 8192 
-	  && uspi->s_bsize != 32768) {
-		printk("ufs_read_super: fs_bsize %u != {4096, 8192, 32768}\n", uspi->s_bsize);
+	/* block size must be a power-of-two between 4k and 32k */
+	if ((uspi->s_bsize & (uspi->s_bsize-1)) ||
+	    (uspi->s_bsize < 4096 || uspi->s_bsize > 32768)) {
+		printk("ufs_read_super: fs_bsize %u != {4096, 8192, 16384, 32768}\n", uspi->s_bsize);
 		goto failed;
 	}
-	if (uspi->s_fsize != 512 && uspi->s_fsize != 1024 
-	  && uspi->s_fsize != 2048 && uspi->s_fsize != 4096) {
+	/* fragment size must be a power-of-two between 512 and 4096 bytes */
+	if ((uspi->s_fsize & (uspi->s_fsize-1)) ||
+	    (uspi->s_fsize < 512 || uspi->s_fsize > 4096)) {
 		printk("ufs_read_super: fs_fsize %u != {512, 1024, 2048. 4096}\n", uspi->s_fsize);
 		goto failed;
 	}
@@ -953,7 +955,51 @@
 	return 0;
 }
 
+static kmem_cache_t * ufs_inode_cachep;
+
+static struct inode *ufs_alloc_inode(struct super_block *sb)
+{
+	struct ufs_inode_info *ei;
+	ei = (struct ufs_inode_info *)kmem_cache_alloc(ufs_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void ufs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(ufs_inode_cachep, UFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct ufs_inode_info *ei = (struct ufs_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	ufs_inode_cachep = kmem_cache_create("ufs_inode_cache",
+					     sizeof(struct ufs_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (ufs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(ufs_inode_cachep))
+		printk(KERN_INFO "ufs_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations ufs_super_ops = {
+	alloc_inode:	ufs_alloc_inode,
+	destroy_inode:	ufs_destroy_inode,
 	read_inode:	ufs_read_inode,
 	write_inode:	ufs_write_inode,
 	delete_inode:	ufs_delete_inode,
@@ -967,15 +1013,27 @@
 
 static int __init init_ufs_fs(void)
 {
-	return register_filesystem(&ufs_fs_type);
+	int err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&ufs_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_ufs_fs(void)
 {
 	unregister_filesystem(&ufs_fs_type);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
 
 module_init(init_ufs_fs)
 module_exit(exit_ufs_fs)
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.2/linux/fs/ufs/symlink.c linux/fs/ufs/symlink.c
--- v2.5.2/linux/fs/ufs/symlink.c	Fri Apr  7 13:38:00 2000
+++ linux/fs/ufs/symlink.c	Mon Jan 21 15:37:32 2002
@@ -26,17 +26,18 @@
  */
 
 #include <linux/fs.h>
+#include <linux/ufs_fs.h>
 
 static int ufs_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
-	char *s = (char *)dentry->d_inode->u.ufs_i.i_u1.i_symlink;
-	return vfs_readlink(dentry, buffer, buflen, s);
+	struct ufs_inode_info *p = UFS_I(dentry->d_inode);
+	return vfs_readlink(dentry, buffer, buflen, (char*)p->i_u1.i_symlink);
 }
 
 static int ufs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char *s = (char *)dentry->d_inode->u.ufs_i.i_u1.i_symlink;
-	return vfs_follow_link(nd, s);
+	struct ufs_inode_info *p = UFS_I(dentry->d_inode);
+	return vfs_follow_link(nd, (char*)p->i_u1.i_symlink);
 }
 
 struct inode_operations ufs_fast_symlink_inode_operations = {
diff -u --recursive --new-file v2.5.2/linux/fs/ufs/truncate.c linux/fs/ufs/truncate.c
--- v2.5.2/linux/fs/ufs/truncate.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/ufs/truncate.c	Mon Jan 21 15:37:32 2002
@@ -67,6 +67,7 @@
 
 static int ufs_trunc_direct (struct inode * inode)
 {
+	struct ufs_inode_info *ufsi = UFS_I(inode);
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct buffer_head * bh;
@@ -86,7 +87,7 @@
 	retry = 0;
 	
 	frag1 = DIRECT_FRAGMENT;
-	frag4 = min_t(u32, UFS_NDIR_FRAGMENT, inode->u.ufs_i.i_lastfrag);
+	frag4 = min_t(u32, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag);
 	frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1);
 	frag3 = frag4 & ~uspi->s_fpbmask;
 	block1 = block2 = 0;
@@ -107,7 +108,7 @@
 	/*
 	 * Free first free fragments
 	 */
-	p = inode->u.ufs_i.i_u1.i_data + ufs_fragstoblks (frag1);
+	p = ufsi->i_u1.i_data + ufs_fragstoblks (frag1);
 	tmp = fs32_to_cpu(sb, *p);
 	if (!tmp )
 		ufs_panic (sb, "ufs_trunc_direct", "internal error");
@@ -132,7 +133,7 @@
 	 * Free whole blocks
 	 */
 	for (i = block1 ; i < block2; i++) {
-		p = inode->u.ufs_i.i_u1.i_data + i;
+		p = ufsi->i_u1.i_data + i;
 		tmp = fs32_to_cpu(sb, *p);
 		if (!tmp)
 			continue;
@@ -170,7 +171,7 @@
 	/*
 	 * Free last free fragments
 	 */
-	p = inode->u.ufs_i.i_u1.i_data + ufs_fragstoblks (frag3);
+	p = ufsi->i_u1.i_data + ufs_fragstoblks (frag3);
 	tmp = fs32_to_cpu(sb, *p);
 	if (!tmp )
 		ufs_panic(sb, "ufs_truncate_direct", "internal error");
@@ -360,6 +361,7 @@
 
 static int ufs_trunc_tindirect (struct inode * inode)
 {
+	struct ufs_inode_info *ufsi = UFS_I(inode);
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct ufs_buffer_head * tind_bh;
@@ -375,7 +377,7 @@
 	
 	tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb))
 		? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0;
-	p = inode->u.ufs_i.i_u1.i_data + UFS_TIND_BLOCK;
+	p = ufsi->i_u1.i_data + UFS_TIND_BLOCK;
 	if (!(tmp = fs32_to_cpu(sb, *p)))
 		return 0;
 	tind_bh = ubh_bread (sb, tmp, uspi->s_bsize);
@@ -422,6 +424,7 @@
 		
 void ufs_truncate (struct inode * inode)
 {
+	struct ufs_inode_info *ufsi = UFS_I(inode);
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct buffer_head * bh;
@@ -439,9 +442,9 @@
 	while (1) {
 		retry = ufs_trunc_direct(inode);
 		retry |= ufs_trunc_indirect (inode, UFS_IND_BLOCK,
-			(u32 *) &inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK]);
+			(u32 *) &ufsi->i_u1.i_data[UFS_IND_BLOCK]);
 		retry |= ufs_trunc_dindirect (inode, UFS_IND_BLOCK + uspi->s_apb,
-			(u32 *) &inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK]);
+			(u32 *) &ufsi->i_u1.i_data[UFS_DIND_BLOCK]);
 		retry |= ufs_trunc_tindirect (inode);
 		if (!retry)
 			break;
@@ -460,7 +463,7 @@
 		}
 	}
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->u.ufs_i.i_lastfrag = DIRECT_FRAGMENT;
+	ufsi->i_lastfrag = DIRECT_FRAGMENT;
 	mark_inode_dirty(inode);
 	UFSD(("EXIT\n"))
 }
diff -u --recursive --new-file v2.5.2/linux/fs/ufs/util.c linux/fs/ufs/util.c
--- v2.5.2/linux/fs/ufs/util.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/ufs/util.c	Mon Jan 21 15:37:32 2002
@@ -9,6 +9,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/locks.h>
+#include <linux/ufs_fs.h>
 
 #include "swab.h"
 #include "util.h"
diff -u --recursive --new-file v2.5.2/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.5.2/linux/fs/umsdos/dir.c	Sat Sep  1 10:59:08 2001
+++ linux/fs/umsdos/dir.c	Mon Jan 21 15:37:32 2002
@@ -204,7 +204,7 @@
 		if (!inode)
 			goto remove_name;
 #ifdef UMSDOS_DEBUG_VERBOSE
-if (inode->u.umsdos_i.i_is_hlink)
+if (UMSDOS_I(inode)->i_is_hlink)
 printk("umsdos_readdir_x: %s/%s already resolved, ino=%ld\n",
 dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino);
 #endif
@@ -214,7 +214,7 @@
 entry.flags));
 		/* check whether to resolve a hard-link */
 		if ((entry.flags & UMSDOS_HLINK) &&
-		    !inode->u.umsdos_i.i_is_hlink) {
+		    !UMSDOS_I(inode)->i_is_hlink) {
 			dret = umsdos_solve_hlink (dret);
 			ret = PTR_ERR(dret);
 			if (IS_ERR(dret))
@@ -361,9 +361,9 @@
 	/*
 	 * This part of the initialization depends only on i_patched.
 	 */
-	if (inode->u.umsdos_i.i_patched)
+	if (UMSDOS_I(inode)->i_patched)
 		goto out;
-	inode->u.umsdos_i.i_patched = 1;
+	UMSDOS_I(inode)->i_patched = 1;
 	if (S_ISREG (entry->mode))
 		entry->mtime = inode->i_mtime;
 	inode->i_mode = entry->mode;
@@ -498,7 +498,7 @@
 
 	/* Check for a hard link */
 	if ((info.entry.flags & UMSDOS_HLINK) &&
-	    !inode->u.umsdos_i.i_is_hlink) {
+	    !UMSDOS_I(inode)->i_is_hlink) {
 		dret = umsdos_solve_hlink (dret);
 		ret = PTR_ERR(dret);
 		if (IS_ERR(dret))
@@ -756,7 +756,7 @@
 	if (!IS_ERR(dentry_dst)) {
 		struct inode *inode = dentry_dst->d_inode;
 		if (inode) {
-			inode->u.umsdos_i.i_is_hlink = 1;
+			UMSDOS_I(inode)->i_is_hlink = 1;
 #ifdef UMSDOS_DEBUG_VERBOSE
 printk ("umsdos_solve_hlink: resolved link %s/%s, ino=%ld\n",
 dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name, inode->i_ino);
diff -u --recursive --new-file v2.5.2/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.5.2/linux/fs/umsdos/inode.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/umsdos/inode.c	Mon Jan 21 15:37:32 2002
@@ -34,7 +34,7 @@
 	PRINTK ((KERN_DEBUG 
 		"put inode %p (%lu) pos %lu count=%d\n"
 		 ,inode, inode->i_ino
-		 ,inode->u.umsdos_i.pos
+		 ,UMSDOS_I(inode)->pos
 		 ,atomic_read(&inode->i_count)));
 
 	if (inode == pseudo_root) {
@@ -42,7 +42,7 @@
 	}
 
 	if (atomic_read(&inode->i_count) == 1)
-		inode->u.umsdos_i.i_patched = 0;
+		UMSDOS_I(inode)->i_patched = 0;
 }
 
 
@@ -67,15 +67,16 @@
 void umsdos_setup_dir(struct dentry *dir)
 {
 	struct inode *inode = dir->d_inode;
+	struct umsdos_inode_info *ui = UMSDOS_I(inode);
 
 	if (!S_ISDIR(inode->i_mode))
 		printk(KERN_ERR "umsdos_setup_dir: %s/%s not a dir!\n",
 			dir->d_parent->d_name.name, dir->d_name.name);
 
-	init_waitqueue_head (&inode->u.umsdos_i.dir_info.p);
-	inode->u.umsdos_i.dir_info.looking = 0;
-	inode->u.umsdos_i.dir_info.creating = 0;
-	inode->u.umsdos_i.dir_info.pid = 0;
+	init_waitqueue_head (&ui->dir_info.p);
+	ui->dir_info.looking = 0;
+	ui->dir_info.creating = 0;
+	ui->dir_info.pid = 0;
 
 	inode->i_op = &umsdos_rdir_inode_operations;
 	inode->i_fop = &umsdos_rdir_operations;
@@ -96,7 +97,7 @@
 	struct inode *inode = dentry->d_inode;
 	struct dentry *demd;
 
-	inode->u.umsdos_i.pos = f_pos;
+	UMSDOS_I(inode)->pos = f_pos;
 
 	/* now check the EMD file */
 	demd = umsdos_get_emd_dentry(dentry->d_parent);
@@ -233,7 +234,7 @@
 	int offs;
 
 Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched));
+dentry->d_parent->d_name.name, dentry->d_name.name, UMSDOS_I(inode)->i_patched));
 
 	if (inode->i_nlink == 0)
 		goto out;
@@ -265,9 +266,9 @@
 
 	/* Read only the start of the entry since we don't touch the name */
 	mapping = demd->d_inode->i_mapping;
-	offs = inode->u.umsdos_i.pos & ~PAGE_CACHE_MASK;
+	offs = UMSDOS_I(inode)->pos & ~PAGE_CACHE_MASK;
 	ret = -ENOMEM;
-	page=grab_cache_page(mapping,inode->u.umsdos_i.pos>>PAGE_CACHE_SHIFT);
+	page=grab_cache_page(mapping,UMSDOS_I(inode)->pos>>PAGE_CACHE_SHIFT);
 	if (!page)
 		goto out_dput;
 	ret=mapping->a_ops->prepare_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);
@@ -363,10 +364,17 @@
 	 * Call msdos-fs to mount the disk.
 	 * Note: this returns res == sb or NULL
 	 */
-	res = msdos_read_super (sb, data, silent);
+	MSDOS_SB(sb)->options.isvfat = 0;
+	res = fat_read_super(sb, data, silent, &umsdos_rdir_inode_operations);
 
-	if (!res)
-		goto out_fail;
+	if (IS_ERR(res))
+		return NULL;
+	if (res == NULL) {
+		if (!silent)
+			printk(KERN_INFO "VFS: Can't find a valid "
+			       "UMSDOS filesystem on dev %s.\n", sb->s_id);
+		return NULL;
+	}
 
 	printk (KERN_INFO "UMSDOS 0.86k "
 		"(compatibility level %d.%d, fast msdos)\n", 
@@ -394,10 +402,6 @@
 		dget (sb->s_root); sb->s_root = dget(new_root);
 	}
 	return sb;
-
-out_fail:
-	printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");
-	return NULL;
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c
--- v2.5.2/linux/fs/umsdos/namei.c	Sat Sep  1 10:59:08 2001
+++ linux/fs/umsdos/namei.c	Mon Jan 21 15:37:32 2002
@@ -28,12 +28,12 @@
 
 static inline void u_sleep_on (struct inode *dir)
 {
-	sleep_on (&dir->u.umsdos_i.dir_info.p);
+	sleep_on (&UMSDOS_I(dir)->dir_info.p);
 }
 
 static inline void u_wake_up (struct inode *dir)
 {
-    	wake_up (&dir->u.umsdos_i.dir_info.p);
+    	wake_up (&UMSDOS_I(dir)->dir_info.p);
 }
 
 /*
@@ -47,9 +47,9 @@
 {
 	int ret = 0;
 
-	if (dir->u.umsdos_i.dir_info.creating
-	    && dir->u.umsdos_i.dir_info.pid != current->pid) {
-	    	PRINTK (("creating && dir_info.pid=%lu, current->pid=%u\n", dir->u.umsdos_i.dir_info.pid, current->pid));
+	if (UMSDOS_I(dir)->dir_info.creating
+	    && UMSDOS_I(dir)->dir_info.pid != current->pid) {
+	    	PRINTK (("creating && dir_info.pid=%lu, current->pid=%u\n", UMSDOS_I(dir)->dir_info.pid, current->pid));
 	    	u_sleep_on (dir);
 		ret = 1;
 	}
@@ -61,7 +61,7 @@
  */
 static void umsdos_waitlookup (struct inode *dir)
 {
-	while (dir->u.umsdos_i.dir_info.looking) {
+	while (UMSDOS_I(dir)->dir_info.looking) {
 	    	u_sleep_on (dir);
 	}
 }
@@ -104,8 +104,8 @@
 	 * if we (the process) own the lock
 	 */
 	while (umsdos_waitcreate (dir) != 0);
-	dir->u.umsdos_i.dir_info.creating++;
-	dir->u.umsdos_i.dir_info.pid = current->pid;
+	UMSDOS_I(dir)->dir_info.creating++;
+	UMSDOS_I(dir)->dir_info.pid = current->pid;
 	umsdos_waitlookup (dir);
 }
 
@@ -124,10 +124,10 @@
 		if (umsdos_waitcreate (dir1) == 0
 		    && umsdos_waitcreate (dir2) == 0) {
 			/* We own both now */
-			dir1->u.umsdos_i.dir_info.creating++;
-			dir1->u.umsdos_i.dir_info.pid = current->pid;
-			dir2->u.umsdos_i.dir_info.creating++;
-			dir2->u.umsdos_i.dir_info.pid = current->pid;
+			UMSDOS_I(dir1)->dir_info.creating++;
+			UMSDOS_I(dir1)->dir_info.pid = current->pid;
+			UMSDOS_I(dir2)->dir_info.creating++;
+			UMSDOS_I(dir2)->dir_info.pid = current->pid;
 			break;
 		}
 	}
@@ -141,7 +141,7 @@
 void umsdos_startlookup (struct inode *dir)
 {
 	while (umsdos_waitcreate (dir) != 0);
-	dir->u.umsdos_i.dir_info.looking++;
+	UMSDOS_I(dir)->dir_info.looking++;
 }
 
 /*
@@ -149,10 +149,10 @@
  */
 void umsdos_unlockcreate (struct inode *dir)
 {
-	dir->u.umsdos_i.dir_info.creating--;
-	if (dir->u.umsdos_i.dir_info.creating < 0) {
-		printk ("UMSDOS: dir->u.umsdos_i.dir_info.creating < 0: %d"
-			,dir->u.umsdos_i.dir_info.creating);
+	UMSDOS_I(dir)->dir_info.creating--;
+	if (UMSDOS_I(dir)->dir_info.creating < 0) {
+		printk ("UMSDOS: UMSDOS_I(dir)->dir_info.creating < 0: %d"
+			,UMSDOS_I(dir)->dir_info.creating);
 	}
     	u_wake_up (dir);
 }
@@ -162,10 +162,10 @@
  */
 void umsdos_endlookup (struct inode *dir)
 {
-	dir->u.umsdos_i.dir_info.looking--;
-	if (dir->u.umsdos_i.dir_info.looking < 0) {
-		printk ("UMSDOS: dir->u.umsdos_i.dir_info.looking < 0: %d"
-			,dir->u.umsdos_i.dir_info.looking);
+	UMSDOS_I(dir)->dir_info.looking--;
+	if (UMSDOS_I(dir)->dir_info.looking < 0) {
+		printk ("UMSDOS: UMSDOS_I(dir)->dir_info.looking < 0: %d"
+			,UMSDOS_I(dir)->dir_info.looking);
 	}
     	u_wake_up (dir);
 }
@@ -618,7 +618,7 @@
 			goto cleanup;
 		}
 		/* mark the inode as a hardlink */
-		oldinode->u.umsdos_i.i_is_hlink = 1;
+		UMSDOS_I(oldinode)->i_is_hlink = 1;
 
 		/*
 		 * Capture the path to the hidden link.
@@ -667,7 +667,7 @@
 	 * the dentry for its real name, not the visible name.
 	 * N.B. make sure it's the hidden inode ...
 	 */
-	if (!oldinode->u.umsdos_i.i_is_hlink)
+	if (!UMSDOS_I(oldinode)->i_is_hlink)
 		printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??\n",
 			olddentry->d_parent->d_name.name,
 			olddentry->d_name.name, oldinode->i_ino);
@@ -721,7 +721,7 @@
 
 
 #ifdef UMSDOS_PARANOIA
-if (!oldinode->u.umsdos_i.i_is_hlink)
+if (!UMSDOS_I(oldinode)->i_is_hlink)
 printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n",
 olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);
 #endif
diff -u --recursive --new-file v2.5.2/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
--- v2.5.2/linux/fs/umsdos/rdir.c	Sat Sep  1 10:59:08 2001
+++ linux/fs/umsdos/rdir.c	Mon Jan 21 15:37:32 2002
@@ -113,7 +113,7 @@
 dentry->d_parent->d_name.name, dentry->d_name.name));
 /* only patch if needed (because we get called even for lookup
    (not only rlookup) stuff sometimes, like in umsdos_covered() */
-		if (dentry->d_inode->u.umsdos_i.i_patched == 0)	
+		if (UMSDOS_I(dentry->d_inode)->i_patched == 0)	
 		umsdos_patch_dentry_inode(dentry, 0);
 
 	}
diff -u --recursive --new-file v2.5.2/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.5.2/linux/fs/vfat/namei.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/vfat/namei.c	Mon Jan 28 13:20:44 2002
@@ -19,13 +19,7 @@
 
 #include <linux/sched.h>
 #include <linux/msdos_fs.h>
-#include <linux/nls.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
 #include <linux/ctype.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
 #include <linux/slab.h>
 
 #define DEBUG_LEVEL 0
@@ -446,7 +440,7 @@
 	(x)->lower = 1;				\
 	(x)->upper = 1;				\
 	(x)->valid = 1;				\
-} while (0);
+} while (0)
 
 static inline unsigned char
 shortname_info_to_lcase(struct shortname_info *base,
@@ -1266,10 +1260,15 @@
 	struct super_block *res;
   
 	MSDOS_SB(sb)->options.isvfat = 1;
-
 	res = fat_read_super(sb, data, silent, &vfat_dir_inode_operations);
-	if (res == NULL)
+	if (IS_ERR(res))
+		return NULL;
+	if (res == NULL) {
+		if (!silent)
+			printk(KERN_INFO "VFS: Can't find a valid"
+			       " VFAT filesystem on dev %s.\n", sb->s_id);
 		return NULL;
+	}
 
 	if (parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
 		MSDOS_SB(sb)->options.dotsOK = 0;
diff -u --recursive --new-file v2.5.2/linux/fs/xattr.c linux/fs/xattr.c
--- v2.5.2/linux/fs/xattr.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/xattr.c	Tue Jan 29 18:46:00 2002
@@ -0,0 +1,341 @@
+/*
+  File: fs/xattr.c
+
+  Extended attribute handling.
+
+  Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
+  Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
+ */
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include <linux/file.h>
+#include <linux/xattr.h>
+#include <asm/uaccess.h>
+
+/*
+ * Extended attribute memory allocation wrappers, originally
+ * based on the Intermezzo PRESTO_ALLOC/PRESTO_FREE macros.
+ * The vmalloc use here is very uncommon - extended attributes
+ * are supposed to be small chunks of metadata, and it is quite
+ * unusual to have very many extended attributes, so lists tend
+ * to be quite short as well.  The 64K upper limit is derived
+ * from the extended attribute size limit used by XFS.
+ * Intentionally allow zero @size for value/list size requests.
+ */
+static void *
+xattr_alloc(size_t size, size_t limit)
+{
+	void *ptr;
+
+	if (size > limit)
+		return ERR_PTR(-E2BIG);
+
+	if (!size)	/* size request, no buffer is needed */
+		return NULL;
+	else if (size <= PAGE_SIZE)
+		ptr = kmalloc((unsigned long) size, GFP_KERNEL);
+	else
+		ptr = vmalloc((unsigned long) size);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+	return ptr;
+}
+
+static void
+xattr_free(void *ptr, size_t size)
+{
+	if (!size)	/* size request, no buffer was needed */
+		return;
+	else if (size <= PAGE_SIZE)
+		kfree(ptr);
+	else
+		vfree(ptr);
+}
+
+/*
+ * Extended attribute SET operations
+ */
+static long
+setxattr(struct dentry *d, char *name, void *value, size_t size, int flags)
+{
+	int error;
+	void *kvalue;
+	char kname[XATTR_NAME_MAX + 1];
+
+	if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
+		return -EINVAL;
+
+	if (copy_from_user(kname, name, XATTR_NAME_MAX))
+		return -EFAULT;
+	kname[XATTR_NAME_MAX] = '\0';
+
+	kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
+	if (IS_ERR(kvalue))
+		return PTR_ERR(kvalue);
+
+	if (size > 0 && copy_from_user(kvalue, value, size)) {
+		xattr_free(kvalue, size);
+		return -EFAULT;
+	}
+
+	error = -EOPNOTSUPP;
+	if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
+		lock_kernel();
+		error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
+		unlock_kernel();
+	}
+
+	xattr_free(kvalue, size);
+	return error;
+}
+
+asmlinkage long
+sys_setxattr(char *path, char *name, void *value, size_t size, int flags)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk(path, &nd);
+	if (error)
+		return error;
+	error = setxattr(nd.dentry, name, value, size, flags);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage long
+sys_lsetxattr(char *path, char *name, void *value, size_t size, int flags)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk_link(path, &nd);
+	if (error)
+		return error;
+	error = setxattr(nd.dentry, name, value, size, flags);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage long
+sys_fsetxattr(int fd, char *name, void *value, size_t size, int flags)
+{
+	struct file *f;
+	int error = -EBADF;
+
+	f = fget(fd);
+	if (!f)
+		return error;
+	error = setxattr(f->f_dentry, name, value, size, flags);
+	fput(f);
+	return error;
+}
+
+/*
+ * Extended attribute GET operations
+ */
+static long
+getxattr(struct dentry *d, char *name, void *value, size_t size)
+{
+	int error;
+	void *kvalue;
+	char kname[XATTR_NAME_MAX + 1];
+
+	if (copy_from_user(kname, name, XATTR_NAME_MAX))
+		return -EFAULT;
+	kname[XATTR_NAME_MAX] = '\0';
+
+	kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
+	if (IS_ERR(kvalue))
+		return PTR_ERR(kvalue);
+
+	error = -EOPNOTSUPP;
+	if (d->d_inode->i_op && d->d_inode->i_op->getxattr) {
+		lock_kernel();
+		error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
+		unlock_kernel();
+	}
+
+	if (kvalue && error > 0)
+		if (copy_to_user(value, kvalue, size))
+			error = -EFAULT;
+	xattr_free(kvalue, size);
+	return error;
+}
+
+asmlinkage long
+sys_getxattr(char *path, char *name, void *value, size_t size)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk(path, &nd);
+	if (error)
+		return error;
+	error = getxattr(nd.dentry, name, value, size);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage long
+sys_lgetxattr(char *path, char *name, void *value, size_t size)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk_link(path, &nd);
+	if (error)
+		return error;
+	error = getxattr(nd.dentry, name, value, size);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage long
+sys_fgetxattr(int fd, char *name, void *value, size_t size)
+{
+	struct file *f;
+	int error = -EBADF;
+
+	f = fget(fd);
+	if (!f)
+		return error;
+	error = getxattr(f->f_dentry, name, value, size);
+	fput(f);
+	return error;
+}
+
+/*
+ * Extended attribute LIST operations
+ */
+static long
+listxattr(struct dentry *d, char *list, size_t size)
+{
+	int error;
+	char *klist;
+
+	klist = (char *)xattr_alloc(size, XATTR_LIST_MAX);
+	if (IS_ERR(klist))
+		return PTR_ERR(klist);
+
+	error = -EOPNOTSUPP;
+	if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
+		lock_kernel();
+		error = d->d_inode->i_op->listxattr(d, klist, size);
+		unlock_kernel();
+	}
+
+	if (klist && error > 0)
+		if (copy_to_user(list, klist, size))
+			error = -EFAULT;
+	xattr_free(klist, size);
+	return error;
+}
+
+asmlinkage long
+sys_listxattr(char *path, char *list, size_t size)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk(path, &nd);
+	if (error)
+		return error;
+	error = listxattr(nd.dentry, list, size);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage long
+sys_llistxattr(char *path, char *list, size_t size)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk_link(path, &nd);
+	if (error)
+		return error;
+	error = listxattr(nd.dentry, list, size);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage long
+sys_flistxattr(int fd, char *list, size_t size)
+{
+	struct file *f;
+	int error = -EBADF;
+
+	f = fget(fd);
+	if (!f)
+		return error;
+	error = listxattr(f->f_dentry, list, size);
+	fput(f);
+	return error;
+}
+
+/*
+ * Extended attribute REMOVE operations
+ */
+static long
+removexattr(struct dentry *d, char *name)
+{
+	int error;
+	char kname[XATTR_NAME_MAX + 1];
+
+	if (copy_from_user(kname, name, XATTR_NAME_MAX))
+		return -EFAULT;
+	kname[XATTR_NAME_MAX] = '\0';
+
+	error = -EOPNOTSUPP;
+	if (d->d_inode->i_op && d->d_inode->i_op->removexattr) {
+		lock_kernel();
+		error = d->d_inode->i_op->removexattr(d, kname);
+		unlock_kernel();
+	}
+	return error;
+}
+
+asmlinkage long
+sys_removexattr(char *path, char *name)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk(path, &nd);
+	if (error)
+		return error;
+	error = removexattr(nd.dentry, name);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage long
+sys_lremovexattr(char *path, char *name)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk_link(path, &nd);
+	if (error)
+		return error;
+	error = removexattr(nd.dentry, name);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage long
+sys_fremovexattr(int fd, char *name)
+{
+	struct file *f;
+	int error = -EBADF;
+
+	f = fget(fd);
+	if (!f)
+		return error;
+	error = removexattr(f->f_dentry, name);
+	fput(f);
+	return error;
+}
diff -u --recursive --new-file v2.5.2/linux/include/asm-alpha/ide.h linux/include/asm-alpha/ide.h
--- v2.5.2/linux/include/asm-alpha/ide.h	Wed May 24 08:40:41 2000
+++ linux/include/asm-alpha/ide.h	Tue Jan 15 11:27:47 2002
@@ -91,7 +91,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -u --recursive --new-file v2.5.2/linux/include/asm-alpha/pci.h linux/include/asm-alpha/pci.h
--- v2.5.2/linux/include/asm-alpha/pci.h	Fri Oct 12 15:35:54 2001
+++ linux/include/asm-alpha/pci.h	Tue Jan 15 11:48:13 2002
@@ -101,6 +101,20 @@
 extern void pci_unmap_single(struct pci_dev *, dma_addr_t, size_t, int);
 extern void pci_unmap_page(struct pci_dev *, dma_addr_t, size_t, int);
 
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
 /* Map a set of buffers described by scatterlist in streaming mode for
    PCI DMA.  This is the scather-gather version of the above
    pci_map_single interface.  Here the scatter gather list elements
diff -u --recursive --new-file v2.5.2/linux/include/asm-alpha/pgalloc.h linux/include/asm-alpha/pgalloc.h
--- v2.5.2/linux/include/asm-alpha/pgalloc.h	Thu May 24 15:20:18 2001
+++ linux/include/asm-alpha/pgalloc.h	Tue Jan 15 10:56:35 2002
@@ -14,7 +14,7 @@
 /* Caches aren't brain-dead on the Alpha. */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm, start, end)	do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
@@ -206,10 +206,10 @@
  * Flush a specified range of user mapping:  on the
  * Alpha we flush the whole user tlb.
  */
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 	unsigned long start, unsigned long end)
 {
-	flush_tlb_mm(mm);
+	flush_tlb_mm(vma->vm_mm);
 }
 
 #else /* CONFIG_SMP */
@@ -217,7 +217,7 @@
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *);
 extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
-extern void flush_tlb_range(struct mm_struct *, unsigned long, unsigned long);
+extern void flush_tlb_range(struct vm_area_struct *, unsigned long, unsigned long);
 
 #endif /* CONFIG_SMP */
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.5.2/linux/include/asm-alpha/pgtable.h	Thu Oct 25 14:00:32 2001
+++ linux/include/asm-alpha/pgtable.h	Tue Jan 15 10:56:35 2002
@@ -344,8 +344,8 @@
 #define kern_addr_valid(addr)	(1)
 #endif
 
-#define io_remap_page_range(start, busaddr, size, prot) \
-    remap_page_range(start, virt_to_phys(__ioremap(busaddr, size)), size, prot)
+#define io_remap_page_range(vma, start, busaddr, size, prot) \
+    remap_page_range(vma, start, virt_to_phys(__ioremap(busaddr, size)), size, prot)
 
 #define pte_ERROR(e) \
 	printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-arc/system.h linux/include/asm-arm/arch-arc/system.h
--- v2.5.2/linux/include/asm-arm/arch-arc/system.h	Sun Aug 12 11:14:00 2001
+++ linux/include/asm-arm/arch-arc/system.h	Tue Jan 15 13:53:51 2002
@@ -10,7 +10,7 @@
 
 static void arch_idle(void)
 {
-	while (!current->need_resched && !hlt_counter);
+	while (!need_resched() && !hlt_counter);
 }
 
 static inline void arch_reset(char mode)
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-cl7500/system.h linux/include/asm-arm/arch-cl7500/system.h
--- v2.5.2/linux/include/asm-arm/arch-cl7500/system.h	Thu Apr 12 12:20:31 2001
+++ linux/include/asm-arm/arch-cl7500/system.h	Tue Jan 15 13:53:51 2002
@@ -10,7 +10,7 @@
 
 static void arch_idle(void)
 {
-	while (!current->need_resched && !hlt_counter)
+	while (!need_resched() && !hlt_counter)
 		iomd_writeb(0, IOMD_SUSMODE);
 }
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-ebsa110/system.h linux/include/asm-arm/arch-ebsa110/system.h
--- v2.5.2/linux/include/asm-arm/arch-ebsa110/system.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-ebsa110/system.h	Tue Jan 15 13:53:51 2002
@@ -17,7 +17,7 @@
  * will stop our MCLK signal (which provides the clock for the glue
  * logic, and therefore the timer interrupt).
  *
- * Instead, we spin, waiting for either hlt_counter or need_resched
+ * Instead, we spin, waiting for either hlt_counter or need_resched()
  * to be set.  If we have been spinning for 2cs, then we drop the
  * core clock down to the memory clock.
  */
@@ -28,13 +28,13 @@
 	start_idle = jiffies;
 
 	do {
-		if (current->need_resched || hlt_counter)
+		if (need_resched() || hlt_counter)
 			goto slow_out;
 	} while (time_before(jiffies, start_idle + HZ/50));
 
 	cpu_do_idle(IDLE_CLOCK_SLOW);
 
-	while (!current->need_resched && !hlt_counter) {
+	while (!need_resched() && !hlt_counter) {
 		/* do nothing slowly */
 	}
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h
--- v2.5.2/linux/include/asm-arm/arch-ebsa285/system.h	Sun Aug 12 11:14:00 2001
+++ linux/include/asm-arm/arch-ebsa285/system.h	Tue Jan 15 13:53:51 2002
@@ -20,14 +20,14 @@
 	start_idle = jiffies;
 
 	do {
-		if (current->need_resched || hlt_counter)
+		if (need_resched() || hlt_counter)
 			goto slow_out;
 		cpu_do_idle(IDLE_WAIT_FAST);
 	} while (time_before(jiffies, start_idle + HZ/50));
 
 	cpu_do_idle(IDLE_CLOCK_SLOW);
 
-	while (!current->need_resched && !hlt_counter) {
+	while (!need_resched() && !hlt_counter) {
 		cpu_do_idle(IDLE_WAIT_SLOW);
 	}
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-nexuspci/system.h linux/include/asm-arm/arch-nexuspci/system.h
--- v2.5.2/linux/include/asm-arm/arch-nexuspci/system.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-nexuspci/system.h	Tue Jan 15 13:53:51 2002
@@ -16,7 +16,7 @@
 
 static void arch_idle(void)
 {
-	while (!current->need_resched && !hlt_counter)
+	while (!need_resched() && !hlt_counter)
 		cpu_do_idle(IDLE_WAIT_SLOW);
 }
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-rpc/system.h linux/include/asm-arm/arch-rpc/system.h
--- v2.5.2/linux/include/asm-arm/arch-rpc/system.h	Sun Aug 12 11:14:00 2001
+++ linux/include/asm-arm/arch-rpc/system.h	Tue Jan 15 13:53:51 2002
@@ -18,14 +18,14 @@
 	start_idle = jiffies;
 
 	do {
-		if (current->need_resched || hlt_counter)
+		if (need_resched() || hlt_counter)
 			goto slow_out;
 		cpu_do_idle(IDLE_WAIT_FAST);
 	} while (time_before(jiffies, start_idle + HZ/50));
 
 	cpu_do_idle(IDLE_CLOCK_SLOW);
 
-	while (!current->need_resched && !hlt_counter) {
+	while (!need_resched() && !hlt_counter) {
 		cpu_do_idle(IDLE_WAIT_SLOW);
 	}
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-sa1100/system.h linux/include/asm-arm/arch-sa1100/system.h
--- v2.5.2/linux/include/asm-arm/arch-sa1100/system.h	Thu Oct 25 13:53:54 2001
+++ linux/include/asm-arm/arch-sa1100/system.h	Tue Jan 15 13:53:51 2002
@@ -10,7 +10,7 @@
 	if (!hlt_counter) {
 		int flags;
 		local_irq_save(flags);
-		if (!current->need_resched)
+		if (!need_resched())
 			cpu_do_idle(0);
 		local_irq_restore(flags);
 	}
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-tbox/system.h linux/include/asm-arm/arch-tbox/system.h
--- v2.5.2/linux/include/asm-arm/arch-tbox/system.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-tbox/system.h	Tue Jan 15 13:53:51 2002
@@ -13,14 +13,14 @@
 	start_idle = jiffies;
 
 	do {
-		if (current->need_resched || hlt_counter)
+		if (need_resched() || hlt_counter)
 			goto slow_out;
 		cpu_do_idle(IDLE_WAIT_FAST);
 	} while (time_before(jiffies, start_idle + HZ/50));
 
 	cpu_do_idle(IDLE_CLOCK_SLOW);
 
-	while (!current->need_resched && !hlt_counter) {
+	while (!need_resched() && !hlt_counter) {
 		cpu_do_idle(IDLE_WAIT_SLOW);
 	}
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/ide.h linux/include/asm-arm/ide.h
--- v2.5.2/linux/include/asm-arm/ide.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/ide.h	Tue Jan 15 11:27:47 2002
@@ -30,7 +30,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/pci.h linux/include/asm-arm/pci.h
--- v2.5.2/linux/include/asm-arm/pci.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-arm/pci.h	Tue Jan 15 11:48:13 2002
@@ -95,6 +95,31 @@
 	/* nothing to do */
 }
 
+/* Whether pci_unmap_{single,page} is a nop depends upon the
+ * configuration.
+ */
+#ifdef CONFIG_SA1111
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+#else /* !(CONFIG_SA1111) */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+#endif /* CONFIG_SA1111 */
+
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h
--- v2.5.2/linux/include/asm-arm/pgtable.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-arm/pgtable.h	Tue Jan 15 10:56:35 2002
@@ -182,8 +182,8 @@
  * remap a physical address `phys' of size `size' with page protection `prot'
  * into virtual address `from'
  */
-#define io_remap_page_range(from,phys,size,prot) \
-		remap_page_range(from,phys,size,prot)
+#define io_remap_page_range(vma,from,phys,size,prot) \
+		remap_page_range(vma,from,phys,size,prot)
 
 #endif /* !__ASSEMBLY__ */
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/proc-armo/cache.h linux/include/asm-arm/proc-armo/cache.h
--- v2.5.2/linux/include/asm-arm/proc-armo/cache.h	Sun Aug 12 11:14:00 2001
+++ linux/include/asm-arm/proc-armo/cache.h	Tue Jan 15 10:56:35 2002
@@ -11,7 +11,7 @@
  */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm,start,end)		do { } while (0)
+#define flush_cache_range(vma,start,end)	do { } while (0)
 #define flush_cache_page(vma,vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 
@@ -34,12 +34,12 @@
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  */
 #define flush_tlb_all()				memc_update_all()
 #define flush_tlb_mm(mm)			memc_update_mm(mm)
-#define flush_tlb_range(mm,start,end)		\
-		do { memc_update_mm(mm); (void)(start); (void)(end); } while (0)
+#define flush_tlb_range(vma,start,end)		\
+		do { memc_update_mm(vma->vm_mm); (void)(start); (void)(end); } while (0)
 #define flush_tlb_page(vma, vmaddr)		do { } while (0)
 
 /*
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/proc-armv/cache.h linux/include/asm-arm/proc-armv/cache.h
--- v2.5.2/linux/include/asm-arm/proc-armv/cache.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-arm/proc-armv/cache.h	Tue Jan 15 10:56:35 2002
@@ -42,9 +42,9 @@
 			cpu_cache_clean_invalidate_all();		\
 	} while (0)
 
-#define flush_cache_range(_mm,_start,_end)				\
+#define flush_cache_range(_vma,_start,_end)				\
 	do {								\
-		if ((_mm) == current->active_mm)			\
+		if ((_vma)->vm_mm == current->active_mm)		\
 			cpu_cache_clean_invalidate_range((_start), (_end), 1); \
 	} while (0)
 
@@ -214,7 +214,7 @@
  *  - flush_tlb_all()			flushes all processes TLBs
  *  - flush_tlb_mm(mm)			flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr)	flushes TLB for specified page
- *  - flush_tlb_range(mm, start, end)	flushes TLB for specified range of pages
+ *  - flush_tlb_range(vma, start, end)	flushes TLB for specified range of pages
  *
  * We drain the write buffer in here to ensure that the page tables in ram
  * are really up to date.  It is more efficient to do this here...
@@ -248,9 +248,9 @@
  *
  * _mm may not be current->active_mm, but may not be NULL.
  */
-#define flush_tlb_range(_mm,_start,_end)				\
+#define flush_tlb_range(_vma,_start,_end)				\
 	do {								\
-		if ((_mm) == current->active_mm)			\
+		if ((_mm)->vm_mm == current->active_mm)			\
 			cpu_tlb_invalidate_range((_start), (_end));	\
 	} while (0)
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/bitops.h linux/include/asm-cris/bitops.h
--- v2.5.2/linux/include/asm-cris/bitops.h	Mon Oct  8 11:43:54 2001
+++ linux/include/asm-cris/bitops.h	Mon Jan 21 16:00:39 2002
@@ -22,6 +22,7 @@
 /* We use generic_ffs so get it; include guards resolve the possible
    mutually inclusion.  */
 #include <linux/bitops.h>
+#include <linux/compiler.h>
 
 /*
  * Some hacks to defeat gcc over-optimizations..
@@ -43,6 +44,8 @@
 
 #define set_bit(nr, addr)    (void)test_and_set_bit(nr, addr)
 
+#define __set_bit(nr, addr)    (void)__test_and_set_bit(nr, addr)
+
 /*
  * clear_bit - Clears a bit in memory
  * @nr: Bit to clear
@@ -56,6 +59,8 @@
 
 #define clear_bit(nr, addr)  (void)test_and_clear_bit(nr, addr)
 
+#define __clear_bit(nr, addr)  (void)__test_and_clear_bit(nr, addr)
+
 /*
  * change_bit - Toggle a bit in memory
  * @nr: Bit to clear
@@ -89,7 +94,7 @@
  * It also implies a memory barrier.
  */
 
-static __inline__ int test_and_set_bit(int nr, void *addr)
+static inline int test_and_set_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -105,6 +110,18 @@
 	return retval;
 }
 
+static inline int __test_and_set_bit(int nr, void *addr)
+{
+	unsigned int mask, retval;
+	unsigned int *adr = (unsigned int *)addr;
+	
+	adr += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	retval = (mask & *adr) != 0;
+	*adr |= mask;
+	return retval;
+}
+
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
  */
@@ -120,7 +137,7 @@
  * It also implies a memory barrier.
  */
 
-static __inline__ int test_and_clear_bit(int nr, void *addr)
+static inline int test_and_clear_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -146,7 +163,7 @@
  * but actually fail.  You must protect multiple accesses with a lock.
  */
 
-static __inline__ int __test_and_clear_bit(int nr, void *addr)
+static inline int __test_and_clear_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned int *adr = (unsigned int *)addr;
@@ -166,7 +183,7 @@
  * It also implies a memory barrier.
  */
 
-static __inline__ int test_and_change_bit(int nr, void *addr)
+static inline int test_and_change_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -183,7 +200,7 @@
 
 /* WARNING: non atomic and it can be reordered! */
 
-static __inline__ int __test_and_change_bit(int nr, void *addr)
+static inline int __test_and_change_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned int *adr = (unsigned int *)addr;
@@ -204,7 +221,7 @@
  * This routine doesn't need to be atomic.
  */
 
-static __inline__ int test_bit(int nr, const void *addr)
+static inline int test_bit(int nr, const void *addr)
 {
 	unsigned int mask;
 	unsigned int *adr = (unsigned int *)addr;
@@ -225,7 +242,7 @@
  * number.  They differ in that the first function also inverts all bits
  * in the input.
  */
-static __inline__ unsigned long cris_swapnwbrlz(unsigned long w)
+static inline unsigned long cris_swapnwbrlz(unsigned long w)
 {
 	/* Let's just say we return the result in the same register as the
 	   input.  Saying we clobber the input but can return the result
@@ -241,7 +258,7 @@
 	return res;
 }
 
-static __inline__ unsigned long cris_swapwbrlz(unsigned long w)
+static inline unsigned long cris_swapwbrlz(unsigned long w)
 {
 	unsigned res;
 	__asm__ ("swapwbr %0 \n\t"
@@ -255,7 +272,7 @@
  * ffz = Find First Zero in word. Undefined if no zero exists,
  * so code should check against ~0UL first..
  */
-static __inline__ unsigned long ffz(unsigned long w)
+static inline unsigned long ffz(unsigned long w)
 {
 	/* The generic_ffs function is used to avoid the asm when the
 	   argument is a constant.  */
@@ -268,7 +285,7 @@
  * Somewhat like ffz but the equivalent of generic_ffs: in contrast to
  * ffz we return the first one-bit *plus one*.
  */
-static __inline__ unsigned long ffs(unsigned long w)
+static inline unsigned long ffs(unsigned long w)
 {
 	/* The generic_ffs function is used to avoid the asm when the
 	   argument is a constant.  */
@@ -283,7 +300,7 @@
  * @offset: The bitnumber to start searching at
  * @size: The maximum size to search
  */
-static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
+static inline int find_next_zero_bit (void * addr, int size, int offset)
 {
 	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
 	unsigned long result = offset & ~31UL;
@@ -331,6 +348,17 @@
 #define find_first_zero_bit(addr, size) \
         find_next_zero_bit((addr), (size), 0)
 
+/*
+ * hweightN - returns the hamming weight of a N-bit word
+ * @x: the word to weigh
+ *
+ * The Hamming Weight of a number is the total number of bits set in it.
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
 #define ext2_set_bit                 test_and_set_bit
 #define ext2_clear_bit               test_and_clear_bit
 #define ext2_test_bit                test_bit
@@ -343,7 +371,45 @@
 #define minix_test_bit(nr,addr) test_bit(nr,addr)
 #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
 
-#endif /* __KERNEL__ */
+#if 0
+/* TODO: see below */
+#define sched_find_first_zero_bit(addr) find_first_zero_bit(addr, 168)
+
+#else
+/* TODO: left out pending where to put it.. (there are .h dependencies) */
+
+ /*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 168-bit bitmap where the first 128 bits are
+ * unlikely to be set. It's guaranteed that at least one of the 168
+ * bits is cleared.
+ */
+#if 0
+#if MAX_RT_PRIO != 128 || MAX_PRIO != 168
+# error update this function.
+#endif
+#else
+#define MAX_RT_PRIO 128
+#define MAX_PRIO 168
+#endif
+
+static inline int sched_find_first_zero_bit(char *bitmap)
+{
+	unsigned int *b = (unsigned int *)bitmap;
+	unsigned int rt;
+
+	rt = b[0] & b[1] & b[2] & b[3];
+	if (unlikely(rt != 0xffffffff))
+		return find_first_zero_bit(bitmap, MAX_RT_PRIO);
+
+	if (b[4] != ~0)
+		return ffz(b[4]) + MAX_RT_PRIO;
+	return ffz(b[5]) + 32 + MAX_RT_PRIO;
+}
+#undef MAX_PRIO
+#undef MAX_RT_PRIO
+#endif
 
+#endif /* __KERNEL__ */
 
 #endif /* _CRIS_BITOPS_H */
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/elf.h linux/include/asm-cris/elf.h
--- v2.5.2/linux/include/asm-cris/elf.h	Tue May  1 16:05:00 2001
+++ linux/include/asm-cris/elf.h	Mon Jan 21 16:00:39 2002
@@ -9,8 +9,9 @@
 
 typedef unsigned long elf_greg_t;
 
-/* These probably need fixing.  */
-#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+/* Note that NGREG is defined to ELF_NGREG in include/linux/elfcore.h, and is
+   thus exposed to user-space. */
+#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
 /* A placeholder; CRIS does not have any fp regs.  */
@@ -45,7 +46,52 @@
 	(_r)->r1 = 0;  (_r)->r0 = 0;  (_r)->mof = 0; (_r)->srp = 0; \
 } while (0)
 
-#undef USE_ELF_CORE_DUMP
+#define USE_ELF_CORE_DUMP
+
+/* The additional layer below is because the stack pointer is missing in 
+   the pt_regs struct, but needed in a core dump. pr_reg is a elf_gregset_t,
+   and should be filled in according to the layout of the user_regs_struct
+   struct; regs is a pt_regs struct. We dump all registers, though several are
+   obviously unnecessary. That way there's less need for intelligence at 
+   the receiving end (i.e. gdb). */
+#define ELF_CORE_COPY_REGS(pr_reg, regs)                   \
+	pr_reg[0] = regs->r0;                              \
+	pr_reg[1] = regs->r1;                              \
+	pr_reg[2] = regs->r2;                              \
+	pr_reg[3] = regs->r3;                              \
+	pr_reg[4] = regs->r4;                              \
+	pr_reg[5] = regs->r5;                              \
+	pr_reg[6] = regs->r6;                              \
+	pr_reg[7] = regs->r7;                              \
+	pr_reg[8] = regs->r8;                              \
+	pr_reg[9] = regs->r9;                              \
+	pr_reg[10] = regs->r10;                            \
+	pr_reg[11] = regs->r11;                            \
+	pr_reg[12] = regs->r12;                            \
+	pr_reg[13] = regs->r13;                            \
+	pr_reg[14] = rdusp();               /* sp */       \
+	pr_reg[15] = regs->irp;             /* pc */       \
+	pr_reg[16] = 0;                     /* p0 */       \
+	pr_reg[17] = rdvr();                /* vr */       \
+	pr_reg[18] = 0;                     /* p2 */       \
+	pr_reg[19] = 0;                     /* p3 */       \
+	pr_reg[20] = 0;                     /* p4 */       \
+	pr_reg[21] = (regs->dccr & 0xffff); /* ccr */      \
+	pr_reg[22] = 0;                     /* p6 */       \
+	pr_reg[23] = regs->mof;             /* mof */      \
+	pr_reg[24] = 0;                     /* p8 */       \
+	pr_reg[25] = 0;                     /* ibr */      \
+	pr_reg[26] = 0;                     /* irp */      \
+	pr_reg[27] = regs->srp;             /* srp */      \
+	pr_reg[28] = 0;                     /* bar */      \
+	pr_reg[29] = regs->dccr;            /* dccr */     \
+	pr_reg[30] = 0;                     /* brp */      \
+	pr_reg[31] = rdusp();               /* usp */      \
+	pr_reg[32] = 0;                     /* csrinstr */ \
+	pr_reg[33] = 0;                     /* csraddr */  \
+	pr_reg[34] = 0;                     /* csrdata */
+
+
 #define ELF_EXEC_PAGESIZE	8192
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/ethernet.h linux/include/asm-cris/ethernet.h
--- v2.5.2/linux/include/asm-cris/ethernet.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-cris/ethernet.h	Mon Jan 21 16:00:39 2002
@@ -0,0 +1,18 @@
+/*  
+ * ioctl defines for ethernet driver
+ *
+ * Copyright (c) 2001 Axis Communications AB
+ * 
+ * Author: Mikael Starvik 
+ *
+ */
+
+#ifndef _CRIS_ETHERNET_H
+#define _CRIS_ETHERNET_H
+#define SET_ETH_SPEED_AUTO      SIOCDEVPRIVATE          /* Auto neg speed */
+#define SET_ETH_SPEED_10        SIOCDEVPRIVATE+1        /* 10 Mbps */
+#define SET_ETH_SPEED_100       SIOCDEVPRIVATE+2        /* 100 Mbps. */
+#define SET_ETH_DUPLEX_AUTO     SIOCDEVPRIVATE+3        /* Auto neg duplex */
+#define SET_ETH_DUPLEX_HALF     SIOCDEVPRIVATE+4        /* Full duplex */
+#define SET_ETH_DUPLEX_FULL     SIOCDEVPRIVATE+5        /* Half duplex */
+#endif /* _CRIS_ETHERNET_H */
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/ide.h linux/include/asm-cris/ide.h
--- v2.5.2/linux/include/asm-cris/ide.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-cris/ide.h	Tue Jan 15 11:27:47 2002
@@ -97,7 +97,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 /* some configuration options we don't need */
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/irq.h linux/include/asm-cris/irq.h
--- v2.5.2/linux/include/asm-cris/irq.h	Mon Oct  8 11:43:54 2001
+++ linux/include/asm-cris/irq.h	Mon Jan 21 16:00:39 2002
@@ -126,6 +126,9 @@
   /* the asm IRQ handler makes sure the causing IRQ is blocked, then it calls
    * do_IRQ (with irq disabled still). after that it unblocks and jumps to
    * ret_from_intr (entry.S)
+   *
+   * The reason the IRQ is blocked is to allow an sti() before the handler which
+   * will acknowledge the interrupt is run.
    */
 
 #define BUILD_IRQ(nr,mask) \
@@ -151,6 +154,41 @@
           "reti\n\t" \
           "nop\n");
 
+/* This is subtle. The timer interrupt is crucial and it should not be disabled for 
+ * too long. However, if it had been a normal interrupt as per BUILD_IRQ, it would
+ * have been BLOCK'ed, and then softirq's are run before we return here to UNBLOCK.
+ * If the softirq's take too much time to run, the timer irq won't run and the 
+ * watchdog will kill us.
+ *
+ * Furthermore, if a lot of other irq's occur before we return here, the multiple_irq
+ * handler is run and it prioritizes the timer interrupt. However if we had BLOCK'ed
+ * it here, we would not get the multiple_irq at all.
+ *
+ * The non-blocking here is based on the knowledge that the timer interrupt is 
+ * registred as a fast interrupt (SA_INTERRUPT) so that we _know_ there will not
+ * be an sti() before the timer irq handler is run to acknowledge the interrupt.
+ */
+
+#define BUILD_TIMER_IRQ(nr,mask) \
+void IRQ_NAME(nr); \
+void sIRQ_NAME(nr); \
+void BAD_IRQ_NAME(nr); \
+__asm__ ( \
+          ".text\n\t" \
+          "IRQ" #nr "_interrupt:\n\t" \
+	  SAVE_ALL \
+	  "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \
+	  "moveq "#nr",$r10\n\t" \
+	  "move.d $sp,$r11\n\t" \
+	  "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \
+	  "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \
+	  "jump ret_from_intr\n\t" \
+          "bad_IRQ" #nr "_interrupt:\n\t" \
+	  "push $r0\n\t" \
+	  BLOCK_IRQ(mask,nr) \
+	  "pop $r0\n\t" \
+          "reti\n\t" \
+          "nop\n");
 
 #endif  /* _ASM_IRQ_H */
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/page.h linux/include/asm-cris/page.h
--- v2.5.2/linux/include/asm-cris/page.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-cris/page.h	Mon Jan 21 16:00:39 2002
@@ -105,8 +105,14 @@
  * to arm and m68k I think)
  */ 
 
-#define virt_to_page(kaddr)    (mem_map + (((unsigned long)kaddr - PAGE_OFFSET) >> PAGE_SHIFT))
-#define VALID_PAGE(page)       ((page - mem_map) < max_mapnr)
+#define virt_to_page(kaddr)    (mem_map + (((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT))
+#define VALID_PAGE(page)       (((page) - mem_map) < max_mapnr)
+
+/* convert a page (based on mem_map and forward) to a physical address
+ * do this by figuring out the virtual address and then use __pa
+ */
+
+#define page_to_phys(page)     __pa((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
 
 /* from linker script */
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/pgalloc.h linux/include/asm-cris/pgalloc.h
--- v2.5.2/linux/include/asm-cris/pgalloc.h	Tue May  1 16:05:00 2001
+++ linux/include/asm-cris/pgalloc.h	Mon Jan 21 16:00:39 2002
@@ -21,7 +21,7 @@
  * Allocate and free page tables.
  */
 
-extern __inline__ pgd_t *get_pgd_slow(void)
+static inline pgd_t *get_pgd_slow(void)
 {
         pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL);
 
@@ -33,12 +33,12 @@
         return ret;
 }
 
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
+static inline void free_pgd_slow(pgd_t *pgd)
 {
         free_page((unsigned long)pgd);
 }
 
-extern __inline__ pgd_t *get_pgd_fast(void)
+static inline pgd_t *get_pgd_fast(void)
 {
         unsigned long *ret;
 
@@ -51,7 +51,7 @@
         return (pgd_t *)ret;
 }
 
-extern __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;
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/pgtable.h linux/include/asm-cris/pgtable.h
--- v2.5.2/linux/include/asm-cris/pgtable.h	Fri Nov  9 14:11:15 2001
+++ linux/include/asm-cris/pgtable.h	Mon Jan 21 16:00:39 2002
@@ -3,6 +3,12 @@
  * HISTORY:
  *
  * $Log: pgtable.h,v $
+ * Revision 1.14  2001/12/10 03:08:50  bjornw
+ * Added pgtable_cache_init dummy
+ *
+ * Revision 1.13  2001/11/12 18:05:38  pkj
+ * Added declaration of paging_init().
+ *
  * Revision 1.12  2001/08/11 00:28:00  bjornw
  * PAGE_CHG_MASK and PAGE_NONE had somewhat untraditional values
  *
@@ -106,12 +112,14 @@
  * the CRIS page table tree.
  */
 
+extern void paging_init(void);
+
 /* The cache doesn't need to be flushed when TLB entries change because 
  * the cache is mapped to physical memory, not virtual memory
  */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm, start, end)	do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_dcache_page(page)                 do { } while (0)
@@ -125,7 +133,7 @@
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *
  */
 
@@ -133,7 +141,7 @@
 extern void flush_tlb_mm(struct mm_struct *mm);
 extern void flush_tlb_page(struct vm_area_struct *vma, 
 			   unsigned long addr);
-extern void flush_tlb_range(struct mm_struct *mm,
+extern void flush_tlb_range(struct vm_area_struct *vma,
 			    unsigned long start,
 			    unsigned long end);
 
@@ -507,6 +515,6 @@
 /*
  * No page table caches to initialise
  */
-#define pgtable_cache_init()	do { } while (0)
+#define pgtable_cache_init()   do { } while (0)
 
 #endif /* _CRIS_PGTABLE_H */
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/processor.h linux/include/asm-cris/processor.h
--- v2.5.2/linux/include/asm-cris/processor.h	Mon Oct  8 11:43:54 2001
+++ linux/include/asm-cris/processor.h	Mon Jan 21 16:00:39 2002
@@ -142,6 +142,6 @@
 #define init_task       (init_task_union.task)
 #define init_stack      (init_task_union.stack)
 
-#define cpu_relax()	do { } while (0)
+#define cpu_relax()     do { } while (0)
 
 #endif /* __ASM_CRIS_PROCESSOR_H */
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/scatterlist.h linux/include/asm-cris/scatterlist.h
--- v2.5.2/linux/include/asm-cris/scatterlist.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-cris/scatterlist.h	Mon Jan 21 16:00:39 2002
@@ -0,0 +1,18 @@
+#ifndef __ASM_CRIS_SCATTERLIST_H
+#define __ASM_CRIS_SCATTERLIST_H
+
+struct scatterlist {
+	char *  address;    /* Location data is to be transferred to */
+	unsigned int length;
+
+	/* The following is i386 highmem junk - not used by us */
+	struct page * page; /* Location for highmem page, if any */
+	unsigned int offset;/* for highmem, page offset */
+
+};
+
+/* i386 junk */
+
+#define ISA_DMA_THRESHOLD (0x1fffffff)
+
+#endif /* !(__ASM_CRIS_SCATTERLIST_H) */
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/unistd.h linux/include/asm-cris/unistd.h
--- v2.5.2/linux/include/asm-cris/unistd.h	Fri Nov  9 14:11:15 2001
+++ linux/include/asm-cris/unistd.h	Mon Jan 21 16:00:39 2002
@@ -378,6 +378,7 @@
 static inline _syscall1(int,close,int,fd)
 static inline _syscall1(int,_exit,int,exitcode)
 static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
 
   /* the following are just while developing the elinux port! */
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/user.h linux/include/asm-cris/user.h
--- v2.5.2/linux/include/asm-cris/user.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/user.h	Mon Jan 21 16:00:39 2002
@@ -28,8 +28,51 @@
  *	to write an integer number of pages.
  */
 
+/* User mode registers, used for core dumps. In order to keep ELF_NGREG
+   sensible we let all registers be 32 bits. The csr registers are included
+   for future use. */
+struct user_regs_struct {
+        unsigned long r0;       /* General registers. */
+        unsigned long r1;
+        unsigned long r2;
+        unsigned long r3;
+        unsigned long r4;
+        unsigned long r5;
+        unsigned long r6;
+        unsigned long r7;
+        unsigned long r8;
+        unsigned long r9;
+        unsigned long r10;
+        unsigned long r11;
+        unsigned long r12;
+        unsigned long r13;
+        unsigned long sp;       /* Stack pointer. */
+        unsigned long pc;       /* Program counter. */
+        unsigned long p0;       /* Constant zero (only 8 bits). */
+        unsigned long vr;       /* Version register (only 8 bits). */
+        unsigned long p2;       /* Reserved. */
+        unsigned long p3;       /* Reserved. */
+        unsigned long p4;       /* Constant zero (only 16 bits). */
+        unsigned long ccr;      /* Condition code register (only 16 bits). */
+        unsigned long p6;       /* Reserved. */
+        unsigned long mof;      /* Multiply overflow register. */
+        unsigned long p8;       /* Constant zero. */
+        unsigned long ibr;      /* Not accessible. */
+        unsigned long irp;      /* Not accessible. */
+        unsigned long srp;      /* Subroutine return pointer. */
+        unsigned long bar;      /* Not accessible. */
+        unsigned long dccr;     /* Dword condition code register. */
+        unsigned long brp;      /* Not accessible. */
+        unsigned long usp;      /* User-mode stack pointer. Same as sp when 
+                                   in user mode. */
+        unsigned long csrinstr; /* Internal status registers. */
+        unsigned long csraddr;
+        unsigned long csrdata;
+};
+
+        
 struct user {
-	struct pt_regs	regs;			/* entire machine state */
+	struct user_regs_struct	regs;		/* entire machine state */
 	size_t		u_tsize;		/* text size (pages) */
 	size_t		u_dsize;		/* data size (pages) */
 	size_t		u_ssize;		/* stack size (pages) */
diff -u --recursive --new-file v2.5.2/linux/include/asm-generic/tlb.h linux/include/asm-generic/tlb.h
--- v2.5.2/linux/include/asm-generic/tlb.h	Fri Sep 14 08:41:04 2001
+++ linux/include/asm-generic/tlb.h	Tue Jan 15 10:56:35 2002
@@ -25,7 +25,7 @@
  * shootdown.
  */
 typedef struct free_pte_ctx {
-	struct mm_struct	*mm;
+	struct vm_area_struct	*vma;
 	unsigned long		nr;	/* set to ~0UL means fast mode */
 	unsigned long	start_addr, end_addr;
 	pte_t	ptes[FREE_PTE_NR];
@@ -37,11 +37,12 @@
 /* tlb_gather_mmu
  *	Return a pointer to an initialized mmu_gather_t.
  */
-static inline mmu_gather_t *tlb_gather_mmu(struct mm_struct *mm)
+static inline mmu_gather_t *tlb_gather_mmu(struct vm_area_struct *vma)
 {
 	mmu_gather_t *tlb = &mmu_gathers[smp_processor_id()];
+	struct mm_struct *mm = vma->vm_mm;
 
-	tlb->mm = mm;
+	tlb->vma = vma;
 	/* Use fast mode if there is only one user of this mm (this process) */
 	tlb->nr = (atomic_read(&(mm)->mm_users) == 1) ? ~0UL : 0UL;
 	return tlb;
@@ -69,7 +70,7 @@
 
 /* tlb_finish_mmu
  *	Called at the end of the shootdown operation to free up any resources
- *	that were required.  The page talbe lock is still held at this point.
+ *	that were required.  The page table lock is still held at this point.
  */
 static inline void tlb_finish_mmu(struct free_pte_ctx *ctx, unsigned long start, unsigned long end)
 {
@@ -77,13 +78,13 @@
 
 	/* Handle the fast case first. */
 	if (ctx->nr == ~0UL) {
-		flush_tlb_range(ctx->mm, start, end);
+		flush_tlb_range(ctx->vma, start, end);
 		return;
 	}
 	nr = ctx->nr;
 	ctx->nr = 0;
 	if (nr)
-		flush_tlb_range(ctx->mm, ctx->start_addr, ctx->end_addr);
+		flush_tlb_range(ctx->vma, ctx->start_addr, ctx->end_addr);
 	for (i=0; i < nr; i++) {
 		pte_t pte = ctx->ptes[i];
 		__free_pte(pte);
@@ -96,9 +97,9 @@
  * attempt to get gcc to generate optimal code since this code is run on each
  * page in a process at exit.
  */
-typedef struct mm_struct mmu_gather_t;
+typedef struct vm_area_struct mmu_gather_t;
 
-#define tlb_gather_mmu(mm)	(mm)
+#define tlb_gather_mmu(vma)	(vma)
 #define tlb_finish_mmu(tlb, start, end)	flush_tlb_range(tlb, start, end)
 #define tlb_remove_page(tlb, ptep, addr)	do {\
 		pte_t __pte = *(ptep);\
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/apic.h linux/include/asm-i386/apic.h
--- v2.5.2/linux/include/asm-i386/apic.h	Thu Nov 22 11:46:19 2001
+++ linux/include/asm-i386/apic.h	Tue Jan 29 21:41:12 2002
@@ -79,6 +79,8 @@
 extern void setup_apic_nmi_watchdog (void);
 extern inline void nmi_watchdog_tick (struct pt_regs * regs);
 extern int APIC_init_uniprocessor (void);
+extern void disable_APIC_timer(void);
+extern void enable_APIC_timer(void);
 
 extern struct pm_dev *apic_pm_register(pm_dev_t, unsigned long, pm_callback);
 extern void apic_pm_unregister(struct pm_dev*);
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h
--- v2.5.2/linux/include/asm-i386/bitops.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-i386/bitops.h	Tue Jan 29 21:41:09 2002
@@ -292,6 +292,34 @@
 }
 
 /**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first set bit, not the number of the byte
+ * containing a bit.
+ */
+static __inline__ int find_first_bit(void * addr, unsigned size)
+{
+	int d0, d1;
+	int res;
+
+	/* This looks at memory. Mark it volatile to tell gcc not to move it around */
+	__asm__ __volatile__(
+		"xorl %%eax,%%eax\n\t"
+		"repe; scasl\n\t"
+		"jz 1f\n\t"
+		"leal -4(%%edi),%%edi\n\t"
+		"bsfl (%%edi),%%eax\n"
+		"1:\tsubl %%ebx,%%edi\n\t"
+		"shll $3,%%edi\n\t"
+		"addl %%edi,%%eax"
+		:"=a" (res), "=&c" (d0), "=&D" (d1)
+		:"1" ((size + 31) >> 5), "2" (addr), "b" (addr));
+	return res;
+}
+
+/**
  * find_next_zero_bit - find the first zero bit in a memory region
  * @addr: The address to base the search on
  * @offset: The bitnumber to start searching at
@@ -304,7 +332,7 @@
 	
 	if (bit) {
 		/*
-		 * Look for zero in first byte
+		 * Look for zero in the first 32 bits.
 		 */
 		__asm__("bsfl %1,%0\n\t"
 			"jne 1f\n\t"
@@ -325,6 +353,39 @@
 }
 
 /**
+ * find_next_bit - find the first set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static __inline__ int find_next_bit (void * addr, int size, int offset)
+{
+	unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
+	int set = 0, bit = offset & 31, res;
+
+	if (bit) {
+		/*
+		 * Look for nonzero in the first 32 bits:
+		 */
+		__asm__("bsfl %1,%0\n\t"
+			"jne 1f\n\t"
+			"movl $32, %0\n"
+			"1:"
+			: "=r" (set)
+			: "r" (*p >> bit));
+		if (set < (32 - bit))
+			return set + offset;
+		set = 32 - bit;
+		p++;
+	}
+	/*
+	 * No set bit yet, search remaining full words for a bit
+	 */
+	res = find_first_bit (p, size - 32 * (p - (unsigned long *) addr));
+	return (offset + set + res);
+}
+
+/**
  * ffz - find first zero in word.
  * @word: The word to search
  *
@@ -335,6 +396,20 @@
 	__asm__("bsfl %1,%0"
 		:"=r" (word)
 		:"r" (~word));
+	return word;
+}
+
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static __inline__ unsigned long __ffs(unsigned long word)
+{
+	__asm__("bsfl %1,%0"
+		:"=r" (word)
+		:"rm" (word));
 	return word;
 }
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/desc.h linux/include/asm-i386/desc.h
--- v2.5.2/linux/include/asm-i386/desc.h	Thu Jul 26 13:40:32 2001
+++ linux/include/asm-i386/desc.h	Tue Jan 29 18:24:01 2002
@@ -18,23 +18,31 @@
  *   9 - APM BIOS support
  *  10 - APM BIOS support
  *  11 - APM BIOS support
+ *  12 - PNPBIOS support
+ *  13 - PNPBIOS support
+ *  14 - PNPBIOS support
+ *  15 - PNPBIOS support
+ *  16 - PNPBIOS support
+ *  17 - not used
+ *  18 - not used
+ *  19 - not used
  *
  * The TSS+LDT descriptors are spread out a bit so that every CPU
  * has an exclusive cacheline for the per-CPU TSS and LDT:
  *
- *  12 - CPU#0 TSS                          <-- new cacheline 
- *  13 - CPU#0 LDT
- *  14 - not used 
- *  15 - not used 
- *  16 - CPU#1 TSS                          <-- new cacheline 
- *  17 - CPU#1 LDT
- *  18 - not used 
- *  19 - not used 
+ *  20 - CPU#0 TSS                          <-- new cacheline 
+ *  21 - CPU#0 LDT
+ *  22 - not used 
+ *  23 - not used 
+ *  24 - CPU#1 TSS                          <-- new cacheline 
+ *  25 - CPU#1 LDT
+ *  26 - not used 
+ *  27 - not used 
  *  ... NR_CPUS per-CPU TSS+LDT's if on SMP
  *
  * Entry into gdt where to find first TSS.
  */
-#define __FIRST_TSS_ENTRY 12
+#define __FIRST_TSS_ENTRY 20
 #define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY+1)
 
 #define __TSS(n) (((n)<<2) + __FIRST_TSS_ENTRY)
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/hw_irq.h linux/include/asm-i386/hw_irq.h
--- v2.5.2/linux/include/asm-i386/hw_irq.h	Thu Nov 22 11:46:18 2001
+++ linux/include/asm-i386/hw_irq.h	Tue Jan 29 21:41:09 2002
@@ -35,13 +35,14 @@
  *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
  *  TLB, reschedule and local APIC vectors are performance-critical.
  *
- *  Vectors 0xf0-0xfa are free (reserved for future Linux use).
+ *  Vectors 0xf0-0xf9 are free (reserved for future Linux use).
  */
 #define SPURIOUS_APIC_VECTOR	0xff
 #define ERROR_APIC_VECTOR	0xfe
 #define INVALIDATE_TLB_VECTOR	0xfd
 #define RESCHEDULE_VECTOR	0xfc
-#define CALL_FUNCTION_VECTOR	0xfb
+#define TASK_MIGRATION_VECTOR	0xfb
+#define CALL_FUNCTION_VECTOR	0xfa
 
 /*
  * Local APIC timer IRQ vector is on a different priority level,
@@ -134,22 +135,6 @@
 	SAVE_ALL \
 	SYMBOL_NAME_STR(call_##x)":\n\t" \
 	"call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
-	"jmp ret_from_intr\n");
-
-#define BUILD_SMP_TIMER_INTERRUPT(x,v) XBUILD_SMP_TIMER_INTERRUPT(x,v)
-#define XBUILD_SMP_TIMER_INTERRUPT(x,v) \
-asmlinkage void x(struct pt_regs * regs); \
-asmlinkage void call_##x(void); \
-__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(x) ":\n\t" \
-	"pushl $"#v"-256\n\t" \
-	SAVE_ALL \
-	"movl %esp,%eax\n\t" \
-	"pushl %eax\n\t" \
-	SYMBOL_NAME_STR(call_##x)":\n\t" \
-	"call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
-	"addl $4,%esp\n\t" \
 	"jmp ret_from_intr\n");
 
 #define BUILD_COMMON_IRQ() \
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/ide.h linux/include/asm-i386/ide.h
--- v2.5.2/linux/include/asm-i386/ide.h	Thu Nov 22 11:46:58 2001
+++ linux/include/asm-i386/ide.h	Tue Jan 29 21:42:50 2002
@@ -95,7 +95,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/mmu_context.h linux/include/asm-i386/mmu_context.h
--- v2.5.2/linux/include/asm-i386/mmu_context.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-i386/mmu_context.h	Tue Jan 29 21:42:34 2002
@@ -1,5 +1,5 @@
-#ifndef __I386_MMU_CONTEXT_H
-#define __I386_MMU_CONTEXT_H
+#ifndef __I386_SCHED_H
+#define __I386_SCHED_H
 
 #include <linux/config.h>
 #include <asm/desc.h>
@@ -16,18 +16,19 @@
 # error update this function.
 #endif
 
-static inline int sched_find_first_zero_bit(char *bitmap)
+static inline int sched_find_first_bit(unsigned long *b)
 {
-	unsigned int *b = (unsigned int *)bitmap;
-	unsigned int rt;
-
-	rt = b[0] & b[1] & b[2] & b[3];
-	if (unlikely(rt != 0xffffffff))
-		return find_first_zero_bit(bitmap, MAX_RT_PRIO);
-
-	if (b[4] != ~0)
-		return ffz(b[4]) + MAX_RT_PRIO;
-	return ffz(b[5]) + 32 + MAX_RT_PRIO;
+	if (unlikely(b[0]))
+		return __ffs(b[0]);
+	if (unlikely(b[1]))
+		return __ffs(b[1]) + 32;
+	if (unlikely(b[2]))
+		return __ffs(b[2]) + 64;
+	if (unlikely(b[3]))
+		return __ffs(b[3]) + 96;
+	if (b[4])
+		return __ffs(b[4]) + 128;
+	return __ffs(b[5]) + 32 + 128;
 }
 /*
  * possibly do the LDT unload here?
@@ -50,13 +51,13 @@
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
 {
-	if (prev != next) {
+	if (likely(prev != next)) {
 		/* stop flush ipis for the previous mm */
 		clear_bit(cpu, &prev->cpu_vm_mask);
 		/*
 		 * Re-load LDT if necessary
 		 */
-		if (prev->context.segments != next->context.segments)
+		if (unlikely(prev->context.segments != next->context.segments))
 			load_LDT(next);
 #ifdef CONFIG_SMP
 		cpu_tlbstate[cpu].state = TLBSTATE_OK;
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/page.h linux/include/asm-i386/page.h
--- v2.5.2/linux/include/asm-i386/page.h	Thu Nov 22 11:46:18 2001
+++ linux/include/asm-i386/page.h	Tue Jan 29 21:41:09 2002
@@ -80,6 +80,12 @@
 
 #define __PAGE_OFFSET		(0xC0000000)
 
+/*
+ * This much address space is reserved for vmalloc() and iomap()
+ * as well as fixmap mappings.
+ */
+#define __VMALLOC_RESERVE	(128 << 20)
+
 #ifndef __ASSEMBLY__
 
 /*
@@ -118,6 +124,9 @@
 #endif /* __ASSEMBLY__ */
 
 #define PAGE_OFFSET		((unsigned long)__PAGE_OFFSET)
+#define VMALLOC_RESERVE		((unsigned long)__VMALLOC_RESERVE)
+#define __MAXMEM		(-__PAGE_OFFSET-__VMALLOC_RESERVE)
+#define MAXMEM			((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
 #define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
 #define virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/pci.h linux/include/asm-i386/pci.h
--- v2.5.2/linux/include/asm-i386/pci.h	Thu Nov 22 11:46:29 2001
+++ linux/include/asm-i386/pci.h	Tue Jan 29 21:41:52 2002
@@ -114,6 +114,14 @@
 	/* Nothing to do */
 }
 
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_SET(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/pgalloc.h linux/include/asm-i386/pgalloc.h
--- v2.5.2/linux/include/asm-i386/pgalloc.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-i386/pgalloc.h	Tue Jan 29 21:41:15 2002
@@ -165,7 +165,7 @@
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  *
  * ..but the i386 has somewhat limited tlb flushing capabilities,
@@ -191,10 +191,10 @@
 		__flush_tlb_one(addr);
 }
 
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 	unsigned long start, unsigned long end)
 {
-	if (mm == current->active_mm)
+	if (vma->vm_mm == current->active_mm)
 		__flush_tlb();
 }
 
@@ -212,9 +212,9 @@
 
 #define flush_tlb()	flush_tlb_current_task()
 
-static inline void flush_tlb_range(struct mm_struct * mm, unsigned long start, unsigned long end)
+static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end)
 {
-	flush_tlb_mm(mm);
+	flush_tlb_mm(vma->vm_mm);
 }
 
 #define TLBSTATE_OK	1
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v2.5.2/linux/include/asm-i386/pgtable.h	Thu Nov 22 11:46:19 2001
+++ linux/include/asm-i386/pgtable.h	Tue Jan 29 21:41:09 2002
@@ -27,7 +27,7 @@
 /* Caches aren't brain-dead on the intel. */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm, start, end)	do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/signal.h linux/include/asm-i386/signal.h
--- v2.5.2/linux/include/asm-i386/signal.h	Thu Nov 22 11:46:18 2001
+++ linux/include/asm-i386/signal.h	Tue Jan 29 21:41:09 2002
@@ -2,6 +2,7 @@
 #define _ASMi386_SIGNAL_H
 
 #include <linux/types.h>
+#include <linux/linkage.h>
 
 /* Avoid too many header ordering problems.  */
 struct siginfo;
@@ -215,6 +216,9 @@
 	__asm__("bsfl %1,%0" : "=r"(word) : "rm"(word) : "cc");
 	return word;
 }
+
+struct pt_regs;
+extern int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/smplock.h linux/include/asm-i386/smplock.h
--- v2.5.2/linux/include/asm-i386/smplock.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-i386/smplock.h	Tue Jan 29 21:41:25 2002
@@ -19,8 +19,8 @@
 do {						\
 	if (unlikely(task->lock_depth >= 0)) {	\
 		spin_unlock(&kernel_flag);	\
-		release_irqlock(cpu);		\
-		__sti();			\
+		if (global_irq_holder == (cpu))	\
+			BUG();			\
 	}					\
 } while (0)
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- v2.5.2/linux/include/asm-i386/unistd.h	Wed Oct 17 10:03:03 2001
+++ linux/include/asm-i386/unistd.h	Tue Jan 29 18:46:00 2002
@@ -230,6 +230,18 @@
 #define __NR_security		223	/* syscall for security modules */
 #define __NR_gettid		224
 #define __NR_readahead		225
+#define __NR_setxattr		226
+#define __NR_lsetxattr		227
+#define __NR_fsetxattr		228
+#define __NR_getxattr		229
+#define __NR_lgetxattr		230
+#define __NR_fgetxattr		231
+#define __NR_listxattr		232
+#define __NR_llistxattr		233
+#define __NR_flistxattr		234
+#define __NR_removexattr	235
+#define __NR_lremovexattr	236
+#define __NR_fremovexattr	237
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-ia64/ide.h linux/include/asm-ia64/ide.h
--- v2.5.2/linux/include/asm-ia64/ide.h	Wed May 24 08:40:41 2000
+++ linux/include/asm-ia64/ide.h	Tue Jan 15 11:27:47 2002
@@ -101,7 +101,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -u --recursive --new-file v2.5.2/linux/include/asm-ia64/pci.h linux/include/asm-ia64/pci.h
--- v2.5.2/linux/include/asm-ia64/pci.h	Fri Nov  9 14:26:17 2001
+++ linux/include/asm-ia64/pci.h	Tue Jan 15 11:48:13 2002
@@ -46,6 +46,20 @@
 #define pci_dma_sync_sg			platform_pci_dma_sync_sg
 #define sg_dma_address			platform_pci_dma_address
 
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
 /*
  * Return whether the given PCI device DMA address mask can be supported properly.  For
  * example, if your device can only drive the low 24-bits during PCI bus mastering, then
diff -u --recursive --new-file v2.5.2/linux/include/asm-ia64/pgalloc.h linux/include/asm-ia64/pgalloc.h
--- v2.5.2/linux/include/asm-ia64/pgalloc.h	Fri Nov  9 14:26:17 2001
+++ linux/include/asm-ia64/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -181,7 +181,7 @@
 	}
 }
 
-extern void flush_tlb_range (struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void flush_tlb_range (struct vm_area_struct *vma, unsigned long start, unsigned long end);
 
 /*
  * Page-granular tlb flush.
@@ -190,7 +190,7 @@
 flush_tlb_page (struct vm_area_struct *vma, unsigned long addr)
 {
 #ifdef CONFIG_SMP
-	flush_tlb_range(vma->vm_mm, (addr & PAGE_MASK), (addr & PAGE_MASK) + PAGE_SIZE);
+	flush_tlb_range(vma, (addr & PAGE_MASK), (addr & PAGE_MASK) + PAGE_SIZE);
 #else
 	if (vma->vm_mm == current->active_mm)
 		asm volatile ("ptc.l %0,%1" :: "r"(addr), "r"(PAGE_SHIFT << 2) : "memory");
@@ -204,9 +204,12 @@
 static inline void
 flush_tlb_pgtables (struct mm_struct *mm, unsigned long start, unsigned long end)
 {
+	struct vm_area_struct vma;
+
 	if (rgn_index(start) != rgn_index(end))
 		printk("flush_tlb_pgtables: can't flush across regions!!\n");
-	flush_tlb_range(mm, ia64_thash(start), ia64_thash(end));
+	vma.vm_mm = mm;
+	flush_tlb_range(&vma, ia64_thash(start), ia64_thash(end));
 }
 
 /*
@@ -217,7 +220,7 @@
 /* Caches aren't brain-dead on the IA-64. */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm, start, end)	do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h
--- v2.5.2/linux/include/asm-m68k/ide.h	Mon Jun 11 19:15:27 2001
+++ linux/include/asm-m68k/ide.h	Tue Jan 15 11:27:47 2002
@@ -89,7 +89,19 @@
 		unsigned unit		: 1;	/* drive select number, 0 or 1 */
 		unsigned head		: 4;	/* always zeros here */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+		unsigned reserved456	: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned bit0		: 1;
+	} b;
+} control_t;
 
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
diff -u --recursive --new-file v2.5.2/linux/include/asm-m68k/motorola_pgalloc.h linux/include/asm-m68k/motorola_pgalloc.h
--- v2.5.2/linux/include/asm-m68k/motorola_pgalloc.h	Mon Jun 11 19:15:27 2001
+++ linux/include/asm-m68k/motorola_pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -241,10 +241,10 @@
 		__flush_tlb_one(addr);
 }
 
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 				   unsigned long start, unsigned long end)
 {
-	if (mm == current->mm)
+	if (vma->vm_mm == current->mm)
 		__flush_tlb();
 }
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-m68k/pgalloc.h linux/include/asm-m68k/pgalloc.h
--- v2.5.2/linux/include/asm-m68k/pgalloc.h	Thu Oct 25 13:53:55 2001
+++ linux/include/asm-m68k/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -89,11 +89,11 @@
 		__flush_cache_030();
 }
 
-extern inline void flush_cache_range(struct mm_struct *mm,
+extern inline void flush_cache_range(struct vm_area_struct *vma,
 				     unsigned long start,
 				     unsigned long end)
 {
-	if (mm == current->mm)
+	if (vma->vm_mm == current->mm)
 	        __flush_cache_030();
 }
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-m68k/sun3_pgalloc.h linux/include/asm-m68k/sun3_pgalloc.h
--- v2.5.2/linux/include/asm-m68k/sun3_pgalloc.h	Mon Jun 11 19:15:27 2001
+++ linux/include/asm-m68k/sun3_pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -216,9 +216,10 @@
 }
 /* Flush a range of pages from TLB. */
 
-static inline void flush_tlb_range (struct mm_struct *mm,
+static inline void flush_tlb_range (struct vm_area_struct *vma,
 		      unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned char seg, oldctx;
 	
 	start &= ~SUN3_PMEG_MASK;
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips/gfx.h linux/include/asm-mips/gfx.h
--- v2.5.2/linux/include/asm-mips/gfx.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips/gfx.h	Tue Jan 15 10:56:36 2002
@@ -48,9 +48,9 @@
 
 #ifdef __KERNEL__
 /* umap.c */
-extern void remove_mapping (struct task_struct *, unsigned long, unsigned long);
+extern void remove_mapping (struct vm_area_struct *vma, struct task_struct *, unsigned long, unsigned long);
 extern void *vmalloc_uncached (unsigned long size);
-extern int vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr);
+extern int vmap_page_range (struct vm_area_struct *vma, unsigned long from, unsigned long size, unsigned long vaddr);
 #endif
 
 #endif /* _ASM_GFX_H */
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips/ide.h linux/include/asm-mips/ide.h
--- v2.5.2/linux/include/asm-mips/ide.h	Sun Sep  9 10:43:01 2001
+++ linux/include/asm-mips/ide.h	Tue Jan 15 11:27:47 2002
@@ -92,6 +92,26 @@
 	} b;
 } select_t;
 
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+#ifdef __MIPSEB__
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+		unsigned reserved456	: 3;
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned bit0		: 1;
+#else
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+#endif
+	} b;
+} control_t;
+
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
 {
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips/pci.h linux/include/asm-mips/pci.h
--- v2.5.2/linux/include/asm-mips/pci.h	Fri Oct 12 15:35:54 2001
+++ linux/include/asm-mips/pci.h	Tue Jan 15 11:48:13 2002
@@ -114,6 +114,14 @@
 	/* Nothing to do */
 }
 
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+
 /*
  * Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips/pgalloc.h linux/include/asm-mips/pgalloc.h
--- v2.5.2/linux/include/asm-mips/pgalloc.h	Mon Jul  2 13:56:40 2001
+++ linux/include/asm-mips/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -16,12 +16,12 @@
  *
  *  - flush_tlb_all() flushes all processes TLB entries
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB entries
- *  - flush_tlb_page(mm, vmaddr) flushes a single page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_page(vma, vmaddr) flushes a single page
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  */
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *mm);
-extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			       unsigned long end);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips/pgtable.h linux/include/asm-mips/pgtable.h
--- v2.5.2/linux/include/asm-mips/pgtable.h	Sun Sep  9 10:43:01 2001
+++ linux/include/asm-mips/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -23,14 +23,14 @@
  *  - flush_cache_all() flushes entire cache
  *  - flush_cache_mm(mm) flushes the specified mm context's cache lines
  *  - flush_cache_page(mm, vmaddr) flushes a single page
- *  - flush_cache_range(mm, start, end) flushes a range of pages
+ *  - flush_cache_range(vma, start, end) flushes a range of pages
  *  - flush_page_to_ram(page) write back kernel page to ram
  *  - flush_icache_range(start, end) flush a range of instructions
  */
 extern void (*_flush_cache_all)(void);
 extern void (*___flush_cache_all)(void);
 extern void (*_flush_cache_mm)(struct mm_struct *mm);
-extern void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start,
+extern void (*_flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
 				 unsigned long end);
 extern void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 extern void (*_flush_cache_sigtramp)(unsigned long addr);
@@ -44,7 +44,7 @@
 #define flush_cache_all()		_flush_cache_all()
 #define __flush_cache_all()		___flush_cache_all()
 #define flush_cache_mm(mm)		_flush_cache_mm(mm)
-#define flush_cache_range(mm,start,end)	_flush_cache_range(mm,start,end)
+#define flush_cache_range(vma,start,end) _flush_cache_range(vma,start,end)
 #define flush_cache_page(vma,page)	_flush_cache_page(vma, page)
 #define flush_cache_sigtramp(addr)	_flush_cache_sigtramp(addr)
 #define flush_page_to_ram(page)		_flush_page_to_ram(page)
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips/umap.h linux/include/asm-mips/umap.h
--- v2.5.2/linux/include/asm-mips/umap.h	Fri Jun 25 17:37:53 1999
+++ linux/include/asm-mips/umap.h	Tue Jan 15 10:56:36 2002
@@ -1,7 +1,7 @@
 #ifndef __MIPS_UMAP_H
 #define __MIPS_UMAP_H
 
-void remove_mapping (struct task_struct *task, unsigned long start,
+void remove_mapping (struct vm_area_struct *vma, struct task_struct *task, unsigned long start,
 unsigned long end);
 
 #endif 
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips64/gfx.h linux/include/asm-mips64/gfx.h
--- v2.5.2/linux/include/asm-mips64/gfx.h	Sun Sep  9 10:43:02 2001
+++ linux/include/asm-mips64/gfx.h	Tue Jan 15 10:56:36 2002
@@ -47,9 +47,9 @@
 
 #ifdef __KERNEL__
 /* umap.c */
-extern void remove_mapping (struct task_struct *, unsigned long, unsigned long);
+extern void remove_mapping (struct vm_area_struct *vma, struct task_struct *, unsigned long, unsigned long);
 extern void *vmalloc_uncached (unsigned long size);
-extern int vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr);
+extern int vmap_page_range (struct vm_area_struct *vma, unsigned long from, unsigned long size, unsigned long vaddr);
 #endif
 
 #endif /* _ASM_GFX_H */
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips64/ide.h linux/include/asm-mips64/ide.h
--- v2.5.2/linux/include/asm-mips64/ide.h	Sun Sep  9 10:43:02 2001
+++ linux/include/asm-mips64/ide.h	Tue Jan 15 11:27:47 2002
@@ -85,7 +85,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips64/pci.h linux/include/asm-mips64/pci.h
--- v2.5.2/linux/include/asm-mips64/pci.h	Fri Oct 12 15:35:54 2001
+++ linux/include/asm-mips64/pci.h	Tue Jan 15 11:48:13 2002
@@ -86,6 +86,20 @@
 extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg,
                             int nelems, int direction);
 
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
 #else /* CONFIG_MAPPED_PCI_IO  */
 
 /*
@@ -123,6 +137,14 @@
 
 	/* Nothing to do */
 }
+
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
 
 /*
  * Map a set of buffers described by scatterlist in streaming
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips64/pgalloc.h linux/include/asm-mips64/pgalloc.h
--- v2.5.2/linux/include/asm-mips64/pgalloc.h	Wed Jul  4 11:50:39 2001
+++ linux/include/asm-mips64/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -15,13 +15,13 @@
  *
  *  - flush_tlb_all() flushes all processes TLB entries
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB entries
- *  - flush_tlb_page(mm, vmaddr) flushes a single page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_page(vma, vmaddr) flushes a single page
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  */
 extern void (*_flush_tlb_all)(void);
 extern void (*_flush_tlb_mm)(struct mm_struct *mm);
-extern void (*_flush_tlb_range)(struct mm_struct *mm, unsigned long start,
+extern void (*_flush_tlb_range)(struct vm_area_struct *vma, unsigned long start,
 			       unsigned long end);
 extern void (*_flush_tlb_page)(struct vm_area_struct *vma, unsigned long page);
 
@@ -29,14 +29,14 @@
 
 #define flush_tlb_all()			_flush_tlb_all()
 #define flush_tlb_mm(mm)		_flush_tlb_mm(mm)
-#define flush_tlb_range(mm,vmaddr,end)	_flush_tlb_range(mm, vmaddr, end)
+#define flush_tlb_range(vma,vmaddr,end)	_flush_tlb_range(vma, vmaddr, end)
 #define flush_tlb_page(vma,page)	_flush_tlb_page(vma, page)
 
 #else /* CONFIG_SMP */
 
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *);
-extern void flush_tlb_range(struct mm_struct *, unsigned long, unsigned long);
+extern void flush_tlb_range(struct vm_area_struct *, unsigned long, unsigned long);
 extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
 
 #endif /* CONFIG_SMP */
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips64/pgtable.h linux/include/asm-mips64/pgtable.h
--- v2.5.2/linux/include/asm-mips64/pgtable.h	Sun Sep  9 10:43:02 2001
+++ linux/include/asm-mips64/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -24,11 +24,11 @@
  *  - flush_cache_all() flushes entire cache
  *  - flush_cache_mm(mm) flushes the specified mm context's cache lines
  *  - flush_cache_page(mm, vmaddr) flushes a single page
- *  - flush_cache_range(mm, start, end) flushes a range of pages
+ *  - flush_cache_range(vma, start, end) flushes a range of pages
  *  - flush_page_to_ram(page) write back kernel page to ram
  */
 extern void (*_flush_cache_mm)(struct mm_struct *mm);
-extern void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start,
+extern void (*_flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
                                  unsigned long end);
 extern void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 extern void (*_flush_page_to_ram)(struct page * page);
@@ -38,7 +38,7 @@
 
 #ifndef CONFIG_CPU_R10000
 #define flush_cache_mm(mm)		_flush_cache_mm(mm)
-#define flush_cache_range(mm,start,end)	_flush_cache_range(mm,start,end)
+#define flush_cache_range(vma,start,end) _flush_cache_range(vma,start,end)
 #define flush_cache_page(vma,page)	_flush_cache_page(vma, page)
 #define flush_page_to_ram(page)		_flush_page_to_ram(page)
 
@@ -62,7 +62,7 @@
  */
 extern void andes_flush_icache_page(unsigned long);
 #define flush_cache_mm(mm)		do { } while(0)
-#define flush_cache_range(mm,start,end)	do { } while(0)
+#define flush_cache_range(vma,start,end) do { } while(0)
 #define flush_cache_page(vma,page)	do { } while(0)
 #define flush_page_to_ram(page)		do { } while(0)
 #define flush_icache_range(start, end)	_flush_cache_l1()
diff -u --recursive --new-file v2.5.2/linux/include/asm-parisc/ide.h linux/include/asm-parisc/ide.h
--- v2.5.2/linux/include/asm-parisc/ide.h	Tue Dec  5 12:29:39 2000
+++ linux/include/asm-parisc/ide.h	Tue Jan 15 11:27:47 2002
@@ -90,7 +90,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -u --recursive --new-file v2.5.2/linux/include/asm-parisc/pci.h linux/include/asm-parisc/pci.h
--- v2.5.2/linux/include/asm-parisc/pci.h	Fri Oct 12 15:35:54 2001
+++ linux/include/asm-parisc/pci.h	Tue Jan 15 11:48:13 2002
@@ -172,6 +172,20 @@
 #define pci_map_sg(p, sg, n, d)		hppa_dma_ops->map_sg(p, sg, n, d)
 #define pci_unmap_sg(p, sg, n, d)	hppa_dma_ops->unmap_sg(p, sg, n, d)
 
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
 /* For U2/Astro/Ike based platforms (which are fully I/O coherent)
 ** dma_sync is a NOP. Let's keep the performance path short here.
 */
diff -u --recursive --new-file v2.5.2/linux/include/asm-parisc/pgalloc.h linux/include/asm-parisc/pgalloc.h
--- v2.5.2/linux/include/asm-parisc/pgalloc.h	Mon Apr 23 15:28:07 2001
+++ linux/include/asm-parisc/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -90,7 +90,7 @@
 }
 #endif
 
-#define flush_cache_range(mm, start, end) do { \
+#define flush_cache_range(vma, start, end) do { \
                 __flush_dcache_range(start, (unsigned long)end - (unsigned long)start); \
                 __flush_icache_range(start, (unsigned long)end - (unsigned long)start); \
 } while(0)
@@ -197,10 +197,10 @@
 		
 }
 
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 	unsigned long start, unsigned long end)
 {
-	__flush_tlb_range(mm->context, start, end - start);
+	__flush_tlb_range(vma->vm_mm->context, start, end - start);
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/include/asm-parisc/pgtable.h linux/include/asm-parisc/pgtable.h
--- v2.5.2/linux/include/asm-parisc/pgtable.h	Sun Nov 11 10:20:21 2001
+++ linux/include/asm-parisc/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -34,10 +34,10 @@
 #define cache_push(paddr, len) \
 	do { \
 		unsigned long vaddr = phys_to_virt(paddr); \
-		flush_cache_range(&init_mm, vaddr, vaddr + len); \
+		flush_cache_range(0, vaddr, vaddr + len); \
 	} while(0)
 #define cache_push_v(vaddr, len) \
-			flush_cache_range(&init_mm, vaddr, vaddr + len)
+			flush_cache_range(0, vaddr, vaddr + len)
 
 /*
  * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
diff -u --recursive --new-file v2.5.2/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.5.2/linux/include/asm-ppc/ide.h	Mon Oct  8 11:40:13 2001
+++ linux/include/asm-ppc/ide.h	Tue Jan 15 11:27:47 2002
@@ -129,6 +129,18 @@
 	} b;
 } select_t;
 
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+		unsigned reserved456	: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned bit0		: 1;
+	} b;
+} control_t;
+
 #if !defined(ide_request_irq)
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/asm-ppc/pci.h linux/include/asm-ppc/pci.h
--- v2.5.2/linux/include/asm-ppc/pci.h	Sun Oct 21 10:13:07 2001
+++ linux/include/asm-ppc/pci.h	Tue Jan 15 11:48:13 2002
@@ -102,6 +102,13 @@
 	/* nothing to do */
 }
 
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
 
 /*
  * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
diff -u --recursive --new-file v2.5.2/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.5.2/linux/include/asm-ppc/pgtable.h	Sun Nov 11 10:20:21 2001
+++ linux/include/asm-ppc/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -18,7 +18,7 @@
 extern void local_flush_tlb_all(void);
 extern void local_flush_tlb_mm(struct mm_struct *mm);
 extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
-extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				  unsigned long end);
 #define update_mmu_cache(vma, addr, pte)	do { } while (0)
 
@@ -32,7 +32,7 @@
 static inline void local_flush_tlb_page(struct vm_area_struct *vma,
 				unsigned long vmaddr)
 	{ __tlbia(); }
-static inline void local_flush_tlb_range(struct mm_struct *mm,
+static inline void local_flush_tlb_range(struct vm_area_struct *vma,
 				unsigned long start, unsigned long end)
 	{ __tlbia(); }
 #define update_mmu_cache(vma, addr, pte)	do { } while (0)
@@ -43,7 +43,7 @@
 extern void local_flush_tlb_all(void);
 extern void local_flush_tlb_mm(struct mm_struct *mm);
 extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
-extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			    unsigned long end);
 
 /*
@@ -80,7 +80,7 @@
  */
 #define flush_cache_all()		do { } while (0)
 #define flush_cache_mm(mm)		do { } while (0)
-#define flush_cache_range(mm, a, b)	do { } while (0)
+#define flush_cache_range(vma, a, b)	do { } while (0)
 #define flush_cache_page(vma, p)	do { } while (0)
 #define flush_icache_page(vma, page)	do { } while (0)
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-s390/ide.h linux/include/asm-s390/ide.h
--- v2.5.2/linux/include/asm-s390/ide.h	Fri May 12 11:41:44 2000
+++ linux/include/asm-s390/ide.h	Tue Jan 15 11:27:47 2002
@@ -26,7 +26,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	do {} while (0)
 #define ide_free_irq(irq,dev_id)		do {} while (0)
diff -u --recursive --new-file v2.5.2/linux/include/asm-s390/pgalloc.h linux/include/asm-s390/pgalloc.h
--- v2.5.2/linux/include/asm-s390/pgalloc.h	Thu Oct 11 09:43:38 2001
+++ linux/include/asm-s390/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -156,7 +156,7 @@
  *    called only from vmalloc/vfree
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  */
 
@@ -196,7 +196,7 @@
 {
 	local_flush_tlb();
 }
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 				   unsigned long start, unsigned long end)
 {
 	local_flush_tlb();
@@ -264,10 +264,10 @@
 {
 	__flush_tlb_mm(vma->vm_mm);
 }
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 				   unsigned long start, unsigned long end)
 {
-	__flush_tlb_mm(mm); 
+	__flush_tlb_mm(vma->vm_mm); 
 }
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/asm-s390/pgtable.h linux/include/asm-s390/pgtable.h
--- v2.5.2/linux/include/asm-s390/pgtable.h	Thu Oct 11 09:43:38 2001
+++ linux/include/asm-s390/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -36,7 +36,7 @@
 /* Caches aren't brain-dead on S390. */
 #define flush_cache_all()                       do { } while (0)
 #define flush_cache_mm(mm)                      do { } while (0)
-#define flush_cache_range(mm, start, end)       do { } while (0)
+#define flush_cache_range(vma, start, end)      do { } while (0)
 #define flush_cache_page(vma, vmaddr)           do { } while (0)
 #define flush_page_to_ram(page)                 do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
diff -u --recursive --new-file v2.5.2/linux/include/asm-s390x/ide.h linux/include/asm-s390x/ide.h
--- v2.5.2/linux/include/asm-s390x/ide.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/ide.h	Tue Jan 15 11:27:47 2002
@@ -26,7 +26,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	do {} while (0)
 #define ide_free_irq(irq,dev_id)		do {} while (0)
diff -u --recursive --new-file v2.5.2/linux/include/asm-s390x/pgalloc.h linux/include/asm-s390x/pgalloc.h
--- v2.5.2/linux/include/asm-s390x/pgalloc.h	Wed Jul 25 14:12:02 2001
+++ linux/include/asm-s390x/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -192,7 +192,7 @@
  *    called only from vmalloc/vfree
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  */
 
@@ -232,7 +232,7 @@
 {
 	local_flush_tlb();
 }
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 				   unsigned long start, unsigned long end)
 {
 	local_flush_tlb();
@@ -291,10 +291,10 @@
 {
 	__flush_tlb_mm(vma->vm_mm);
 }
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 				   unsigned long start, unsigned long end)
 {
-	__flush_tlb_mm(mm); 
+	__flush_tlb_mm(vma->vm_mm);
 }
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/asm-s390x/pgtable.h linux/include/asm-s390x/pgtable.h
--- v2.5.2/linux/include/asm-s390x/pgtable.h	Thu Oct 11 09:43:38 2001
+++ linux/include/asm-s390x/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -32,7 +32,7 @@
 /* Caches aren't brain-dead on S390. */
 #define flush_cache_all()                       do { } while (0)
 #define flush_cache_mm(mm)                      do { } while (0)
-#define flush_cache_range(mm, start, end)       do { } while (0)
+#define flush_cache_range(vma, start, end)      do { } while (0)
 #define flush_cache_page(vma, vmaddr)           do { } while (0)
 #define flush_page_to_ram(page)                 do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
diff -u --recursive --new-file v2.5.2/linux/include/asm-sh/ide.h linux/include/asm-sh/ide.h
--- v2.5.2/linux/include/asm-sh/ide.h	Sat Sep  8 12:29:09 2001
+++ linux/include/asm-sh/ide.h	Tue Jan 15 11:27:47 2002
@@ -116,7 +116,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -u --recursive --new-file v2.5.2/linux/include/asm-sh/mmu_context.h linux/include/asm-sh/mmu_context.h
--- v2.5.2/linux/include/asm-sh/mmu_context.h	Sat Sep  8 12:29:09 2001
+++ linux/include/asm-sh/mmu_context.h	Thu Jan 24 12:08:15 2002
@@ -185,4 +185,28 @@
 enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
 {
 }
+
+/*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 168-bit bitmap where the first 128 bits are
+ * unlikely to be set. It's guaranteed that at least one of the 168
+ * bits is cleared.
+ */
+#if MAX_RT_PRIO != 128 || MAX_PRIO != 168
+# error update this function.
+#endif
+
+static inline int sched_find_first_zero_bit(unsigned long *b)
+{
+	unsigned int rt;
+
+	rt = b[0] & b[1] & b[2] & b[3];
+	if (unlikely(rt != 0xffffffff))
+		return find_first_zero_bit(b, MAX_RT_PRIO);
+
+	if (b[4] != ~0)
+		return ffz(b[4]) + MAX_RT_PRIO;
+	return ffz(b[5]) + 32 + MAX_RT_PRIO;
+}
+
 #endif /* __ASM_SH_MMU_CONTEXT_H */
diff -u --recursive --new-file v2.5.2/linux/include/asm-sh/pci.h linux/include/asm-sh/pci.h
--- v2.5.2/linux/include/asm-sh/pci.h	Tue Dec 18 14:56:40 2001
+++ linux/include/asm-sh/pci.h	Tue Jan 15 11:48:13 2002
@@ -89,6 +89,31 @@
 	return virt_to_bus(ptr);
 }
 
+/* pci_unmap_{single,page} being a nop depends upon the
+ * configuration.
+ */
+#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+#else
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+#endif
+
 /* Unmap a single streaming mode DMA translation.  The dma_addr and size
  * must match what was provided for in a previous pci_map_single call.  All
  * other usages are undefined.
diff -u --recursive --new-file v2.5.2/linux/include/asm-sh/pgalloc.h linux/include/asm-sh/pgalloc.h
--- v2.5.2/linux/include/asm-sh/pgalloc.h	Sat Sep  8 12:29:09 2001
+++ linux/include/asm-sh/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -78,14 +78,14 @@
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  */
 
 extern void flush_tlb(void);
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *mm);
-extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			    unsigned long end);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 extern void __flush_tlb_page(unsigned long asid, unsigned long page);
diff -u --recursive --new-file v2.5.2/linux/include/asm-sh/pgtable.h linux/include/asm-sh/pgtable.h
--- v2.5.2/linux/include/asm-sh/pgtable.h	Sun Nov 11 10:20:21 2001
+++ linux/include/asm-sh/pgtable.h	Thu Jan 24 12:08:15 2002
@@ -23,7 +23,7 @@
  *  - flush_cache_all() flushes entire cache
  *  - flush_cache_mm(mm) flushes the specified mm context's cache lines
  *  - flush_cache_page(mm, vmaddr) flushes a single page
- *  - flush_cache_range(mm, start, end) flushes a range of pages
+ *  - flush_cache_range(vma, start, end) flushes a range of pages
  *
  *  - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache
  *  - flush_page_to_ram(page) write back kernel page to ram
@@ -35,7 +35,7 @@
  */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm, start, end)	do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
@@ -55,7 +55,7 @@
 
 extern void flush_cache_all(void);
 extern void flush_cache_mm(struct mm_struct *mm);
-extern void flush_cache_range(struct mm_struct *mm, unsigned long start,
+extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 			      unsigned long end);
 extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr);
 extern void flush_dcache_page(struct page *pg);
@@ -235,6 +235,19 @@
 static inline pte_t pte_mkdirty(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
 static inline pte_t pte_mkyoung(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; }
+
+/*
+ * Macro and implementation to make a page protection as uncachable.
+ */
+#define pgprot_noncached pgprot_noncached
+
+static inline pgprot_t pgprot_noncached(pgprot_t _prot)
+{
+	unsigned long prot = pgprot_val(_prot);
+
+	prot &= ~_PAGE_CACHABLE;
+	return __pgprot(prot);
+}
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
diff -u --recursive --new-file v2.5.2/linux/include/asm-sh/processor.h linux/include/asm-sh/processor.h
--- v2.5.2/linux/include/asm-sh/processor.h	Fri Oct  5 12:11:05 2001
+++ linux/include/asm-sh/processor.h	Thu Jan 24 12:08:15 2002
@@ -184,18 +184,22 @@
 
 #define unlazy_fpu(tsk) do { 			\
 	if ((tsk)->flags & PF_USEDFPU) {	\
-		grab_fpu();			\
 		save_fpu(tsk); 			\
 	}					\
 } while (0)
 
 #define clear_fpu(tsk) do { 			\
-	if ((tsk)->flags & PF_USEDFPU)	 	\
+	if ((tsk)->flags & PF_USEDFPU) { 	\
 		(tsk)->flags &= ~PF_USEDFPU; 	\
+		release_fpu();			\
+	}					\
 } while (0)
 
 /* Double presision, NANS as NANS, rounding to nearest, no exceptions */
 #define FPSCR_INIT  0x00080000
+
+#define	FPSCR_CAUSE_MASK	0x0001f000	/* Cause bits */
+#define	FPSCR_FLAG_MASK		0x0000007c	/* Flag bits */
 
 /*
  * Return saved PC of a blocked thread.
diff -u --recursive --new-file v2.5.2/linux/include/asm-sh/scatterlist.h linux/include/asm-sh/scatterlist.h
--- v2.5.2/linux/include/asm-sh/scatterlist.h	Fri Oct 12 15:35:54 2001
+++ linux/include/asm-sh/scatterlist.h	Thu Jan 24 12:08:15 2002
@@ -2,7 +2,11 @@
 #define __ASM_SH_SCATTERLIST_H
 
 struct scatterlist {
-    char *  address;    /* Location data is to be transferred to */
+    char *  address;    /* Location data is to be transferred to, NULL for
+			 * highmem page */
+    struct page * page; /* Location for highmem page, if any */
+    unsigned int offset;/* for highmem, page offset */
+    dma_addr_t dma_address;
     unsigned int length;
 };
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc/ide.h linux/include/asm-sparc/ide.h
--- v2.5.2/linux/include/asm-sparc/ide.h	Mon Jun 19 17:59:39 2000
+++ linux/include/asm-sparc/ide.h	Wed Jan 23 15:28:40 2002
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.6 2000/05/27 00:49:37 davem Exp $
+/* $Id: ide.h,v 1.7 2002/01/16 20:58:40 davem Exp $
  * ide.h: SPARC PCI specific IDE glue.
  *
  * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
@@ -83,6 +83,18 @@
 		unsigned int	head	: 4;
 	} b;
 } select_t;
+
+typedef union {
+	unsigned int all		: 8;	/* all of the bits together */
+	struct {
+		unsigned int HOB	: 1;	/* 48-bit address ordering */
+		unsigned int reserved456: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned int SRST	: 1;	/* host soft reset bit */
+		unsigned int nIEN	: 1;	/* device INTRQ to host */
+		unsigned int bit0	: 1;
+	} b;
+} control_t;
 
 static __inline__ int ide_request_irq(unsigned int irq,
 				      void (*handler)(int, void *, struct pt_regs *),
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc/pci.h linux/include/asm-sparc/pci.h
--- v2.5.2/linux/include/asm-sparc/pci.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-sparc/pci.h	Tue Jan 15 11:48:13 2002
@@ -64,6 +64,20 @@
  */
 extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction);
 
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc/pgalloc.h linux/include/asm-sparc/pgalloc.h
--- v2.5.2/linux/include/asm-sparc/pgalloc.h	Sun Oct 21 10:36:54 2001
+++ linux/include/asm-sparc/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -1,4 +1,4 @@
-/* $Id: pgalloc.h,v 1.15 2001/10/18 09:06:37 davem Exp $ */
+/* $Id: pgalloc.h,v 1.16 2001/12/21 04:56:17 davem Exp $ */
 #ifndef _SPARC_PGALLOC_H
 #define _SPARC_PGALLOC_H
 
@@ -13,22 +13,22 @@
 #ifdef CONFIG_SMP
 BTFIXUPDEF_CALL(void, local_flush_cache_all, void)
 BTFIXUPDEF_CALL(void, local_flush_cache_mm, struct mm_struct *)
-BTFIXUPDEF_CALL(void, local_flush_cache_range, struct mm_struct *, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, local_flush_cache_range, struct vm_area_struct *, unsigned long, unsigned long)
 BTFIXUPDEF_CALL(void, local_flush_cache_page, struct vm_area_struct *, unsigned long)
 
 #define local_flush_cache_all() BTFIXUP_CALL(local_flush_cache_all)()
 #define local_flush_cache_mm(mm) BTFIXUP_CALL(local_flush_cache_mm)(mm)
-#define local_flush_cache_range(mm,start,end) BTFIXUP_CALL(local_flush_cache_range)(mm,start,end)
+#define local_flush_cache_range(vma,start,end) BTFIXUP_CALL(local_flush_cache_range)(vma,start,end)
 #define local_flush_cache_page(vma,addr) BTFIXUP_CALL(local_flush_cache_page)(vma,addr)
 
 BTFIXUPDEF_CALL(void, local_flush_tlb_all, void)
 BTFIXUPDEF_CALL(void, local_flush_tlb_mm, struct mm_struct *)
-BTFIXUPDEF_CALL(void, local_flush_tlb_range, struct mm_struct *, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, local_flush_tlb_range, struct vm_area_struct *, unsigned long, unsigned long)
 BTFIXUPDEF_CALL(void, local_flush_tlb_page, struct vm_area_struct *, unsigned long)
 
 #define local_flush_tlb_all() BTFIXUP_CALL(local_flush_tlb_all)()
 #define local_flush_tlb_mm(mm) BTFIXUP_CALL(local_flush_tlb_mm)(mm)
-#define local_flush_tlb_range(mm,start,end) BTFIXUP_CALL(local_flush_tlb_range)(mm,start,end)
+#define local_flush_tlb_range(vma,start,end) BTFIXUP_CALL(local_flush_tlb_range)(vma,start,end)
 #define local_flush_tlb_page(vma,addr) BTFIXUP_CALL(local_flush_tlb_page)(vma,addr)
 
 BTFIXUPDEF_CALL(void, local_flush_page_to_ram, unsigned long)
@@ -39,14 +39,14 @@
 
 extern void smp_flush_cache_all(void);
 extern void smp_flush_cache_mm(struct mm_struct *mm);
-extern void smp_flush_cache_range(struct mm_struct *mm,
+extern void smp_flush_cache_range(struct vm_area_struct *vma,
 				  unsigned long start,
 				  unsigned long end);
 extern void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 
 extern void smp_flush_tlb_all(void);
 extern void smp_flush_tlb_mm(struct mm_struct *mm);
-extern void smp_flush_tlb_range(struct mm_struct *mm,
+extern void smp_flush_tlb_range(struct vm_area_struct *vma,
 				  unsigned long start,
 				  unsigned long end);
 extern void smp_flush_tlb_page(struct vm_area_struct *mm, unsigned long page);
@@ -56,18 +56,18 @@
 
 BTFIXUPDEF_CALL(void, flush_cache_all, void)
 BTFIXUPDEF_CALL(void, flush_cache_mm, struct mm_struct *)
-BTFIXUPDEF_CALL(void, flush_cache_range, struct mm_struct *, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, flush_cache_range, struct vm_area_struct *, unsigned long, unsigned long)
 BTFIXUPDEF_CALL(void, flush_cache_page, struct vm_area_struct *, unsigned long)
 
 #define flush_cache_all() BTFIXUP_CALL(flush_cache_all)()
 #define flush_cache_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm)
-#define flush_cache_range(mm,start,end) BTFIXUP_CALL(flush_cache_range)(mm,start,end)
+#define flush_cache_range(vma,start,end) BTFIXUP_CALL(flush_cache_range)(vma,start,end)
 #define flush_cache_page(vma,addr) BTFIXUP_CALL(flush_cache_page)(vma,addr)
 #define flush_icache_range(start, end)		do { } while (0)
 
 BTFIXUPDEF_CALL(void, flush_tlb_all, void)
 BTFIXUPDEF_CALL(void, flush_tlb_mm, struct mm_struct *)
-BTFIXUPDEF_CALL(void, flush_tlb_range, struct mm_struct *, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, flush_tlb_range, struct vm_area_struct *, unsigned long, unsigned long)
 BTFIXUPDEF_CALL(void, flush_tlb_page, struct vm_area_struct *, unsigned long)
 
 extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end)
@@ -76,7 +76,7 @@
 
 #define flush_tlb_all() BTFIXUP_CALL(flush_tlb_all)()
 #define flush_tlb_mm(mm) BTFIXUP_CALL(flush_tlb_mm)(mm)
-#define flush_tlb_range(mm,start,end) BTFIXUP_CALL(flush_tlb_range)(mm,start,end)
+#define flush_tlb_range(vma,start,end) BTFIXUP_CALL(flush_tlb_range)(vma,start,end)
 #define flush_tlb_page(vma,addr) BTFIXUP_CALL(flush_tlb_page)(vma,addr)
 
 BTFIXUPDEF_CALL(void, __flush_page_to_ram, unsigned long)
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v2.5.2/linux/include/asm-sparc/pgtable.h	Tue Nov 13 09:16:05 2001
+++ linux/include/asm-sparc/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.109 2001/11/13 00:49:32 davem Exp $ */
+/* $Id: pgtable.h,v 1.110 2001/12/21 04:56:17 davem Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -445,7 +445,7 @@
 #define kern_addr_valid(addr) \
 	(test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap))
 
-extern int io_remap_page_range(unsigned long from, unsigned long to,
+extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long to,
 			       unsigned long size, pgprot_t prot, int space);
 
 #include <asm-generic/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc64/ide.h linux/include/asm-sparc64/ide.h
--- v2.5.2/linux/include/asm-sparc64/ide.h	Mon Oct  1 09:19:56 2001
+++ linux/include/asm-sparc64/ide.h	Wed Jan 23 15:28:40 2002
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.21 2001/09/25 20:21:48 kanoj Exp $
+/* $Id: ide.h,v 1.22 2002/01/16 20:58:40 davem Exp $
  * ide.h: Ultra/PCI specific IDE glue.
  *
  * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
@@ -79,6 +79,18 @@
 		unsigned int	head	: 4;
 	} b;
 } select_t;
+
+typedef union {
+	unsigned int all		: 8;	/* all of the bits together */
+	struct {
+		unsigned int HOB	: 1;	/* 48-bit address ordering */
+		unsigned int reserved456: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned int SRST	: 1;	/* host soft reset bit */
+		unsigned int nIEN	: 1;	/* device INTRQ to host */
+		unsigned int bit0	: 1;
+	} b;
+} control_t;
 
 static __inline__ int ide_request_irq(unsigned int irq,
 				      void (*handler)(int, void *, struct pt_regs *),
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc64/irq.h linux/include/asm-sparc64/irq.h
--- v2.5.2/linux/include/asm-sparc64/irq.h	Sun Mar 25 18:14:21 2001
+++ linux/include/asm-sparc64/irq.h	Wed Jan 23 15:28:40 2002
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.20 2001/03/09 01:31:40 davem Exp $
+/* $Id: irq.h,v 1.21 2002/01/23 11:27:36 davem Exp $
  * irq.h: IRQ registers on the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -11,10 +11,7 @@
 #include <linux/config.h>
 #include <linux/linkage.h>
 #include <linux/kernel.h>
-
-struct devid_cookie {
-	int dummy;
-};
+#include <asm/pil.h>
 
 /* You should not mess with this directly. That's the job of irq.c.
  *
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc64/pci.h linux/include/asm-sparc64/pci.h
--- v2.5.2/linux/include/asm-sparc64/pci.h	Tue Nov 13 09:16:05 2001
+++ linux/include/asm-sparc64/pci.h	Tue Jan 15 11:48:13 2002
@@ -77,6 +77,20 @@
 	pci_map_single(dev, (page_address(page) + (off)), size, dir)
 #define pci_unmap_page(dev,addr,sz,dir) pci_unmap_single(dev,addr,sz,dir)
 
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc64/pgalloc.h linux/include/asm-sparc64/pgalloc.h
--- v2.5.2/linux/include/asm-sparc64/pgalloc.h	Tue Oct 30 15:08:11 2001
+++ linux/include/asm-sparc64/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -1,4 +1,4 @@
-/* $Id: pgalloc.h,v 1.29 2001/10/20 12:38:51 davem Exp $ */
+/* $Id: pgalloc.h,v 1.30 2001/12/21 04:56:17 davem Exp $ */
 #ifndef _SPARC64_PGALLOC_H
 #define _SPARC64_PGALLOC_H
 
@@ -15,8 +15,7 @@
 /* These are the same regardless of whether this is an SMP kernel or not. */
 #define flush_cache_mm(__mm) \
 	do { if ((__mm) == current->mm) flushw_user(); } while(0)
-#define flush_cache_range(mm, start, end) \
-	flush_cache_mm(mm)
+extern void flush_cache_range(struct vm_area_struct *, unsigned long, unsigned long);
 #define flush_cache_page(vma, page) \
 	flush_cache_mm((vma)->vm_mm)
 
@@ -35,8 +34,10 @@
 extern void flush_dcache_page_impl(struct page *page);
 #ifdef CONFIG_SMP
 extern void smp_flush_dcache_page_impl(struct page *page, int cpu);
+extern void flush_dcache_page_all(struct mm_struct *mm, struct page *page);
 #else
 #define smp_flush_dcache_page_impl(page,cpu) flush_dcache_page_impl(page)
+#define flush_dcache_page_all(mm,page) flush_dcache_page_impl(page)
 #endif
 
 extern void flush_dcache_page(struct page *page);
@@ -62,11 +63,11 @@
 	__flush_tlb_mm(CTX_HWBITS((__mm)->context), SECONDARY_CONTEXT); \
 } while(0)
 
-#define flush_tlb_range(__mm, start, end) \
-do { if(CTX_VALID((__mm)->context)) { \
+#define flush_tlb_range(__vma, start, end) \
+do { if(CTX_VALID((__vma)->vm_mm->context)) { \
 	unsigned long __start = (start)&PAGE_MASK; \
 	unsigned long __end = PAGE_ALIGN(end); \
-	__flush_tlb_range(CTX_HWBITS((__mm)->context), __start, \
+	__flush_tlb_range(CTX_HWBITS((__vma)->vm_mm->context), __start, \
 			  SECONDARY_CONTEXT, __end, PAGE_SIZE, \
 			  (__end - __start)); \
      } \
@@ -84,15 +85,15 @@
 extern void smp_flush_cache_all(void);
 extern void smp_flush_tlb_all(void);
 extern void smp_flush_tlb_mm(struct mm_struct *mm);
-extern void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				unsigned long end);
 extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page);
 
 #define flush_cache_all()	smp_flush_cache_all()
 #define flush_tlb_all()		smp_flush_tlb_all()
 #define flush_tlb_mm(mm)	smp_flush_tlb_mm(mm)
-#define flush_tlb_range(mm, start, end) \
-	smp_flush_tlb_range(mm, start, end)
+#define flush_tlb_range(vma, start, end) \
+	smp_flush_tlb_range(vma, start, end)
 #define flush_tlb_page(vma, page) \
 	smp_flush_tlb_page((vma)->vm_mm, page)
 
@@ -122,9 +123,13 @@
 	vpte_base = (tlb_type == spitfire ?
 		     VPTE_BASE_SPITFIRE :
 		     VPTE_BASE_CHEETAH);
-	flush_tlb_range(mm,
-			vpte_base + (s >> (PAGE_SHIFT - 3)),
-			vpte_base + (e >> (PAGE_SHIFT - 3)));
+	{
+		struct vm_area_struct vma;
+		vma.vm_mm = mm;
+		flush_tlb_range(&vma,
+				vpte_base + (s >> (PAGE_SHIFT - 3)),
+				vpte_base + (e >> (PAGE_SHIFT - 3)));
+	}
 }
 #undef VPTE_BASE_SPITFIRE
 #undef VPTE_BASE_CHEETAH
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.5.2/linux/include/asm-sparc64/pgtable.h	Tue Nov 13 09:16:05 2001
+++ linux/include/asm-sparc64/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.152 2001/11/12 09:43:39 davem Exp $
+/* $Id: pgtable.h,v 1.155 2001/12/21 04:56:17 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)
@@ -328,7 +336,7 @@
 #define kern_addr_valid(addr)	\
 	(test_bit(__pa((unsigned long)(addr))>>22, sparc64_valid_addr_bitmap))
 
-extern int io_remap_page_range(unsigned long from, unsigned long offset,
+extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset,
 			       unsigned long size, pgprot_t prot, int space);
 
 #include <asm-generic/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc64/pil.h linux/include/asm-sparc64/pil.h
--- v2.5.2/linux/include/asm-sparc64/pil.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/pil.h	Wed Jan 23 15:28:40 2002
@@ -0,0 +1,21 @@
+/* $Id: pil.h,v 1.1 2002/01/23 11:27:36 davem Exp $ */
+#ifndef _SPARC64_PIL_H
+#define _SPARC64_PIL_H
+
+/* To avoid some locking problems, we hard allocate certain PILs
+ * for SMP cross call messages.  cli() does not block the cross
+ * call delivery, so when SMP locking is an issue we reschedule
+ * the event into a PIL interrupt which is blocked by cli().
+ *
+ * XXX In fact the whole set of PILs used for hardware interrupts
+ * XXX may be allocated in this manner.  All of the devices can
+ * XXX happily sit at the same PIL.  We would then need only two
+ * XXX PILs, one for devices and one for the CPU local timer tick.
+ */
+#define PIL_MIGRATE	1
+
+#ifndef __ASSEMBLY__
+#define PIL_RESERVED(PIL)	((PIL) == PIL_MIGRATE)
+#endif
+
+#endif /* !(_SPARC64_PIL_H) */
diff -u --recursive --new-file v2.5.2/linux/include/linux/adfs_fs.h linux/include/linux/adfs_fs.h
--- v2.5.2/linux/include/linux/adfs_fs.h	Thu Nov 22 11:48:07 2001
+++ linux/include/linux/adfs_fs.h	Tue Jan 29 21:42:50 2002
@@ -41,6 +41,7 @@
 #define ADFS_SUPER_MAGIC	 0xadf5
 
 #ifdef __KERNEL__
+#include <linux/adfs_fs_i.h>
 /*
  * Calculate the boot block checksum on an ADFS drive.  Note that this will
  * appear to be correct if the sector contains all zeros, so also check that
@@ -57,6 +58,11 @@
 	} while (p != ptr);
 
 	return (result & 0xff) != ptr[511];
+}
+
+static inline struct adfs_inode_info *ADFS_I(struct inode *inode)
+{
+	return list_entry(inode, struct adfs_inode_info, vfs_inode);
 }
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/adfs_fs_i.h linux/include/linux/adfs_fs_i.h
--- v2.5.2/linux/include/linux/adfs_fs_i.h	Sun Feb 13 10:45:13 2000
+++ linux/include/linux/adfs_fs_i.h	Mon Jan 28 13:20:44 2002
@@ -18,6 +18,7 @@
 	unsigned int	filetype;	/* RISC OS file type		*/
 	unsigned int	attr;		/* RISC OS permissions		*/
 	int		stamped:1;	/* RISC OS file has date/time	*/
+	struct inode vfs_inode;
 };
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h
--- v2.5.2/linux/include/linux/affs_fs.h	Thu Apr 19 22:57:06 2001
+++ linux/include/linux/affs_fs.h	Mon Jan 21 15:37:32 2002
@@ -6,6 +6,8 @@
 
 #include <linux/types.h>
 
+#include <linux/affs_fs_i.h>
+
 #define AFFS_SUPER_MAGIC 0xadff
 
 struct affs_date;
diff -u --recursive --new-file v2.5.2/linux/include/linux/affs_fs_i.h linux/include/linux/affs_fs_i.h
--- v2.5.2/linux/include/linux/affs_fs_i.h	Thu Nov 22 11:46:19 2001
+++ linux/include/linux/affs_fs_i.h	Mon Jan 21 15:37:32 2002
@@ -3,9 +3,6 @@
 
 #include <linux/a.out.h>
 
-// move this to linux/coda.h!!!
-#include <linux/time.h>
-
 #define AFFS_CACHE_SIZE		PAGE_SIZE
 //#define AFFS_CACHE_SIZE		(4*4)
 
@@ -48,10 +45,13 @@
 	unsigned char i_pad;
 	s32	 i_parent;			/* parent ino */
 #endif
+	struct inode vfs_inode;
 };
 
 /* short cut to get to the affs specific inode data */
-#define AFFS_INODE	(&inode->u.affs_i)
-#define AFFS_DIR	(&dir->u.affs_i)
+static inline struct affs_inode_info *AFFS_I(struct inode *inode)
+{
+	return list_entry(inode, struct affs_inode_info, vfs_inode);
+}
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/amigaffs.h linux/include/linux/amigaffs.h
--- v2.5.2/linux/include/linux/amigaffs.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/amigaffs.h	Mon Jan 21 15:37:32 2002
@@ -93,32 +93,32 @@
 static inline void
 affs_lock_link(struct inode *inode)
 {
-	down(&AFFS_INODE->i_link_lock);
+	down(&AFFS_I(inode)->i_link_lock);
 }
 static inline void
 affs_unlock_link(struct inode *inode)
 {
-	up(&AFFS_INODE->i_link_lock);
+	up(&AFFS_I(inode)->i_link_lock);
 }
 static inline void
 affs_lock_dir(struct inode *inode)
 {
-	down(&AFFS_INODE->i_hash_lock);
+	down(&AFFS_I(inode)->i_hash_lock);
 }
 static inline void
 affs_unlock_dir(struct inode *inode)
 {
-	up(&AFFS_INODE->i_hash_lock);
+	up(&AFFS_I(inode)->i_hash_lock);
 }
 static inline void
 affs_lock_ext(struct inode *inode)
 {
-	down(&AFFS_INODE->i_ext_lock);
+	down(&AFFS_I(inode)->i_ext_lock);
 }
 static inline void
 affs_unlock_ext(struct inode *inode)
 {
-	up(&AFFS_INODE->i_ext_lock);
+	up(&AFFS_I(inode)->i_ext_lock);
 }
 
 #ifdef __LITTLE_ENDIAN
diff -u --recursive --new-file v2.5.2/linux/include/linux/bfs_fs.h linux/include/linux/bfs_fs.h
--- v2.5.2/linux/include/linux/bfs_fs.h	Tue Nov 28 22:43:39 2000
+++ linux/include/linux/bfs_fs.h	Mon Jan 28 13:20:44 2002
@@ -6,6 +6,8 @@
 #ifndef _LINUX_BFS_FS_H
 #define _LINUX_BFS_FS_H
 
+#include <linux/bfs_fs_i.h>
+
 #define BFS_BSIZE_BITS		9
 #define BFS_BSIZE		(1<<BFS_BSIZE_BITS)
 
@@ -86,6 +88,11 @@
 /* dir.c */
 extern struct inode_operations bfs_dir_inops;
 extern struct file_operations bfs_dir_operations;
+
+static inline struct bfs_inode_info *BFS_I(struct inode *inode)
+{
+	return list_entry(inode, struct bfs_inode_info, vfs_inode);
+}
 
 #endif /* __KERNEL__ */
 #endif	/* _LINUX_BFS_FS_H */
diff -u --recursive --new-file v2.5.2/linux/include/linux/bfs_fs_i.h linux/include/linux/bfs_fs_i.h
--- v2.5.2/linux/include/linux/bfs_fs_i.h	Tue Nov 28 22:43:39 2000
+++ linux/include/linux/bfs_fs_i.h	Mon Jan 28 13:20:44 2002
@@ -13,6 +13,7 @@
 	unsigned long i_dsk_ino; /* inode number from the disk, can be 0 */
 	unsigned long i_sblock;
 	unsigned long i_eblock;
+	struct inode vfs_inode;
 };
 
 #endif	/* _LINUX_BFS_FS_I */
diff -u --recursive --new-file v2.5.2/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.5.2/linux/include/linux/blk.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/blk.h	Tue Jan 29 21:42:34 2002
@@ -90,9 +90,9 @@
 
 #define _elv_add_request(q, rq, back, p) do {				      \
 	if ((back))							      \
-		_elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \
+		_elv_add_request_core((q), (rq), (q)->queue_head.prev, (p));  \
 	else								      \
-		_elv_add_request_core((q), (rq), &(q)->queue_head, 0);	      \
+		_elv_add_request_core((q), (rq), &(q)->queue_head, (p));      \
 } while (0)
 
 #define elv_add_request(q, rq, back) _elv_add_request((q), (rq), (back), 1)
diff -u --recursive --new-file v2.5.2/linux/include/linux/blkdev.h linux/include/linux/blkdev.h
--- v2.5.2/linux/include/linux/blkdev.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/blkdev.h	Tue Jan 29 21:41:44 2002
@@ -80,6 +80,7 @@
  	*/
 	__REQ_DRIVE_CMD,
 	__REQ_DRIVE_TASK,
+	__REQ_DRIVE_ACB,
 
 	__REQ_PC,	/* packet command (special) */
 	__REQ_BLOCK_PC,	/* queued down pc from block layer */
@@ -99,10 +100,13 @@
 #define REQ_DONTPREP	(1 << __REQ_DONTPREP)
 #define REQ_DRIVE_CMD	(1 << __REQ_DRIVE_CMD)
 #define REQ_DRIVE_TASK	(1 << __REQ_DRIVE_TASK)
+#define REQ_DRIVE_ACB	(1 << __REQ_DRIVE_ACB)
 #define REQ_PC		(1 << __REQ_PC)
 #define REQ_SENSE	(1 << __REQ_SENSE)
 #define REQ_BLOCK_PC	(1 << __REQ_BLOCK_PC)
 #define REQ_SPECIAL	(1 << __REQ_SPECIAL)
+
+#define REQ_DRIVE_TASKFILE	REQ_DRIVE_ACB
 
 #include <linux/elevator.h>
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/cciss_ioctl.h linux/include/linux/cciss_ioctl.h
--- v2.5.2/linux/include/linux/cciss_ioctl.h	Tue May  1 16:05:00 2001
+++ linux/include/linux/cciss_ioctl.h	Fri Jan 18 14:05:55 2002
@@ -184,6 +184,11 @@
 #define CCISS_GETDRIVVER   _IOR(CCISS_IOC_MAGIC, 9, DriverVer_type)
 #define CCISS_REVALIDVOLS  _IO(CCISS_IOC_MAGIC, 10)
 #define CCISS_PASSTHRU	   _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct)
+#define CCISS_DEREGDISK	   _IO(CCISS_IOC_MAGIC, 12)
 
+/* no longer used... use REGNEWD instead */ 
+#define CCISS_REGNEWDISK  _IOW(CCISS_IOC_MAGIC, 13, int)
+
+#define CCISS_REGNEWD	   _IO(CCISS_IOC_MAGIC, 14)
 
 #endif  
diff -u --recursive --new-file v2.5.2/linux/include/linux/coda.h linux/include/linux/coda.h
--- v2.5.2/linux/include/linux/coda.h	Wed Apr 25 16:18:54 2001
+++ linux/include/linux/coda.h	Tue Jan 29 21:41:09 2002
@@ -99,6 +99,7 @@
 
 
 #if defined(__linux__)
+#include <linux/time.h>
 #define cdev_t u_quad_t
 #ifndef __KERNEL__
 #if !defined(_UQUAD_T_) && (!defined(__GLIBC__) || __GLIBC__ < 2)
diff -u --recursive --new-file v2.5.2/linux/include/linux/coda_fs_i.h linux/include/linux/coda_fs_i.h
--- v2.5.2/linux/include/linux/coda_fs_i.h	Thu Nov 22 11:46:19 2001
+++ linux/include/linux/coda_fs_i.h	Tue Jan 29 21:41:11 2002
@@ -24,6 +24,7 @@
 	unsigned int       c_contcount; /* refcount for container file */
         struct coda_cred   c_cached_cred; /* credentials of cached perms */
         unsigned int       c_cached_perm; /* cached access permissions */
+	struct inode	   vfs_inode;
 };
 
 /* flags */
diff -u --recursive --new-file v2.5.2/linux/include/linux/coda_linux.h linux/include/linux/coda_linux.h
--- v2.5.2/linux/include/linux/coda_linux.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/coda_linux.h	Mon Jan 21 15:37:32 2002
@@ -111,7 +111,10 @@
 
 /* inode to cnode access functions */
 
-#define ITOC(inode) (&((inode)->u.coda_i))
+static inline struct coda_inode_info *ITOC(struct inode *inode)
+{
+	return list_entry(inode, struct coda_inode_info, vfs_inode);
+}
 
 static __inline__ struct ViceFid *coda_i2f(struct inode *inode)
 {
diff -u --recursive --new-file v2.5.2/linux/include/linux/device.h linux/include/linux/device.h
--- v2.5.2/linux/include/linux/device.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/device.h	Tue Jan 29 21:41:26 2002
@@ -80,7 +80,7 @@
 	atomic_t	refcount;	/* refcount to make sure the device
 					 * persists for the right amount of time */
 
-	struct driver_dir_entry	* dir;
+	struct driver_dir_entry	dir;
 
 	struct device_driver *driver;	/* which driver has allocated this
 					   device */
@@ -123,7 +123,7 @@
 	struct list_head devices;	/* children devices */
 
 	struct device *self;		/* pointer to controlling device */
-	struct driver_dir_entry	* dir;	/* driverfs directory */
+	struct driver_dir_entry	dir;	/* driverfs directory */
 
 	char	name[DEVICE_NAME_SIZE];
 	char	bus_id[BUS_ID_SIZE];
@@ -147,22 +147,12 @@
  * High level routines for use by the bus drivers
  */
 extern int device_register(struct device * dev);
-extern struct device * device_alloc(void);
-extern void device_init_dev(struct device * dev);
 
 extern int iobus_register(struct iobus * iobus);
-extern struct iobus * iobus_alloc(void);
-extern void iobus_init(struct iobus * iobus);
 
-extern int device_create_file(struct device *device, const char * name, mode_t mode,
-			      struct driverfs_operations * ops, void * data);
+extern int device_create_file(struct device *device, struct driver_file_entry * entry);
 extern void device_remove_file(struct device * dev, const char * name);
 
-extern int iobus_create_file(struct iobus *bus, const char * name, mode_t mode,
-			     struct driverfs_operations * ops, void * data);
-extern void iobus_remove_file(struct iobus * iobus, const char * name);
-
-
 /*
  * Platform "fixup" functions - allow the platform to have their say
  * about devices and actions that the general device layer doesn't
@@ -196,32 +186,12 @@
  */
 static inline void get_device(struct device * dev)
 {
+	BUG_ON(!atomic_read(&dev->refcount));
 	atomic_inc(&dev->refcount);
 }
 
 extern void put_device(struct device * dev);
 
-
-/**
- * valid_device - check if device is valid
- * @dev:	device in question
- *
- * Check whether or not a device can be operated on.
- * If so, increment the reference count and carry on.
- */
-static inline int valid_device(struct device * dev)
-{
-	int val;
-
-	lock_device(dev);
-	val = atomic_read(&dev->refcount);
-	if (val)
-		get_device(dev);
-	unlock_device(dev);
-	return (val > 0);
-}
-
-
 static inline void lock_iobus(struct iobus * iobus)
 {
 	spin_lock(&iobus->lock);
@@ -234,18 +204,8 @@
 
 static inline void get_iobus(struct iobus * iobus)
 {
+	BUG_ON(!atomic_read(&iobus->refcount));
 	atomic_inc(&iobus->refcount);
-}
-
-static inline int valid_iobus(struct iobus * iobus)
-{
-	int val;
-	lock_iobus(iobus);
-	val = atomic_read(&iobus->refcount);
-	if (val)
-		get_iobus(iobus);
-	unlock_iobus(iobus);
-	return (val > 0);
 }
 
 extern void put_iobus(struct iobus * iobus);
diff -u --recursive --new-file v2.5.2/linux/include/linux/dnotify.h linux/include/linux/dnotify.h
--- v2.5.2/linux/include/linux/dnotify.h	Fri Sep 22 14:21:22 2000
+++ linux/include/linux/dnotify.h	Tue Jan 29 21:43:03 2002
@@ -4,6 +4,8 @@
  * Copyright 2000 (C) Stephen Rothwell
  */
 
+#include <linux/fs.h>
+
 struct dnotify_struct {
 	struct dnotify_struct *	dn_next;
 	int			dn_magic;
diff -u --recursive --new-file v2.5.2/linux/include/linux/driverfs_fs.h linux/include/linux/driverfs_fs.h
--- v2.5.2/linux/include/linux/driverfs_fs.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/driverfs_fs.h	Wed Jan 23 11:12:17 2002
@@ -26,11 +26,6 @@
 #ifndef _DRIVER_FS_H_
 #define _DRIVER_FS_H_
 
-struct driverfs_operations {
-	ssize_t	(*read) (char *, size_t, loff_t, void *);
-	ssize_t (*write)(const char *, size_t, loff_t, void*);
-};
-
 struct driver_dir_entry {
 	char			* name;
 	struct dentry		* dentry;
@@ -38,6 +33,8 @@
 	struct list_head	files;
 };
 
+struct device;
+
 struct driver_file_entry {
 	struct driver_dir_entry * parent;
 	struct list_head	node;
@@ -45,21 +42,16 @@
 	mode_t			mode;
 	struct dentry		* dentry;
 	void			* data;
-	struct driverfs_operations	* ops;
-};
 
-extern struct driver_dir_entry *
-driverfs_create_dir_entry(const char * name, mode_t mode);
+	ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off);
+	ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off);
+};
 
 extern int
 driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *);
 
 extern void
 driverfs_remove_dir(struct driver_dir_entry * entry);
-
-extern struct driver_file_entry *
-driverfs_create_entry (const char * name, mode_t mode,
-		       struct driverfs_operations * ops, void * data);
 
 extern int
 driverfs_create_file(struct driver_file_entry * entry,
diff -u --recursive --new-file v2.5.2/linux/include/linux/efs_fs.h linux/include/linux/efs_fs.h
--- v2.5.2/linux/include/linux/efs_fs.h	Mon Dec 11 13:26:51 2000
+++ linux/include/linux/efs_fs.h	Mon Jan 21 15:37:32 2002
@@ -37,13 +37,11 @@
 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
 #endif
 
-#ifdef _EFS_USE_GENERIC
-#define INODE_INFO(i) (struct efs_inode_info *)	&((i)->u.generic_ip)
-#define SUPER_INFO(s) (struct efs_sb_info *)	&((s)->u.generic_sbp)
-#else
-#define INODE_INFO(i)				&((i)->u.efs_i)
+static inline struct efs_inode_info *INODE_INFO(struct inode *inode)
+{
+	return list_entry(inode, struct efs_inode_info, vfs_inode);
+}
 #define SUPER_INFO(s)				&((s)->u.efs_sb)
-#endif
 
 extern struct inode_operations efs_dir_inode_operations;
 extern struct file_operations efs_dir_operations;
diff -u --recursive --new-file v2.5.2/linux/include/linux/efs_fs_i.h linux/include/linux/efs_fs_i.h
--- v2.5.2/linux/include/linux/efs_fs_i.h	Thu May 13 23:50:15 1999
+++ linux/include/linux/efs_fs_i.h	Mon Jan 21 15:37:32 2002
@@ -61,6 +61,7 @@
 	int		lastextent;
 
 	efs_extent	extents[EFS_DIRECTEXTENTS];
+	struct inode	vfs_inode;
 };
 
 #endif	/* __EFS_FS_I_H__ */
diff -u --recursive --new-file v2.5.2/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v2.5.2/linux/include/linux/ext2_fs.h	Thu Nov 22 11:46:52 2001
+++ linux/include/linux/ext2_fs.h	Tue Jan 29 21:41:28 2002
@@ -532,101 +532,4 @@
 #define EXT2_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT2_DIR_ROUND) & \
 					 ~EXT2_DIR_ROUND)
 
-#ifdef __KERNEL__
-/*
- * Function prototypes
- */
-
-/*
- * Ok, these declarations are also in <linux/kernel.h> but none of the
- * ext2 source programs needs to include it so they are duplicated here.
- */
-# define NORET_TYPE    /**/
-# define ATTRIB_NORET  __attribute__((noreturn))
-# define NORET_AND     noreturn,
-
-/* balloc.c */
-extern int ext2_bg_has_super(struct super_block *sb, int group);
-extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);
-extern int ext2_new_block (struct inode *, unsigned long,
-			   __u32 *, __u32 *, int *);
-extern void ext2_free_blocks (struct inode *, unsigned long,
-			      unsigned long);
-extern unsigned long ext2_count_free_blocks (struct super_block *);
-extern void ext2_check_blocks_bitmap (struct super_block *);
-extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
-						    unsigned int block_group,
-						    struct buffer_head ** bh);
-
-/* dir.c */
-extern int ext2_add_link (struct dentry *, struct inode *);
-extern ino_t ext2_inode_by_name(struct inode *, struct dentry *);
-extern int ext2_make_empty(struct inode *, struct inode *);
-extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct dentry *, struct page **);
-extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *);
-extern int ext2_empty_dir (struct inode *);
-extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **);
-extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *);
-
-/* fsync.c */
-extern int ext2_sync_file (struct file *, struct dentry *, int);
-extern int ext2_fsync_inode (struct inode *, int);
-
-/* ialloc.c */
-extern struct inode * ext2_new_inode (const struct inode *, int);
-extern void ext2_free_inode (struct inode *);
-extern unsigned long ext2_count_free_inodes (struct super_block *);
-extern void ext2_check_inodes_bitmap (struct super_block *);
-extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
-
-/* inode.c */
-extern void ext2_read_inode (struct inode *);
-extern void ext2_write_inode (struct inode *, int);
-extern void ext2_put_inode (struct inode *);
-extern void ext2_delete_inode (struct inode *);
-extern int ext2_sync_inode (struct inode *);
-extern void ext2_discard_prealloc (struct inode *);
-extern void ext2_truncate (struct inode *);
-
-/* ioctl.c */
-extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
-		       unsigned long);
-
-/* super.c */
-extern void ext2_error (struct super_block *, const char *, const char *, ...)
-	__attribute__ ((format (printf, 3, 4)));
-extern NORET_TYPE void ext2_panic (struct super_block *, const char *,
-				   const char *, ...)
-	__attribute__ ((NORET_AND format (printf, 3, 4)));
-extern void ext2_warning (struct super_block *, const char *, const char *, ...)
-	__attribute__ ((format (printf, 3, 4)));
-extern void ext2_update_dynamic_rev (struct super_block *sb);
-extern void ext2_put_super (struct super_block *);
-extern void ext2_write_super (struct super_block *);
-extern int ext2_remount (struct super_block *, int *, char *);
-extern struct super_block * ext2_read_super (struct super_block *,void *,int);
-extern int ext2_statfs (struct super_block *, struct statfs *);
-
-/*
- * Inodes and files operations
- */
-
-/* dir.c */
-extern struct file_operations ext2_dir_operations;
-
-/* file.c */
-extern struct inode_operations ext2_file_inode_operations;
-extern struct file_operations ext2_file_operations;
-
-/* inode.c */
-extern struct address_space_operations ext2_aops;
-
-/* namei.c */
-extern struct inode_operations ext2_dir_inode_operations;
-
-/* symlink.c */
-extern struct inode_operations ext2_fast_symlink_inode_operations;
-
-#endif	/* __KERNEL__ */
-
 #endif	/* _LINUX_EXT2_FS_H */
diff -u --recursive --new-file v2.5.2/linux/include/linux/ext2_fs_i.h linux/include/linux/ext2_fs_i.h
--- v2.5.2/linux/include/linux/ext2_fs_i.h	Mon Sep 17 13:16:30 2001
+++ linux/include/linux/ext2_fs_i.h	Wed Dec 31 16:00:00 1969
@@ -1,41 +0,0 @@
-/*
- *  linux/include/linux/ext2_fs_i.h
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- *  from
- *
- *  linux/include/linux/minix_fs_i.h
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-#ifndef _LINUX_EXT2_FS_I
-#define _LINUX_EXT2_FS_I
-
-/*
- * second extended file system inode data in memory
- */
-struct ext2_inode_info {
-	__u32	i_data[15];
-	__u32	i_flags;
-	__u32	i_faddr;
-	__u8	i_frag_no;
-	__u8	i_frag_size;
-	__u16	i_osync;
-	__u32	i_file_acl;
-	__u32	i_dir_acl;
-	__u32	i_dtime;
-	__u32	i_block_group;
-	__u32	i_next_alloc_block;
-	__u32	i_next_alloc_goal;
-	__u32	i_prealloc_block;
-	__u32	i_prealloc_count;
-	__u32	i_dir_start_lookup;
-	int	i_new_inode:1;	/* Is a freshly allocated inode */
-};
-
-#endif	/* _LINUX_EXT2_FS_I */
diff -u --recursive --new-file v2.5.2/linux/include/linux/ext3_fs.h linux/include/linux/ext3_fs.h
--- v2.5.2/linux/include/linux/ext3_fs.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/ext3_fs.h	Mon Jan 21 15:37:32 2002
@@ -443,7 +443,10 @@
 
 #ifdef __KERNEL__
 #define EXT3_SB(sb)	(&((sb)->u.ext3_sb))
-#define EXT3_I(inode)	(&((inode)->u.ext3_i))
+static inline struct ext3_inode_info *EXT3_I(struct inode *inode)
+{
+	return list_entry(inode, struct ext3_inode_info, vfs_inode);
+}
 #else
 /* Assume that user mode programs are passing in an ext3fs superblock, not
  * a kernel struct super_block.  This will allow us to call the feature-test
@@ -451,7 +454,7 @@
 #define EXT3_SB(sb)	(sb)
 #endif
 
-#define NEXT_ORPHAN(inode) (inode)->u.ext3_i.i_dtime
+#define NEXT_ORPHAN(inode) EXT3_I(inode)->i_dtime
 
 /*
  * Codes for operating systems
@@ -620,7 +623,7 @@
 extern int ext3_sync_file (struct file *, struct dentry *, int);
 
 /* ialloc.c */
-extern struct inode * ext3_new_inode (handle_t *, const struct inode *, int);
+extern struct inode * ext3_new_inode (handle_t *, struct inode *, int);
 extern void ext3_free_inode (handle_t *, struct inode *);
 extern struct inode * ext3_orphan_get (struct super_block *, ino_t);
 extern unsigned long ext3_count_free_inodes (struct super_block *);
diff -u --recursive --new-file v2.5.2/linux/include/linux/ext3_fs_i.h linux/include/linux/ext3_fs_i.h
--- v2.5.2/linux/include/linux/ext3_fs_i.h	Thu Nov 22 11:46:19 2001
+++ linux/include/linux/ext3_fs_i.h	Tue Jan 29 21:41:12 2002
@@ -28,7 +28,6 @@
 	__u32	i_faddr;
 	__u8	i_frag_no;
 	__u8	i_frag_size;
-	__u16	unused;			/* formerly i_osync */
 #endif
 	__u32	i_file_acl;
 	__u32	i_dir_acl;
@@ -73,6 +72,7 @@
 	 * by other means, so we have truncate_sem.
 	 */
 	struct rw_semaphore truncate_sem;
+	struct inode vfs_inode;
 };
 
 #endif	/* _LINUX_EXT3_FS_I */
diff -u --recursive --new-file v2.5.2/linux/include/linux/ext3_jbd.h linux/include/linux/ext3_jbd.h
--- v2.5.2/linux/include/linux/ext3_jbd.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/ext3_jbd.h	Mon Jan 21 15:37:32 2002
@@ -289,7 +289,7 @@
 		return 1;
 	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA)
 		return 1;
-	if (inode->u.ext3_i.i_flags & EXT3_JOURNAL_DATA_FL)
+	if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL)
 		return 1;
 	return 0;
 }
diff -u --recursive --new-file v2.5.2/linux/include/linux/fb.h linux/include/linux/fb.h
--- v2.5.2/linux/include/linux/fb.h	Mon Dec 11 13:16:53 2000
+++ linux/include/linux/fb.h	Wed Jan 23 15:25:34 2002
@@ -94,6 +94,18 @@
 #define FB_ACCEL_IGS_CYBER5000	35	/* CyberPro 5000		*/
 #define FB_ACCEL_SIS_GLAMOUR    36	/* SiS 300/630/540              */
 
+
+#define FB_ACCEL_NEOMAGIC_NM2070 90	/* NeoMagic NM2070              */
+#define FB_ACCEL_NEOMAGIC_NM2090 91	/* NeoMagic NM2090              */
+#define FB_ACCEL_NEOMAGIC_NM2093 92	/* NeoMagic NM2093              */
+#define FB_ACCEL_NEOMAGIC_NM2097 93	/* NeoMagic NM2097              */
+#define FB_ACCEL_NEOMAGIC_NM2160 94	/* NeoMagic NM2160              */
+#define FB_ACCEL_NEOMAGIC_NM2200 95	/* NeoMagic NM2200              */
+#define FB_ACCEL_NEOMAGIC_NM2230 96	/* NeoMagic NM2230              */
+#define FB_ACCEL_NEOMAGIC_NM2360 97	/* NeoMagic NM2360              */
+#define FB_ACCEL_NEOMAGIC_NM2380 98	/* NeoMagic NM2380              */
+
+
 struct fb_fix_screeninfo {
 	char id[16];			/* identification string eg "TT Builtin" */
 	unsigned long smem_start;	/* Start of frame buffer mem */
diff -u --recursive --new-file v2.5.2/linux/include/linux/file.h linux/include/linux/file.h
--- v2.5.2/linux/include/linux/file.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/file.h	Tue Jan 29 21:41:09 2002
@@ -5,31 +5,40 @@
 #ifndef __LINUX_FILE_H
 #define __LINUX_FILE_H
 
-#include <linux/sched.h>
+#include <asm/atomic.h>
+#include <linux/posix_types.h>
+#include <linux/compiler.h>
+
+/*
+ * The default fd array needs to be at least BITS_PER_LONG,
+ * as this is the granularity returned by copy_fdset().
+ */
+#define NR_OPEN_DEFAULT BITS_PER_LONG
+
+/*
+ * Open file table structure
+ */
+struct files_struct {
+        atomic_t count;
+        rwlock_t file_lock;     /* Protects all the below members.  Nests inside tsk->alloc_lock */
+        int max_fds;
+        int max_fdset;
+        int next_fd;
+        struct file ** fd;      /* current fd array */
+        fd_set *close_on_exec;
+        fd_set *open_fds;
+        fd_set close_on_exec_init;
+        fd_set open_fds_init;
+        struct file * fd_array[NR_OPEN_DEFAULT];
+};
 
 extern void FASTCALL(fput(struct file *));
 extern struct file * FASTCALL(fget(unsigned int fd));
- 
-static inline int get_close_on_exec(unsigned int fd)
-{
-	struct files_struct *files = current->files;
-	int res;
-	read_lock(&files->file_lock);
-	res = FD_ISSET(fd, files->close_on_exec);
-	read_unlock(&files->file_lock);
-	return res;
-}
+extern void FASTCALL(set_close_on_exec(unsigned int fd, int flag));
+extern void put_filp(struct file *);
+extern int get_unused_fd(void);
+extern void FASTCALL(put_unused_fd(unsigned int fd));
 
-static inline void set_close_on_exec(unsigned int fd, int flag)
-{
-	struct files_struct *files = current->files;
-	write_lock(&files->file_lock);
-	if (flag)
-		FD_SET(fd, files->close_on_exec);
-	else
-		FD_CLR(fd, files->close_on_exec);
-	write_unlock(&files->file_lock);
-}
 
 static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
 {
@@ -43,60 +52,9 @@
 /*
  * Check whether the specified fd has an open file.
  */
-static inline struct file * fcheck(unsigned int fd)
-{
-	struct file * file = NULL;
-	struct files_struct *files = current->files;
-
-	if (fd < files->max_fds)
-		file = files->fd[fd];
-	return file;
-}
-
-extern void put_filp(struct file *);
-
-extern int get_unused_fd(void);
-
-static inline void __put_unused_fd(struct files_struct *files, unsigned int fd)
-{
-	FD_CLR(fd, files->open_fds);
-	if (fd < files->next_fd)
-		files->next_fd = fd;
-}
-
-static inline void put_unused_fd(unsigned int fd)
-{
-	struct files_struct *files = current->files;
-
-	write_lock(&files->file_lock);
-	__put_unused_fd(files, fd);
-	write_unlock(&files->file_lock);
-}
-
-/*
- * Install a file pointer in the fd array.  
- *
- * The VFS is full of places where we drop the files lock between
- * setting the open_fds bitmap and installing the file in the file
- * array.  At any such point, we are vulnerable to a dup2() race
- * installing a file in the array before us.  We need to detect this and
- * fput() the struct file we are about to overwrite in this case.
- *
- * It should never happen - if we allow dup2() do it, _really_ bad things
- * will follow.
- */
-
-static inline void fd_install(unsigned int fd, struct file * file)
-{
-	struct files_struct *files = current->files;
-	
-	write_lock(&files->file_lock);
-	if (files->fd[fd])
-		BUG();
-	files->fd[fd] = file;
-	write_unlock(&files->file_lock);
-}
+#define fcheck(fd)	fcheck_files(current->files, fd)
 
-void put_files_struct(struct files_struct *fs);
+extern void FASTCALL(fd_install(unsigned int fd, struct file * file));
+void FASTCALL(put_files_struct(struct files_struct *fs));
 
 #endif /* __LINUX_FILE_H */
diff -u --recursive --new-file v2.5.2/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.5.2/linux/include/linux/fs.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/fs.h	Tue Jan 29 21:41:12 2002
@@ -262,7 +262,7 @@
 
 	wait_queue_head_t b_wait;
 
-	struct inode *	     b_inode;
+	int b_inode;				/* will go away */
 	struct list_head     b_inode_buffers;	/* doubly linked list of inode dirty buffers */
 };
 
@@ -287,32 +287,9 @@
 
 
 #include <linux/pipe_fs_i.h>
-#include <linux/minix_fs_i.h>
-#include <linux/ext2_fs_i.h>
-#include <linux/ext3_fs_i.h>
-#include <linux/hpfs_fs_i.h>
-#include <linux/ntfs_fs_i.h>
-#include <linux/msdos_fs_i.h>
-#include <linux/umsdos_fs_i.h>
-#include <linux/iso_fs_i.h>
-#include <linux/nfs_fs_i.h>
-#include <linux/sysv_fs_i.h>
-#include <linux/affs_fs_i.h>
-#include <linux/ufs_fs_i.h>
-#include <linux/efs_fs_i.h>
-#include <linux/coda_fs_i.h>
+/* #include <linux/umsdos_fs_i.h> */
 #include <linux/romfs_fs_i.h>
-#include <linux/shmem_fs.h>
-#include <linux/smb_fs_i.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/adfs_fs_i.h>
-#include <linux/qnx4_fs_i.h>
-#include <linux/reiserfs_fs_i.h>
-#include <linux/bfs_fs_i.h>
-#include <linux/udf_fs_i.h>
-#include <linux/ncp_fs_i.h>
 #include <linux/proc_fs_i.h>
-#include <linux/jffs2_fs_i.h>
 #include <linux/cramfs_fs_sb.h>
 
 /*
@@ -476,37 +453,20 @@
 	unsigned int		i_attr_flags;
 	__u32			i_generation;
 	union {
-		struct minix_inode_info		minix_i;
-		struct ext2_inode_info		ext2_i;
-		struct ext3_inode_info		ext3_i;
-		struct hpfs_inode_info		hpfs_i;
-		struct ntfs_inode_info		ntfs_i;
-		struct msdos_inode_info		msdos_i;
-		struct umsdos_inode_info	umsdos_i;
-		struct iso_inode_info		isofs_i;
-		struct nfs_inode_info		nfs_i;
-		struct sysv_inode_info		sysv_i;
-		struct affs_inode_info		affs_i;
-		struct ufs_inode_info		ufs_i;
-		struct efs_inode_info		efs_i;
+		/* struct umsdos_inode_info	umsdos_i; */
 		struct romfs_inode_info		romfs_i;
-		struct shmem_inode_info		shmem_i;
-		struct coda_inode_info		coda_i;
-		struct smb_inode_info		smbfs_i;
-		struct hfs_inode_info		hfs_i;
-		struct adfs_inode_info		adfs_i;
-		struct qnx4_inode_info		qnx4_i;
-		struct reiserfs_inode_info	reiserfs_i;
-		struct bfs_inode_info		bfs_i;
-		struct udf_inode_info		udf_i;
-		struct ncp_inode_info		ncpfs_i;
 		struct proc_inode_info		proc_i;
 		struct socket			socket_i;
-		struct jffs2_inode_info		jffs2_i;
 		void				*generic_ip;
 	} u;
 };
 
+#include <linux/shmem_fs.h>
+/* will die */
+#include <linux/coda_fs_i.h>
+#include <linux/ext3_fs_i.h>
+#include <linux/efs_fs_i.h>
+
 struct fown_struct {
 	int pid;		/* pid or -pgrp where SIGIO should be sent */
 	uid_t uid, euid;	/* uid/euid of process setting the owner */
@@ -563,6 +523,9 @@
  */
 typedef struct files_struct *fl_owner_t;
 
+/* that will die - we need it for nfs_lock_info */
+#include <linux/nfs_fs_i.h>
+
 struct file_lock {
 	struct file_lock *fl_next;	/* singly linked list for this inode  */
 	struct list_head fl_link;	/* doubly linked list of all locks */
@@ -850,6 +813,10 @@
 	int (*revalidate) (struct dentry *);
 	int (*setattr) (struct dentry *, struct iattr *);
 	int (*getattr) (struct dentry *, struct iattr *);
+	int (*setxattr) (struct dentry *, char *, void *, size_t, int);
+	int (*getxattr) (struct dentry *, char *, void *, size_t);
+	int (*listxattr) (struct dentry *, char *, size_t);
+	int (*removexattr) (struct dentry *, char *);
 };
 
 struct seq_file;
@@ -859,6 +826,9 @@
  * without the big kernel lock held in all filesystems.
  */
 struct super_operations {
+   	struct inode *(*alloc_inode)(struct super_block *sb);
+	void (*destroy_inode)(struct inode *);
+
 	void (*read_inode) (struct inode *);
   
   	/* reiserfs kludge.  reiserfs needs 64 bits of information to
@@ -1151,7 +1121,16 @@
 extern void FASTCALL(__mark_dirty(struct buffer_head *bh));
 extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh));
 extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh));
-extern void FASTCALL(buffer_insert_inode_data_queue(struct buffer_head *, struct inode *));
+extern void FASTCALL(buffer_insert_list(struct buffer_head *, struct list_head *));
+
+static inline void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+{
+	buffer_insert_list(bh, &inode->i_dirty_buffers);
+}
+static inline void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
+{
+	buffer_insert_list(bh, &inode->i_dirty_data_buffers);
+}
 
 #define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state)
 
@@ -1219,10 +1198,16 @@
 extern int fsync_super(struct super_block *);
 extern int fsync_no_super(struct block_device *);
 extern void sync_inodes_sb(struct super_block *);
-extern int osync_inode_buffers(struct inode *);
-extern int osync_inode_data_buffers(struct inode *);
-extern int fsync_inode_buffers(struct inode *);
-extern int fsync_inode_data_buffers(struct inode *);
+extern int osync_buffers_list(struct list_head *);
+extern int fsync_buffers_list(struct list_head *);
+static inline int fsync_inode_buffers(struct inode *inode)
+{
+	return fsync_buffers_list(&inode->i_dirty_buffers);
+}
+static inline int fsync_inode_data_buffers(struct inode *inode)
+{
+	return fsync_buffers_list(&inode->i_dirty_data_buffers);
+}
 extern int inode_has_buffers(struct inode *);
 extern void filemap_fdatasync(struct address_space *);
 extern void filemap_fdatawait(struct address_space *);
@@ -1327,6 +1312,7 @@
 #define user_path_walk(name,nd)	 __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
 #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
 
+extern void inode_init_once(struct inode *);
 extern void iput(struct inode *);
 extern void force_delete(struct inode *);
 extern struct inode * igrab(struct inode *);
@@ -1340,20 +1326,8 @@
 }
 
 extern void clear_inode(struct inode *);
-extern struct inode * get_empty_inode(void);
-
-static inline struct inode * new_inode(struct super_block *sb)
-{
-	struct inode *inode = get_empty_inode();
-	if (inode) {
-		inode->i_sb = sb;
-		inode->i_dev = sb->s_dev;
-		inode->i_blkbits = sb->s_blocksize_bits;
-	}
-	return inode;
-}
+extern struct inode *new_inode(struct super_block *);
 extern void remove_suid(struct inode *inode);
-
 extern void insert_inode_hash(struct inode *);
 extern void remove_inode_hash(struct inode *);
 extern struct file * get_empty_filp(void);
@@ -1458,6 +1432,7 @@
 extern int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
 extern int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*,
 				unsigned long *);
+extern int generic_cont_expand(struct inode *inode, loff_t size) ;
 extern int block_commit_write(struct page *page, unsigned from, unsigned to);
 extern int block_sync_page(struct page *);
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/hdreg.h linux/include/linux/hdreg.h
--- v2.5.2/linux/include/linux/hdreg.h	Thu Nov 22 11:46:18 2001
+++ linux/include/linux/hdreg.h	Tue Jan 29 21:41:09 2002
@@ -6,104 +6,269 @@
  * Various sources.  
  */
 
-#define HD_IRQ 14		/* the standard disk interrupt */
+#define HD_IRQ 14			/* the standard disk interrupt */
 
 /* ide.c has its own port definitions in "ide.h" */
 
 /* Hd controller regs. Ref: IBM AT Bios-listing */
-#define HD_DATA		0x1f0	/* _CTL when writing */
-#define HD_ERROR	0x1f1	/* see err-bits */
-#define HD_NSECTOR	0x1f2	/* nr of sectors to read/write */
-#define HD_SECTOR	0x1f3	/* starting sector */
-#define HD_LCYL		0x1f4	/* starting cylinder */
-#define HD_HCYL		0x1f5	/* high byte of starting cyl */
-#define HD_CURRENT	0x1f6	/* 101dhhhh , d=drive, hhhh=head */
-#define HD_STATUS	0x1f7	/* see status-bits */
-#define HD_FEATURE HD_ERROR	/* same io address, read=error, write=feature */
-#define HD_PRECOMP HD_FEATURE	/* obsolete use of this port - predates IDE */
-#define HD_COMMAND HD_STATUS	/* same io address, read=status, write=cmd */
+#define HD_DATA		0x1f0		/* _CTL when writing */
+#define HD_ERROR	0x1f1		/* see err-bits */
+#define HD_NSECTOR	0x1f2		/* nr of sectors to read/write */
+#define HD_SECTOR	0x1f3		/* starting sector */
+#define HD_LCYL		0x1f4		/* starting cylinder */
+#define HD_HCYL		0x1f5		/* high byte of starting cyl */
+#define HD_CURRENT	0x1f6		/* 101dhhhh , d=drive, hhhh=head */
+#define HD_STATUS	0x1f7		/* see status-bits */
+#define HD_FEATURE	HD_ERROR	/* same io address, read=error, write=feature */
+#define HD_PRECOMP	HD_FEATURE	/* obsolete use of this port - predates IDE */
+#define HD_COMMAND	HD_STATUS	/* same io address, read=status, write=cmd */
 
-#define HD_CMD		0x3f6	/* used for resets */
-#define HD_ALTSTATUS	0x3f6	/* same as HD_STATUS but doesn't clear irq */
+#define HD_CMD		0x3f6		/* used for resets */
+#define HD_ALTSTATUS	0x3f6		/* same as HD_STATUS but doesn't clear irq */
 
 /* remainder is shared between hd.c, ide.c, ide-cd.c, and the hdparm utility */
 
 /* Bits of HD_STATUS */
-#define ERR_STAT	0x01
-#define INDEX_STAT	0x02
-#define ECC_STAT	0x04	/* Corrected error */
-#define DRQ_STAT	0x08
-#define SEEK_STAT	0x10
-#define WRERR_STAT	0x20
-#define READY_STAT	0x40
-#define BUSY_STAT	0x80
-
-/* Values for HD_COMMAND */
-#define WIN_RESTORE		0x10
-#define WIN_READ		0x20
-#define WIN_WRITE		0x30
-#define WIN_WRITE_VERIFY	0x3C
-#define WIN_VERIFY		0x40
-#define WIN_FORMAT		0x50
-#define WIN_INIT		0x60
-#define WIN_SEEK		0x70
-#define WIN_DIAGNOSE		0x90
-#define WIN_SPECIFY		0x91	/* set drive geometry translation */
-#define WIN_IDLEIMMEDIATE	0xE1	/* force drive to become "ready" */
-#define WIN_SETIDLE1		0xE3
-#define WIN_SETIDLE2		0x97
-
-#define WIN_STANDBYNOW1		0xE0
-#define WIN_STANDBYNOW2		0x94
-#define WIN_SLEEPNOW1		0xE6
-#define WIN_SLEEPNOW2		0x99
-#define WIN_CHECKPOWERMODE1	0xE5
-#define WIN_CHECKPOWERMODE2	0x98
-
-#define WIN_DOORLOCK		0xDE	/* lock door on removable drives */
-#define WIN_DOORUNLOCK		0xDF	/* unlock door on removable drives */
-
-#define WIN_MULTREAD		0xC4	/* read sectors using multiple mode */
-#define WIN_MULTWRITE		0xC5	/* write sectors using multiple mode */
-#define WIN_SETMULT		0xC6	/* enable/disable multiple mode */
-#define WIN_IDENTIFY		0xEC	/* ask drive to identify itself	*/
-#define WIN_IDENTIFY_DMA	0xEE	/* same as WIN_IDENTIFY, but DMA */
-#define WIN_SETFEATURES		0xEF	/* set special drive features */
-#define WIN_READDMA		0xC8	/* read sectors using DMA transfers */
-#define WIN_WRITEDMA		0xCA	/* write sectors using DMA transfers */
-
-#define WIN_QUEUED_SERVICE	0xA2	/* */
-#define WIN_READDMA_QUEUED	0xC7	/* read sectors using Queued DMA transfers */
-#define WIN_WRITEDMA_QUEUED	0xCC	/* write sectors using Queued DMA transfers */
-
-#define WIN_READ_BUFFER		0xE4	/* force read only 1 sector */
-#define WIN_WRITE_BUFFER	0xE8	/* force write only 1 sector */
-
-#define WIN_SMART		0xB0	/* self-monitoring and reporting */
-
-/* Additional drive command codes used by ATAPI devices. */
-#define WIN_PIDENTIFY		0xA1	/* identify ATAPI device	*/
-#define WIN_SRST		0x08	/* ATAPI soft reset command */
-#define WIN_PACKETCMD		0xA0	/* Send a packet command. */
+#define ERR_STAT		0x01
+#define INDEX_STAT		0x02
+#define ECC_STAT		0x04	/* Corrected error */
+#define DRQ_STAT		0x08
+#define SEEK_STAT		0x10
+#define WRERR_STAT		0x20
+#define READY_STAT		0x40
+#define BUSY_STAT		0x80
 
-#define DISABLE_SEAGATE		0xFB
-#define EXABYTE_ENABLE_NEST	0xF0
+/* Bits for HD_ERROR */
+#define MARK_ERR		0x01	/* Bad address mark */
+#define TRK0_ERR		0x02	/* couldn't find track 0 */
+#define ABRT_ERR		0x04	/* Command aborted */
+#define MCR_ERR			0x08	/* media change request */
+#define ID_ERR			0x10	/* ID field not found */
+#define MC_ERR			0x20	/* media changed */
+#define ECC_ERR			0x40	/* Uncorrectable ECC error */
+#define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
+#define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
+
+/*
+ * Command Header sizes for IOCTL commands
+ *	HDIO_DRIVE_CMD, HDIO_DRIVE_TASK, and HDIO_DRIVE_TASKFILE
+ */
+
+#if 0
+#include <asm/hdreg.h>
+typedef ide_ioreg_t task_ioreg_t;
+#else
+typedef unsigned char task_ioreg_t;
+#endif
+
+#define HDIO_DRIVE_CMD_HDR_SIZE		4*sizeof(task_ioreg_t)
+#define HDIO_DRIVE_TASK_HDR_SIZE	8*sizeof(task_ioreg_t)
+#define HDIO_DRIVE_HOB_HDR_SIZE		8*sizeof(task_ioreg_t)
+
+#define IDE_DRIVE_TASK_INVALID		-1
+#define IDE_DRIVE_TASK_NO_DATA		0
+#define IDE_DRIVE_TASK_SET_XFER		1
+
+#define IDE_DRIVE_TASK_IN		2
+
+#define IDE_DRIVE_TASK_OUT		3
+#define IDE_DRIVE_TASK_RAW_WRITE	4
+
+struct hd_drive_cmd_hdr {
+	task_ioreg_t command;
+	task_ioreg_t sector_number;
+	task_ioreg_t feature;
+	task_ioreg_t sector_count;
+};
 
-/* WIN_SMART sub-commands */
+typedef struct hd_drive_task_hdr {
+	task_ioreg_t data;
+	task_ioreg_t feature;
+	task_ioreg_t sector_count;
+	task_ioreg_t sector_number;
+	task_ioreg_t low_cylinder;
+	task_ioreg_t high_cylinder;
+	task_ioreg_t device_head;
+	task_ioreg_t command;
+} task_struct_t;
+
+typedef struct hd_drive_hob_hdr {
+	task_ioreg_t data;
+	task_ioreg_t feature;
+	task_ioreg_t sector_count;
+	task_ioreg_t sector_number;
+	task_ioreg_t low_cylinder;
+	task_ioreg_t high_cylinder;
+	task_ioreg_t device_head;
+	task_ioreg_t control;
+} hob_struct_t;
+
+typedef union ide_reg_valid_s {
+	unsigned all				: 16;
+	struct {
+		unsigned data			: 1;
+		unsigned error_feature		: 1;
+		unsigned sector			: 1;
+		unsigned nsector		: 1;
+		unsigned lcyl			: 1;
+		unsigned hcyl			: 1;
+		unsigned select			: 1;
+		unsigned status_command		: 1;
+
+		unsigned data_hob		: 1;
+		unsigned error_feature_hob	: 1;
+		unsigned sector_hob		: 1;
+		unsigned nsector_hob		: 1;
+		unsigned lcyl_hob		: 1;
+		unsigned hcyl_hob		: 1;
+		unsigned select_hob		: 1;
+		unsigned control_hob		: 1;
+	} b;
+} ide_reg_valid_t;
+
+/*
+ * Define standard taskfile in/out register
+ */
+#define IDE_TASKFILE_STD_OUT_FLAGS	0xFE
+#define IDE_TASKFILE_STD_IN_FLAGS	0xFE
+#define IDE_HOB_STD_OUT_FLAGS		0xC0
+#define IDE_HOB_STD_IN_FLAGS		0xC0
+
+typedef struct ide_task_request_s {
+	task_ioreg_t	io_ports[8];
+	task_ioreg_t	hob_ports[8];
+	ide_reg_valid_t	out_flags;
+	ide_reg_valid_t	in_flags;
+	int		data_phase;
+	int		req_cmd;
+	unsigned long	out_size;
+	unsigned long	in_size;
+} ide_task_request_t;
+
+typedef struct ide_ioctl_request_s {
+	ide_task_request_t	*task_request;
+	unsigned char		*out_buffer;
+	unsigned char		*in_buffer;
+} ide_ioctl_request_t;
+
+#define TASKFILE_INVALID		0x7fff
+#define TASKFILE_48			0x8000
+
+#define TASKFILE_NO_DATA		0x0000
+
+#define TASKFILE_IN			0x0001
+#define TASKFILE_MULTI_IN		0x0002
+
+#define TASKFILE_OUT			0x0004
+#define TASKFILE_MULTI_OUT		0x0008
+#define TASKFILE_IN_OUT			0x0010
+
+#define TASKFILE_IN_DMA			0x0020
+#define TASKFILE_OUT_DMA		0x0040
+#define TASKFILE_IN_DMAQ		0x0080
+#define TASKFILE_OUT_DMAQ		0x0100
+
+#define TASKFILE_P_IN			0x0200
+#define TASKFILE_P_OUT			0x0400
+#define TASKFILE_P_IN_DMA		0x0800
+#define TASKFILE_P_OUT_DMA		0x1000
+#define TASKFILE_P_IN_DMAQ		0x2000
+#define TASKFILE_P_OUT_DMAQ		0x4000
+
+/* ATA/ATAPI Commands pre T13 Spec */
+#define WIN_NOP				0x00
+#define CFA_REQ_EXT_ERROR_CODE		0x03 /* CFA Request Extended Error Code */
+#define WIN_SRST			0x08 /* ATAPI soft reset command */
+#define WIN_DEVICE_RESET		0x08
+#define WIN_RESTORE			0x10
+#define WIN_READ			0x20 /* 28-Bit */
+#define WIN_READ_EXT			0x24 /* 48-Bit */
+#define WIN_READDMA_EXT			0x25 /* 48-Bit */
+#define WIN_READDMA_QUEUED_EXT		0x26 /* 48-Bit */
+#define WIN_READ_NATIVE_MAX_EXT		0x27 /* 48-Bit */
+#define WIN_MULTREAD_EXT		0x29 /* 48-Bit */
+#define WIN_WRITE			0x30 /* 28-Bit */
+#define WIN_WRITE_EXT			0x34 /* 48-Bit */
+#define WIN_WRITEDMA_EXT		0x35 /* 48-Bit */
+#define WIN_WRITEDMA_QUEUED_EXT		0x36 /* 48-Bit */
+#define WIN_SET_MAX_EXT			0x37 /* 48-Bit */
+#define CFA_WRITE_SECT_WO_ERASE		0x38 /* CFA Write Sectors without erase */
+#define WIN_MULTWRITE_EXT		0x39 /* 48-Bit */
+#define WIN_WRITE_VERIFY		0x3C /* 28-Bit */
+#define WIN_VERIFY			0x40 /* 28-Bit - Read Verify Sectors */
+#define WIN_VERIFY_EXT			0x42 /* 48-Bit */
+#define WIN_FORMAT			0x50
+#define WIN_INIT			0x60
+#define WIN_SEEK			0x70
+#define CFA_TRANSLATE_SECTOR		0x87 /* CFA Translate Sector */
+#define WIN_DIAGNOSE			0x90
+#define WIN_SPECIFY			0x91 /* set drive geometry translation */
+#define WIN_DOWNLOAD_MICROCODE		0x92
+#define WIN_STANDBYNOW2			0x94
+#define WIN_SETIDLE2			0x97
+#define WIN_CHECKPOWERMODE2		0x98
+#define WIN_SLEEPNOW2			0x99
+#define WIN_PACKETCMD			0xA0 /* Send a packet command. */
+#define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
+#define WIN_QUEUED_SERVICE		0xA2
+#define WIN_SMART			0xB0 /* self-monitoring and reporting */
+#define CFA_ERASE_SECTORS       	0xC0
+#define WIN_MULTREAD			0xC4 /* read sectors using multiple mode*/
+#define WIN_MULTWRITE			0xC5 /* write sectors using multiple mode */
+#define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
+#define WIN_READDMA_QUEUED		0xC7 /* read sectors using Queued DMA transfers */
+#define WIN_READDMA			0xC8 /* read sectors using DMA transfers */
+#define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */
+#define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
+#define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
+#define WIN_GETMEDIASTATUS		0xDA	
+#define WIN_DOORLOCK			0xDE /* lock door on removable drives */
+#define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */
+#define WIN_STANDBYNOW1			0xE0
+#define WIN_IDLEIMMEDIATE		0xE1 /* force drive to become "ready" */
+#define WIN_STANDBY             	0xE2 /* Set device in Standby Mode */
+#define WIN_SETIDLE1			0xE3
+#define WIN_READ_BUFFER			0xE4 /* force read only 1 sector */
+#define WIN_CHECKPOWERMODE1		0xE5
+#define WIN_SLEEPNOW1			0xE6
+#define WIN_FLUSH_CACHE			0xE7
+#define WIN_WRITE_BUFFER		0xE8 /* force write only 1 sector */
+#define WIN_FLUSH_CACHE_EXT		0xEA /* 48-Bit */
+#define WIN_IDENTIFY			0xEC /* ask drive to identify itself	*/
+#define WIN_MEDIAEJECT			0xED
+#define WIN_IDENTIFY_DMA		0xEE /* same as WIN_IDENTIFY, but DMA */
+#define WIN_SETFEATURES			0xEF /* set special drive features */
+#define EXABYTE_ENABLE_NEST		0xF0
+#define WIN_SECURITY_SET_PASS		0xF1
+#define WIN_SECURITY_UNLOCK		0xF2
+#define WIN_SECURITY_ERASE_PREPARE	0xF3
+#define WIN_SECURITY_ERASE_UNIT		0xF4
+#define WIN_SECURITY_FREEZE_LOCK	0xF5
+#define WIN_SECURITY_DISABLE		0xF6
+#define WIN_READ_NATIVE_MAX		0xF8 /* return the native maximum address */
+#define WIN_SET_MAX			0xF9
+#define DISABLE_SEAGATE			0xFB
 
-#define SMART_READ_VALUES	0xd0
-#define SMART_READ_THRESHOLDS	0xd1
-#define SMART_AUTOSAVE		0xd2
-#define SMART_SAVE		0xd3
-#define SMART_IMMEDIATE_OFFLINE	0xd4
-#define SMART_READ_LOG_SECTOR	0xd5
-#define SMART_WRITE_LOG_SECTOR	0xd6
-#define SMART_WRITE_THRESHOLDS	0xd7
-#define SMART_ENABLE		0xd8
-#define SMART_DISABLE		0xd9
-#define SMART_STATUS		0xda
-#define SMART_AUTO_OFFLINE	0xdb
+/* WIN_SMART sub-commands */
 
+#define SMART_READ_VALUES		0xD0
+#define SMART_READ_THRESHOLDS		0xD1
+#define SMART_AUTOSAVE			0xD2
+#define SMART_SAVE			0xD3
+#define SMART_IMMEDIATE_OFFLINE		0xD4
+#define SMART_READ_LOG_SECTOR		0xD5
+#define SMART_WRITE_LOG_SECTOR		0xD6
+#define SMART_WRITE_THRESHOLDS		0xD7
+#define SMART_ENABLE			0xD8
+#define SMART_DISABLE			0xD9
+#define SMART_STATUS			0xDA
+#define SMART_AUTO_OFFLINE		0xDB
+
+/* Password used in TF4 & TF5 executing SMART commands */
+
+#define SMART_LCYL_PASS			0x4F
+#define SMART_HCYL_PASS			0xC2
+		
 /* WIN_SETFEATURES sub-commands */
 
 #define SETFEATURES_EN_WCACHE	0x02	/* Enable write cache */
@@ -131,6 +296,7 @@
 #define SETFEATURES_DIS_DEFECT	0x04	/* Disable Defect Management */
 #define SETFEATURES_EN_APM	0x05	/* Enable advanced power management */
 #define SETFEATURES_DIS_MSN	0x31	/* Disable Media Status Notification */
+#define SETFEATURES_EN_AAM	0x42	/* Enable Automatic Acoustic Management */
 #define SETFEATURES_DIS_RLA	0x55	/* Disable read look-ahead feature */
 #define SETFEATURES_EN_RI	0x5D	/* Enable release interrupt */
 #define SETFEATURES_EN_SI	0x5E	/* Enable SERVICE interrupt */
@@ -141,29 +307,19 @@
 #define SETFEATURES_EN_MSN	0x95	/* Enable Media Status Notification */
 #define SETFEATURES_EN_RLA	0xAA	/* Enable read look-ahead feature */
 #define SETFEATURES_PREFETCH	0xAB	/* Sets drive prefetch value */
+#define SETFEATURES_DIS_AAM	0xC2	/* Disable Automatic Acoustic Management */
 #define SETFEATURES_EN_RPOD	0xCC	/* Enable reverting to power on defaults */
 #define SETFEATURES_DIS_RI	0xDD	/* Disable release interrupt */
 #define SETFEATURES_DIS_SI	0xDE	/* Disable SERVICE interrupt */
 
 /* WIN_SECURITY sub-commands */
 
-#define SECURITY_SET_PASSWORD		0xBA	/* 0xF1 */
-#define SECURITY_UNLOCK			0xBB	/* 0xF2 */
-#define SECURITY_ERASE_PREPARE		0xBC	/* 0xF3 */
-#define SECURITY_ERASE_UNIT		0xBD	/* 0xF4 */
-#define SECURITY_FREEZE_LOCK		0xBE	/* 0xF5 */
-#define SECURITY_DISABLE_PASSWORD	0xBF	/* 0xF6 */
-
-/* Bits for HD_ERROR */
-#define MARK_ERR	0x01	/* Bad address mark */
-#define TRK0_ERR	0x02	/* couldn't find track 0 */
-#define ABRT_ERR	0x04	/* Command aborted */
-#define MCR_ERR		0x08	/* media change request */
-#define ID_ERR		0x10	/* ID field not found */
-#define MC_ERR		0x20	/* media changed */
-#define ECC_ERR		0x40	/* Uncorrectable ECC error */
-#define	BBD_ERR		0x80	/* pre-EIDE meaning:  block marked bad */
-#define	ICRC_ERR	0x80	/* new meaning:  CRC error during transfer */
+#define SECURITY_SET_PASSWORD		0xBA
+#define SECURITY_UNLOCK			0xBB
+#define SECURITY_ERASE_PREPARE		0xBC
+#define SECURITY_ERASE_UNIT		0xBD
+#define SECURITY_FREEZE_LOCK		0xBE
+#define SECURITY_DISABLE_PASSWORD	0xBF
 
 struct hd_geometry {
       unsigned char heads;
@@ -172,6 +328,14 @@
       unsigned long start;
 };
 
+/* BIG GEOMETRY */
+struct hd_big_geometry {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned int cylinders;
+	unsigned long start;
+};
+
 /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */
 #define HDIO_GETGEO		0x0301	/* get device geometry */
 #define HDIO_GET_UNMASKINTR	0x0302	/* get current unmask setting */
@@ -186,9 +350,10 @@
 #define HDIO_GET_IDENTITY	0x030d	/* get IDE identification info */
 #define HDIO_GET_WCACHE		0x030e	/* get write cache mode on|off */
 #define HDIO_GET_ACOUSTIC	0x030f	/* get acoustic value */
+#define	HDIO_GET_ADDRESS	0x0310	/* */
 
 #define HDIO_GET_BUSSTATE	0x031a	/* get the bus state of the hwif */
-#define HDIO_TRISTATE_HWIF	0x031b	/* OBSOLETE - use SET_BUSSTATE */
+#define HDIO_TRISTATE_HWIF	0x031b	/* execute a channel tristate */
 #define HDIO_DRIVE_RESET	0x031c	/* execute a device reset */
 #define HDIO_DRIVE_TASKFILE	0x031d	/* execute raw taskfile */
 #define HDIO_DRIVE_TASK		0x031e	/* execute task and special drive command */
@@ -211,6 +376,7 @@
 #define HDIO_SET_ACOUSTIC	0x032c	/* change acoustic behavior */
 #define HDIO_SET_BUSSTATE	0x032d	/* set the bus state of the hwif */
 #define HDIO_SET_QDMA		0x032e	/* change use-qdma flag */
+#define HDIO_SET_ADDRESS	0x032f	/* change lba addressing modes */
 
 /* bus states */
 enum {
@@ -219,34 +385,30 @@
 	BUSSTATE_TRISTATE
 };
 
-/* BIG GEOMETRY */
-struct hd_big_geometry {
-	unsigned char heads;
-	unsigned char sectors;
-	unsigned int cylinders;
-	unsigned long start;
-};
-
 /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */
 #define HDIO_GETGEO_BIG		0x0330	/* */
 #define HDIO_GETGEO_BIG_RAW	0x0331	/* */
 
 #define __NEW_HD_DRIVE_ID
-/* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
+/* structure returned by HDIO_GET_IDENTITY,
+ * as per ANSI NCITS ATA6 rev.1b spec
+ */
 struct hd_driveid {
 	unsigned short	config;		/* lots of obsolete bit flags */
-	unsigned short	cyls;		/* "physical" cyls */
+	unsigned short	cyls;		/* Obsolete, "physical" cyls */
 	unsigned short	reserved2;	/* reserved (word 2) */
-	unsigned short	heads;		/* "physical" heads */
+	unsigned short	heads;		/* Obsolete, "physical" heads */
 	unsigned short	track_bytes;	/* unformatted bytes per track */
 	unsigned short	sector_bytes;	/* unformatted bytes per sector */
-	unsigned short	sectors;	/* "physical" sectors per track */
+	unsigned short	sectors;	/* Obsolete, "physical" sectors per track */
 	unsigned short	vendor0;	/* vendor unique */
 	unsigned short	vendor1;	/* vendor unique */
-	unsigned short	vendor2;	/* vendor unique */
+	unsigned short	vendor2;	/* Retired vendor unique */
 	unsigned char	serial_no[20];	/* 0 = not_specified */
-	unsigned short	buf_type;
-	unsigned short	buf_size;	/* 512 byte increments; 0 = not_specified */
+	unsigned short	buf_type;	/* Retired */
+	unsigned short	buf_size;	/* Retired, 512 byte increments
+					 * 0 = not_specified
+					 */
 	unsigned short	ecc_bytes;	/* for r/w long cmds; 0 = not_specified */
 	unsigned char	fw_rev[8];	/* 0 = not_specified */
 	unsigned char	model[40];	/* 0 = not_specified */
@@ -254,72 +416,223 @@
 	unsigned char	vendor3;	/* vendor unique */
 	unsigned short	dword_io;	/* 0=not_implemented; 1=implemented */
 	unsigned char	vendor4;	/* vendor unique */
-	unsigned char	capability;	/* bits 0:DMA 1:LBA 2:IORDYsw 3:IORDYsup*/
+	unsigned char	capability;	/* (upper byte of word 49)
+					 *  3:	IORDYsup
+					 *  2:	IORDYsw
+					 *  1:	LBA
+					 *  0:	DMA
+					 */
 	unsigned short	reserved50;	/* reserved (word 50) */
-	unsigned char	vendor5;	/* vendor unique */
-	unsigned char	tPIO;		/* 0=slow, 1=medium, 2=fast */
-	unsigned char	vendor6;	/* vendor unique */
-	unsigned char	tDMA;		/* 0=slow, 1=medium, 2=fast */
-	unsigned short	field_valid;	/* bits 0:cur_ok 1:eide_ok */
-	unsigned short	cur_cyls;	/* logical cylinders */
-	unsigned short	cur_heads;	/* logical heads */
-	unsigned short	cur_sectors;	/* logical sectors per track */
-	unsigned short	cur_capacity0;	/* logical total sectors on drive */
-	unsigned short	cur_capacity1;	/*  (2 words, misaligned int)     */
+	unsigned char	vendor5;	/* Obsolete, vendor unique */
+	unsigned char	tPIO;		/* Obsolete, 0=slow, 1=medium, 2=fast */
+	unsigned char	vendor6;	/* Obsolete, vendor unique */
+	unsigned char	tDMA;		/* Obsolete, 0=slow, 1=medium, 2=fast */
+	unsigned short	field_valid;	/* (word 53)
+					 *  2:	ultra_ok	word  88
+					 *  1:	eide_ok		words 64-70
+					 *  0:	cur_ok		words 54-58
+					 */
+	unsigned short	cur_cyls;	/* Obsolete, logical cylinders */
+	unsigned short	cur_heads;	/* Obsolete, l heads */
+	unsigned short	cur_sectors;	/* Obsolete, l sectors per track */
+	unsigned short	cur_capacity0;	/* Obsolete, l total sectors on drive */
+	unsigned short	cur_capacity1;	/* Obsolete, (2 words, misaligned int)     */
 	unsigned char	multsect;	/* current multiple sector count */
 	unsigned char	multsect_valid;	/* when (bit0==1) multsect is ok */
-	unsigned int	lba_capacity;	/* total number of sectors */
-	unsigned short	dma_1word;	/* single-word dma info */
+	unsigned int	lba_capacity;	/* Obsolete, total number of sectors */
+	unsigned short	dma_1word;	/* Obsolete, single-word dma info */
 	unsigned short	dma_mword;	/* multiple-word dma info */
 	unsigned short  eide_pio_modes; /* bits 0:mode3 1:mode4 */
 	unsigned short  eide_dma_min;	/* min mword dma cycle time (ns) */
 	unsigned short  eide_dma_time;	/* recommended mword dma cycle time (ns) */
 	unsigned short  eide_pio;       /* min cycle time (ns), no IORDY  */
 	unsigned short  eide_pio_iordy; /* min cycle time (ns), with IORDY */
-	unsigned short	words69_70[2];	/* reserved words 69-70 */
+	unsigned short	words69_70[2];	/* reserved words 69-70
+					 * future command overlap and queuing
+					 */
 	/* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
-	unsigned short	words71_74[4];	/* reserved words 71-74 */
-	unsigned short  queue_depth;	/*  */
+	unsigned short	words71_74[4];	/* reserved words 71-74
+					 * for IDENTIFY PACKET DEVICE command
+					 */
+	unsigned short  queue_depth;	/* (word 75)
+					 * 15:5	reserved
+					 *  4:0	Maximum queue depth -1
+					 */
 	unsigned short  words76_79[4];	/* reserved words 76-79 */
-	unsigned short  major_rev_num;	/*  */
-	unsigned short  minor_rev_num;	/*  */
-	unsigned short  command_set_1;	/* bits 0:Smart 1:Security 2:Removable 3:PM */
-	unsigned short  command_set_2;	/* bits 14:Smart Enabled 13:0 zero */
-	unsigned short  cfsse;		/* command set-feature supported extensions */
-	unsigned short  cfs_enable_1;	/* command set-feature enabled */
-	unsigned short  cfs_enable_2;	/* command set-feature enabled */
-	unsigned short  csf_default;	/* command set-feature default */
-	unsigned short  dma_ultra;	/*  */
+	unsigned short  major_rev_num;	/* (word 80) */
+	unsigned short  minor_rev_num;	/* (word 81) */
+	unsigned short  command_set_1;	/* (word 82) supported
+					 * 15:	Obsolete
+					 * 14:	NOP command
+					 * 13:	READ_BUFFER
+					 * 12:	WRITE_BUFFER
+					 * 11:	Obsolete
+					 * 10:	Host Protected Area
+					 *  9:	DEVICE Reset
+					 *  8:	SERVICE Interrupt
+					 *  7:	Release Interrupt
+					 *  6:	look-ahead
+					 *  5:	write cache
+					 *  4:	PACKET Command
+					 *  3:	Power Management Feature Set
+					 *  2:	Removable Feature Set
+					 *  1:	Security Feature Set
+					 *  0:	SMART Feature Set
+					 */
+	unsigned short  command_set_2;	/* (word 83)
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:	FLUSH CACHE EXT
+					 * 12:	FLUSH CACHE
+					 * 11:	Device Configuration Overlay
+					 * 10:	48-bit Address Feature Set
+					 *  9:	Automatic Acoustic Management
+					 *  8:	SET MAX security
+					 *  7:	reserved 1407DT PARTIES
+					 *  6:	SetF sub-command Power-Up
+					 *  5:	Power-Up in Standby Feature Set
+					 *  4:	Removable Media Notification
+					 *  3:	APM Feature Set
+					 *  2:	CFA Feature Set
+					 *  1:	READ/WRITE DMA QUEUED
+					 *  0:	Download MicroCode
+					 */
+	unsigned short  cfsse;		/* (word 84)
+					 * cmd set-feature supported extensions
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:3	reserved
+					 *  2:	Media Serial Number Valid
+					 *  1:	SMART selt-test supported
+					 *  0:	SMART error logging
+					 */
+	unsigned short  cfs_enable_1;	/* (word 85)
+					 * command set-feature enabled
+					 * 15:	Obsolete
+					 * 14:	NOP command
+					 * 13:	READ_BUFFER
+					 * 12:	WRITE_BUFFER
+					 * 11:	Obsolete
+					 * 10:	Host Protected Area
+					 *  9:	DEVICE Reset
+					 *  8:	SERVICE Interrupt
+					 *  7:	Release Interrupt
+					 *  6:	look-ahead
+					 *  5:	write cache
+					 *  4:	PACKET Command
+					 *  3:	Power Management Feature Set
+					 *  2:	Removable Feature Set
+					 *  1:	Security Feature Set
+					 *  0:	SMART Feature Set
+					 */
+	unsigned short  cfs_enable_2;	/* (word 86)
+					 * command set-feature enabled
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:	FLUSH CACHE EXT
+					 * 12:	FLUSH CACHE
+					 * 11:	Device Configuration Overlay
+					 * 10:	48-bit Address Feature Set
+					 *  9:	Automatic Acoustic Management
+					 *  8:	SET MAX security
+					 *  7:	reserved 1407DT PARTIES
+					 *  6:	SetF sub-command Power-Up
+					 *  5:	Power-Up in Standby Feature Set
+					 *  4:	Removable Media Notification
+					 *  3:	APM Feature Set
+					 *  2:	CFA Feature Set
+					 *  1:	READ/WRITE DMA QUEUED
+					 *  0:	Download MicroCode
+					 */
+	unsigned short  csf_default;	/* (word 87)
+					 * command set-feature default
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:3	reserved
+					 *  2:	Media Serial Number Valid
+					 *  1:	SMART selt-test supported
+					 *  0:	SMART error logging
+					 */
+	unsigned short  dma_ultra;	/* (word 88) */
 	unsigned short	word89;		/* reserved (word 89) */
 	unsigned short	word90;		/* reserved (word 90) */
 	unsigned short	CurAPMvalues;	/* current APM values */
 	unsigned short	word92;		/* reserved (word 92) */
-	unsigned short	hw_config;	/* hardware config */
-	unsigned short  words94_125[32];/* reserved words 94-125 */
-	unsigned short	last_lun;	/* reserved (word 126) */
-	unsigned short	word127;	/* reserved (word 127) */
-	unsigned short	dlf;		/* device lock function
+	unsigned short	hw_config;	/* hardware config (word 93)
+					 * 15:
+					 * 14:
+					 * 13:
+					 * 12:
+					 * 11:
+					 * 10:
+					 *  9:
+					 *  8:
+					 *  7:
+					 *  6:
+					 *  5:
+					 *  4:
+					 *  3:
+					 *  2:
+					 *  1:
+					 *  0:
+					 */
+	unsigned short	acoustic;	/* (word 94)
+					 * 15:8	Vendor's recommended value
+					 *  7:0	current value
+					 */
+	unsigned short	words95_99[5];	/* reserved words 95-99 */
+#if 0
+	unsigned short	words100_103[4]	;/* reserved words 100-103 */
+#else
+	unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
+#endif
+	unsigned short	words104_125[22];/* reserved words 104-125 */
+	unsigned short	last_lun;	/* (word 126) */
+	unsigned short	word127;	/* (word 127) Feature Set
+					 * Removable Media Notification
+					 * 15:2	reserved
+					 *  1:0	00 = not supported
+					 *	01 = supported
+					 *	10 = reserved
+					 *	11 = reserved
+					 */
+	unsigned short	dlf;		/* (word 128)
+					 * device lock function
 					 * 15:9	reserved
-					 * 8	security level 1:max 0:high
-					 * 7:6	reserved
-					 * 5	enhanced erase
-					 * 4	expire
-					 * 3	frozen
-					 * 2	locked
-					 * 1	en/disabled
-					 * 0	capability
+					 *  8	security level 1:max 0:high
+					 *  7:6	reserved
+					 *  5	enhanced erase
+					 *  4	expire
+					 *  3	frozen
+					 *  2	locked
+					 *  1	en/disabled
+					 *  0	capability
 					 */
-	unsigned short  csfo;		/* current set features options
+	unsigned short  csfo;		/*  (word 129)
+					 * current set features options
 					 * 15:4	reserved
-					 * 3	auto reassign
-					 * 2	reverting
-					 * 1	read-look-ahead
-					 * 0	write cache
+					 *  3:	auto reassign
+					 *  2:	reverting
+					 *  1:	read-look-ahead
+					 *  0:	write cache
 					 */
 	unsigned short	words130_155[26];/* reserved vendor words 130-155 */
-	unsigned short	word156;
+	unsigned short	word156;	/* reserved vendor word 156 */
 	unsigned short	words157_159[3];/* reserved vendor words 157-159 */
-	unsigned short	words160_255[95];/* reserved words 160-255 */
+	unsigned short	cfa_power;	/* (word 160) CFA Power Mode
+					 * 15 word 160 supported
+					 * 14 reserved
+					 * 13
+					 * 12
+					 * 11:0
+					 */
+	unsigned short	words161_175[14];/* Reserved for CFA */
+	unsigned short	words176_205[31];/* Current Media Serial Number */
+	unsigned short	words206_254[48];/* reserved words 206-254 */
+	unsigned short	integrity_word;	/* (word 255)
+					 * 15:8 Checksum
+					 *  7:0 Signature
+					 */
 };
 
 /*
diff -u --recursive --new-file v2.5.2/linux/include/linux/hfs_fs.h linux/include/linux/hfs_fs.h
--- v2.5.2/linux/include/linux/hfs_fs.h	Tue Feb 13 14:13:44 2001
+++ linux/include/linux/hfs_fs.h	Mon Jan 28 13:20:35 2002
@@ -317,7 +317,12 @@
 extern int hfs_mac2triv(char *, const struct hfs_name *);
 extern void hfs_tolower(unsigned char *, int);
 
-#define	HFS_I(X)	(&((X)->u.hfs_i))
+#include <linux/hfs_fs_i.h>
+
+static inline struct hfs_inode_info *HFS_I(struct inode *inode)
+{
+	return list_entry(inode, struct hfs_inode_info, vfs_inode);
+}
 #define	HFS_SB(X)	(&((X)->u.hfs_sb))
 
 static inline void hfs_nameout(struct inode *dir, struct hfs_name *out,
diff -u --recursive --new-file v2.5.2/linux/include/linux/hfs_fs_i.h linux/include/linux/hfs_fs_i.h
--- v2.5.2/linux/include/linux/hfs_fs_i.h	Tue Feb 13 14:13:44 2001
+++ linux/include/linux/hfs_fs_i.h	Mon Jan 28 13:20:35 2002
@@ -39,6 +39,7 @@
 
         /* for dentry cleanup */
         void (*d_drop_op)(struct dentry *, const ino_t);
+	struct inode vfs_inode;
 };
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/highmem.h linux/include/linux/highmem.h
--- v2.5.2/linux/include/linux/highmem.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/highmem.h	Tue Jan 29 21:41:43 2002
@@ -95,17 +95,6 @@
 	kunmap(page);
 }
 
-static inline void memclear_highpage(struct page *page, unsigned int offset, unsigned int size)
-{
-	char *kaddr;
-
-	if (offset + size > PAGE_SIZE)
-		BUG();
-	kaddr = kmap(page);
-	memset(kaddr + offset, 0, size);
-	kunmap(page);
-}
-
 /*
  * Same but also flushes aliased cache contents to RAM.
  */
@@ -117,6 +106,7 @@
 		BUG();
 	kaddr = kmap(page);
 	memset(kaddr + offset, 0, size);
+	flush_dcache_page(page);
 	flush_page_to_ram(page);
 	kunmap(page);
 }
@@ -130,17 +120,6 @@
 	copy_user_page(vto, vfrom, vaddr);
 	kunmap_atomic(vfrom, KM_USER0);
 	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 -u --recursive --new-file v2.5.2/linux/include/linux/hpfs_fs_i.h linux/include/linux/hpfs_fs_i.h
--- v2.5.2/linux/include/linux/hpfs_fs_i.h	Thu Feb 10 12:17:00 2000
+++ linux/include/linux/hpfs_fs_i.h	Mon Jan 21 15:37:32 2002
@@ -18,24 +18,7 @@
 	unsigned i_dirty : 1;
 	struct semaphore i_sem;	/* semaphore */
 	loff_t **i_rddir_off;
+	struct inode vfs_inode;
 };
-
-#define i_hpfs_dno u.hpfs_i.i_dno
-#define i_hpfs_parent_dir u.hpfs_i.i_parent_dir
-#define i_hpfs_n_secs u.hpfs_i.i_n_secs
-#define i_hpfs_file_sec u.hpfs_i.i_file_sec
-#define i_hpfs_disk_sec u.hpfs_i.i_disk_sec
-#define i_hpfs_dpos u.hpfs_i.i_dpos
-#define i_hpfs_dsubdno u.hpfs_i.i_dsubdno
-#define i_hpfs_ea_size u.hpfs_i.i_ea_size
-#define i_hpfs_conv u.hpfs_i.i_conv
-#define i_hpfs_ea_mode u.hpfs_i.i_ea_mode
-#define i_hpfs_ea_uid u.hpfs_i.i_ea_uid
-#define i_hpfs_ea_gid u.hpfs_i.i_ea_gid
-/*#define i_hpfs_lock u.hpfs_i.i_lock*/
-/*#define i_hpfs_queue u.hpfs_i.i_queue*/
-#define i_hpfs_sem u.hpfs_i.i_sem
-#define i_hpfs_rddir_off u.hpfs_i.i_rddir_off
-#define i_hpfs_dirty u.hpfs_i.i_dirty
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.5.2/linux/include/linux/ide.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/ide.h	Tue Jan 29 21:42:50 2002
@@ -65,13 +65,14 @@
 /*
  * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
  */
-#define IDE_DRIVE_CMD		99	/* (magic) undef to reduce kernel size*/
+#define IDE_DRIVE_CMD			99	/* (magic) undef to reduce kernel size*/
+
+#define IDE_DRIVE_TASK			98
 
 /*
- * IDE_DRIVE_TASK is used to implement many features needed for raw tasks
+ * IDE_DRIVE_TASKFILE is used to implement many features needed for raw tasks
  */
-#define IDE_DRIVE_TASK		98
-#define IDE_DRIVE_CMD_AEB	98
+#define IDE_DRIVE_TASKFILE		97
 
 /*
  *  "No user-serviceable parts" beyond this point  :)
@@ -120,6 +121,17 @@
 #define IDE_FEATURE_OFFSET	IDE_ERROR_OFFSET
 #define IDE_COMMAND_OFFSET	IDE_STATUS_OFFSET
 
+#define IDE_DATA_OFFSET_HOB	(0)
+#define IDE_ERROR_OFFSET_HOB	(1)
+#define IDE_NSECTOR_OFFSET_HOB	(2)
+#define IDE_SECTOR_OFFSET_HOB	(3)
+#define IDE_LCYL_OFFSET_HOB	(4)
+#define IDE_HCYL_OFFSET_HOB	(5)
+#define IDE_SELECT_OFFSET_HOB	(6)
+#define IDE_CONTROL_OFFSET_HOB	(7)
+
+#define IDE_FEATURE_OFFSET_HOB	IDE_ERROR_OFFSET_HOB
+
 #define IDE_DATA_REG		(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
 #define IDE_ERROR_REG		(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
 #define IDE_NSECTOR_REG		(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
@@ -131,6 +143,16 @@
 #define IDE_CONTROL_REG		(HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
 #define IDE_IRQ_REG		(HWIF(drive)->io_ports[IDE_IRQ_OFFSET])
 
+#define IDE_DATA_REG_HOB	(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
+#define IDE_ERROR_REG_HOB	(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
+#define IDE_NSECTOR_REG_HOB	(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
+#define IDE_SECTOR_REG_HOB	(HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
+#define IDE_LCYL_REG_HOB	(HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
+#define IDE_HCYL_REG_HOB	(HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
+#define IDE_SELECT_REG_HOB	(HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
+#define IDE_STATUS_REG_HOB	(HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
+#define IDE_CONTROL_REG_HOB	(HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
+
 #define IDE_FEATURE_REG		IDE_ERROR_REG
 #define IDE_COMMAND_REG		IDE_STATUS_REG
 #define IDE_ALTSTATUS_REG	IDE_CONTROL_REG
@@ -171,11 +193,21 @@
 #define PARTN_BITS	6	/* number of minor dev bits for partitions */
 #define PARTN_MASK	((1<<PARTN_BITS)-1)	/* a useful bit mask */
 #define MAX_DRIVES	2	/* per interface; 2 assumed by lots of code */
-#define SECTOR_WORDS	(512 / 4)	/* number of 32bit words per sector */
+#define CASCADE_DRIVES	8	/* per interface; 8|2 assumed by lots of code */
+#define SECTOR_SIZE	512
+#define SECTOR_WORDS	(SECTOR_SIZE / 4)	/* number of 32bit words per sector */
 #define IDE_LARGE_SEEK(b1,b2,t)	(((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
 #define IDE_MIN(a,b)	((a)<(b) ? (a):(b))
 #define IDE_MAX(a,b)	((a)>(b) ? (a):(b))
 
+#ifndef SPLIT_WORD
+#  define SPLIT_WORD(W,HB,LB) ((HB)=(W>>8), (LB)=(W-((W>>8)<<8)))
+#endif
+#ifndef MAKE_WORD
+#  define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB))
+#endif
+
+
 /*
  * Timeouts for various operations:
  */
@@ -185,8 +217,7 @@
 #else
 #define WAIT_READY	(3*HZ/100)	/* 30msec - should be instantaneous */
 #endif /* CONFIG_APM || CONFIG_APM_MODULE */
-#define WAIT_PIDENTIFY	(10*HZ)	/* 10sec  - should be less than 3ms (?)
-				            if all ATAPI CD is closed at boot */
+#define WAIT_PIDENTIFY	(10*HZ)	/* 10sec  - should be less than 3ms (?), if all ATAPI CD is closed at boot */
 #define WAIT_WORSTCASE	(30*HZ)	/* 30sec  - worst case when spinning up */
 #define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
 #define WAIT_MIN_SLEEP	(2*HZ/100)	/* 20msec - minimum sleep time */
@@ -224,6 +255,11 @@
 		(drive)->quirk_list = hwif->quirkproc(drive);	\
 }
 
+#define HOST(hwif,chipset)					\
+{								\
+	return ((hwif)->chipset == chipset) ? 1 : 0;		\
+}
+
 #define IDE_DEBUG(lineno) \
 	printk("%s,%s,line=%d\n", __FILE__, __FUNCTION__, (lineno))
 
@@ -249,11 +285,11 @@
                 ide_pmac,       ide_etrax100
 } hwif_chipset_t;
 
+
 #define IDE_CHIPSET_PCI_MASK    \
     ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
 #define IDE_CHIPSET_IS_PCI(c)   ((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
 
-
 /*
  * Structure to hold all information about the location of this port
  */
@@ -292,16 +328,20 @@
 #ifndef HAVE_ARCH_OUT_BYTE
 #ifdef REALLY_FAST_IO
 #define OUT_BYTE(b,p)          outb((b),(p))
+#define OUT_WORD(w,p)          outw((w),(p))
 #else
 #define OUT_BYTE(b,p)          outb_p((b),(p))
+#define OUT_WORD(w,p)          outw_p((w),(p))
 #endif
 #endif
 
 #ifndef HAVE_ARCH_IN_BYTE
 #ifdef REALLY_FAST_IO
-#define IN_BYTE(p)             (byte)inb_p(p)
-#else
 #define IN_BYTE(p)             (byte)inb(p)
+#define IN_WORD(p)             (short)inw(p)
+#else
+#define IN_BYTE(p)             (byte)inb_p(p)
+#define IN_WORD(p)             (short)inw_p(p)
 #endif
 #endif
 
@@ -361,6 +401,7 @@
 	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
 	unsigned remap_0_to_1	: 2;	/* 0=remap if ezdrive, 1=remap, 2=noremap */
 	unsigned ata_flash	: 1;	/* 1=present, 0=default */
+	unsigned	addressing;	/* : 2; 0=28-bit, 1=48-bit, 2=64-bit */
 	byte		scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
 	byte		media;		/* disk, cdrom, tape, floppy, ... */
 	select_t	select;		/* basic drive/head select reg value */
@@ -373,7 +414,7 @@
 	byte		bad_wstat;	/* used for ignoring WRERR_STAT */
 	byte		nowerr;		/* used for ignoring WRERR_STAT */
 	byte		sect0;		/* offset of first sector for DM6:DDO */
-	byte 		usage;		/* current "open()" count for drive */
+	unsigned int	usage;		/* current "open()" count for drive */
 	byte 		head;		/* "real" number of heads */
 	byte		sect;		/* "real" sectors per track */
 	byte		bios_head;	/* BIOS/fdisk/LILO number of heads */
@@ -381,6 +422,7 @@
 	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned int	cyl;		/* "real" number of cyls */
 	unsigned long	capacity;	/* total number of sectors */
+	unsigned long long capacity48;	/* total number of sectors */
 	unsigned int	drive_data;	/* for use by tuneproc/selectproc as needed */
 	void		  *hwif;	/* actually (ide_hwif_t *) */
 	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
@@ -402,6 +444,8 @@
 	byte		init_speed;	/* transfer rate set at boot */
 	byte		current_speed;	/* current transfer rate set */
 	byte		dn;		/* now wide spread use */
+	byte		wcache;		/* status of write cache */
+	byte		acoustic;	/* acoustic management */
 	unsigned int	failures;	/* current failure count */
 	unsigned int	max_failures;	/* maximum allowed failure count */
 } ide_drive_t;
@@ -471,7 +515,7 @@
 /*
  * ide soft-power support
  */
-typedef int (ide_busproc_t) (struct hwif_s *, int);
+typedef int (ide_busproc_t) (ide_drive_t *, int);
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
 typedef struct ide_pci_devid_s {
@@ -538,7 +582,6 @@
 	byte		bus_state;	/* power state of the IDE bus */
 } ide_hwif_t;
 
-
 /*
  * Status returned from various ide_ functions
  */
@@ -550,7 +593,9 @@
 /*
  *  internal ide interrupt handler type
  */
+typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
 typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
+typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
 
 /*
  * when ide_timer_expiry fires, invoke a handler of this type
@@ -573,6 +618,8 @@
 	ide_expiry_t		*expiry;	/* queried upon timeouts */
 } ide_hwgroup_t;
 
+/* structure attached to the request for IDE_TASK_CMDS */
+
 /*
  * configurable drive settings
  */
@@ -623,6 +670,8 @@
 #ifdef CONFIG_PROC_FS
 void proc_ide_create(void);
 void proc_ide_destroy(void);
+void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
 void destroy_proc_ide_drives(ide_hwif_t *);
 void create_proc_ide_interfaces(void);
 void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
@@ -655,6 +704,8 @@
 #define IDE_SUBDRIVER_VERSION	1
 
 typedef int		(ide_cleanup_proc)(ide_drive_t *);
+typedef int		(ide_standby_proc)(ide_drive_t *);
+typedef int		(ide_flushcache_proc)(ide_drive_t *);
 typedef ide_startstop_t	(ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
 typedef void		(ide_end_request_proc)(byte, ide_hwgroup_t *);
 typedef int		(ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
@@ -676,6 +727,8 @@
 	unsigned supports_dma		: 1;
 	unsigned supports_dsc_overlap	: 1;
 	ide_cleanup_proc		*cleanup;
+	ide_standby_proc		*standby;
+	ide_flushcache_proc		*flushcache;
 	ide_do_request_proc		*do_request;
 	ide_end_request_proc		*end_request;
 	ide_ioctl_proc			*ioctl;
@@ -733,19 +786,7 @@
 inline int __ide_end_request(ide_hwgroup_t *, int, int);
 int ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
 
-/*
- * This is used for (nearly) all data transfers from/to the IDE interface
- * FIXME for 2.5, to a pointer pass verses memcpy........
- */
-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-
-/*
- * This is used for (nearly) all ATAPI data transfers from/to the IDE interface
- * FIXME for 2.5, to a pointer pass verses memcpy........
- */
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+int drive_is_ready (ide_drive_t *drive);
 
 /*
  * This is used on exit from the driver, to designate the next irq handler
@@ -768,7 +809,7 @@
  * Issue a simple drive command
  * The drive must be selected beforehand.
  */
-void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
+void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
 
 /*
  * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
@@ -843,6 +884,9 @@
  */
 #define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
 
+#define task_rq_offset(rq) \
+	(((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
+
 extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
 {
 	return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
@@ -854,6 +898,24 @@
 }
 
 /*
+ * for now, taskfile requests are special :/
+ */
+extern inline char *ide_map_rq(struct request *rq, unsigned long *flags)
+{
+	if (rq->bio)
+		return ide_map_buffer(rq, flags);
+	else
+		return rq->buffer + task_rq_offset(rq);
+}
+
+extern inline void ide_unmap_rq(struct request *rq, char *buf,
+				unsigned long *flags)
+{
+	if (rq->bio)
+		ide_unmap_buffer(buf, flags);
+}
+
+/*
  * This function issues a special IDE device request
  * onto the request queue.
  *
@@ -883,24 +945,91 @@
 /*
  * Clean up after success/failure of an explicit drive cmd.
  * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
+ * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK).
  */
 void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
 
 /*
- * Issue ATA command and wait for completion.
+ * Issue ATA command and wait for completion. use for implementing commands in kernel
  */
 int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
+
 int ide_wait_cmd_task (ide_drive_t *drive, byte *buf);
+ 
+typedef struct ide_task_s {
+	task_ioreg_t		tfRegister[8];
+	task_ioreg_t		hobRegister[8];
+	ide_reg_valid_t		tf_out_flags;
+	ide_reg_valid_t		tf_in_flags;
+	int			data_phase;
+	int			command_type;
+	ide_pre_handler_t	*prehandler;
+	ide_handler_t		*handler;
+	ide_post_handler_t	*posthandler;
+	void			*special;	/* valid_t generally */
+	struct request		*rq;		/* copy of request */
+	unsigned long		block;		/* copy of block */
+} ide_task_t;
+
+void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+
+/*
+ * taskfile io for disks for now...
+ */
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task);
+
+/*
+ * Builds request from ide_ioctl
+ */
+void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler);
+
+/*
+ * Special Flagged Register Validation Caller
+ */
+// ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task);
+
+ide_startstop_t set_multmode_intr (ide_drive_t *drive);
+ide_startstop_t set_geometry_intr (ide_drive_t *drive);
+ide_startstop_t recal_intr (ide_drive_t *drive);
+ide_startstop_t task_no_data_intr (ide_drive_t *drive);
+ide_startstop_t task_in_intr (ide_drive_t *drive);
+ide_startstop_t task_mulin_intr (ide_drive_t *drive);
+ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq);
+ide_startstop_t task_out_intr (ide_drive_t *drive);
+ide_startstop_t task_mulout_intr (ide_drive_t *drive);
+void ide_init_drive_taskfile (struct request *rq);
+
+int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf);
+
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *cmd, byte *buf);
+
+ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
+ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
+/* Expects args is a full set of TF registers and parses the command type */
+int ide_cmd_type_parser (ide_task_t *args);
+
+int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+
+#ifdef CONFIG_PKT_TASK_IOCTL
+int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+#endif /* CONFIG_PKT_TASK_IOCTL */
 
 void ide_delay_50ms (void);
 int system_bus_clock(void);
 
 byte ide_auto_reduce_xfer (ide_drive_t *drive);
 int ide_driveid_update (ide_drive_t *drive);
-int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args);
 int ide_config_drive_speed (ide_drive_t *drive, byte speed);
 byte eighty_ninty_three (ide_drive_t *drive);
-int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
+int set_transfer (ide_drive_t *drive, ide_task_t *args);
 
 /*
  * ide_system_bus_speed() returns what we think is the system VESA/PCI
@@ -911,12 +1040,6 @@
 int ide_system_bus_speed (void);
 
 /*
- * ide_multwrite() transfers a block of up to mcount sectors of data
- * to a drive as part of a disk multwrite operation.
- */
-int ide_multwrite (ide_drive_t *drive, unsigned int mcount);
-
-/*
  * idedisk_input_data() is a wrapper around ide_input_data() which copes
  * with byte-swapping the input data if required.
  */
@@ -951,23 +1074,30 @@
 extern ide_proc_entry_t generic_subdriver_entries[];
 #endif
 
+int ide_reinit_drive (ide_drive_t *drive);
+
 #ifdef _IDE_C
 #ifdef CONFIG_BLK_DEV_IDE
 int ideprobe_init (void);
 #endif /* CONFIG_BLK_DEV_IDE */
 #ifdef CONFIG_BLK_DEV_IDEDISK
+int idedisk_reinit (ide_drive_t *drive);
 int idedisk_init (void);
 #endif /* CONFIG_BLK_DEV_IDEDISK */
 #ifdef CONFIG_BLK_DEV_IDECD
+int ide_cdrom_reinit (ide_drive_t *drive);
 int ide_cdrom_init (void);
 #endif /* CONFIG_BLK_DEV_IDECD */
 #ifdef CONFIG_BLK_DEV_IDETAPE
+int idetape_reinit (ide_drive_t *drive);
 int idetape_init (void);
 #endif /* CONFIG_BLK_DEV_IDETAPE */
 #ifdef CONFIG_BLK_DEV_IDEFLOPPY
+int idefloppy_reinit (ide_drive_t *drive);
 int idefloppy_init (void);
 #endif /* CONFIG_BLK_DEV_IDEFLOPPY */
 #ifdef CONFIG_BLK_DEV_IDESCSI
+int idescsi_reinit (ide_drive_t *drive);
 int idescsi_init (void);
 #endif /* CONFIG_BLK_DEV_IDESCSI */
 #endif /* _IDE_C */
@@ -1006,6 +1136,9 @@
 #endif
 
 void hwif_unregister (ide_hwif_t *hwif);
+
+void export_ide_init_queue (ide_drive_t *drive);
+byte export_probe_for_drive (ide_drive_t *drive);
 
 extern spinlock_t ide_lock;
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/init.h linux/include/linux/init.h
--- v2.5.2/linux/include/linux/init.h	Thu Nov 22 11:46:18 2001
+++ linux/include/linux/init.h	Tue Jan 29 21:41:09 2002
@@ -50,8 +50,26 @@
 
 extern initcall_t __initcall_start, __initcall_end;
 
-#define __initcall(fn)								\
-	static initcall_t __initcall_##fn __init_call = fn
+/* initcalls are now grouped by functionality into separate 
+ * subsections. Ordering inside the subsections is determined
+ * by link order. 
+ * For backwards compatability, initcall() puts the call in 
+ * the device init subsection.
+ */
+
+#define __define_initcall(level,fn) \
+	static initcall_t __initcall_##fn __attribute__ ((unused,__section__ (".initcall" level ".init"))) = fn
+
+#define early_arch_initcall(fn)		__define_initcall("1",fn)
+#define mem_initcall(fn)		__define_initcall("2",fn)
+#define subsys_initcall(fn)		__define_initcall("3",fn)
+#define arch_initcall(fn)		__define_initcall("4",fn)
+#define fs_initcall(fn)			__define_initcall("5",fn)
+#define device_initcall(fn)		__define_initcall("6",fn)
+#define late_initcall(fn)		__define_initcall("7",fn)
+
+#define __initcall(fn) device_initcall(fn)
+
 #define __exitcall(fn)								\
 	static exitcall_t __exitcall_##fn __exit_call = fn
 
@@ -80,7 +98,7 @@
 #define __initdata	__attribute__ ((__section__ (".data.init")))
 #define __exitdata	__attribute__ ((unused, __section__ (".data.exit")))
 #define __initsetup	__attribute__ ((unused,__section__ (".setup.init")))
-#define __init_call	__attribute__ ((unused,__section__ (".initcall.init")))
+#define __init_call(level)  __attribute__ ((unused,__section__ (".initcall" level ".init")))
 #define __exit_call	__attribute__ ((unused,__section__ (".exitcall.exit")))
 
 /* For assembly routines */
@@ -140,6 +158,14 @@
 	{ return x; }
 
 #define __setup(str,func) /* nothing */
+
+#define early_arch_initcall(fn)		module_init(fn)
+#define mem_initcall(fn)		module_init(fn)
+#define subsys_initcall(fn)		module_init(fn)
+#define arch_initcall(fn)		module_init(fn)
+#define fs_initcall(fn)			module_init(fn)
+#define device_initcall(fn)		module_init(fn)
+#define late_initcall(fn)		module_init(fn)
 
 #endif
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/init_task.h linux/include/linux/init_task.h
--- v2.5.2/linux/include/linux/init_task.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/init_task.h	Tue Jan 29 21:42:47 2002
@@ -0,0 +1,94 @@
+#ifndef _LINUX__INIT_TASK_H
+#define _LINUX__INIT_TASK_H
+
+#include <linux/file.h>
+
+#define INIT_FILES \
+{ 							\
+	count:		ATOMIC_INIT(1), 		\
+	file_lock:	RW_LOCK_UNLOCKED, 		\
+	max_fds:	NR_OPEN_DEFAULT, 		\
+	max_fdset:	__FD_SETSIZE, 			\
+	next_fd:	0, 				\
+	fd:		&init_files.fd_array[0], 	\
+	close_on_exec:	&init_files.close_on_exec_init, \
+	open_fds:	&init_files.open_fds_init, 	\
+	close_on_exec_init: { { 0, } }, 		\
+	open_fds_init:	{ { 0, } }, 			\
+	fd_array:	{ NULL, } 			\
+}
+
+#define INIT_MM(name) \
+{			 				\
+	mm_rb:		RB_ROOT,			\
+	pgd:		swapper_pg_dir, 		\
+	mm_users:	ATOMIC_INIT(2), 		\
+	mm_count:	ATOMIC_INIT(1), 		\
+	mmap_sem:	__RWSEM_INITIALIZER(name.mmap_sem), \
+	page_table_lock: SPIN_LOCK_UNLOCKED, 		\
+	mmlist:		LIST_HEAD_INIT(name.mmlist),	\
+}
+
+#define INIT_SIGNALS {	\
+	count:		ATOMIC_INIT(1), 		\
+	action:		{ {{0,}}, }, 			\
+	siglock:	SPIN_LOCK_UNLOCKED 		\
+}
+
+#define INIT_TASK_WORK				\
+{						\
+	need_resched:	0,			\
+	syscall_trace:	0,			\
+	sigpending:	0,			\
+	notify_resume:	0,			\
+}
+
+/*
+ *  INIT_TASK is used to set up the first task table, touch at
+ * your own risk!. Base=0, limit=0x1fffff (=2MB)
+ */
+#define INIT_TASK(tsk)	\
+{									\
+    state:		0,						\
+    flags:		0,						\
+    work:		INIT_TASK_WORK,					\
+    addr_limit:		KERNEL_DS,					\
+    exec_domain:	&default_exec_domain,				\
+    lock_depth:		-1,						\
+    __nice:		DEF_USER_NICE,					\
+    policy:		SCHED_OTHER,					\
+    cpus_allowed:	-1,						\
+    mm:			NULL,						\
+    active_mm:		&init_mm,					\
+    run_list:		LIST_HEAD_INIT(tsk.run_list),			\
+    time_slice:		HZ,						\
+    next_task:		&tsk,						\
+    prev_task:		&tsk,						\
+    p_opptr:		&tsk,						\
+    p_pptr:		&tsk,						\
+    thread_group:	LIST_HEAD_INIT(tsk.thread_group),		\
+    wait_chldexit:	__WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
+    real_timer:		{						\
+	function:		it_real_fn				\
+    },									\
+    cap_effective:	CAP_INIT_EFF_SET,				\
+    cap_inheritable:	CAP_INIT_INH_SET,				\
+    cap_permitted:	CAP_FULL_SET,					\
+    keep_capabilities:	0,						\
+    rlim:		INIT_RLIMITS,					\
+    user:		INIT_USER,					\
+    comm:		"swapper",					\
+    thread:		INIT_THREAD,					\
+    fs:			&init_fs,					\
+    files:		&init_files,					\
+    sigmask_lock:	SPIN_LOCK_UNLOCKED,				\
+    sig:		&init_signals,					\
+    pending:		{ NULL, &tsk.pending.head, {{0}}},		\
+    blocked:		{{0}},						\
+    alloc_lock:		SPIN_LOCK_UNLOCKED,				\
+    journal_info:	NULL,						\
+}
+
+
+
+#endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/isdn.h linux/include/linux/isdn.h
--- v2.5.2/linux/include/linux/isdn.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/isdn.h	Sun Jan 27 11:33:38 2002
@@ -178,8 +178,6 @@
  * the correspondent code in isdn.c
  */
 
-#define ISDN_MINOR_B        0
-#define ISDN_MINOR_BMAX     (ISDN_MAX_CHANNELS-1)
 #define ISDN_MINOR_CTRL     64
 #define ISDN_MINOR_CTRLMAX  (64 + (ISDN_MAX_CHANNELS-1))
 #define ISDN_MINOR_PPP      128
@@ -633,7 +631,6 @@
 #ifdef CONFIG_DEVFS_FS
 	devfs_handle_t devfs_handle_isdninfo;
 	devfs_handle_t devfs_handle_isdnctrl;
-	devfs_handle_t devfs_handle_isdnX[ISDN_MAX_CHANNELS];
 	devfs_handle_t devfs_handle_isdnctrlX[ISDN_MAX_CHANNELS];
 #ifdef CONFIG_ISDN_PPP
 	devfs_handle_t devfs_handle_ipppX[ISDN_MAX_CHANNELS];
diff -u --recursive --new-file v2.5.2/linux/include/linux/iso_fs.h linux/include/linux/iso_fs.h
--- v2.5.2/linux/include/linux/iso_fs.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/iso_fs.h	Tue Jan 29 21:41:53 2002
@@ -170,6 +170,12 @@
 
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
+#include <linux/iso_fs_i.h>
+
+static inline struct iso_inode_info *ISOFS_I(struct inode *inode)
+{
+	return list_entry(inode, struct iso_inode_info, vfs_inode);
+}
 
 static inline int isonum_711(char *p)
 {
diff -u --recursive --new-file v2.5.2/linux/include/linux/iso_fs_i.h linux/include/linux/iso_fs_i.h
--- v2.5.2/linux/include/linux/iso_fs_i.h	Thu Oct 25 18:00:44 2001
+++ linux/include/linux/iso_fs_i.h	Mon Jan 28 13:20:44 2002
@@ -16,6 +16,7 @@
 	unsigned char i_format_parm[3];
 	unsigned long i_next_section_ino;
 	off_t i_section_size;
+	struct inode vfs_inode;
 };
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/jffs2_fs_i.h linux/include/linux/jffs2_fs_i.h
--- v2.5.2/linux/include/linux/jffs2_fs_i.h	Fri Sep 14 14:04:07 2001
+++ linux/include/linux/jffs2_fs_i.h	Mon Jan 28 13:20:44 2002
@@ -50,12 +50,16 @@
 	//	struct jffs2_raw_node_ref *lastnode;
 	__u16 flags;
 	__u8 usercompr;
+	struct inode vfs_inode;
 };
 
 #ifdef JFFS2_OUT_OF_KERNEL
 #define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u)
 #else
-#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i)
+static inline struct jffs2_inode_info *JFFS2_INODE_INFO(struct inode *inode)
+{
+	return list_entry(inode, struct jffs2_inode_info, vfs_inode);
+}
 #endif
 
 #endif /* _JFFS2_FS_I */
diff -u --recursive --new-file v2.5.2/linux/include/linux/limits.h linux/include/linux/limits.h
--- v2.5.2/linux/include/linux/limits.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/limits.h	Tue Jan 29 18:48:30 2002
@@ -13,6 +13,9 @@
 #define NAME_MAX         255	/* # chars in a file name */
 #define PATH_MAX        4096	/* # chars in a path name including nul */
 #define PIPE_BUF        4096	/* # bytes in atomic write to a pipe */
+#define XATTR_NAME_MAX   255	/* # chars in an extended attribute name */
+#define XATTR_SIZE_MAX 65536	/* size of an extended attribute value (64k) */
+#define XATTR_LIST_MAX 65536	/* size of extended attribute namelist (64k) */
 
 #define RTSIG_MAX	  32
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/mii.h linux/include/linux/mii.h
--- v2.5.2/linux/include/linux/mii.h	Thu Nov 22 11:48:09 2001
+++ linux/include/linux/mii.h	Tue Jan 29 21:44:00 2002
@@ -70,6 +70,8 @@
 #define ADVERTISE_LPACK         0x4000  /* Ack link partners response  */
 #define ADVERTISE_NPAGE         0x8000  /* Next page bit               */
 
+#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
+			ADVERTISE_CSMA)
 #define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
                        ADVERTISE_100HALF | ADVERTISE_100FULL)
 
@@ -100,6 +102,27 @@
 #define NWAYTEST_RESV1          0x00ff  /* Unused...                   */
 #define NWAYTEST_LOOPBACK       0x0100  /* Enable loopback for N-way   */
 #define NWAYTEST_RESV2          0xfe00  /* Unused...                   */
+
+
+struct mii_if_info {
+	int phy_id;
+	int advertising;
+
+	unsigned int full_duplex : 1;
+	unsigned int duplex_lock : 1;
+
+	struct net_device *dev;
+	int (*mdio_read) (struct net_device *dev, int phy_id, int location);
+	void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
+};
+
+struct ethtool_cmd;
+
+int mii_link_ok (struct mii_if_info *mii);
+int mii_nway_restart (struct mii_if_info *mii);
+int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
+int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
+
 
 /* This structure is used in all SIOCxMIIxxx ioctl calls */
 struct mii_ioctl_data {
diff -u --recursive --new-file v2.5.2/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h
--- v2.5.2/linux/include/linux/minix_fs.h	Fri Sep  7 09:45:51 2001
+++ linux/include/linux/minix_fs.h	Wed Jan 23 15:32:20 2002
@@ -89,6 +89,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/minix_fs_i.h>
+
 /*
  * change the define below to 0 if you want names > info->s_namelen chars to be
  * truncated. Else they will be disallowed (ENAMETOOLONG).
@@ -128,6 +130,11 @@
 extern struct file_operations minix_file_operations;
 extern struct file_operations minix_dir_operations;
 extern struct dentry_operations minix_dentry_operations;
+
+static inline struct minix_inode_info *minix_i(struct inode *inode)
+{
+	return list_entry(inode, struct minix_inode_info, vfs_inode);
+}
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/minix_fs_i.h linux/include/linux/minix_fs_i.h
--- v2.5.2/linux/include/linux/minix_fs_i.h	Thu Jan  4 04:07:58 1996
+++ linux/include/linux/minix_fs_i.h	Wed Jan 23 15:32:20 2002
@@ -9,6 +9,7 @@
 		__u16 i1_data[16];
 		__u32 i2_data[16];
 	} u;
+	struct inode vfs_inode;
 };
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.5.2/linux/include/linux/mm.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/mm.h	Tue Jan 29 21:41:15 2002
@@ -356,10 +356,10 @@
 extern void shmem_lock(struct file * file, int lock);
 extern int shmem_zero_setup(struct vm_area_struct *);
 
-extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size);
+extern void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned long size);
 extern int copy_page_range(struct mm_struct *dst, struct mm_struct *src, struct vm_area_struct *vma);
-extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot);
-extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot);
+extern int remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long to, unsigned long size, pgprot_t prot);
+extern int zeromap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long size, pgprot_t prot);
 
 extern int vmtruncate(struct inode * inode, loff_t offset);
 extern pmd_t *FASTCALL(__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address));
diff -u --recursive --new-file v2.5.2/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v2.5.2/linux/include/linux/msdos_fs.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/msdos_fs.h	Mon Jan 28 13:20:44 2002
@@ -4,9 +4,7 @@
 /*
  * The MS-DOS filesystem constants/structures
  */
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/fd.h>
+#include <linux/msdos_fs_i.h>
 
 #include <asm/byteorder.h>
 
@@ -19,13 +17,14 @@
 #define MSDOS_DPS_BITS	4 /* log2(MSDOS_DPS) */
 #define MSDOS_DIR_BITS	5 /* log2(sizeof(struct msdos_dir_entry)) */
 
+/* directory limit */
+#define FAT_MAX_DIR_ENTRIES	(65536)
+#define FAT_MAX_DIR_SIZE	(FAT_MAX_DIR_ENTRIES << MSDOS_DIR_BITS)
+
 #define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
 
 #define FAT_CACHE    8 /* FAT cache size */
 
-#define MSDOS_MAX_EXTRA	3 /* tolerate up to that number of clusters which are
-			     inaccessible because the FAT is too short */
-
 #define ATTR_RO      1  /* read-only */
 #define ATTR_HIDDEN  2  /* hidden */
 #define ATTR_SYS     4  /* system */
@@ -48,11 +47,6 @@
 #define CASE_LOWER_BASE 8	/* base is lower case */
 #define CASE_LOWER_EXT  16	/* extension is lower case */
 
-#define SCAN_ANY     0  /* either hidden or not */
-#define SCAN_HID     1  /* only hidden */
-#define SCAN_NOTHID  2  /* only not hidden */
-#define SCAN_NOTANY  3  /* test name, then use SCAN_HID or SCAN_NOTHID */
-
 #define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */
 #define IS_FREE(n) (!*(n) || *(const unsigned char *) (n) == DELETED_FLAG)
 
@@ -60,7 +54,10 @@
 	/* valid file mode bits */
 
 #define MSDOS_SB(s) (&((s)->u.msdos_sb))
-#define MSDOS_I(i) (&((i)->u.msdos_i))
+static inline struct msdos_inode_info *MSDOS_I(struct inode *inode)
+{
+	return list_entry(inode, struct msdos_inode_info, vfs_inode);
+}
 
 #define MSDOS_NAME 11 /* maximum name length */
 #define MSDOS_LONGNAME 256 /* maximum name length */
@@ -78,8 +75,8 @@
 
 #define FAT_FSINFO_SIG1		0x41615252
 #define FAT_FSINFO_SIG2		0x61417272
-#define IS_FSINFO(x)		(CF_LE_L((x)->signature1) == FAT_FSINFO_SIG1	 \
-				 && CF_LE_L((x)->signature2) == FAT_FSINFO_SIG2)
+#define IS_FSINFO(x)	(CF_LE_L((x)->signature1) == FAT_FSINFO_SIG1	\
+			 && CF_LE_L((x)->signature2) == FAT_FSINFO_SIG2)
 
 /*
  * Inode flags
@@ -184,10 +181,6 @@
 	int ino;		       /* ino for the file */
 };
 
-/* Determine whether this FS has kB-aligned data. */
-#define MSDOS_CAN_BMAP(mib) (!(((mib)->cluster_size & 1) || \
-    ((mib)->data_start & 1)))
-
 /* Convert attribute bits and a mask to the UNIX mode. */
 #define MSDOS_MKMODE(a,m) (m & (a & ATTR_RO ? S_IRUGO|S_IXUGO : S_IRWXUGO))
 
@@ -297,7 +290,7 @@
 extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
 
 /* fat/misc.c */
-extern void fat_fs_panic(struct super_block *s, const char *msg);
+extern void fat_fs_panic(struct super_block *s, const char *fmt, ...);
 extern int fat_is_binary(char conversion, char *extension);
 extern void lock_fat(struct super_block *sb);
 extern void unlock_fat(struct super_block *sb);
diff -u --recursive --new-file v2.5.2/linux/include/linux/msdos_fs_i.h linux/include/linux/msdos_fs_i.h
--- v2.5.2/linux/include/linux/msdos_fs_i.h	Thu Feb 10 12:17:00 2000
+++ linux/include/linux/msdos_fs_i.h	Mon Jan 28 13:20:44 2002
@@ -12,8 +12,8 @@
 	int i_attrs;	/* unused attribute bits */
 	int i_ctime_ms;	/* unused change time in milliseconds */
 	int i_location;	/* on-disk position of directory entry or 0 */
-	struct inode *i_fat_inode;	/* struct inode of this one */
 	struct list_head i_fat_hash;	/* hash by i_location */
+	struct inode vfs_inode;
 };
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/mtd/cfi.h linux/include/linux/mtd/cfi.h
--- v2.5.2/linux/include/linux/mtd/cfi.h	Thu Oct  4 15:13:18 2001
+++ linux/include/linux/mtd/cfi.h	Tue Jan 15 13:53:51 2002
@@ -368,7 +368,7 @@
 static inline void cfi_udelay(int us)
 {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-	if (current->need_resched) {
+	if (need_resched()) {
 		unsigned long t = us * HZ / 1000000;
 		if (t < 1)
 			t = 1;
diff -u --recursive --new-file v2.5.2/linux/include/linux/ncp_fs.h linux/include/linux/ncp_fs.h
--- v2.5.2/linux/include/linux/ncp_fs.h	Fri Feb  9 11:29:44 2001
+++ linux/include/linux/ncp_fs.h	Wed Jan 23 15:32:20 2002
@@ -12,6 +12,7 @@
 #include <linux/in.h>
 #include <linux/types.h>
 
+#include <linux/ncp_fs_i.h>
 #include <linux/ipx.h>
 #include <linux/ncp_no.h>
 
@@ -192,7 +193,10 @@
 #define NCP_SBP(sb)		(&((sb)->u.ncpfs_sb))
 
 #define NCP_SERVER(inode)	NCP_SBP((inode)->i_sb)
-#define NCP_FINFO(inode)	(&((inode)->u.ncpfs_i))
+static inline struct ncp_inode_info *NCP_FINFO(struct inode *inode)
+{
+	return list_entry(inode, struct ncp_inode_info, vfs_inode);
+}
 
 #ifdef DEBUG_NCP_MALLOC
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/ncp_fs_i.h linux/include/linux/ncp_fs_i.h
--- v2.5.2/linux/include/linux/ncp_fs_i.h	Thu Jun 29 10:42:56 2000
+++ linux/include/linux/ncp_fs_i.h	Wed Jan 23 15:32:20 2002
@@ -15,16 +15,16 @@
  * all the information we need to work with an inode after creation.
  */
 struct ncp_inode_info {
-	__u32	dirEntNum __attribute__((packed));
-	__u32	DosDirNum __attribute__((packed));
-	__u32	volNumber __attribute__((packed));
+	__u32	dirEntNum;
+	__u32	DosDirNum;
+	__u32	volNumber;
 	__u32	nwattr;
 	struct semaphore open_sem;
 	atomic_t	opened;
 	int	access;
-	__u32	server_file_handle __attribute__((packed));
-	__u8	open_create_action __attribute__((packed));
-	__u8	file_handle[6] __attribute__((packed));
+	__u32	server_file_handle;
+	__u8	file_handle[6];
+	struct inode vfs_inode;
 };
 
 #endif	/* __KERNEL__ */
diff -u --recursive --new-file v2.5.2/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.5.2/linux/include/linux/netdevice.h	Thu Nov 22 11:47:09 2001
+++ linux/include/linux/netdevice.h	Tue Jan 29 21:41:48 2002
@@ -278,6 +278,10 @@
 	struct net_device_stats* (*get_stats)(struct net_device *dev);
 	struct iw_statistics*	(*get_wireless_stats)(struct net_device *dev);
 
+	/* List of functions to handle Wireless Extensions (instead of ioctl).
+	 * See <net/iw_handler.h> for details. Jean II */
+	struct iw_handler_def *	wireless_handlers;
+
 	/*
 	 * This marks the end of the "visible" part of the structure. All
 	 * fields hereafter are internal to the system, and may change at
diff -u --recursive --new-file v2.5.2/linux/include/linux/netfilter_ipv4/ip_tables.h linux/include/linux/netfilter_ipv4/ip_tables.h
--- v2.5.2/linux/include/linux/netfilter_ipv4/ip_tables.h	Thu Jul 26 13:58:46 2001
+++ linux/include/linux/netfilter_ipv4/ip_tables.h	Wed Jan 23 15:28:40 2002
@@ -428,6 +428,9 @@
 
 	/* Man behind the curtain... */
 	struct ipt_table_info *private;
+
+	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
+	struct module *me;
 };
 
 extern int ipt_register_table(struct ipt_table *table);
diff -u --recursive --new-file v2.5.2/linux/include/linux/netfilter_ipv4/ipt_ULOG.h linux/include/linux/netfilter_ipv4/ipt_ULOG.h
--- v2.5.2/linux/include/linux/netfilter_ipv4/ipt_ULOG.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/netfilter_ipv4/ipt_ULOG.h	Wed Jan 23 15:28:40 2002
@@ -0,0 +1,46 @@
+/* Header file for IP tables userspace logging, Version 1.8
+ *
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
+ * 
+ * Distributed under the terms of GNU GPL */
+
+#ifndef _IPT_ULOG_H
+#define _IPT_ULOG_H
+
+#ifndef NETLINK_NFLOG
+#define NETLINK_NFLOG 	5
+#endif
+
+#define ULOG_MAC_LEN	80
+#define ULOG_PREFIX_LEN	32
+
+#define ULOG_MAX_QLEN	50
+/* Why 50? Well... there is a limit imposed by the slab cache 131000
+ * bytes. So the multipart netlink-message has to be < 131000 bytes.
+ * Assuming a standard ethernet-mtu of 1500, we could define this up
+ * to 80... but even 50 seems to be big enough. */
+
+/* private data structure for each rule with a ULOG target */
+struct ipt_ulog_info {
+	unsigned int nl_group;
+	size_t copy_range;
+	size_t qthreshold;
+	char prefix[ULOG_PREFIX_LEN];
+};
+
+/* Format of the ULOG packets passed through netlink */
+typedef struct ulog_packet_msg {
+	unsigned long mark;
+	long timestamp_sec;
+	long timestamp_usec;
+	unsigned int hook;
+	char indev_name[IFNAMSIZ];
+	char outdev_name[IFNAMSIZ];
+	size_t data_len;
+	char prefix[ULOG_PREFIX_LEN];
+	unsigned char mac_len;
+	unsigned char mac[ULOG_MAC_LEN];
+	unsigned char payload[0];
+} ulog_packet_msg_t;
+
+#endif /*_IPT_ULOG_H*/
diff -u --recursive --new-file v2.5.2/linux/include/linux/netfilter_ipv4/ipt_ah.h linux/include/linux/netfilter_ipv4/ipt_ah.h
--- v2.5.2/linux/include/linux/netfilter_ipv4/ipt_ah.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/netfilter_ipv4/ipt_ah.h	Wed Jan 23 15:28:40 2002
@@ -0,0 +1,16 @@
+#ifndef _IPT_AH_H
+#define _IPT_AH_H
+
+struct ipt_ah
+{
+	u_int32_t spis[2];			/* Security Parameter Index */
+	u_int8_t  invflags;			/* Inverse flags */
+};
+
+
+
+/* Values for "invflags" field in struct ipt_ah. */
+#define IPT_AH_INV_SPI		0x01	/* Invert the sense of spi. */
+#define IPT_AH_INV_MASK	0x01	/* All possible flags. */
+
+#endif /*_IPT_AH_H*/
diff -u --recursive --new-file v2.5.2/linux/include/linux/netfilter_ipv4/ipt_esp.h linux/include/linux/netfilter_ipv4/ipt_esp.h
--- v2.5.2/linux/include/linux/netfilter_ipv4/ipt_esp.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/netfilter_ipv4/ipt_esp.h	Wed Jan 23 15:28:40 2002
@@ -0,0 +1,16 @@
+#ifndef _IPT_ESP_H
+#define _IPT_ESP_H
+
+struct ipt_esp
+{
+	u_int32_t spis[2];			/* Security Parameter Index */
+	u_int8_t  invflags;			/* Inverse flags */
+};
+
+
+
+/* Values for "invflags" field in struct ipt_esp. */
+#define IPT_ESP_INV_SPI		0x01	/* Invert the sense of spi. */
+#define IPT_ESP_INV_MASK	0x01	/* All possible flags. */
+
+#endif /*_IPT_ESP_H*/
diff -u --recursive --new-file v2.5.2/linux/include/linux/netfilter_ipv4.h linux/include/linux/netfilter_ipv4.h
--- v2.5.2/linux/include/linux/netfilter_ipv4.h	Thu Nov 22 11:48:57 2001
+++ linux/include/linux/netfilter_ipv4.h	Tue Jan 29 21:44:23 2002
@@ -73,4 +73,81 @@
 /* 2.4 firewalling went 64 through 67. */
 #define SO_ORIGINAL_DST 80
 
+
+/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue 
+ *
+ * Ideally this would be ins some netfilter_utility module, but creating this
+ * module for just one function doesn't make sense. -HW */
+
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/route.h>
+#include <linux/ip.h>
+
+static inline int route_me_harder(struct sk_buff **pskb)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct rtable *rt;
+	struct rt_key key = { dst:iph->daddr,
+			      src:iph->saddr,
+			      oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
+			      tos:RT_TOS(iph->tos)|RTO_CONN,
+#ifdef CONFIG_IP_ROUTE_FWMARK
+			      fwmark:(*pskb)->nfmark
+#endif
+			    };
+	struct net_device *dev_src = NULL;
+	int err;
+
+	/* accomodate ip_route_output_slow(), which expects the key src to be
+	   0 or a local address; however some non-standard hacks like
+	   ipt_REJECT.c:send_reset() can cause packets with foreign
+           saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */
+	if(key.src && !(dev_src = ip_dev_find(key.src)))
+		key.src = 0;
+
+	if ((err=ip_route_output_key(&rt, &key)) != 0) {
+		printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n",
+			NIPQUAD(iph->daddr), NIPQUAD(iph->saddr),
+			(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
+			RT_TOS(iph->tos)|RTO_CONN,
+#ifdef CONFIG_IP_ROUTE_FWMARK
+			(*pskb)->nfmark,
+#else
+			0UL,
+#endif
+			err);
+		goto out;
+	}
+
+	/* Drop old route. */
+	dst_release((*pskb)->dst);
+
+	(*pskb)->dst = &rt->u.dst;
+
+	/* Change in oif may mean change in hh_len. */
+	if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) {
+		struct sk_buff *nskb;
+
+		nskb = skb_realloc_headroom(*pskb,
+					    (*pskb)->dst->dev->hard_header_len);
+		if (!nskb) {
+			err = -ENOMEM;
+			goto out;
+		}
+		if ((*pskb)->sk)
+			skb_set_owner_w(nskb, (*pskb)->sk);
+		kfree_skb(*pskb);
+		*pskb = nskb;
+	}
+
+out:
+	if (dev_src)
+		dev_put(dev_src);
+
+	return err;
+}
+
 #endif /*__LINUX_IP_NETFILTER_H*/
diff -u --recursive --new-file v2.5.2/linux/include/linux/netfilter_ipv6/ip6_tables.h linux/include/linux/netfilter_ipv6/ip6_tables.h
--- v2.5.2/linux/include/linux/netfilter_ipv6/ip6_tables.h	Thu Jul 26 13:59:06 2001
+++ linux/include/linux/netfilter_ipv6/ip6_tables.h	Wed Jan 23 15:28:40 2002
@@ -435,6 +435,9 @@
 
 	/* Man behind the curtain... */
 	struct ip6t_table_info *private;
+
+	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
+	struct module *me;
 };
 
 extern int ip6t_register_table(struct ip6t_table *table);
diff -u --recursive --new-file v2.5.2/linux/include/linux/netlink.h linux/include/linux/netlink.h
--- v2.5.2/linux/include/linux/netlink.h	Thu Jul 26 14:00:17 2001
+++ linux/include/linux/netlink.h	Wed Jan 23 15:28:40 2002
@@ -5,6 +5,8 @@
 #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_NFLOG		5	/* netfilter/iptables ULOG */
 #define NETLINK_ARPD		8
 #define NETLINK_ROUTE6		11	/* af_inet6 route comm channel */
 #define NETLINK_IP6_FW		13
diff -u --recursive --new-file v2.5.2/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.5.2/linux/include/linux/nfs_fs.h	Thu Nov 22 11:47:00 2001
+++ linux/include/linux/nfs_fs.h	Tue Jan 29 21:42:01 2002
@@ -63,67 +63,154 @@
  */
 #define NFS_SUPER_MAGIC			0x6969
 
-static inline struct nfs_inode_info *NFS_I(struct inode *inode)
+/*
+ * These are the default flags for swap requests
+ */
+#define NFS_RPC_SWAPFLAGS		(RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS)
+
+/* Flags in the RPC client structure */
+#define NFS_CLNTF_BUFSIZE	0x0001	/* readdir buffer in longwords */
+
+#define NFS_RW_SYNC		0x0001	/* O_SYNC handling */
+#define NFS_RW_SWAP		0x0002	/* This is a swap request */
+
+/*
+ * When flushing a cluster of dirty pages, there can be different
+ * strategies:
+ */
+#define FLUSH_AGING		0	/* only flush old buffers */
+#define FLUSH_SYNC		1	/* file being synced, or contention */
+#define FLUSH_WAIT		2	/* wait for completion */
+#define FLUSH_STABLE		4	/* commit to stable storage */
+
+#ifdef __KERNEL__
+
+/*
+ * nfs fs inode data in memory
+ */
+struct nfs_inode {
+	/*
+	 * The 64bit 'inode number'
+	 */
+	__u64 fsid;
+	__u64 fileid;
+
+	/*
+	 * NFS file handle
+	 */
+	struct nfs_fh		fh;
+
+	/*
+	 * Various flags
+	 */
+	unsigned short		flags;
+
+	/*
+	 * read_cache_jiffies is when we started read-caching this inode,
+	 * and read_cache_mtime is the mtime of the inode at that time.
+	 * attrtimeo is for how long the cached information is assumed
+	 * to be valid. A successful attribute revalidation doubles
+	 * attrtimeo (up to acregmax/acdirmax), a failure resets it to
+	 * acregmin/acdirmin.
+	 *
+	 * We need to revalidate the cached attrs for this inode if
+	 *
+	 *	jiffies - read_cache_jiffies > attrtimeo
+	 *
+	 * and invalidate any cached data/flush out any dirty pages if
+	 * we find that
+	 *
+	 *	mtime != read_cache_mtime
+	 */
+	unsigned long		read_cache_jiffies;
+	__u64			read_cache_ctime;
+	__u64			read_cache_mtime;
+	__u64			read_cache_isize;
+	unsigned long		attrtimeo;
+	unsigned long		attrtimeo_timestamp;
+
+	/*
+	 * This is the cookie verifier used for NFSv3 readdir
+	 * operations
+	 */
+	__u32			cookieverf[2];
+
+	/*
+	 * This is the list of dirty unwritten pages.
+	 */
+	struct list_head	read;
+	struct list_head	dirty;
+	struct list_head	commit;
+	struct list_head	writeback;
+
+	unsigned int		nread,
+				ndirty,
+				ncommit,
+				npages;
+
+	/* Flush daemon info */
+	struct inode		*hash_next,
+				*hash_prev;
+	unsigned long		nextscan;
+
+	/* Credentials for shared mmap */
+	struct rpc_cred		*mm_cred;
+
+	struct inode		vfs_inode;
+};
+
+/*
+ * Legal inode flag values
+ */
+#define NFS_INO_STALE		0x0001		/* possible stale inode */
+#define NFS_INO_ADVISE_RDPLUS   0x0002          /* advise readdirplus */
+#define NFS_INO_REVALIDATING	0x0004		/* revalidating attrs */
+#define NFS_IS_SNAPSHOT		0x0010		/* a snapshot file */
+#define NFS_INO_FLUSH		0x0020		/* inode is due for flushing */
+#define NFS_INO_NEW		0x0040		/* hadn't been filled yet */
+
+static inline struct nfs_inode *NFS_I(struct inode *inode)
 {
-	return &inode->u.nfs_i;
+	return list_entry(inode, struct nfs_inode, vfs_inode);
 }
 
-#define NFS_FH(inode)			(&(inode)->u.nfs_i.fh)
+#define NFS_FH(inode)			(&NFS_I(inode)->fh)
 #define NFS_SERVER(inode)		(&(inode)->i_sb->u.nfs_sb.s_server)
 #define NFS_CLIENT(inode)		(NFS_SERVER(inode)->client)
 #define NFS_PROTO(inode)		(NFS_SERVER(inode)->rpc_ops)
 #define NFS_REQUESTLIST(inode)		(NFS_SERVER(inode)->rw_requests)
 #define NFS_ADDR(inode)			(RPC_PEERADDR(NFS_CLIENT(inode)))
 #define NFS_CONGESTED(inode)		(RPC_CONGESTED(NFS_CLIENT(inode)))
-#define NFS_COOKIEVERF(inode)		((inode)->u.nfs_i.cookieverf)
-#define NFS_READTIME(inode)		((inode)->u.nfs_i.read_cache_jiffies)
-#define NFS_CACHE_CTIME(inode)		((inode)->u.nfs_i.read_cache_ctime)
-#define NFS_CACHE_MTIME(inode)		((inode)->u.nfs_i.read_cache_mtime)
-#define NFS_CACHE_ISIZE(inode)		((inode)->u.nfs_i.read_cache_isize)
-#define NFS_NEXTSCAN(inode)		((inode)->u.nfs_i.nextscan)
+#define NFS_COOKIEVERF(inode)		(NFS_I(inode)->cookieverf)
+#define NFS_READTIME(inode)		(NFS_I(inode)->read_cache_jiffies)
+#define NFS_CACHE_CTIME(inode)		(NFS_I(inode)->read_cache_ctime)
+#define NFS_CACHE_MTIME(inode)		(NFS_I(inode)->read_cache_mtime)
+#define NFS_CACHE_ISIZE(inode)		(NFS_I(inode)->read_cache_isize)
+#define NFS_NEXTSCAN(inode)		(NFS_I(inode)->nextscan)
 #define NFS_CACHEINV(inode) \
 do { \
 	NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \
 } while (0)
-#define NFS_ATTRTIMEO(inode)		((inode)->u.nfs_i.attrtimeo)
+#define NFS_ATTRTIMEO(inode)		(NFS_I(inode)->attrtimeo)
 #define NFS_MINATTRTIMEO(inode) \
 	(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \
 			       : NFS_SERVER(inode)->acregmin)
 #define NFS_MAXATTRTIMEO(inode) \
 	(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmax \
 			       : NFS_SERVER(inode)->acregmax)
-#define NFS_ATTRTIMEO_UPDATE(inode)	((inode)->u.nfs_i.attrtimeo_timestamp)
+#define NFS_ATTRTIMEO_UPDATE(inode)	(NFS_I(inode)->attrtimeo_timestamp)
 
-#define NFS_FLAGS(inode)		((inode)->u.nfs_i.flags)
+#define NFS_FLAGS(inode)		(NFS_I(inode)->flags)
 #define NFS_REVALIDATING(inode)		(NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
 #define NFS_STALE(inode)		(NFS_FLAGS(inode) & NFS_INO_STALE)
+#define NFS_NEW(inode)			(NFS_FLAGS(inode) & NFS_INO_NEW)
 
-#define NFS_FILEID(inode)		((inode)->u.nfs_i.fileid)
-#define NFS_FSID(inode)			((inode)->u.nfs_i.fsid)
+#define NFS_FILEID(inode)		(NFS_I(inode)->fileid)
+#define NFS_FSID(inode)			(NFS_I(inode)->fsid)
 
 /* Inode Flags */
 #define NFS_USE_READDIRPLUS(inode)	((NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS) ? 1 : 0)
 
-/*
- * These are the default flags for swap requests
- */
-#define NFS_RPC_SWAPFLAGS		(RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS)
-
-/* Flags in the RPC client structure */
-#define NFS_CLNTF_BUFSIZE	0x0001	/* readdir buffer in longwords */
-
-#define NFS_RW_SYNC		0x0001	/* O_SYNC handling */
-#define NFS_RW_SWAP		0x0002	/* This is a swap request */
-
-/*
- * When flushing a cluster of dirty pages, there can be different
- * strategies:
- */
-#define FLUSH_AGING		0	/* only flush old buffers */
-#define FLUSH_SYNC		1	/* file being synced, or contention */
-#define FLUSH_WAIT		2	/* wait for completion */
-#define FLUSH_STABLE		4	/* commit to stable storage */
-
 static inline
 loff_t page_offset(struct page *page)
 {
@@ -136,7 +223,6 @@
 	return page->index;
 }
 
-#ifdef __KERNEL__
 /*
  * linux/fs/nfs/inode.c
  */
@@ -220,13 +306,13 @@
 static inline int
 nfs_have_read(struct inode *inode)
 {
-	return !list_empty(&inode->u.nfs_i.read);
+	return !list_empty(&NFS_I(inode)->read);
 }
 
 static inline int
 nfs_have_writebacks(struct inode *inode)
 {
-	return !list_empty(&inode->u.nfs_i.writeback);
+	return !list_empty(&NFS_I(inode)->writeback);
 }
 
 static inline int
diff -u --recursive --new-file v2.5.2/linux/include/linux/nfs_fs_i.h linux/include/linux/nfs_fs_i.h
--- v2.5.2/linux/include/linux/nfs_fs_i.h	Thu Nov 22 11:46:19 2001
+++ linux/include/linux/nfs_fs_i.h	Tue Jan 29 21:41:11 2002
@@ -6,87 +6,6 @@
 #include <linux/nfs.h>
 
 /*
- * nfs fs inode data in memory
- */
-struct nfs_inode_info {
-	/*
-	 * The 64bit 'inode number'
-	 */
-	__u64 fsid;
-	__u64 fileid;
-
-	/*
-	 * NFS file handle
-	 */
-	struct nfs_fh		fh;
-
-	/*
-	 * Various flags
-	 */
-	unsigned short		flags;
-
-	/*
-	 * read_cache_jiffies is when we started read-caching this inode,
-	 * and read_cache_mtime is the mtime of the inode at that time.
-	 * attrtimeo is for how long the cached information is assumed
-	 * to be valid. A successful attribute revalidation doubles
-	 * attrtimeo (up to acregmax/acdirmax), a failure resets it to
-	 * acregmin/acdirmin.
-	 *
-	 * We need to revalidate the cached attrs for this inode if
-	 *
-	 *	jiffies - read_cache_jiffies > attrtimeo
-	 *
-	 * and invalidate any cached data/flush out any dirty pages if
-	 * we find that
-	 *
-	 *	mtime != read_cache_mtime
-	 */
-	unsigned long		read_cache_jiffies;
-	__u64			read_cache_ctime;
-	__u64			read_cache_mtime;
-	__u64			read_cache_isize;
-	unsigned long		attrtimeo;
-	unsigned long		attrtimeo_timestamp;
-
-	/*
-	 * This is the cookie verifier used for NFSv3 readdir
-	 * operations
-	 */
-	__u32			cookieverf[2];
-
-	/*
-	 * This is the list of dirty unwritten pages.
-	 */
-	struct list_head	read;
-	struct list_head	dirty;
-	struct list_head	commit;
-	struct list_head	writeback;
-
-	unsigned int		nread,
-				ndirty,
-				ncommit,
-				npages;
-
-	/* Flush daemon info */
-	struct inode		*hash_next,
-				*hash_prev;
-	unsigned long		nextscan;
-
-	/* Credentials for shared mmap */
-	struct rpc_cred		*mm_cred;
-};
-
-/*
- * Legal inode flag values
- */
-#define NFS_INO_STALE		0x0001		/* possible stale inode */
-#define NFS_INO_ADVISE_RDPLUS   0x0002          /* advise readdirplus */
-#define NFS_INO_REVALIDATING	0x0004		/* revalidating attrs */
-#define NFS_IS_SNAPSHOT		0x0010		/* a snapshot file */
-#define NFS_INO_FLUSH		0x0020		/* inode is due for flushing */
-
-/*
  * NFS lock info
  */
 struct nfs_lock_info {
diff -u --recursive --new-file v2.5.2/linux/include/linux/ntfs_fs_i.h linux/include/linux/ntfs_fs_i.h
--- v2.5.2/linux/include/linux/ntfs_fs_i.h	Thu Nov 22 11:46:18 2001
+++ linux/include/linux/ntfs_fs_i.h	Tue Jan 29 21:41:09 2002
@@ -88,4 +88,10 @@
 	} u;	
 };
 
+/* this is a kludge */
+struct ntfs_i {
+	struct ntfs_inode_info n;
+	struct inode vfs_inode;
+};
+
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.5.2/linux/include/linux/pci.h	Thu Nov 22 11:46:30 2001
+++ linux/include/linux/pci.h	Tue Jan 29 21:41:52 2002
@@ -301,6 +301,7 @@
 #include <linux/ioport.h>
 #include <linux/list.h>
 #include <linux/errno.h>
+#include <linux/device.h>
 
 /* File state for mmap()s on /proc/bus/pci/X/Y */
 enum pci_mmap_state {
@@ -363,6 +364,8 @@
 					   this is D0-D3, D0 being fully functional,
 					   and D3 being off. */
 
+	struct	device	dev;		/* Generic device interface */
+
 	/* device is compatible with these IDs */
 	unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
 	unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];
@@ -429,6 +432,8 @@
 	unsigned char	productver;	/* product version */
 	unsigned char	checksum;	/* if zero - checksum passed */
 	unsigned char	pad1;
+
+	struct iobus	iobus;		/* Generic device interface */
 };
 
 #define pci_bus_b(n) list_entry(n, struct pci_bus, node)
@@ -525,7 +530,6 @@
 
 /* Generic PCI functions used internally */
 
-void pci_init(void);
 int pci_bus_exists(const struct list_head *list, int nr);
 struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
 struct pci_bus *pci_alloc_primary_bus(int bus);
diff -u --recursive --new-file v2.5.2/linux/include/linux/pnpbios.h linux/include/linux/pnpbios.h
--- v2.5.2/linux/include/linux/pnpbios.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/pnpbios.h	Tue Jan 29 18:24:01 2002
@@ -0,0 +1,211 @@
+/*
+ * Include file for the interface to a PnP BIOS
+ *
+ * Original BIOS code (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de)
+ * PnP handler parts (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
+ * Minor reorganizations by David Hinds <dhinds@zen.stanford.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LINUX_PNPBIOS_H
+#define _LINUX_PNPBIOS_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/pci.h>
+
+/*
+ * Status codes (warnings and errors)
+ */
+#define PNP_SUCCESS                     0x00
+#define PNP_NOT_SET_STATICALLY          0x7f
+#define PNP_UNKNOWN_FUNCTION            0x81
+#define PNP_FUNCTION_NOT_SUPPORTED      0x82
+#define PNP_INVALID_HANDLE              0x83
+#define PNP_BAD_PARAMETER               0x84
+#define PNP_SET_FAILED                  0x85
+#define PNP_EVENTS_NOT_PENDING          0x86
+#define PNP_SYSTEM_NOT_DOCKED           0x87
+#define PNP_NO_ISA_PNP_CARDS            0x88
+#define PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89
+#define PNP_CONFIG_CHANGE_FAILED_NO_BATTERY 0x8a
+#define PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT 0x8b
+#define PNP_BUFFER_TOO_SMALL            0x8c
+#define PNP_USE_ESCD_SUPPORT            0x8d
+#define PNP_MESSAGE_NOT_SUPPORTED       0x8e
+#define PNP_HARDWARE_ERROR              0x8f
+
+#define ESCD_SUCCESS                    0x00
+#define ESCD_IO_ERROR_READING           0x55
+#define ESCD_INVALID                    0x56
+#define ESCD_BUFFER_TOO_SMALL           0x59
+#define ESCD_NVRAM_TOO_SMALL            0x5a
+#define ESCD_FUNCTION_NOT_SUPPORTED     0x81
+
+/*
+ * Events that can be received by "get event"
+ */
+#define PNPEV_ABOUT_TO_CHANGE_CONFIG	0x0001
+#define PNPEV_DOCK_CHANGED		0x0002
+#define PNPEV_SYSTEM_DEVICE_CHANGED	0x0003
+#define PNPEV_CONFIG_CHANGED_FAILED	0x0004
+#define PNPEV_UNKNOWN_SYSTEM_EVENT	0xffff
+/* 0x8000 through 0xfffe are OEM defined */
+
+/*
+ * Messages that should be sent through "send message"
+ */
+#define PNPMSG_OK			0x00
+#define PNPMSG_ABORT			0x01
+#define PNPMSG_UNDOCK_DEFAULT_ACTION	0x40
+#define PNPMSG_POWER_OFF		0x41
+#define PNPMSG_PNP_OS_ACTIVE		0x42
+#define PNPMSG_PNP_OS_INACTIVE		0x43
+/* 0x8000 through 0xffff are OEM defined */
+
+#pragma pack(1)
+struct pnp_dev_node_info {
+	__u16	no_nodes;
+	__u16	max_node_size;
+};
+struct pnp_docking_station_info {
+	__u32	location_id;
+	__u32	serial;
+	__u16	capabilities;
+};
+struct pnp_isa_config_struc {
+	__u8	revision;
+	__u8	no_csns;
+	__u16	isa_rd_data_port;
+	__u16	reserved;
+};
+struct escd_info_struc {
+	__u16	min_escd_write_size;
+	__u16	escd_size;
+	__u32	nv_storage_base;
+};
+struct pnp_bios_node {
+	__u16	size;
+	__u8	handle;
+	__u32	eisa_id;
+	__u8	type_code[3];
+	__u16	flags;
+	__u8	data[0];
+};
+#pragma pack()
+
+struct pnpbios_device_id
+{
+	char id[8];
+	unsigned long driver_data;
+};
+
+struct pnpbios_driver {
+	struct list_head node;
+	char *name;
+	const struct pnpbios_device_id *id_table;	/* NULL if wants all devices */
+	int  (*probe)  (struct pci_dev *dev, const struct pnpbios_device_id *id);	/* New device inserted */
+	void (*remove) (struct pci_dev *dev);		/* Device removed, either due to hotplug remove or module remove */
+};
+
+#ifdef CONFIG_PNPBIOS
+
+/* exported */
+extern int  pnpbios_register_driver(struct pnpbios_driver *drv);
+extern void pnpbios_unregister_driver(struct pnpbios_driver *drv);
+
+/* non-exported */
+#define pnpbios_for_each_dev(dev) \
+	for(dev = pnpbios_dev_g(pnpbios_devices.next); dev != pnpbios_dev_g(&pnpbios_devices); dev = pnpbios_dev_g(dev->global_list.next))
+
+
+#define pnpbios_dev_g(n) list_entry(n, struct pci_dev, global_list)
+
+static __inline struct pnpbios_driver *pnpbios_dev_driver(const struct pci_dev *dev)
+{
+	return (struct pnpbios_driver *)dev->driver;
+}
+
+extern int  pnpbios_dont_use_current_config;
+extern void *pnpbios_kmalloc(size_t size, int f);
+extern void pnpbios_init (void);
+extern void pnpbios_proc_init (void);
+
+extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data);
+extern int pnp_bios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
+extern int pnp_bios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
+#if needed
+extern int pnp_bios_get_event (u16 *message);
+extern int pnp_bios_send_message (u16 message);
+extern int pnp_bios_set_stat_res (char *info);
+extern int pnp_bios_get_stat_res (char *info);
+extern int pnp_bios_apm_id_table (char *table, u16 *size);
+extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data);
+extern int pnp_bios_escd_info (struct escd_info_struc *data);
+extern int pnp_bios_read_escd (char *data, u32 nvram_base);
+extern int pnp_bios_write_escd (char *data, u32 nvram_base);
+#endif
+
+/*
+ * a helper function which helps ensure correct pnpbios_driver
+ * setup and cleanup for commonly-encountered hotplug/modular cases
+ *
+ * This MUST stay in a header, as it checks for -DMODULE
+ */
+ 
+static inline int pnpbios_module_init(struct pnpbios_driver *drv)
+{
+	int rc = pnpbios_register_driver (drv);
+
+	if (rc > 0)
+		return 0;
+
+	/* iff CONFIG_HOTPLUG and built into kernel, we should
+	 * leave the driver around for future hotplug events.
+	 * For the module case, a hotplug daemon of some sort
+	 * should load a module in response to an insert event. */
+#if defined(CONFIG_HOTPLUG) && !defined(MODULE)
+	if (rc == 0)
+		return 0;
+#else
+	if (rc == 0)
+		rc = -ENODEV;		
+#endif
+
+	/* if we get here, we need to clean up pci driver instance
+	 * and return some sort of error */
+	pnpbios_unregister_driver (drv);
+	
+	return rc;
+}
+
+#else /* CONFIG_PNPBIOS */
+
+static __inline__ int pnpbios_register_driver(struct pnpbios_driver *drv)
+{
+	return 0;
+}
+
+static __inline__ void pnpbios_unregister_driver(struct pnpbios_driver *drv)
+{
+	return;
+}
+
+#endif /* CONFIG_PNPBIOS */
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_PNPBIOS_H */
diff -u --recursive --new-file v2.5.2/linux/include/linux/qnx4_fs.h linux/include/linux/qnx4_fs.h
--- v2.5.2/linux/include/linux/qnx4_fs.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/qnx4_fs.h	Mon Jan 21 15:37:32 2002
@@ -97,6 +97,12 @@
 #define QNX4DEBUG(X) (void) 0
 #endif
 
+struct qnx4_inode_info {
+	struct qnx4_inode_entry raw;
+	unsigned long mmu_private;
+	struct inode vfs_inode;
+};
+
 extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry);
 extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
 extern unsigned long qnx4_block_map(struct inode *inode, long iblock);
@@ -119,6 +125,16 @@
 extern int qnx4_sync_file(struct file *file, struct dentry *dentry, int);
 extern int qnx4_sync_inode(struct inode *inode);
 extern int qnx4_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh, int create);
+
+static inline struct qnx4_inode_info *qnx4_i(struct inode *inode)
+{
+	return list_entry(inode, struct qnx4_inode_info, vfs_inode);
+}
+
+static inline struct qnx4_inode_entry *qnx4_raw_inode(struct inode *inode)
+{
+	return &qnx4_i(inode)->raw;
+}
 
 #endif				/* __KERNEL__ */
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/qnx4_fs_i.h linux/include/linux/qnx4_fs_i.h
--- v2.5.2/linux/include/linux/qnx4_fs_i.h	Thu Feb 10 12:17:00 2000
+++ linux/include/linux/qnx4_fs_i.h	Wed Dec 31 16:00:00 1969
@@ -1,39 +0,0 @@
-/*
- *  Name                         : qnx4_fs_i.h
- *  Author                       : Richard Frowijn
- *  Function                     : qnx4 inode definitions
- *  Version                      : 1.0.2
- *  Last modified                : 2000-01-06
- *
- *  History                      : 23-03-1998 created
- *
- */
-#ifndef _QNX4_FS_I
-#define _QNX4_FS_I
-
-#include <linux/qnxtypes.h>
-
-/*
- * qnx4 fs inode entry
- */
-struct qnx4_inode_info {
-	char		i_reserved[16];	/* 16 */
-	qnx4_off_t	i_size;		/*  4 */
-	qnx4_xtnt_t	i_first_xtnt;	/*  8 */
-	__u32		i_xblk;		/*  4 */
-	__s32		i_ftime;	/*  4 */
-	__s32		i_mtime;	/*  4 */
-	__s32		i_atime;	/*  4 */
-	__s32		i_ctime;	/*  4 */
-	qnx4_nxtnt_t	i_num_xtnts;	/*  2 */
-	qnx4_mode_t	i_mode;		/*  2 */
-	qnx4_muid_t	i_uid;		/*  2 */
-	qnx4_mgid_t	i_gid;		/*  2 */
-	qnx4_nlink_t	i_nlink;	/*  2 */
-	__u8		i_zero[4];	/*  4 */
-	qnx4_ftype_t	i_type;		/*  1 */
-	__u8		i_status;	/*  1 */
-	unsigned long	mmu_private;
-};
-
-#endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h
--- v2.5.2/linux/include/linux/reiserfs_fs.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/reiserfs_fs.h	Tue Jan 29 10:47:05 2002
@@ -20,6 +20,7 @@
 #include <asm/unaligned.h>
 #include <linux/bitops.h>
 #include <linux/proc_fs.h>
+#include <linux/reiserfs_fs_i.h>
 #endif
 
 /*
@@ -52,48 +53,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
@@ -129,6 +99,135 @@
  * Structure of super block on disk, a version of which in RAM is often accessed as s->u.reiserfs_sb.s_rs
  * the version in RAM is part of a larger structure containing fields never written to disk.
  */
+#define UNSET_HASH 0 // read_super will guess about, what hash names
+                     // in directories were sorted with
+#define TEA_HASH  1
+#define YURA_HASH 2
+#define R5_HASH   3
+#define DEFAULT_HASH R5_HASH
+
+
+struct journal_params {
+    __u32 jp_journal_1st_block;	      /* where does journal start from on its
+				       * device */
+    __u32 jp_journal_dev;	      /* journal device st_rdev */
+    __u32 jp_journal_size;	      /* size of the journal */
+    __u32 jp_journal_trans_max;	      /* max number of blocks in a transaction. */
+    __u32 jp_journal_magic; 	      /* random value made on fs creation (this
+				       * was sb_journal_block_count) */
+    __u32 jp_journal_max_batch;	      /* max number of blocks to batch into a
+				       * trans */
+    __u32 jp_journal_max_commit_age;  /* in seconds, how old can an async
+				       * commit be */
+    __u32 jp_journal_max_trans_age;   /* in seconds, how old can a transaction
+				       * be */
+};
+
+/* this is the super from 3.5.X, where X >= 10 */
+struct reiserfs_super_block_v1
+{
+    __u32 s_block_count;	   /* blocks count         */
+    __u32 s_free_blocks;           /* free blocks count    */
+    __u32 s_root_block;            /* root block number    */
+    struct journal_params s_journal;
+    __u16 s_blocksize;             /* block size */
+    __u16 s_oid_maxsize;	   /* max size of object id array, see
+				    * get_objectid() commentary  */
+    __u16 s_oid_cursize;	   /* current size of object id array */
+    __u16 s_umount_state;          /* this is set to 1 when filesystem was
+				    * umounted, to 2 - when not */    
+    char s_magic[10];              /* reiserfs magic string indicates that
+				    * file system is reiserfs:
+				    * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
+    __u16 s_fs_state;	           /* it is set to used by fsck to mark which
+				    * phase of rebuilding is done */
+    __u32 s_hash_function_code;    /* indicate, what hash function is being use
+				    * to sort names in a directory*/
+    __u16 s_tree_height;           /* height of disk tree */
+    __u16 s_bmap_nr;               /* amount of bitmap blocks needed to address
+				    * each block of file system */
+    __u16 s_version;               /* this field is only reliable on filesystem
+				    * with non-standard journal */
+    __u16 s_reserved_for_journal;  /* size in blocks of journal area on main
+				    * device, we need to keep after
+				    * making fs with non-standard journal */	
+} __attribute__ ((__packed__));
+
+#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))
+
+/* this is the on disk super block */
+struct reiserfs_super_block
+{
+    struct reiserfs_super_block_v1 s_v1;
+    __u32 s_inode_generation;
+    __u32 s_flags;                  /* Right now used only by inode-attributes, if enabled */
+    unsigned char s_uuid[16];       /* filesystem unique identifier */
+    unsigned char s_label[16];      /* filesystem volume label */
+    char s_unused[88] ;             /* zero filled by mkreiserfs and
+				     * reiserfs_convert_objectid_map_v1()
+				     * so any additions must be updated
+				     * there as well. */
+}  __attribute__ ((__packed__));
+
+#define SB_SIZE (sizeof(struct reiserfs_super_block))
+
+#define REISERFS_VERSION_1 0
+#define REISERFS_VERSION_2 2
+
+
+// on-disk super block fields converted to cpu form
+#define SB_DISK_SUPER_BLOCK(s) ((s)->u.reiserfs_sb.s_rs)
+#define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1))
+#define SB_BLOCKSIZE(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize))
+#define SB_BLOCK_COUNT(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count))
+#define SB_FREE_BLOCKS(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks))
+#define SB_REISERFS_MAGIC(s) \
+        (SB_V1_DISK_SUPER_BLOCK(s)->s_magic)
+#define SB_ROOT_BLOCK(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_root_block))
+#define SB_TREE_HEIGHT(s) \
+        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height))
+#define SB_REISERFS_STATE(s) \
+        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state))
+#define SB_VERSION(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_version))
+#define SB_BMAP_NR(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr))
+
+#define PUT_SB_BLOCK_COUNT(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_block_count = cpu_to_le32(val); } while (0)
+#define PUT_SB_FREE_BLOCKS(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks = cpu_to_le32(val); } while (0)
+#define PUT_SB_ROOT_BLOCK(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_root_block = cpu_to_le32(val); } while (0)
+#define PUT_SB_TREE_HEIGHT(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height = cpu_to_le16(val); } while (0)
+#define PUT_SB_REISERFS_STATE(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state = cpu_to_le16(val); } while (0) 
+#define PUT_SB_VERSION(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_version = cpu_to_le16(val); } while (0)
+#define PUT_SB_BMAP_NR(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr = cpu_to_le16 (val); } while (0)
+
+
+#define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal)
+#define SB_ONDISK_JOURNAL_SIZE(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size))
+#define SB_ONDISK_JOURNAL_1st_BLOCK(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_1st_block))
+#define SB_ONDISK_JOURNAL_DEVICE(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev))
+#define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \
+         le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal))
+
+#define is_block_in_log_or_reserved_area(s, block) \
+         block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \
+         && block < SB_JOURNAL_1st_RESERVED_BLOCK(s) +  \
+         ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \
+         SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s))) 
+
+
 
 				/* used by gcc */
 #define REISERFS_SUPER_MAGIC 0x52654973
@@ -136,34 +235,28 @@
                                    look at the superblock, etc. */
 #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
 #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs"
 
-extern char reiserfs_super_magic_string[];
-extern char reiser2fs_super_magic_string[];
-
-static inline int is_reiserfs_magic_string (const struct reiserfs_super_block * rs)
-{
-    return (!strncmp (rs->s_magic, reiserfs_super_magic_string, 
-		      strlen ( reiserfs_super_magic_string)) ||
-	    !strncmp (rs->s_magic, reiser2fs_super_magic_string, 
-		      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 */
+extern const char reiserfs_3_5_magic_string[];
+extern const char reiserfs_3_6_magic_string[];
+extern const char reiserfs_jr_magic_string[];
+
+int is_reiserfs_3_5 (struct reiserfs_super_block * rs);
+int is_reiserfs_3_6 (struct reiserfs_super_block * rs);
+int is_reiserfs_jr (struct reiserfs_super_block * rs);
+
+/* 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
+#define REISERFS_JOURNAL_OFFSET_IN_BYTES REISERFS_DISK_OFFSET_IN_BYTES
 
 /* 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 +265,58 @@
 #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;
 };
 
+/* there are two formats of keys: 3.5 and 3.6
+ */
+#define KEY_FORMAT_3_5 0
+#define KEY_FORMAT_3_6 1
 
-/* 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
-
-// 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
+
+
+static inline struct reiserfs_inode_info *REISERFS_I(struct inode *inode)
+{
+	return list_entry(inode, struct reiserfs_inode_info, vfs_inode);
+}
+/** this says about version of key of all items (but stat data) the
+    object consists of */
+#define get_inode_item_key_version( inode )                                    \
+    ((REISERFS_I(inode)->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)                                      \
+                REISERFS_I(inode)->i_flags |= i_item_key_version_mask;      \
+            else                                                               \
+                REISERFS_I(inode)->i_flags &= ~i_item_key_version_mask; })
+
+#define get_inode_sd_version(inode)                                            \
+    ((REISERFS_I(inode)->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)                                        \
+                REISERFS_I(inode)->i_flags |= i_stat_data_version_mask;     \
+            else                                                               \
+                REISERFS_I(inode)->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)) || \
@@ -234,7 +332,7 @@
 
 
 /*
- * values for s_state field
+ * values for s_umount_state field
  */
 #define REISERFS_VALID_FS    1
 #define REISERFS_ERROR_FS    2
@@ -246,21 +344,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 {
@@ -286,9 +369,9 @@
     __u64 linear;
 } __attribute__ ((__packed__)) offset_v2_esafe_overlay;
 
-static inline __u16 offset_v2_k_type( struct offset_v2 *v2 )
+static inline __u16 offset_v2_k_type( const struct offset_v2 *v2 )
 {
-    offset_v2_esafe_overlay tmp = *(offset_v2_esafe_overlay *)v2;
+    offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2;
     tmp.linear = le64_to_cpu( tmp.linear );
     return tmp.offset_v2.k_type;
 }
@@ -301,9 +384,9 @@
     tmp->linear = le64_to_cpu(tmp->linear);
 }
  
-static inline loff_t offset_v2_k_offset( struct offset_v2 *v2 )
+static inline loff_t offset_v2_k_offset( const struct offset_v2 *v2 )
 {
-    offset_v2_esafe_overlay tmp = *(offset_v2_esafe_overlay *)v2;
+    offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2;
     tmp.linear = le64_to_cpu( tmp.linear );
     return tmp.offset_v2.k_offset;
 }
@@ -341,18 +424,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 +438,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 +462,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 +469,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 +510,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 +540,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 +554,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 +569,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 +583,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 +595,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 +608,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 +652,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 +674,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 +825,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 +879,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 +1013,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 +1057,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
@@ -1257,24 +1251,18 @@
 #define UNFM_P_SIZE (sizeof(unp_t))
 
 // 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 INODE_PKEY(inode) ((struct key *)(REISERFS_I(inode)->i_key))
 
 #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)
+
+static inline loff_t max_reiserfs_offset (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 +1295,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 +1517,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 )
@@ -1621,6 +1598,7 @@
   __u32 j_last_flush_trans_id ;		/* id of last fully flushed transaction */
   __u32 j_first_unflushed_offset ;      /* offset in the log of where to start replay after a crash */
   __u32 j_mount_id ;
+  /* 12 */ struct journal_params jh_journal;
 } ;
 
 extern task_queue reiserfs_commit_thread_tq ;
@@ -1628,7 +1606,10 @@
 
 /* biggest tunable defines are right here */
 #define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */
-#define JOURNAL_MAX_BATCH   900 /* max blocks to batch into one transaction, don't make this any bigger than 900 */
+#define JOURNAL_TRANS_MAX_DEFAULT 1024   /* biggest possible single transaction, don't change for now (8/3/99) */
+#define JOURNAL_TRANS_MIN_DEFAULT 256
+#define JOURNAL_MAX_BATCH_DEFAULT   900 /* max blocks to batch into one transaction, don't make this any bigger than 900 */
+#define JOURNAL_MIN_RATIO 2
 #define JOURNAL_MAX_COMMIT_AGE 30 
 #define JOURNAL_MAX_TRANS_AGE 30
 #define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9)
@@ -1666,7 +1647,7 @@
 void reiserfs_check_lock_depth(char *caller) ;
 void reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh, int wait) ;
 void reiserfs_restore_prepared_buffer(struct super_block *, struct buffer_head *bh) ;
-int journal_init(struct super_block *) ;
+int journal_init(struct super_block *, const char * j_dev_name, int old_format) ;
 int journal_release(struct reiserfs_transaction_handle*, struct super_block *) ;
 int journal_release_error(struct reiserfs_transaction_handle*, struct super_block *) ;
 int journal_end(struct reiserfs_transaction_handle *, struct super_block *, unsigned long) ;
@@ -1675,17 +1656,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, unsigned long bl, 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 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) ;
@@ -1724,6 +1700,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);
@@ -1761,16 +1741,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);
 }
 
 
@@ -1814,17 +1794,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 i_block_size(inode) ((inode)->i_sb->s_blocksize)
 #define file_size(inode) ((inode)->i_size)
@@ -1833,81 +1808,41 @@
 #define tail_has_to_be_packed(inode) (!dont_have_tails ((inode)->i_sb) &&\
 !STORE_TAIL_IN_UNFM(file_size (inode), tail_size(inode), i_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,
+void make_cpu_key (struct cpu_key * cpu_key, struct inode * inode, loff_t offset,
 		   int type, int key_length);
 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, sector_t 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, 
+				   struct inode * dir, int mode, 
 				   const char * symname, int item_len,
 				   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 )
@@ -2004,8 +1939,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);
@@ -2086,9 +2019,6 @@
 __u32 yura_hash (const signed char *msg, int len);
 __u32 r5_hash (const signed char *msg, int len);
 
-/* version.c */
-const char *reiserfs_get_version_string(void) CONSTF;
-
 /* the ext2 bit routines adjust for big or little endian as
 ** appropriate for the arch, so in our laziness we use them rather
 ** than using the bit routines they call more directly.  These
@@ -2098,83 +2028,6 @@
 #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
    think, that truncate should work without problems on a filesystem
@@ -2184,12 +2037,6 @@
    absolutely safe */
 #define SPARE_SPACE 500
 
-static inline unsigned long reiserfs_get_journal_block(const struct super_block *s) {
-    return le32_to_cpu(SB_DISK_SUPER_BLOCK(s)->s_journal_block) ;
-}
-static inline unsigned long reiserfs_get_journal_orig_size(const struct super_block *s) {
-    return le32_to_cpu(SB_DISK_SUPER_BLOCK(s)->s_orig_journal_size) ;
-}
 
 /* prototypes from ioctl.c */
 int reiserfs_ioctl (struct inode * inode, struct file * filp, 
diff -u --recursive --new-file v2.5.2/linux/include/linux/reiserfs_fs_i.h linux/include/linux/reiserfs_fs_i.h
--- v2.5.2/linux/include/linux/reiserfs_fs_i.h	Thu Nov 22 11:46:19 2001
+++ linux/include/linux/reiserfs_fs_i.h	Tue Jan 29 10:47:05 2002
@@ -3,50 +3,46 @@
 
 #include <linux/list.h>
 
-struct reiserfs_inode_info {
-  __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
+/** 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;
+
 
-  int i_pack_on_close ; // file might need tail packing on close 
+struct reiserfs_inode_info {
+    __u32 i_key [4];/* key is still 4 32 bit integers */
+    /** 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.
+    __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.....
+    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 */
 
-				   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;
-  
-  /* 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 ;
+    struct inode vfs_inode;
 };
-
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h
--- v2.5.2/linux/include/linux/reiserfs_fs_sb.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/reiserfs_fs_sb.h	Tue Jan 29 21:41:12 2002
@@ -8,140 +8,71 @@
 #include <linux/tqueue.h>
 #endif
 
-//
-// super block's field values
-//
-/*#define REISERFS_VERSION 0 undistributed bitmap */
-/*#define REISERFS_VERSION 1 distributed bitmap and resizer*/
-#define REISERFS_VERSION_2 2 /* distributed bitmap, resizer, 64-bit, etc*/
-#define UNSET_HASH 0 // read_super will guess about, what hash names
-                     // in directories were sorted with
-#define TEA_HASH  1
-#define YURA_HASH 2
-#define R5_HASH   3
-#define DEFAULT_HASH R5_HASH
 
-/* this is the on disk super block */
-
-struct reiserfs_super_block
-{
-  __u32 s_block_count;
-  __u32 s_free_blocks;                  /* free blocks count    */
-  __u32 s_root_block;           	/* root block number    */
-  __u32 s_journal_block;           	/* journal block number    */
-  __u32 s_journal_dev;           	/* journal device number  */
-
-  /* Since journal size is currently a #define in a header file, if 
-  ** someone creates a disk with a 16MB journal and moves it to a 
-  ** system with 32MB journal default, they will overflow their journal 
-  ** when they mount the disk.  s_orig_journal_size, plus some checks
-  ** while mounting (inside journal_init) prevent that from happening
-  */
-
-				/* great comment Chris. Thanks.  -Hans */
-
-  __u32 s_orig_journal_size; 		
-  __u32 s_journal_trans_max ;           /* max number of blocks in a transaction.  */
-  __u32 s_journal_block_count ;         /* total size of the journal. can change over time  */
-  __u32 s_journal_max_batch ;           /* max number of blocks to batch into a trans */
-  __u32 s_journal_max_commit_age ;      /* in seconds, how old can an async commit be */
-  __u32 s_journal_max_trans_age ;       /* in seconds, how old can a transaction be */
-  __u16 s_blocksize;                   	/* block size           */
-  __u16 s_oid_maxsize;			/* max size of object id array, see get_objectid() commentary  */
-  __u16 s_oid_cursize;			/* current size of object id array */
-  __u16 s_state;                       	/* valid or error       */
-  char s_magic[12];                     /* reiserfs magic string indicates that file system is reiserfs */
-  __u32 s_hash_function_code;		/* indicate, what hash function is being use to sort names in a directory*/
-  __u16 s_tree_height;                  /* height of disk tree */
-  __u16 s_bmap_nr;                      /* amount of bitmap blocks needed to address each block of file system */
-  __u16 s_version;		/* I'd prefer it if this was a string,
-                                   something like "3.6.4", and maybe
-                                   16 bytes long mostly unused. We
-                                   don't need to save bytes in the
-                                   superblock. -Hans */
-  __u16 s_reserved;
-  __u32 s_inode_generation;
-  char s_unused[124] ;			/* zero filled by mkreiserfs */
-} __attribute__ ((__packed__));
-
-#define SB_SIZE (sizeof(struct reiserfs_super_block))
 /* struct reiserfs_super_block accessors/mutators
  * since this is a disk structure, it will always be in 
  * little endian format. */
-#define sb_block_count(sbp)           (le32_to_cpu((sbp)->s_block_count))
-#define set_sb_block_count(sbp,v)     ((sbp)->s_block_count = cpu_to_le32(v))
-#define sb_free_blocks(sbp)           (le32_to_cpu((sbp)->s_free_blocks))
-#define set_sb_free_blocks(sbp,v)     ((sbp)->s_free_blocks = cpu_to_le32(v))
-#define sb_root_block(sbp)            (le32_to_cpu((sbp)->s_root_block))
-#define set_sb_root_block(sbp,v)      ((sbp)->s_root_block = cpu_to_le32(v))
-#define sb_journal_block(sbp)         (le32_to_cpu((sbp)->s_journal_block))
-#define set_sb_journal_block(sbp,v)   ((sbp)->s_journal_block = cpu_to_le32(v))
-#define sb_journal_dev(sbp)           (le32_to_cpu((sbp)->s_journal_dev))
-#define set_sb_journal_dev(sbp,v)     ((sbp)->s_journal_dev = cpu_to_le32(v))
-#define sb_orig_journal_size(sbp)   (le32_to_cpu((sbp)->s_orig_journal_size))
-#define set_sb_orig_journal_size(sbp,v) \
-                            ((sbp)->s_orig_journal_size = cpu_to_le32(v))
-#define sb_journal_trans_max(sbp)     (le32_to_cpu((sbp)->s_journal_trans_max))
-#define set_journal_trans_max(sbp,v) \
-                            ((sbp)->s_journal_trans_max = cpu_to_le32(v))
-#define sb_journal_block_count(sbp)  (le32_to_cpu((sbp)->journal_block_count))
-#define sb_set_journal_block_count(sbp,v) \
-                            ((sbp)->s_journal_block_count = cpu_to_le32(v))
-#define sb_journal_max_batch(sbp)     (le32_to_cpu((sbp)->s_journal_max_batch))
-#define set_sb_journal_max_batch(sbp,v) \
-                            ((sbp)->s_journal_max_batch = cpu_to_le32(v))
-#define sb_jourmal_max_commit_age(sbp) \
-                            (le32_to_cpu((sbp)->s_journal_max_commit_age))
-#define set_sb_journal_max_commit_age(sbp,v) \
-                            ((sbp)->s_journal_max_commit_age = cpu_to_le32(v))
-#define sb_jourmal_max_trans_age(sbp) \
-                            (le32_to_cpu((sbp)->s_journal_max_trans_age))
-#define set_sb_journal_max_trans_age(sbp,v) \
-                            ((sbp)->s_journal_max_trans_age = cpu_to_le32(v))
-#define sb_blocksize(sbp)             (le16_to_cpu((sbp)->s_blocksize))
-#define set_sb_blocksize(sbp,v)       ((sbp)->s_blocksize = cpu_to_le16(v))
-#define sb_oid_maxsize(sbp)           (le16_to_cpu((sbp)->s_oid_maxsize))
-#define set_sb_oid_maxsize(sbp,v)     ((sbp)->s_oid_maxsize = cpu_to_le16(v))
-#define sb_oid_cursize(sbp)           (le16_to_cpu((sbp)->s_oid_cursize))
-#define set_sb_oid_cursize(sbp,v)     ((sbp)->s_oid_cursize = cpu_to_le16(v))
-#define sb_state(sbp)                 (le16_to_cpu((sbp)->s_state))
-#define set_sb_state(sbp,v)           ((sbp)->s_state = cpu_to_le16(v))
+#define sb_block_count(sbp)         (le32_to_cpu((sbp)->s_v1.s_block_count))
+#define set_sb_block_count(sbp,v)   ((sbp)->s_v1.s_block_count = cpu_to_le32(v))
+#define sb_free_blocks(sbp)         (le32_to_cpu((sbp)->s_v1.s_free_blocks))
+#define set_sb_free_blocks(sbp,v)   ((sbp)->s_v1.s_free_blocks = cpu_to_le32(v))
+#define sb_root_block(sbp)          (le32_to_cpu((sbp)->s_v1.s_root_block))
+#define set_sb_root_block(sbp,v)    ((sbp)->s_v1.s_root_block = cpu_to_le32(v))
+
+#define sb_jp_journal_1st_block(sbp)  \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_1st_block))
+#define set_sb_jp_journal_1st_block(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_1st_block = cpu_to_le32(v))
+#define sb_jp_journal_dev(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_dev))
+#define set_sb_jp_journal_dev(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_dev = cpu_to_le32(v))
+#define sb_jp_journal_size(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_size))
+#define set_sb_jp_journal_size(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_size = cpu_to_le32(v))
+#define sb_jp_journal_trans_max(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_trans_max))
+#define set_sb_jp_journal_trans_max(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_trans_max = cpu_to_le32(v))
+#define sb_jp_journal_magic(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_magic))
+#define set_sb_jp_journal_magic(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_magic = cpu_to_le32(v))
+#define sb_jp_journal_max_batch(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_batch))
+#define set_sb_jp_journal_max_batch(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_max_batch = cpu_to_le32(v))
+#define sb_jp_jourmal_max_commit_age(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_commit_age))
+#define set_sb_jp_journal_max_commit_age(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_max_commit_age = cpu_to_le32(v))
+
+#define sb_blocksize(sbp)          (le16_to_cpu((sbp)->s_v1.s_blocksize))
+#define set_sb_blocksize(sbp,v)    ((sbp)->s_v1.s_blocksize = cpu_to_le16(v))
+#define sb_oid_maxsize(sbp)        (le16_to_cpu((sbp)->s_v1.s_oid_maxsize))
+#define set_sb_oid_maxsize(sbp,v)  ((sbp)->s_v1.s_oid_maxsize = cpu_to_le16(v))
+#define sb_oid_cursize(sbp)        (le16_to_cpu((sbp)->s_v1.s_oid_cursize))
+#define set_sb_oid_cursize(sbp,v)  ((sbp)->s_v1.s_oid_cursize = cpu_to_le16(v))
+#define sb_umount_state(sbp)       (le16_to_cpu((sbp)->s_v1.s_umount_state))
+#define set_sb_umount_state(sbp,v) ((sbp)->s_v1.s_umount_state = cpu_to_le16(v))
+#define sb_fs_state(sbp)           (le16_to_cpu((sbp)->s_v1.s_fs_state))
+#define set_sb_fs_state(sbp,v)     ((sbp)->s_v1.s_fs_state = cpu_to_le16(v)) 
 #define sb_hash_function_code(sbp) \
-                            (le32_to_cpu((sbp)->s_hash_function_code))
+              (le32_to_cpu((sbp)->s_v1.s_hash_function_code))
 #define set_sb_hash_function_code(sbp,v) \
-                            ((sbp)->s_hash_function_code = cpu_to_le32(v))
-#define sb_tree_height(sbp)           (le16_to_cpu((sbp)->s_tree_height))
-#define set_sb_tree_height(sbp,v)     ((sbp)->s_tree_height = cpu_to_le16(v))
-#define sb_bmap_nr(sbp)               (le16_to_cpu((sbp)->s_bmap_nr))
-#define set_sb_bmap_nr(sbp,v)         ((sbp)->s_bmap_nr = cpu_to_le16(v))
-#define sb_version(sbp)               (le16_to_cpu((sbp)->s_version))
-#define set_sb_version(sbp,v)         ((sbp)->s_version = cpu_to_le16(v))
-
-/* this is the super from 3.5.X, where X >= 10 */
-struct reiserfs_super_block_v1
-{
-  __u32 s_block_count;			/* blocks count         */
-  __u32 s_free_blocks;                  /* free blocks count    */
-  __u32 s_root_block;           	/* root block number    */
-  __u32 s_journal_block;           	/* journal block number    */
-  __u32 s_journal_dev;           	/* journal device number  */
-  __u32 s_orig_journal_size; 		/* size of the journal on FS creation.  used to make sure they don't overflow it */
-  __u32 s_journal_trans_max ;           /* max number of blocks in a transaction.  */
-  __u32 s_journal_block_count ;         /* total size of the journal. can change over time  */
-  __u32 s_journal_max_batch ;           /* max number of blocks to batch into a trans */
-  __u32 s_journal_max_commit_age ;      /* in seconds, how old can an async commit be */
-  __u32 s_journal_max_trans_age ;       /* in seconds, how old can a transaction be */
-  __u16 s_blocksize;                   	/* block size           */
-  __u16 s_oid_maxsize;			/* max size of object id array, see get_objectid() commentary  */
-  __u16 s_oid_cursize;			/* current size of object id array */
-  __u16 s_state;                       	/* valid or error       */
-  char s_magic[16];                     /* reiserfs magic string indicates that file system is reiserfs */
-  __u16 s_tree_height;                  /* height of disk tree */
-  __u16 s_bmap_nr;                      /* amount of bitmap blocks needed to address each block of file system */
-  __u32 s_reserved;
-} __attribute__ ((__packed__));
-
-#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))
+              ((sbp)->s_v1.s_hash_function_code = cpu_to_le32(v))
+#define sb_tree_height(sbp)        (le16_to_cpu((sbp)->s_v1.s_tree_height))
+#define set_sb_tree_height(sbp,v)  ((sbp)->s_v1.s_tree_height = cpu_to_le16(v))
+#define sb_bmap_nr(sbp)            (le16_to_cpu((sbp)->s_v1.s_bmap_nr))
+#define set_sb_bmap_nr(sbp,v)      ((sbp)->s_v1.s_bmap_nr = cpu_to_le16(v))
+#define sb_version(sbp)            (le16_to_cpu((sbp)->s_v1.s_version))
+#define set_sb_version(sbp,v)      ((sbp)->s_v1.s_version = cpu_to_le16(v))
+
+#define sb_reserved_for_journal(sbp) \
+              (le16_to_cpu((sbp)->s_v1.s_reserved_for_journal))
+#define set_sb_reserved_for_journal(sbp,v) \
+              ((sbp)->s_v1.s_reserved_for_journal = cpu_to_le16(v))
 
 /* LOGGING -- */
 
@@ -170,7 +101,6 @@
 				/* we have a node size define somewhere in reiserfs_fs.h. -Hans */
 #define JOURNAL_BLOCK_SIZE  4096 /* BUG gotta get rid of this */
 #define JOURNAL_MAX_CNODE   1500 /* max cnodes to allocate. */
-#define JOURNAL_TRANS_MAX 1024   /* biggest possible single transaction, don't change for now (8/3/99) */
 #define JOURNAL_HASH_SIZE 8192   
 #define JOURNAL_NUM_BITMAPS 5 /* number of copies of the bitmaps to have floating.  Must be >= 2 */
 #define JOURNAL_LIST_COUNT 64
@@ -263,7 +193,12 @@
   struct buffer_head ** j_ap_blocks ; /* journal blocks on disk */
   struct reiserfs_journal_cnode *j_last ; /* newest journal block */
   struct reiserfs_journal_cnode *j_first ; /*  oldest journal block.  start here for traverse */
-				
+
+  kdev_t               j_dev;
+  struct file         *j_dev_file;
+  struct block_device *j_dev_bd;  
+  int j_1st_reserved_block;     /* first block on s_dev of reserved area journal */        
+	
   int j_state ;			
   unsigned long j_trans_id ;
   unsigned long j_mount_id ;
@@ -294,13 +229,18 @@
   int j_cnode_used ;	      /* number of cnodes on the used list */
   int j_cnode_free ;          /* number of cnodes on the free list */
 
+  unsigned int s_journal_trans_max ;           /* max number of blocks in a transaction.  */
+  unsigned int s_journal_max_batch ;           /* max number of blocks to batch into a trans */
+  unsigned int s_journal_max_commit_age ;      /* in seconds, how old can an async commit be */
+  unsigned int s_journal_max_trans_age ;       /* in seconds, how old can a transaction be */  
+
   struct reiserfs_journal_cnode *j_cnode_free_list ;
   struct reiserfs_journal_cnode *j_cnode_free_orig ; /* orig pointer returned from vmalloc */
 
   int j_free_bitmap_nodes ;
   int j_used_bitmap_nodes ;
   struct list_head j_bitmap_nodes ;
-  struct inode j_dummy_inode ;
+  struct list_head j_dirty_buffers ;
   struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS] ;	/* array of bitmaps to record the deleted blocks */
   struct reiserfs_journal_list j_journal_list[JOURNAL_LIST_COUNT] ;	    /* array of all the journal lists */
   struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE] ; 	    /* hash table for real buffer heads in current trans */ 
@@ -407,6 +347,8 @@
 				/* To be obsoleted soon by per buffer seals.. -Hans */
     atomic_t s_generation_counter; // increased by one every time the
     // tree gets re-balanced
+    unsigned long s_properties;    /* File system properties. Currently holds
+				     on-disk FS format */
     
     /* session statistics */
     int s_kmallocs;
@@ -420,11 +362,19 @@
     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;
 };
 
+/* Definitions of reiserfs on-disk properties: */
+#define REISERFS_3_5 0
+#define REISERFS_3_6 1
 
+/* Mount options */
 #define NOTAIL 0  /* -o notail: no tails will be created in a session */
 #define REPLAYONLY 3 /* replay journal and return 0. Use by fsck */
 #define REISERFS_NOLOG 4      /* -o nolog: turn journalling off */
@@ -474,7 +424,8 @@
 #define dont_have_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << NOTAIL))
 #define replay_only(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REPLAYONLY))
 #define reiserfs_dont_log(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NOLOG))
-#define old_format_only(s) ((SB_VERSION(s) != REISERFS_VERSION_2) && !((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_CONVERT)))
+#define old_format_only(s) ((s)->u.reiserfs_sb.s_properties & (1 << REISERFS_3_5))
+#define convert_reiserfs(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_CONVERT))
 
 
 void reiserfs_file_buffer (struct buffer_head * bh, int list);
@@ -490,29 +441,19 @@
 
 #define SB_BUFFER_WITH_SB(s) ((s)->u.reiserfs_sb.s_sbh)
 #define SB_JOURNAL(s) ((s)->u.reiserfs_sb.s_journal)
+#define SB_JOURNAL_1st_RESERVED_BLOCK(s) (SB_JOURNAL(s)->j_1st_reserved_block)
 #define SB_JOURNAL_LIST(s) (SB_JOURNAL(s)->j_journal_list)
 #define SB_JOURNAL_LIST_INDEX(s) (SB_JOURNAL(s)->j_journal_list_index) 
 #define SB_JOURNAL_LEN_FREE(s) (SB_JOURNAL(s)->j_journal_len_free) 
 #define SB_AP_BITMAP(s) ((s)->u.reiserfs_sb.s_ap_bitmap)
 
+#define SB_DISK_JOURNAL_HEAD(s) (SB_JOURNAL(s)->j_header_bh->)
 
-// on-disk super block fields converted to cpu form
-#define SB_DISK_SUPER_BLOCK(s)        ((s)->u.reiserfs_sb.s_rs)
-#define SB_BLOCK_COUNT(s)             sb_block_count (SB_DISK_SUPER_BLOCK(s))
-#define SB_FREE_BLOCKS(s)             sb_free_blocks (SB_DISK_SUPER_BLOCK(s))
-#define SB_REISERFS_MAGIC(s)          (SB_DISK_SUPER_BLOCK(s)->s_magic)
-#define SB_ROOT_BLOCK(s)              sb_root_block (SB_DISK_SUPER_BLOCK(s))
-#define SB_TREE_HEIGHT(s)             sb_tree_height (SB_DISK_SUPER_BLOCK(s))
-#define SB_REISERFS_STATE(s)          sb_state (SB_DISK_SUPER_BLOCK(s))
-#define SB_VERSION(s)                 sb_version (SB_DISK_SUPER_BLOCK(s))
-#define SB_BMAP_NR(s)                 sb_bmap_nr(SB_DISK_SUPER_BLOCK(s))
-
-#define PUT_SB_BLOCK_COUNT(s, val)    do { set_sb_block_count( SB_DISK_SUPER_BLOCK(s), val); } while (0)
-#define PUT_SB_FREE_BLOCKS(s, val)    do { set_sb_free_blocks( SB_DISK_SUPER_BLOCK(s), val); } while (0)
-#define PUT_SB_ROOT_BLOCK(s, val)     do { set_sb_root_block( SB_DISK_SUPER_BLOCK(s), val); } while (0)
-#define PUT_SB_TREE_HEIGHT(s, val)    do { set_sb_tree_height( SB_DISK_SUPER_BLOCK(s), val); } while (0)
-#define PUT_SB_REISERFS_STATE(s, val) do { set_sb_state( SB_DISK_SUPER_BLOCK(s), val); } while (0) 
-#define PUT_SB_VERSION(s, val)        do { set_sb_version( SB_DISK_SUPER_BLOCK(s), val); } while (0)
-#define PUT_SB_BMAP_NR(s, val)        do { set_sb_bmap_nr( SB_DISK_SUPER_BLOCK(s), val); } while (0)
+#define SB_JOURNAL_TRANS_MAX(s)      (SB_JOURNAL(s)->s_journal_trans_max)
+#define SB_JOURNAL_MAX_BATCH(s)      (SB_JOURNAL(s)->s_journal_max_batch)
+#define SB_JOURNAL_MAX_COMMIT_AGE(s) (SB_JOURNAL(s)->s_journal_max_commit_age)
+#define SB_JOURNAL_MAX_TRANS_AGE(s)  (SB_JOURNAL(s)->s_journal_max_trans_age)
+#define SB_JOURNAL_DEV(s)            (SB_JOURNAL(s)->j_dev)
+  
 
 #endif	/* _LINUX_REISER_FS_SB */
diff -u --recursive --new-file v2.5.2/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
--- v2.5.2/linux/include/linux/rtnetlink.h	Thu Jul 26 14:01:13 2001
+++ linux/include/linux/rtnetlink.h	Wed Jan 23 15:28:40 2002
@@ -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,23 +576,19 @@
 #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);
 extern void rtnetlink_init(void);
 
 #define ASSERT_RTNL() do { if (down_trylock(&rtnl_sem) == 0)  { up(&rtnl_sem); \
-printk("RTNL: assertion failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } \
+printk("RTNL: assertion failed at " __FILE__ "(%d)\n", __LINE__); } \
 		   } while(0);
-#define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
+#define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d)\n", __LINE__); }
 
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.5.2/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.5.2/linux/include/linux/sched.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/sched.h	Tue Jan 29 21:41:12 2002
@@ -25,6 +25,7 @@
 #include <linux/signal.h>
 #include <linux/securebits.h>
 #include <linux/fs_struct.h>
+#include <linux/compiler.h>
 
 struct exec_domain;
 
@@ -136,16 +137,21 @@
 extern rwlock_t tasklist_lock;
 extern spinlock_t mmlist_lock;
 
+typedef struct task_struct task_t;
+
 extern void sched_init(void);
-extern void init_idle(void);
+extern void init_idle(task_t *idle, int cpu);
 extern void show_state(void);
 extern void cpu_init (void);
 extern void trap_init(void);
 extern void update_process_times(int user);
 extern void update_one_process(struct task_struct *p, unsigned long user,
 			       unsigned long system, int cpu);
-extern void expire_task(struct task_struct *p);
-extern void idle_tick(void);
+extern void scheduler_tick(struct task_struct *p);
+extern void sched_task_migrated(struct task_struct *p);
+extern void smp_migrate_task(int cpu, task_t *task);
+extern unsigned long cache_decay_ticks;
+
 
 #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
@@ -156,44 +162,7 @@
 extern int start_context_thread(void);
 extern int current_is_keventd(void);
 
-/*
- * The default fd array needs to be at least BITS_PER_LONG,
- * as this is the granularity returned by copy_fdset().
- */
-#define NR_OPEN_DEFAULT BITS_PER_LONG
-
 struct namespace;
-/*
- * Open file table structure
- */
-struct files_struct {
-	atomic_t count;
-	rwlock_t file_lock;	/* Protects all the below members.  Nests inside tsk->alloc_lock */
-	int max_fds;
-	int max_fdset;
-	int next_fd;
-	struct file ** fd;	/* current fd array */
-	fd_set *close_on_exec;
-	fd_set *open_fds;
-	fd_set close_on_exec_init;
-	fd_set open_fds_init;
-	struct file * fd_array[NR_OPEN_DEFAULT];
-};
-
-#define INIT_FILES \
-{ 							\
-	count:		ATOMIC_INIT(1), 		\
-	file_lock:	RW_LOCK_UNLOCKED, 		\
-	max_fds:	NR_OPEN_DEFAULT, 		\
-	max_fdset:	__FD_SETSIZE, 			\
-	next_fd:	0, 				\
-	fd:		&init_files.fd_array[0], 	\
-	close_on_exec:	&init_files.close_on_exec_init, \
-	open_fds:	&init_files.open_fds_init, 	\
-	close_on_exec_init: { { 0, } }, 		\
-	open_fds_init:	{ { 0, } }, 			\
-	fd_array:	{ NULL, } 			\
-}
 
 /* Maximum number of active map areas.. This is a random (large) number */
 #define MAX_MAP_COUNT	(65536)
@@ -230,17 +199,6 @@
 
 extern int mmlist_nr;
 
-#define INIT_MM(name) \
-{			 				\
-	mm_rb:		RB_ROOT,			\
-	pgd:		swapper_pg_dir, 		\
-	mm_users:	ATOMIC_INIT(2), 		\
-	mm_count:	ATOMIC_INIT(1), 		\
-	mmap_sem:	__RWSEM_INITIALIZER(name.mmap_sem), \
-	page_table_lock: SPIN_LOCK_UNLOCKED, 		\
-	mmlist:		LIST_HEAD_INIT(name.mmlist),	\
-}
-
 struct signal_struct {
 	atomic_t		count;
 	struct k_sigaction	action[_NSIG];
@@ -248,12 +206,6 @@
 };
 
 
-#define INIT_SIGNALS {	\
-	count:		ATOMIC_INIT(1), 		\
-	action:		{ {{0,}}, }, 			\
-	siglock:	SPIN_LOCK_UNLOCKED 		\
-}
-
 /*
  * Some day this will be a full-fledged user tracking system..
  */
@@ -275,22 +227,31 @@
 extern struct user_struct root_user;
 #define INIT_USER (&root_user)
 
-typedef struct task_struct task_t;
 typedef struct prio_array prio_array_t;
 
+/* this struct must occupy one 32-bit chunk so that is can be read in one go */
+struct task_work {
+	__s8	need_resched;
+	__u8	syscall_trace;	/* count of syscall interceptors */
+	__u8	sigpending;
+	__u8	notify_resume;	/* request for notification on
+				   userspace execution resumption */
+} __attribute__((packed));
+
 struct task_struct {
 	/*
 	 * offsets of these are hardcoded elsewhere - touch with care
 	 */
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	unsigned long flags;	/* per process flags, defined below */
-	int sigpending;
+	volatile struct task_work work;
+
 	mm_segment_t addr_limit;	/* thread address space:
 					 	0-0xBFFFFFFF for user-thead
 						0-0xFFFFFFFF for kernel-thread
 					 */
 	struct exec_domain *exec_domain;
-	volatile long need_resched;
+	long __pad;
 	unsigned long ptrace;
 
 	int lock_depth;		/* Lock depth */
@@ -305,7 +266,9 @@
 	prio_array_t *array;
 
 	unsigned int time_slice;
-	unsigned long sleep_jtime;
+
+	unsigned long sleep_avg;
+	unsigned long sleep_timestamp;
 
 	unsigned long policy;
 	unsigned long cpus_allowed;
@@ -428,7 +391,7 @@
  */
 
 #define PT_PTRACED	0x00000001
-#define PT_TRACESYS	0x00000002
+#define PT_SYSCALLTRACE	0x00000002	/* T if syscall_trace is +1 for ptrace() */
 #define PT_DTRACE	0x00000004	/* delayed trace (used on m68k, i386) */
 #define PT_TRACESYSGOOD	0x00000008
 #define PT_PTRACE_CAP	0x00000010	/* ptracer can follow suid-exec */
@@ -444,56 +407,58 @@
  * them out at 128 to make it easier to search the
  * scheduler bitmap.
  */
-#define MAX_RT_PRIO	128
+#define MAX_RT_PRIO		128
 /*
  * The lower the priority of a process, the more likely it is
  * to run. Priority of a process goes from 0 to 167. The 0-99
  * priority range is allocated to RT tasks, the 128-167 range
  * is for SCHED_OTHER tasks.
  */
-#define MAX_PRIO	(MAX_RT_PRIO+40)
-#define DEF_USER_NICE	0
+#define MAX_PRIO		(MAX_RT_PRIO + 40)
 
 /*
  * Scales user-nice values [ -20 ... 0 ... 19 ]
- * to static priority [ 24 ... 63 (MAX_PRIO-1) ]
+ * to static priority [ 128 ... 167 (MAX_PRIO-1) ]
  *
- * User-nice value of -20 == static priority 24, and
- * user-nice value 19 == static priority 63. The lower
+ * User-nice value of -20 == static priority 128, and
+ * user-nice value 19 == static priority 167. The lower
  * the priority value, the higher the task's priority.
- *
- * Note that while static priority cannot go below 24,
- * the priority of a process can go as low as 0.
  */
-#define NICE_TO_PRIO(n)	(MAX_PRIO-1 + (n) - 19)
-
-#define DEF_PRIO NICE_TO_PRIO(DEF_USER_NICE)
+#define NICE_TO_PRIO(n)		(MAX_RT_PRIO + (n) + 20)
+#define DEF_USER_NICE		0
 
 /*
- * Default timeslice is 90 msecs, maximum is 150 msecs.
- * Minimum timeslice is 20 msecs.
+ * Default timeslice is 150 msecs, maximum is 300 msecs.
+ * Minimum timeslice is 10 msecs.
+ *
+ * These are the 'tuning knobs' of the scheduler:
  */
-#define MIN_TIMESLICE	( 20 * HZ / 1000)
-#define MAX_TIMESLICE	(150 * HZ / 1000)
+#define MIN_TIMESLICE		( 10 * HZ / 1000)
+#define MAX_TIMESLICE		(300 * HZ / 1000)
+#define CHILD_FORK_PENALTY	95
+#define PARENT_FORK_PENALTY	100
+#define EXIT_WEIGHT		3
+#define PRIO_INTERACTIVE_RATIO	20
+#define PRIO_CPU_HOG_RATIO	60
+#define PRIO_BONUS_RATIO	70
+#define INTERACTIVE_DELTA	3
+#define MAX_SLEEP_AVG		(2*HZ)
+#define STARVATION_LIMIT	(2*HZ)
 
-#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
-#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
+#define USER_PRIO(p)		((p)-MAX_RT_PRIO)
+#define MAX_USER_PRIO		(USER_PRIO(MAX_PRIO))
 
 /*
- * PRIO_TO_TIMESLICE scales priority values [ 100 ... 139  ]
- * to initial time slice values [ MAX_TIMESLICE (150 msec) ... 2 ]
+ * NICE_TO_TIMESLICE scales nice values [ -20 ... 19 ]
+ * to time slice values.
  *
  * The higher a process's priority, the bigger timeslices
  * it gets during one round of execution. But even the lowest
  * priority process gets MIN_TIMESLICE worth of execution time.
  */
-#define PRIO_TO_TIMESLICE(p) \
-	((( (MAX_USER_PRIO-1-USER_PRIO(p))*(MAX_TIMESLICE-MIN_TIMESLICE) + \
-		MAX_USER_PRIO-1) / MAX_USER_PRIO) + MIN_TIMESLICE)
-
-#define RT_PRIO_TO_TIMESLICE(p) \
-	((( (MAX_RT_PRIO-(p)-1)*(MAX_TIMESLICE-MIN_TIMESLICE) + \
-			MAX_RT_PRIO-1) / MAX_RT_PRIO) + MIN_TIMESLICE)
+
+#define NICE_TO_TIMESLICE(n) (MIN_TIMESLICE + \
+	((MAX_TIMESLICE - MIN_TIMESLICE) * (19-(n))) / 39)
 
 extern void set_cpus_allowed(task_t *p, unsigned long new_mask);
 extern void set_user_nice(task_t *p, long nice);
@@ -505,53 +470,6 @@
  */
 extern struct exec_domain	default_exec_domain;
 
-/*
- *  INIT_TASK is used to set up the first task table, touch at
- * your own risk!. Base=0, limit=0x1fffff (=2MB)
- */
-#define INIT_TASK(tsk)	\
-{									\
-    state:		0,						\
-    flags:		0,						\
-    sigpending:		0,						\
-    addr_limit:		KERNEL_DS,					\
-    exec_domain:	&default_exec_domain,				\
-    lock_depth:		-1,						\
-    __nice:		DEF_USER_NICE,					\
-    policy:		SCHED_OTHER,					\
-    cpus_allowed:	-1,						\
-    mm:			NULL,						\
-    active_mm:		&init_mm,					\
-    run_list:		LIST_HEAD_INIT(tsk.run_list),			\
-    time_slice:		PRIO_TO_TIMESLICE(DEF_PRIO),			\
-    next_task:		&tsk,						\
-    prev_task:		&tsk,						\
-    p_opptr:		&tsk,						\
-    p_pptr:		&tsk,						\
-    thread_group:	LIST_HEAD_INIT(tsk.thread_group),		\
-    wait_chldexit:	__WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
-    real_timer:		{						\
-	function:		it_real_fn				\
-    },									\
-    cap_effective:	CAP_INIT_EFF_SET,				\
-    cap_inheritable:	CAP_INIT_INH_SET,				\
-    cap_permitted:	CAP_FULL_SET,					\
-    keep_capabilities:	0,						\
-    rlim:		INIT_RLIMITS,					\
-    user:		INIT_USER,					\
-    comm:		"swapper",					\
-    thread:		INIT_THREAD,					\
-    fs:			&init_fs,					\
-    files:		&init_files,					\
-    sigmask_lock:	SPIN_LOCK_UNLOCKED,				\
-    sig:		&init_signals,					\
-    pending:		{ NULL, &tsk.pending.head, {{0}}},		\
-    blocked:		{{0}},						\
-    alloc_lock:		SPIN_LOCK_UNLOCKED,				\
-    journal_info:	NULL,						\
-}
-
-
 #ifndef INIT_TASK_SIZE
 # define INIT_TASK_SIZE	2048*sizeof(long)
 #endif
@@ -667,7 +585,18 @@
 
 static inline int signal_pending(struct task_struct *p)
 {
-	return (p->sigpending != 0);
+	return (p->work.sigpending != 0);
+}
+  
+static inline int need_resched(void)
+{
+	return unlikely(current->work.need_resched != 0);
+}
+
+static inline void cond_resched(void)
+{
+	if (need_resched())
+		schedule();
 }
 
 /*
@@ -706,7 +635,7 @@
 
 static inline void recalc_sigpending(struct task_struct *t)
 {
-	t->sigpending = has_pending_signals(&t->pending.signal, &t->blocked);
+	t->work.sigpending = has_pending_signals(&t->pending.signal, &t->blocked);
 }
 
 /* True if we are on the alternate signal stack.  */
diff -u --recursive --new-file v2.5.2/linux/include/linux/shmem_fs.h linux/include/linux/shmem_fs.h
--- v2.5.2/linux/include/linux/shmem_fs.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/shmem_fs.h	Mon Jan 21 15:37:32 2002
@@ -28,7 +28,7 @@
 	unsigned long		swapped;
 	int			locked;     /* into memory */
 	struct list_head	list;
-	struct inode	       *inode;
+	struct inode		vfs_inode;
 };
 
 struct shmem_sb_info {
@@ -39,6 +39,9 @@
 	spinlock_t    stat_lock;
 };
 
-#define SHMEM_I(inode)  (&inode->u.shmem_i)
+static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
+{
+	return list_entry(inode, struct shmem_inode_info, vfs_inode);
+}
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- v2.5.2/linux/include/linux/smb_fs.h	Tue Oct  2 17:03:34 2001
+++ linux/include/linux/smb_fs.h	Mon Jan 28 13:20:34 2002
@@ -10,6 +10,7 @@
 #define _LINUX_SMB_FS_H
 
 #include <linux/smb.h>
+#include <linux/smb_fs_i.h>
 
 /*
  * ioctl commands
@@ -28,6 +29,10 @@
 #include <linux/smb_mount.h>
 #include <asm/unaligned.h>
 
+static inline struct smb_inode_info *SMB_I(struct inode *inode)
+{
+	return list_entry(inode, struct smb_inode_info, vfs_inode);
+}
 
 /* macro names are short for word, double-word, long value (?) */
 #define WVAL(buf,pos) \
@@ -157,7 +162,7 @@
 static inline int
 smb_is_open(struct inode *i)
 {
-	return (i->u.smbfs_i.open == server_from_inode(i)->generation);
+	return (SMB_I(i)->open == server_from_inode(i)->generation);
 }
 
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/smb_fs_i.h linux/include/linux/smb_fs_i.h
--- v2.5.2/linux/include/linux/smb_fs_i.h	Thu Nov 22 11:46:18 2001
+++ linux/include/linux/smb_fs_i.h	Mon Jan 28 13:20:34 2002
@@ -30,6 +30,8 @@
 	unsigned long oldmtime;	/* last time refreshed */
 	unsigned long closed;	/* timestamp when closed */
 	unsigned openers;	/* number of fileid users */
+
+	struct inode vfs_inode;	/* must be at the end */
 };
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- v2.5.2/linux/include/linux/sysv_fs.h	Fri Nov  9 13:45:35 2001
+++ linux/include/linux/sysv_fs.h	Wed Jan 23 15:32:20 2002
@@ -21,6 +21,15 @@
 #include <linux/sched.h>	/* declares wake_up() */
 #include <linux/sysv_fs_sb.h>	/* defines the sv_... shortcuts */
 
+/* temporary hack. */
+#include <linux/sysv_fs_i.h>
+static inline struct sysv_inode_info *SYSV_I(struct inode *inode)
+{
+	/* I think list_entry should have a more descriptive name..  --hch */
+	return list_entry(inode, struct sysv_inode_info, vfs_inode);
+}
+/* end temporary hack. */
+
 
 /* Layout on disk */
 /* ============== */
diff -u --recursive --new-file v2.5.2/linux/include/linux/sysv_fs_i.h linux/include/linux/sysv_fs_i.h
--- v2.5.2/linux/include/linux/sysv_fs_i.h	Fri Nov  9 13:45:35 2001
+++ linux/include/linux/sysv_fs_i.h	Wed Jan 23 15:32:20 2002
@@ -11,6 +11,7 @@
 				 * then 1 triple indirection block.
 				 */
 	u32 i_dir_start_lookup;
+	struct inode  vfs_inode;
 };
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/tcp_diag.h linux/include/linux/tcp_diag.h
--- v2.5.2/linux/include/linux/tcp_diag.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/tcp_diag.h	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/include/linux/time.h linux/include/linux/time.h
--- v2.5.2/linux/include/linux/time.h	Thu Nov 22 11:46:18 2001
+++ linux/include/linux/time.h	Tue Jan 29 21:41:09 2002
@@ -100,8 +100,6 @@
 #ifdef __KERNEL__
 extern void do_gettimeofday(struct timeval *tv);
 extern void do_settimeofday(struct timeval *tv);
-extern void get_fast_time(struct timeval *tv);
-extern void (*do_get_fast_time)(struct timeval *);
 #endif
 
 #define FD_SETSIZE		__FD_SETSIZE
diff -u --recursive --new-file v2.5.2/linux/include/linux/udf_fs_i.h linux/include/linux/udf_fs_i.h
--- v2.5.2/linux/include/linux/udf_fs_i.h	Mon Jul  2 14:10:02 2001
+++ linux/include/linux/udf_fs_i.h	Wed Jan 23 15:32:20 2002
@@ -47,6 +47,7 @@
 	unsigned i_strat_4096 : 1;
 	unsigned i_new_inode : 1;
 	unsigned reserved : 26;
+	struct inode vfs_inode;
 };
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h
--- v2.5.2/linux/include/linux/ufs_fs.h	Thu Nov 22 11:46:18 2001
+++ linux/include/linux/ufs_fs.h	Mon Jan 21 15:37:32 2002
@@ -223,7 +223,7 @@
 
 #define	UFS_MAXNAMLEN 255
 #define UFS_MAXMNTLEN 512
-#define UFS_MAXCSBUFS 31
+/* #define UFS_MAXCSBUFS 31 */
 #define UFS_LINK_MAX 32000
 
 /*
@@ -508,6 +508,218 @@
 #define UFS_SF_APPEND     0x00040000  /* append-only */
 #define UFS_SF_NOUNLINK   0x00100000  /* can't be removed or renamed */
 
+/*
+ * This structure is used for reading disk structures larger
+ * than the size of fragment.
+ */
+struct ufs_buffer_head {
+	unsigned fragment;			/* first fragment */
+	unsigned count;				/* number of fragments */
+	struct buffer_head * bh[UFS_MAXFRAG];	/* buffers */
+};
+
+struct ufs_cg_private_info {
+	struct ufs_cylinder_group ucg;
+	__u32	c_cgx;		/* number of cylidner group */
+	__u16	c_ncyl;		/* number of cyl's this cg */
+	__u16	c_niblk;	/* number of inode blocks this cg */
+	__u32	c_ndblk;	/* number of data blocks this cg */
+	__u32	c_rotor;	/* position of last used block */
+	__u32	c_frotor;	/* position of last used frag */
+	__u32	c_irotor;	/* position of last used inode */
+	__u32	c_btotoff;	/* (__u32) block totals per cylinder */
+	__u32	c_boff;		/* (short) free block positions */
+	__u32	c_iusedoff;	/* (char) used inode map */
+	__u32	c_freeoff;	/* (u_char) free block map */
+	__u32	c_nextfreeoff;	/* (u_char) next available space */
+	__u32	c_clustersumoff;/* (u_int32) counts of avail clusters */
+	__u32	c_clusteroff;	/* (u_int8) free cluster map */
+	__u32	c_nclusterblks;	/* number of clusters this cg */
+};	
+
+struct ufs_sb_private_info {
+	struct ufs_buffer_head s_ubh; /* buffer containing super block */
+	__u32	s_sblkno;	/* offset of super-blocks in filesys */
+	__u32	s_cblkno;	/* offset of cg-block in filesys */
+	__u32	s_iblkno;	/* offset of inode-blocks in filesys */
+	__u32	s_dblkno;	/* offset of first data after cg */
+	__u32	s_cgoffset;	/* cylinder group offset in cylinder */
+	__u32	s_cgmask;	/* used to calc mod fs_ntrak */
+	__u32	s_size;		/* number of blocks (fragments) in fs */
+	__u32	s_dsize;	/* number of data blocks in fs */
+	__u32	s_ncg;		/* number of cylinder groups */
+	__u32	s_bsize;	/* size of basic blocks */
+	__u32	s_fsize;	/* size of fragments */
+	__u32	s_fpb;		/* fragments per block */
+	__u32	s_minfree;	/* minimum percentage of free blocks */
+	__u32	s_bmask;	/* `blkoff'' calc of blk offsets */
+	__u32	s_fmask;	/* s_fsize mask */
+	__u32	s_bshift;	/* `lblkno'' calc of logical blkno */
+	__u32   s_fshift;	/* s_fsize shift */
+	__u32	s_fpbshift;	/* fragments per block shift */
+	__u32	s_fsbtodb;	/* fsbtodb and dbtofsb shift constant */
+	__u32	s_sbsize;	/* actual size of super block */
+	__u32   s_csmask;	/* csum block offset */
+	__u32	s_csshift;	/* csum block number */
+	__u32	s_nindir;	/* value of NINDIR */
+	__u32	s_inopb;	/* value of INOPB */
+	__u32	s_nspf;		/* value of NSPF */
+	__u32	s_npsect;	/* # sectors/track including spares */
+	__u32	s_interleave;	/* hardware sector interleave */
+	__u32	s_trackskew;	/* sector 0 skew, per track */
+	__u32	s_csaddr;	/* blk addr of cyl grp summary area */
+	__u32	s_cssize;	/* size of cyl grp summary area */
+	__u32	s_cgsize;	/* cylinder group size */
+	__u32	s_ntrak;	/* tracks per cylinder */
+	__u32	s_nsect;	/* sectors per track */
+	__u32	s_spc;		/* sectors per cylinder */
+	__u32	s_ipg;		/* inodes per group */
+	__u32	s_fpg;		/* fragments per group */
+	__u32	s_cpc;		/* cyl per cycle in postbl */
+	__s32	s_contigsumsize;/* size of cluster summary array, 44bsd */
+	__s64	s_qbmask;	/* ~usb_bmask */
+	__s64	s_qfmask;	/* ~usb_fmask */
+	__s32	s_postblformat;	/* format of positional layout tables */
+	__s32	s_nrpos;	/* number of rotational positions */
+        __s32	s_postbloff;	/* (__s16) rotation block list head */
+	__s32	s_rotbloff;	/* (__u8) blocks for each rotation */
+
+	__u32	s_fpbmask;	/* fragments per block mask */
+	__u32	s_apb;		/* address per block */
+	__u32	s_2apb;		/* address per block^2 */
+	__u32	s_3apb;		/* address per block^3 */
+	__u32	s_apbmask;	/* address per block mask */
+	__u32	s_apbshift;	/* address per block shift */
+	__u32	s_2apbshift;	/* address per block shift * 2 */
+	__u32	s_3apbshift;	/* address per block shift * 3 */
+	__u32	s_nspfshift;	/* number of sector per fragment shift */
+	__u32	s_nspb;		/* number of sector per block */
+	__u32	s_inopf;	/* inodes per fragment */
+	__u32	s_sbbase;	/* offset of NeXTstep superblock */
+	__u32	s_bpf;		/* bits per fragment */
+	__u32	s_bpfshift;	/* bits per fragment shift*/
+	__u32	s_bpfmask;	/* bits per fragment mask */
+
+	__u32	s_maxsymlinklen;/* upper limit on fast symlinks' size */
+};
+
+/*
+ * Sizes of this structures are:
+ *	ufs_super_block_first	512
+ *	ufs_super_block_second	512
+ *	ufs_super_block_third	356
+ */
+struct ufs_super_block_first {
+	__u32	fs_link;
+	__u32	fs_rlink;
+	__u32	fs_sblkno;
+	__u32	fs_cblkno;
+	__u32	fs_iblkno;
+	__u32	fs_dblkno;
+	__u32	fs_cgoffset;
+	__u32	fs_cgmask;
+	__u32	fs_time;
+	__u32	fs_size;
+	__u32	fs_dsize;
+	__u32	fs_ncg;
+	__u32	fs_bsize;
+	__u32	fs_fsize;
+	__u32	fs_frag;
+	__u32	fs_minfree;
+	__u32	fs_rotdelay;
+	__u32	fs_rps;
+	__u32	fs_bmask;
+	__u32	fs_fmask;
+	__u32	fs_bshift;
+	__u32	fs_fshift;
+	__u32	fs_maxcontig;
+	__u32	fs_maxbpg;
+	__u32	fs_fragshift;
+	__u32	fs_fsbtodb;
+	__u32	fs_sbsize;
+	__u32	fs_csmask;
+	__u32	fs_csshift;
+	__u32	fs_nindir;
+	__u32	fs_inopb;
+	__u32	fs_nspf;
+	__u32	fs_optim;
+	union {
+		struct {
+			__u32	fs_npsect;
+		} fs_sun;
+		struct {
+			__s32	fs_state;
+		} fs_sunx86;
+	} fs_u1;
+	__u32	fs_interleave;
+	__u32	fs_trackskew;
+	__u32	fs_id[2];
+	__u32	fs_csaddr;
+	__u32	fs_cssize;
+	__u32	fs_cgsize;
+	__u32	fs_ntrak;
+	__u32	fs_nsect;
+	__u32	fs_spc;
+	__u32	fs_ncyl;
+	__u32	fs_cpg;
+	__u32	fs_ipg;
+	__u32	fs_fpg;
+	struct ufs_csum fs_cstotal;
+	__s8	fs_fmod;
+	__s8	fs_clean;
+	__s8	fs_ronly;
+	__s8	fs_flags;
+	__s8	fs_fsmnt[UFS_MAXMNTLEN - 212];
+
+};
+
+struct ufs_super_block_second {
+	__s8	fs_fsmnt[212];
+	__u32	fs_cgrotor;
+	__u32	fs_csp[UFS_MAXCSBUFS];
+	__u32	fs_maxcluster;
+	__u32	fs_cpc;
+	__u16	fs_opostbl[82];
+};	
+
+struct ufs_super_block_third {
+	__u16	fs_opostbl[46];
+	union {
+		struct {
+			__s32	fs_sparecon[53];/* reserved for future constants */
+			__s32	fs_reclaim;
+			__s32	fs_sparecon2[1];
+			__s32	fs_state;	/* file system state time stamp */
+			__u32	fs_qbmask[2];	/* ~usb_bmask */
+			__u32	fs_qfmask[2];	/* ~usb_fmask */
+		} fs_sun;
+		struct {
+			__s32	fs_sparecon[53];/* reserved for future constants */
+			__s32	fs_reclaim;
+			__s32	fs_sparecon2[1];
+			__u32	fs_npsect;	/* # sectors/track including spares */
+			__u32	fs_qbmask[2];	/* ~usb_bmask */
+			__u32	fs_qfmask[2];	/* ~usb_fmask */
+		} fs_sunx86;
+		struct {
+			__s32	fs_sparecon[50];/* reserved for future constants */
+			__s32	fs_contigsumsize;/* size of cluster summary array */
+			__s32	fs_maxsymlinklen;/* max length of an internal symlink */
+			__s32	fs_inodefmt;	/* format of on-disk inodes */
+			__u32	fs_maxfilesize[2];	/* max representable file size */
+			__u32	fs_qbmask[2];	/* ~usb_bmask */
+			__u32	fs_qfmask[2];	/* ~usb_fmask */
+			__s32	fs_state;	/* file system state time stamp */
+		} fs_44;
+	} fs_u2;
+	__s32	fs_postblformat;
+	__s32	fs_nrpos;
+	__s32	fs_postbloff;
+	__s32	fs_rotbloff;
+	__s32	fs_magic;
+	__u8	fs_space[1];
+};
+
 #ifdef __KERNEL__
 
 /* balloc.c */
@@ -539,7 +751,7 @@
 
 /* ialloc.c */
 extern void ufs_free_inode (struct inode *inode);
-extern struct inode * ufs_new_inode (const struct inode *, int);
+extern struct inode * ufs_new_inode (struct inode *, int);
 
 /* inode.c */
 extern int ufs_frag_map (struct inode *, int);
@@ -566,6 +778,13 @@
 
 /* truncate.c */
 extern void ufs_truncate (struct inode *);
+
+#include <linux/ufs_fs_i.h>
+
+static inline struct ufs_inode_info *UFS_I(struct inode *inode)
+{
+	return list_entry(inode, struct ufs_inode_info, vfs_inode);
+}
 
 #endif	/* __KERNEL__ */
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/ufs_fs_i.h linux/include/linux/ufs_fs_i.h
--- v2.5.2/linux/include/linux/ufs_fs_i.h	Mon Nov 19 14:55:46 2001
+++ linux/include/linux/ufs_fs_i.h	Mon Jan 21 15:37:32 2002
@@ -26,6 +26,7 @@
 	__u32	i_oeftflag;
 	__u16	i_osync;
 	__u32	i_lastfrag;
+	struct inode vfs_inode;
 };
 
 #endif /* _LINUX_UFS_FS_I_H */
diff -u --recursive --new-file v2.5.2/linux/include/linux/ufs_fs_sb.h linux/include/linux/ufs_fs_sb.h
--- v2.5.2/linux/include/linux/ufs_fs_sb.h	Thu Nov 22 11:46:19 2001
+++ linux/include/linux/ufs_fs_sb.h	Mon Jan 21 15:37:32 2002
@@ -14,107 +14,15 @@
 #ifndef __LINUX_UFS_FS_SB_H
 #define __LINUX_UFS_FS_SB_H
 
-#include <linux/ufs_fs.h>
-
-/*
- * This structure is used for reading disk structures larger
- * than the size of fragment.
- */
-struct ufs_buffer_head {
-	unsigned fragment;			/* first fragment */
-	unsigned count;				/* number of fragments */
-	struct buffer_head * bh[UFS_MAXFRAG];	/* buffers */
-};
-
-struct ufs_cg_private_info {
-	struct ufs_cylinder_group ucg;
-	__u32	c_cgx;		/* number of cylidner group */
-	__u16	c_ncyl;		/* number of cyl's this cg */
-	__u16	c_niblk;	/* number of inode blocks this cg */
-	__u32	c_ndblk;	/* number of data blocks this cg */
-	__u32	c_rotor;	/* position of last used block */
-	__u32	c_frotor;	/* position of last used frag */
-	__u32	c_irotor;	/* position of last used inode */
-	__u32	c_btotoff;	/* (__u32) block totals per cylinder */
-	__u32	c_boff;		/* (short) free block positions */
-	__u32	c_iusedoff;	/* (char) used inode map */
-	__u32	c_freeoff;	/* (u_char) free block map */
-	__u32	c_nextfreeoff;	/* (u_char) next available space */
-	__u32	c_clustersumoff;/* (u_int32) counts of avail clusters */
-	__u32	c_clusteroff;	/* (u_int8) free cluster map */
-	__u32	c_nclusterblks;	/* number of clusters this cg */
-};	
-
-struct ufs_sb_private_info {
-	struct ufs_buffer_head s_ubh; /* buffer containing super block */
-	__u32	s_sblkno;	/* offset of super-blocks in filesys */
-	__u32	s_cblkno;	/* offset of cg-block in filesys */
-	__u32	s_iblkno;	/* offset of inode-blocks in filesys */
-	__u32	s_dblkno;	/* offset of first data after cg */
-	__u32	s_cgoffset;	/* cylinder group offset in cylinder */
-	__u32	s_cgmask;	/* used to calc mod fs_ntrak */
-	__u32	s_size;		/* number of blocks (fragments) in fs */
-	__u32	s_dsize;	/* number of data blocks in fs */
-	__u32	s_ncg;		/* number of cylinder groups */
-	__u32	s_bsize;	/* size of basic blocks */
-	__u32	s_fsize;	/* size of fragments */
-	__u32	s_fpb;		/* fragments per block */
-	__u32	s_minfree;	/* minimum percentage of free blocks */
-	__u32	s_bmask;	/* `blkoff'' calc of blk offsets */
-	__u32	s_fmask;	/* s_fsize mask */
-	__u32	s_bshift;	/* `lblkno'' calc of logical blkno */
-	__u32   s_fshift;	/* s_fsize shift */
-	__u32	s_fpbshift;	/* fragments per block shift */
-	__u32	s_fsbtodb;	/* fsbtodb and dbtofsb shift constant */
-	__u32	s_sbsize;	/* actual size of super block */
-	__u32   s_csmask;	/* csum block offset */
-	__u32	s_csshift;	/* csum block number */
-	__u32	s_nindir;	/* value of NINDIR */
-	__u32	s_inopb;	/* value of INOPB */
-	__u32	s_nspf;		/* value of NSPF */
-	__u32	s_npsect;	/* # sectors/track including spares */
-	__u32	s_interleave;	/* hardware sector interleave */
-	__u32	s_trackskew;	/* sector 0 skew, per track */
-	__u32	s_csaddr;	/* blk addr of cyl grp summary area */
-	__u32	s_cssize;	/* size of cyl grp summary area */
-	__u32	s_cgsize;	/* cylinder group size */
-	__u32	s_ntrak;	/* tracks per cylinder */
-	__u32	s_nsect;	/* sectors per track */
-	__u32	s_spc;		/* sectors per cylinder */
-	__u32	s_ipg;		/* inodes per group */
-	__u32	s_fpg;		/* fragments per group */
-	__u32	s_cpc;		/* cyl per cycle in postbl */
-	__s32	s_contigsumsize;/* size of cluster summary array, 44bsd */
-	__s64	s_qbmask;	/* ~usb_bmask */
-	__s64	s_qfmask;	/* ~usb_fmask */
-	__s32	s_postblformat;	/* format of positional layout tables */
-	__s32	s_nrpos;	/* number of rotational positions */
-        __s32	s_postbloff;	/* (__s16) rotation block list head */
-	__s32	s_rotbloff;	/* (__u8) blocks for each rotation */
-
-	__u32	s_fpbmask;	/* fragments per block mask */
-	__u32	s_apb;		/* address per block */
-	__u32	s_2apb;		/* address per block^2 */
-	__u32	s_3apb;		/* address per block^3 */
-	__u32	s_apbmask;	/* address per block mask */
-	__u32	s_apbshift;	/* address per block shift */
-	__u32	s_2apbshift;	/* address per block shift * 2 */
-	__u32	s_3apbshift;	/* address per block shift * 3 */
-	__u32	s_nspfshift;	/* number of sector per fragment shift */
-	__u32	s_nspb;		/* number of sector per block */
-	__u32	s_inopf;	/* inodes per fragment */
-	__u32	s_sbbase;	/* offset of NeXTstep superblock */
-	__u32	s_bpf;		/* bits per fragment */
-	__u32	s_bpfshift;	/* bits per fragment shift*/
-	__u32	s_bpfmask;	/* bits per fragment mask */
-
-	__u32	s_maxsymlinklen;/* upper limit on fast symlinks' size */
-};
-
 
 #define UFS_MAX_GROUP_LOADED 8
 #define UFS_CGNO_EMPTY ((unsigned)-1)
 
+struct ufs_sb_private_info;
+struct ufs_cg_private_info;
+struct ufs_csum;
+#define UFS_MAXCSBUFS 31
+
 struct ufs_sb_info {
 	struct ufs_sb_private_info * s_uspi;	
 	struct ufs_csum	* s_csp[UFS_MAXCSBUFS];
@@ -127,121 +35,4 @@
 	unsigned s_mount_opt;
 };
 
-/*
- * Sizes of this structures are:
- *	ufs_super_block_first	512
- *	ufs_super_block_second	512
- *	ufs_super_block_third	356
- */
-struct ufs_super_block_first {
-	__u32	fs_link;
-	__u32	fs_rlink;
-	__u32	fs_sblkno;
-	__u32	fs_cblkno;
-	__u32	fs_iblkno;
-	__u32	fs_dblkno;
-	__u32	fs_cgoffset;
-	__u32	fs_cgmask;
-	__u32	fs_time;
-	__u32	fs_size;
-	__u32	fs_dsize;
-	__u32	fs_ncg;
-	__u32	fs_bsize;
-	__u32	fs_fsize;
-	__u32	fs_frag;
-	__u32	fs_minfree;
-	__u32	fs_rotdelay;
-	__u32	fs_rps;
-	__u32	fs_bmask;
-	__u32	fs_fmask;
-	__u32	fs_bshift;
-	__u32	fs_fshift;
-	__u32	fs_maxcontig;
-	__u32	fs_maxbpg;
-	__u32	fs_fragshift;
-	__u32	fs_fsbtodb;
-	__u32	fs_sbsize;
-	__u32	fs_csmask;
-	__u32	fs_csshift;
-	__u32	fs_nindir;
-	__u32	fs_inopb;
-	__u32	fs_nspf;
-	__u32	fs_optim;
-	union {
-		struct {
-			__u32	fs_npsect;
-		} fs_sun;
-		struct {
-			__s32	fs_state;
-		} fs_sunx86;
-	} fs_u1;
-	__u32	fs_interleave;
-	__u32	fs_trackskew;
-	__u32	fs_id[2];
-	__u32	fs_csaddr;
-	__u32	fs_cssize;
-	__u32	fs_cgsize;
-	__u32	fs_ntrak;
-	__u32	fs_nsect;
-	__u32	fs_spc;
-	__u32	fs_ncyl;
-	__u32	fs_cpg;
-	__u32	fs_ipg;
-	__u32	fs_fpg;
-	struct ufs_csum fs_cstotal;
-	__s8	fs_fmod;
-	__s8	fs_clean;
-	__s8	fs_ronly;
-	__s8	fs_flags;
-	__s8	fs_fsmnt[UFS_MAXMNTLEN - 212];
-
-};
-
-struct ufs_super_block_second {
-	__s8	fs_fsmnt[212];
-	__u32	fs_cgrotor;
-	__u32	fs_csp[UFS_MAXCSBUFS];
-	__u32	fs_maxcluster;
-	__u32	fs_cpc;
-	__u16	fs_opostbl[82];
-};	
-
-struct ufs_super_block_third {
-	__u16	fs_opostbl[46];
-	union {
-		struct {
-			__s32	fs_sparecon[53];/* reserved for future constants */
-			__s32	fs_reclaim;
-			__s32	fs_sparecon2[1];
-			__s32	fs_state;	/* file system state time stamp */
-			__u32	fs_qbmask[2];	/* ~usb_bmask */
-			__u32	fs_qfmask[2];	/* ~usb_fmask */
-		} fs_sun;
-		struct {
-			__s32	fs_sparecon[53];/* reserved for future constants */
-			__s32	fs_reclaim;
-			__s32	fs_sparecon2[1];
-			__u32	fs_npsect;	/* # sectors/track including spares */
-			__u32	fs_qbmask[2];	/* ~usb_bmask */
-			__u32	fs_qfmask[2];	/* ~usb_fmask */
-		} fs_sunx86;
-		struct {
-			__s32	fs_sparecon[50];/* reserved for future constants */
-			__s32	fs_contigsumsize;/* size of cluster summary array */
-			__s32	fs_maxsymlinklen;/* max length of an internal symlink */
-			__s32	fs_inodefmt;	/* format of on-disk inodes */
-			__u32	fs_maxfilesize[2];	/* max representable file size */
-			__u32	fs_qbmask[2];	/* ~usb_bmask */
-			__u32	fs_qfmask[2];	/* ~usb_fmask */
-			__s32	fs_state;	/* file system state time stamp */
-		} fs_44;
-	} fs_u2;
-	__s32	fs_postblformat;
-	__s32	fs_nrpos;
-	__s32	fs_postbloff;
-	__s32	fs_rotbloff;
-	__s32	fs_magic;
-	__u8	fs_space[1];
-};
-
-#endif /* __LINUX_UFS_FS_SB_H */
+#endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p
--- v2.5.2/linux/include/linux/umsdos_fs.p	Wed Aug  2 12:06:11 2000
+++ linux/include/linux/umsdos_fs.p	Mon Jan 21 15:37:32 2002
@@ -93,3 +93,8 @@
 /* rdir.c 22/03/95 03.31.42 */
 struct dentry *umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo);
 struct dentry *UMSDOS_rlookup (struct inode *dir, struct dentry *dentry);
+
+static inline struct umsdos_inode_info *UMSDOS_I(struct inode *inode)
+{
+	return &inode->u.umsdos_i;
+}
diff -u --recursive --new-file v2.5.2/linux/include/linux/usb.h linux/include/linux/usb.h
--- v2.5.2/linux/include/linux/usb.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/usb.h	Tue Jan 29 21:44:41 2002
@@ -576,13 +576,12 @@
 					/* ... less overhead for QUEUE_BULK */
 #define USB_TIMEOUT_KILLED	0x1000	/* only set by HCD! */
 
-typedef struct
-{
+struct usb_iso_packet_descriptor {
 	unsigned int offset;
 	unsigned int length;		/* expected length */
 	unsigned int actual_length;
 	unsigned int status;
-} iso_packet_descriptor_t;
+};
 
 struct urb;
 
@@ -642,11 +641,11 @@
  * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to 
  *	collect the transfer status for each buffer.
  *
- * This structure identifies USB transfer requests.  URBs may be allocated
- * in any way, although usb_alloc_urb() is often convenient.  Initialization
- * may be done using various usb_fill_*_urb() functions.  URBs are submitted
- * using usb_submit_urb(), and pending requests may be canceled using
- * usb_unlink_urb().
+ * This structure identifies USB transfer requests.  URBs must be allocated by
+ * calling usb_alloc_urb() and freed with a call to usb_free_urb().
+ * Initialization may be done using various usb_fill_*_urb() functions.  URBs
+ * are submitted using usb_submit_urb(), and pending requests may be canceled
+ * using usb_unlink_urb().
  *
  * Initialization:
  *
@@ -722,6 +721,7 @@
 struct urb
 {
 	spinlock_t lock;		/* lock for the URB */
+	atomic_t count;			/* reference count of the URB */
 	void *hcpriv;			/* private data for host controller */
 	struct list_head urb_list;	/* list pointer to all active urbs */
 	struct urb *next; 		/* (in) pointer to next URB */
@@ -741,11 +741,9 @@
 	int timeout;			/* (in) timeout, in jiffies */
 	void *context;			/* (in) context for completion */
 	usb_complete_t complete;	/* (in) completion routine */
-	iso_packet_descriptor_t iso_frame_desc[0];	/* (in) ISO ONLY */
+	struct usb_iso_packet_descriptor iso_frame_desc[0];	/* (in) ISO ONLY */
 };
 
-typedef struct urb urb_t;
-
 /**
  * usb_fill_control_urb - initializes a control urb
  * @urb: pointer to the urb to initialize.
@@ -857,6 +855,8 @@
 
 extern struct urb *usb_alloc_urb(int iso_packets);
 extern void usb_free_urb(struct urb *urb);
+#define usb_put_urb usb_free_urb
+extern struct urb *usb_get_urb(struct urb *urb);
 extern int usb_submit_urb(struct urb *urb);
 extern int usb_unlink_urb(struct urb *urb);
 
@@ -884,6 +884,7 @@
 	char *buf, size_t size);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
 extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
+extern int usb_make_path(struct usb_device *dev, char *buf, size_t size);
 
 /*
  * timeouts, in seconds, used for sending/receiving control messages
@@ -1099,7 +1100,7 @@
  *  - endpoint number (4 bits)
  *  - current Data0/1 state (1 bit) [Historical; now gone]
  *  - direction (1 bit)
- *  - speed (1 bit)
+ *  - speed (1 bit) [Historical and specific to USB 1.1; now gone.]
  *  - max packet size (2 bits: 8, 16, 32 or 64) [Historical; now gone.]
  *  - pipe type (2 bits: control, interrupt, bulk, isochronous)
  *
@@ -1110,25 +1111,22 @@
  * Let's not fall in that trap. We'll just encode it as a simple
  * unsigned int. The encoding is:
  *
- *  - max size:		bits 0-1	(00 = 8, 01 = 16, 10 = 32, 11 = 64) [Historical; now gone.]
- *  - direction:	bit 7		(0 = Host-to-Device [Out], 1 = Device-to-Host [In])
+ *  - max size:		bits 0-1	[Historical; now gone.]
+ *  - direction:	bit 7		(0 = Host-to-Device [Out],
+ *					 1 = Device-to-Host [In])
  *  - device:		bits 8-14
  *  - endpoint:		bits 15-18
  *  - Data0/1:		bit 19		[Historical; now gone. ]
- *  - speed:		bit 26		(0 = Full, 1 = Low Speed)
- *  - pipe type:	bits 30-31	(00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk)
+ *  - lowspeed:		bit 26		[Historical; now gone. ]
+ *  - pipe type:	bits 30-31	(00 = isochronous, 01 = interrupt,
+ *					 10 = control, 11 = bulk)
  *
  * Why? Because it's arbitrary, and whatever encoding we select is really
  * up to us. This one happens to share a lot of bit positions with the UHCI
  * specification, so that much of the uhci driver can just mask the bits
  * appropriately.
- *
- * NOTE:  there's no encoding (yet?) for a "high speed" endpoint; treat them
- * like full speed devices.
  */
 
-// FIXME 2.5 get rid of usb_pipeslow(), just use dev->speed
-
 #define PIPE_ISOCHRONOUS		0
 #define PIPE_INTERRUPT			1
 #define PIPE_CONTROL			2
@@ -1142,9 +1140,7 @@
 #define usb_pipeout(pipe)	((((pipe) >> 7) & 1) ^ 1)
 #define usb_pipein(pipe)	(((pipe) >> 7) & 1)
 #define usb_pipedevice(pipe)	(((pipe) >> 8) & 0x7f)
-#define usb_pipe_endpdev(pipe)	(((pipe) >> 8) & 0x7ff)
 #define usb_pipeendpoint(pipe)	(((pipe) >> 15) & 0xf)
-#define usb_pipeslow(pipe)	(((pipe) >> 26) & 1)
 #define usb_pipetype(pipe)	(((pipe) >> 30) & 3)
 #define usb_pipeisoc(pipe)	(usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
 #define usb_pipeint(pipe)	(usb_pipetype((pipe)) == PIPE_INTERRUPT)
@@ -1166,13 +1162,7 @@
 
 static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
 {
-	return (dev->devnum << 8) | (endpoint << 15) |
-		((dev->speed == USB_SPEED_LOW) << 26);
-}
-
-static inline unsigned int __default_pipe(struct usb_device *dev)
-{
-	return ((dev->speed == USB_SPEED_LOW) << 26);
+	return (dev->devnum << 8) | (endpoint << 15);
 }
 
 /* Create various pipes... */
@@ -1184,8 +1174,8 @@
 #define usb_rcvbulkpipe(dev,endpoint)	((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
 #define usb_sndintpipe(dev,endpoint)	((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
 #define usb_rcvintpipe(dev,endpoint)	((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
-#define usb_snddefctrl(dev)		((PIPE_CONTROL << 30) | __default_pipe(dev))
-#define usb_rcvdefctrl(dev)		((PIPE_CONTROL << 30) | __default_pipe(dev) | USB_DIR_IN)
+#define usb_snddefctrl(dev)		((PIPE_CONTROL << 30))
+#define usb_rcvdefctrl(dev)		((PIPE_CONTROL << 30) | USB_DIR_IN)
 
 /* -------------------------------------------------------------------------- */
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/usbdev_fs_i.h linux/include/linux/usbdev_fs_i.h
--- v2.5.2/linux/include/linux/usbdev_fs_i.h	Mon Jan 10 11:32:48 2000
+++ linux/include/linux/usbdev_fs_i.h	Wed Dec 31 16:00:00 1969
@@ -1,11 +0,0 @@
-struct usb_device;
-struct usb_bus;
-
-struct usbdev_inode_info {
-	struct list_head dlist;
-	struct list_head slist;
-	union {
-		struct usb_device *dev;
-		struct usb_bus *bus;
-	} p;
-};
diff -u --recursive --new-file v2.5.2/linux/include/linux/usbdev_fs_sb.h linux/include/linux/usbdev_fs_sb.h
--- v2.5.2/linux/include/linux/usbdev_fs_sb.h	Tue May 22 10:25:36 2001
+++ linux/include/linux/usbdev_fs_sb.h	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-struct usbdev_sb_info {
-	struct list_head slist;
-	struct list_head ilist;
-	uid_t devuid;
-	gid_t devgid;
-	umode_t devmode;
-	uid_t busuid;
-	gid_t busgid;
-	umode_t busmode;
-	uid_t listuid;
-	gid_t listgid;
-	umode_t listmode;
-};
diff -u --recursive --new-file v2.5.2/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.5.2/linux/include/linux/videodev.h	Fri Nov  9 14:11:15 2001
+++ linux/include/linux/videodev.h	Tue Jan 15 10:56:36 2002
@@ -8,6 +8,7 @@
 
 #include <linux/poll.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/mm.h>
 
 struct video_device
 {
@@ -25,7 +26,7 @@
 	unsigned int (*poll)(struct video_device *, struct file *, poll_table *);
 #endif
 	int (*ioctl)(struct video_device *, unsigned int , void *);
-	int (*mmap)(struct video_device *, const char *, unsigned long);
+	int (*mmap)(struct vm_area_struct *vma, struct video_device *, const char *, unsigned long);
 	int (*initialize)(struct video_device *);	
 	void *priv;		/* Used to be 'private' but that upsets C++ */
 	int busy;
diff -u --recursive --new-file v2.5.2/linux/include/linux/wireless.h linux/include/linux/wireless.h
--- v2.5.2/linux/include/linux/wireless.h	Thu Nov 22 11:47:12 2001
+++ linux/include/linux/wireless.h	Tue Jan 29 21:41:51 2002
@@ -1,9 +1,10 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	12	5.10.01
+ * Version :	13	6.12.01
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _LINUX_WIRELESS_H
@@ -11,6 +12,8 @@
 
 /************************** DOCUMENTATION **************************/
 /*
+ * Initial APIs (1996 -> onward) :
+ * -----------------------------
  * Basically, the wireless extensions are for now a set of standard ioctl
  * call + /proc/net/wireless
  *
@@ -27,16 +30,27 @@
  * We have the list of command plus a structure descibing the
  * data exchanged...
  * Note that to add these ioctl, I was obliged to modify :
- *	net/core/dev.c (two place + add include)
- *	net/ipv4/af_inet.c (one place + add include)
+ *	# net/core/dev.c (two place + add include)
+ *	# net/ipv4/af_inet.c (one place + add include)
  *
  * /proc/net/wireless is a copy of /proc/net/dev.
  * We have a structure for data passed from the driver to /proc/net/wireless
  * Too add this, I've modified :
- *	net/core/dev.c (two other places)
- *	include/linux/netdevice.h (one place)
- *	include/linux/proc_fs.h (one place)
+ *	# net/core/dev.c (two other places)
+ *	# include/linux/netdevice.h (one place)
+ *	# include/linux/proc_fs.h (one place)
+ *
+ * New driver API (2001 -> onward) :
+ * -------------------------------
+ * This file is only concerned with the user space API and common definitions.
+ * The new driver API is defined and documented in :
+ *	# include/net/iw_handler.h
  *
+ * Note as well that /proc/net/wireless implementation has now moved in :
+ *	# include/linux/wireless.c
+ *
+ * Other comments :
+ * --------------
  * Do not add here things that are redundant with other mechanisms
  * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
  * wireless specific.
@@ -54,16 +68,14 @@
 #include <linux/socket.h>		/* for "struct sockaddr" et al	*/
 #include <linux/if.h>			/* for IFNAMSIZ and co... */
 
-/**************************** CONSTANTS ****************************/
-
-/* --------------------------- VERSION --------------------------- */
+/***************************** VERSION *****************************/
 /*
  * This constant is used to know the availability of the wireless
  * extensions and to know which version of wireless extensions it is
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	12
+#define WIRELESS_EXT	13
 
 /*
  * Changes :
@@ -123,12 +135,20 @@
  *	- Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
  *	- Add new statistics (frag, retry, beacon)
  *	- Add average quality (for user space calibration)
+ *
+ * V12 to V13
+ * ----------
+ *	- Document creation of new driver API.
+ *	- Extract union iwreq_data from struct iwreq (for new driver API).
+ *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
  */
 
+/**************************** CONSTANTS ****************************/
+
 /* -------------------------- IOCTL LIST -------------------------- */
 
 /* Basic operations */
-#define SIOCSIWNAME	0x8B00		/* Unused */
+#define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
 #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
 #define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
 #define SIOCGIWNWID	0x8B03		/* get network id */
@@ -414,13 +434,49 @@
 
 /* ------------------------ IOCTL REQUEST ------------------------ */
 /*
+ * This structure defines the payload of an ioctl, and is used 
+ * below.
+ *
+ * Note that this structure should fit on the memory footprint
+ * of iwreq (which is the same as ifreq), which mean a max size of
+ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
+ * You should check this when increasing the structures defined
+ * above in this file...
+ */
+union	iwreq_data
+{
+	/* Config - generic */
+	char		name[IFNAMSIZ];
+	/* Name : used to verify the presence of  wireless extensions.
+	 * Name of the protocol/provider... */
+
+	struct iw_point	essid;		/* Extended network name */
+	struct iw_param	nwid;		/* network id (or domain - the cell) */
+	struct iw_freq	freq;		/* frequency or channel :
+					 * 0-1000 = channel
+					 * > 1000 = frequency in Hz */
+
+	struct iw_param	sens;		/* signal level threshold */
+	struct iw_param	bitrate;	/* default bit rate */
+	struct iw_param	txpower;	/* default transmit power */
+	struct iw_param	rts;		/* RTS threshold threshold */
+	struct iw_param	frag;		/* Fragmentation threshold */
+	__u32		mode;		/* Operation mode */
+	struct iw_param	retry;		/* Retry limits & lifetime */
+
+	struct iw_point	encoding;	/* Encoding stuff : tokens */
+	struct iw_param	power;		/* PM duration/timeout */
+
+	struct sockaddr	ap_addr;	/* Access point address */
+
+	struct iw_point	data;		/* Other large parameters */
+};
+
+/*
  * The structure to exchange data for ioctl.
  * This structure is the same as 'struct ifreq', but (re)defined for
  * convenience...
- *
- * Note that it should fit on the same memory footprint !
- * You should check this when increasing the above structures (16 octets)
- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
+ * Do I need to remind you about structure size (32 octets) ?
  */
 struct	iwreq 
 {
@@ -429,35 +485,8 @@
 		char	ifrn_name[IFNAMSIZ];	/* if name, e.g. "eth0" */
 	} ifr_ifrn;
 
-	/* Data part */
-	union
-	{
-		/* Config - generic */
-		char		name[IFNAMSIZ];
-		/* Name : used to verify the presence of  wireless extensions.
-		 * Name of the protocol/provider... */
-
-		struct iw_point	essid;	/* Extended network name */
-		struct iw_param	nwid;	/* network id (or domain - the cell) */
-		struct iw_freq	freq;	/* frequency or channel :
-					 * 0-1000 = channel
-					 * > 1000 = frequency in Hz */
-
-		struct iw_param	sens;		/* signal level threshold */
-		struct iw_param	bitrate;	/* default bit rate */
-		struct iw_param	txpower;	/* default transmit power */
-		struct iw_param	rts;		/* RTS threshold threshold */
-		struct iw_param	frag;		/* Fragmentation threshold */
-		__u32		mode;		/* Operation mode */
-		struct iw_param	retry;		/* Retry limits & lifetime */
-
-		struct iw_point	encoding;	/* Encoding stuff : tokens */
-		struct iw_param	power;		/* PM duration/timeout */
-
-		struct sockaddr	ap_addr;	/* Access point address */
-
-		struct iw_point	data;		/* Other large parameters */
-	}	u;
+	/* Data part (defined just above) */
+	union	iwreq_data	u;
 };
 
 /* -------------------------- IOCTL DATA -------------------------- */
diff -u --recursive --new-file v2.5.2/linux/include/linux/xattr.h linux/include/linux/xattr.h
--- v2.5.2/linux/include/linux/xattr.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/xattr.h	Tue Jan 29 18:48:30 2002
@@ -0,0 +1,15 @@
+/*
+  File: linux/xattr.h
+
+  Extended attributes handling.
+
+  Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
+  Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
+*/
+#ifndef _LINUX_XATTR_H
+#define _LINUX_XATTR_H
+
+#define XATTR_CREATE	0x1	/* set value, fail if attr already exists */
+#define XATTR_REPLACE	0x2	/* set value, fail if attr does not exist */
+
+#endif	/* _LINUX_XATTR_H */
diff -u --recursive --new-file v2.5.2/linux/include/linux/zlib.h linux/include/linux/zlib.h
--- v2.5.2/linux/include/linux/zlib.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/zlib.h	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,654 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.1.3, July 9th, 1998
+
+  Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.1.3"
+
+/* 
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    void     *workspace; /* memory allocated for this stream */
+
+    int     data_type;  /* best guess about the data type: ascii or binary */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_PACKET_FLUSH  2
+#define Z_SYNC_FLUSH    3
+#define Z_FULL_FLUSH    4
+#define Z_FINISH        5
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlib_zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+ZEXTERN int ZEXPORT zlib_deflate_workspacesize OF((void));
+/*
+   Returns the number of bytes that needs to be allocated for a per-
+   stream workspace.  A pointer to this number of bytes should be
+   returned in stream->workspace before calling zlib_deflateInit().
+*/
+
+/* 
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT zlib_deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  the compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+  
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).
+*/
+
+
+ZEXTERN int ZEXPORT zlib_deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+ZEXTERN int ZEXPORT zlib_inflate_workspacesize OF((void));
+/*
+   Returns the number of bytes that needs to be allocated for a per-
+   stream workspace.  A pointer to this number of bytes should be
+   returned in stream->workspace before calling zlib_inflateInit().
+*/
+
+/* 
+ZEXTERN int ZEXPORT zlib_inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, and workspace must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT zlib_inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may some
+  introduce some output latency (reading input without producing any output)
+  except when forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+  output as possible to the output buffer. The flushing behavior of inflate is
+  not specified for values of the flush parameter other than Z_SYNC_FLUSH
+  and Z_FINISH, but the current implementation actually flushes as much output
+  as possible anyway.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+     If a preset dictionary is needed at this point (see inflateSetDictionary
+  below), inflate sets strm-adler to the adler32 checksum of the
+  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
+  it sets strm->adler to the adler32 checksum of all output produced
+  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+  an error code as described below. At the end of the stream, inflate()
+  checks that its computed adler32 checksum is equal to that saved by the
+  compressor and returns Z_STREAM_END only if the checksum is correct.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect
+  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+  enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
+  case, the application may then call inflateSync to look for a good
+  compression block.
+*/
+
+
+ZEXTERN int ZEXPORT zlib_inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*   
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match).  Filtered data consists mostly of small values with a
+   somewhat random distribution. In this case, the compression algorithm is
+   tuned to compress them better. The effect of Z_FILTERED is to force more
+   Huffman coding and less string matching; it is somewhat intermediate
+   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+   the compression ratio but not the correctness of the compressed output even
+   if it is not set appropriately.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+                            
+ZEXTERN int ZEXPORT zlib_deflateSetDictionary OF((z_streamp strm,
+						     const Bytef *dictionary,
+						     uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front.
+
+     Upon return of this function, strm->adler is set to the Adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The Adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.)
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT zlib_deflateCopy OF((z_streamp dest,
+					    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT zlib_deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT zlib_deflateParams OF((z_streamp strm,
+					      int level,
+					      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+/*   
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. If a compressed stream with a larger window size is given as
+   input, inflate() will return with the error code Z_DATA_ERROR instead of
+   trying to allocate a larger window.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+   memLevel). msg is set to null if there is no error message.  inflateInit2
+   does not perform any decompression apart from reading the zlib header if
+   present: this will be done by inflate(). (So next_in and avail_in may be
+   modified, but next_out and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT zlib_inflateSetDictionary OF((z_streamp strm,
+						     const Bytef *dictionary,
+						     uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate
+   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the Adler32 value returned by this call of
+   inflate. The compressor and decompressor must use exactly the same
+   dictionary (see deflateSetDictionary).
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect Adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT zlib_inflateSync OF((z_streamp strm));
+/* 
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT zlib_inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int ZEXPORT zlib_inflateIncomp OF((z_stream *strm));
+/*
+     This function adds the data at next_in (avail_in bytes) to the output
+   history without performing any output.  There must be no pending output,
+   and the decompressor must be expecting to see the start of a block.
+   Calling this function is equivalent to decompressing a stored block
+   containing the data at next_in (except that the data is not output).
+*/
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT zlib_deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT zlib_inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT zlib_deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT zlib_inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+#define zlib_deflateInit(strm, level) \
+        zlib_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define zlib_inflateInit(strm) \
+        zlib_inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define zlib_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        zlib_deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define zlib_inflateInit2(strm, windowBits) \
+        zlib_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zlib_zError           OF((int err));
+ZEXTERN int            ZEXPORT zlib_inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT zlib_get_crc_table    OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
diff -u --recursive --new-file v2.5.2/linux/include/linux/zlib_fs.h linux/include/linux/zlib_fs.h
--- v2.5.2/linux/include/linux/zlib_fs.h	Mon Nov  5 13:40:59 2001
+++ linux/include/linux/zlib_fs.h	Tue Jan 29 21:30:41 2002
@@ -1,679 +1,36 @@
-/* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.1.3, July 9th, 1998
-
-  Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  jloup@gzip.org          madler@alumni.caltech.edu
-
-
-  The data format used by the zlib library is described by RFCs (Request for
-  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
-  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
-*/
-
-#ifndef _ZLIB_H
-#define _ZLIB_H
-
-#include "zconf.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define ZLIB_VERSION "1.1.3"
-
-/* 
-     The 'zlib' compression library provides in-memory compression and
-  decompression functions, including integrity checks of the uncompressed
-  data.  This version of the library supports only one compression method
-  (deflation) but other algorithms will be added later and will have the same
-  stream interface.
-
-     Compression can be done in a single step if the buffers are large
-  enough (for example if an input file is mmap'ed), or can be done by
-  repeated calls of the compression function.  In the latter case, the
-  application must provide more input and/or consume the output
-  (providing more output space) before each call.
-
-     The library also supports reading and writing files in gzip (.gz) format
-  with an interface similar to that of stdio.
-
-     The library does not install any signal handler. The decoder checks
-  the consistency of the compressed data, so the library should never
-  crash even in case of corrupted input.
-*/
-
-typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
-
-struct internal_state;
-
-typedef struct z_stream_s {
-    Bytef    *next_in;  /* next input byte */
-    uInt     avail_in;  /* number of bytes available at next_in */
-    uLong    total_in;  /* total nb of input bytes read so far */
-
-    Bytef    *next_out; /* next output byte should be put there */
-    uInt     avail_out; /* remaining free space at next_out */
-    uLong    total_out; /* total nb of bytes output so far */
-
-    char     *msg;      /* last error message, NULL if no error */
-    struct internal_state FAR *state; /* not visible by applications */
-
-    void     *workspace; /* memory allocated for this stream */
-
-    int     data_type;  /* best guess about the data type: ascii or binary */
-    uLong   adler;      /* adler32 value of the uncompressed data */
-    uLong   reserved;   /* reserved for future use */
-} z_stream;
-
-typedef z_stream FAR *z_streamp;
-
-/*
-   The application must update next_in and avail_in when avail_in has
-   dropped to zero. It must update next_out and avail_out when avail_out
-   has dropped to zero. The application must initialize zalloc, zfree and
-   opaque before calling the init function. All other fields are set by the
-   compression library and must not be updated by the application.
-
-   The opaque value provided by the application will be passed as the first
-   parameter for calls of zalloc and zfree. This can be useful for custom
-   memory management. The compression library attaches no meaning to the
-   opaque value.
-
-   zalloc must return Z_NULL if there is not enough memory for the object.
-   If zlib is used in a multi-threaded application, zalloc and zfree must be
-   thread safe.
-
-   On 16-bit systems, the functions zalloc and zfree must be able to allocate
-   exactly 65536 bytes, but will not be required to allocate more than this
-   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
-   pointers returned by zalloc for objects of exactly 65536 bytes *must*
-   have their offset normalized to zero. The default allocation function
-   provided by this library ensures this (see zutil.c). To reduce memory
-   requirements and avoid any allocation of 64K objects, at the expense of
-   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
-
-   The fields total_in and total_out can be used for statistics or
-   progress reports. After compression, total_in holds the total size of
-   the uncompressed data and may be saved for use in the decompressor
-   (particularly if the decompressor wants to decompress everything in
-   a single step).
-*/
-
-                        /* constants */
-
-#define Z_NO_FLUSH      0
-#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
-#define Z_SYNC_FLUSH    2
-#define Z_FULL_FLUSH    3
-#define Z_FINISH        4
-/* Allowed flush values; see deflate() below for details */
-
-#define Z_OK            0
-#define Z_STREAM_END    1
-#define Z_NEED_DICT     2
-#define Z_ERRNO        (-1)
-#define Z_STREAM_ERROR (-2)
-#define Z_DATA_ERROR   (-3)
-#define Z_MEM_ERROR    (-4)
-#define Z_BUF_ERROR    (-5)
-#define Z_VERSION_ERROR (-6)
-/* Return codes for the compression/decompression functions. Negative
- * values are errors, positive values are used for special but normal events.
- */
-
-#define Z_NO_COMPRESSION         0
-#define Z_BEST_SPEED             1
-#define Z_BEST_COMPRESSION       9
-#define Z_DEFAULT_COMPRESSION  (-1)
-/* compression levels */
-
-#define Z_FILTERED            1
-#define Z_HUFFMAN_ONLY        2
-#define Z_DEFAULT_STRATEGY    0
-/* compression strategy; see deflateInit2() below for details */
-
-#define Z_BINARY   0
-#define Z_ASCII    1
-#define Z_UNKNOWN  2
-/* Possible values of the data_type field */
-
-#define Z_DEFLATED   8
-/* The deflate compression method (the only one supported in this version) */
-
-#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
-
-                        /* basic functions */
-
-ZEXTERN const char * ZEXPORT zlib_fs_zlibVersion OF((void));
-/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
-   If the first character differs, the library code actually used is
-   not compatible with the zlib.h header file used by the application.
-   This check is automatically made by deflateInit and inflateInit.
- */
-
-/* 
-ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
-
-     Initializes the internal stream state for compression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.
-   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
-   use default allocation functions.
-
-     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
-   1 gives best speed, 9 gives best compression, 0 gives no compression at
-   all (the input data is simply copied a block at a time).
-   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
-   compression (currently equivalent to level 6).
-
-     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
-   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
-   with the version assumed by the caller (ZLIB_VERSION).
-   msg is set to null if there is no error message.  deflateInit does not
-   perform any compression: this will be done by deflate().
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_deflate OF((z_streamp strm, int flush));
-/*
-    deflate compresses as much data as possible, and stops when the input
-  buffer becomes empty or the output buffer becomes full. It may introduce some
-  output latency (reading input without producing any output) except when
-  forced to flush.
-
-    The detailed semantics are as follows. deflate performs one or both of the
-  following actions:
-
-  - Compress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in and avail_in are updated and
-    processing will resume at this point for the next call of deflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly. This action is forced if the parameter flush is non zero.
-    Forcing flush frequently degrades the compression ratio, so this parameter
-    should be set only when necessary (in interactive applications).
-    Some output may be provided even if flush is not set.
-
-  Before the call of deflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating avail_in or avail_out accordingly; avail_out
-  should never be zero before the call. The application can consume the
-  compressed output when it wants, for example when the output buffer is full
-  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
-  and with zero avail_out, it must be called again after making room in the
-  output buffer because there might be more output pending.
-
-    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
-  flushed to the output buffer and the output is aligned on a byte boundary, so
-  that the decompressor can get all input data available so far. (In particular
-  avail_in is zero after the call if enough output space has been provided
-  before the call.)  Flushing may degrade compression for some compression
-  algorithms and so it should be used only when necessary.
-
-    If flush is set to Z_FULL_FLUSH, all output is flushed as with
-  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
-  restart from this point if previous compressed data has been damaged or if
-  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
-  the compression.
-
-    If deflate returns with avail_out == 0, this function must be called again
-  with the same value of the flush parameter and more output space (updated
-  avail_out), until the flush is complete (deflate returns with non-zero
-  avail_out).
-
-    If the parameter flush is set to Z_FINISH, pending input is processed,
-  pending output is flushed and deflate returns with Z_STREAM_END if there
-  was enough output space; if deflate returns with Z_OK, this function must be
-  called again with Z_FINISH and more output space (updated avail_out) but no
-  more input data, until it returns with Z_STREAM_END or an error. After
-  deflate has returned Z_STREAM_END, the only possible operations on the
-  stream are deflateReset or deflateEnd.
-  
-    Z_FINISH can be used immediately after deflateInit if all the compression
-  is to be done in a single step. In this case, avail_out must be at least
-  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
-  Z_STREAM_END, then it must be called again as described above.
-
-    deflate() sets strm->adler to the adler32 checksum of all input read
-  so far (that is, total_in bytes).
-
-    deflate() may update data_type if it can make a good guess about
-  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
-  binary. This field is only for information purposes and does not affect
-  the compression algorithm in any manner.
-
-    deflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if all input has been
-  consumed and all output has been produced (only when flush is set to
-  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
-  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
-  (for example avail_in or avail_out was zero).
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_deflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
-   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
-   prematurely (some input or output was discarded). In the error case,
-   msg may be set but then points to a static string (which must not be
-   deallocated).
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_inflate_workspacesize OF((void));
-/*
-   Returns the number of bytes that needs to be allocated for a per-
-   stream workspace.  A pointer to this number of bytes should be
-   returned in stream->workspace before calling zlib_fs_inflateInit().
-*/
-
-/* 
-ZEXTERN int ZEXPORT zlib_fs_inflateInit OF((z_streamp strm));
-
-     Initializes the internal stream state for decompression. The fields
-   next_in, avail_in, and workspace must be initialized before by
-   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
-   value depends on the compression method), inflateInit determines the
-   compression method from the zlib header and allocates all data structures
-   accordingly; otherwise the allocation will be deferred to the first call of
-   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
-   use default allocation functions.
-
-     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
-   version assumed by the caller.  msg is set to null if there is no error
-   message. inflateInit does not perform any decompression apart from reading
-   the zlib header if present: this will be done by inflate().  (So next_in and
-   avail_in may be modified, but next_out and avail_out are unchanged.)
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_inflate OF((z_streamp strm, int flush));
-/*
-    inflate decompresses as much data as possible, and stops when the input
-  buffer becomes empty or the output buffer becomes full. It may some
-  introduce some output latency (reading input without producing any output)
-  except when forced to flush.
-
-  The detailed semantics are as follows. inflate performs one or both of the
-  following actions:
-
-  - Decompress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in is updated and processing
-    will resume at this point for the next call of inflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly.  inflate() provides as much output as possible, until there
-    is no more input data or no more space in the output buffer (see below
-    about the flush parameter).
-
-  Before the call of inflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating the next_* and avail_* values accordingly.
-  The application can consume the uncompressed output when it wants, for
-  example when the output buffer is full (avail_out == 0), or after each
-  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
-  must be called again after making room in the output buffer because there
-  might be more output pending.
-
-    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
-  output as possible to the output buffer. The flushing behavior of inflate is
-  not specified for values of the flush parameter other than Z_SYNC_FLUSH
-  and Z_FINISH, but the current implementation actually flushes as much output
-  as possible anyway.
-
-    inflate() should normally be called until it returns Z_STREAM_END or an
-  error. However if all decompression is to be performed in a single step
-  (a single call of inflate), the parameter flush should be set to
-  Z_FINISH. In this case all pending input is processed and all pending
-  output is flushed; avail_out must be large enough to hold all the
-  uncompressed data. (The size of the uncompressed data may have been saved
-  by the compressor for this purpose.) The next operation on this stream must
-  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
-  is never required, but can be used to inform inflate that a faster routine
-  may be used for the single inflate() call.
-
-     If a preset dictionary is needed at this point (see inflateSetDictionary
-  below), inflate sets strm-adler to the adler32 checksum of the
-  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
-  it sets strm->adler to the adler32 checksum of all output produced
-  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
-  an error code as described below. At the end of the stream, inflate()
-  checks that its computed adler32 checksum is equal to that saved by the
-  compressor and returns Z_STREAM_END only if the checksum is correct.
-
-    inflate() returns Z_OK if some progress has been made (more input processed
-  or more output produced), Z_STREAM_END if the end of the compressed data has
-  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
-  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
-  corrupted (input stream not conforming to the zlib format or incorrect
-  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
-  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
-  enough memory, Z_BUF_ERROR if no progress is possible or if there was not
-  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
-  case, the application may then call inflateSync to look for a good
-  compression block.
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_inflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
-   was inconsistent. In the error case, msg may be set but then points to a
-   static string (which must not be deallocated).
-*/
-
-                        /* Advanced functions */
-
-/*
-    The following functions are needed only in some special applications.
-*/
-
-/*   
-ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
-                                     int  level,
-                                     int  method,
-                                     int  windowBits,
-                                     int  memLevel,
-                                     int  strategy));
-
-     This is another version of deflateInit with more compression options. The
-   fields next_in, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The method parameter is the compression method. It must be Z_DEFLATED in
-   this version of the library.
-
-     The windowBits parameter is the base two logarithm of the window size
-   (the size of the history buffer).  It should be in the range 8..15 for this
-   version of the library. Larger values of this parameter result in better
-   compression at the expense of memory usage. The default value is 15 if
-   deflateInit is used instead.
-
-     The memLevel parameter specifies how much memory should be allocated
-   for the internal compression state. memLevel=1 uses minimum memory but
-   is slow and reduces compression ratio; memLevel=9 uses maximum memory
-   for optimal speed. The default value is 8. See zconf.h for total memory
-   usage as a function of windowBits and memLevel.
-
-     The strategy parameter is used to tune the compression algorithm. Use the
-   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
-   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
-   string match).  Filtered data consists mostly of small values with a
-   somewhat random distribution. In this case, the compression algorithm is
-   tuned to compress them better. The effect of Z_FILTERED is to force more
-   Huffman coding and less string matching; it is somewhat intermediate
-   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
-   the compression ratio but not the correctness of the compressed output even
-   if it is not set appropriately.
-
-      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
-   method). msg is set to null if there is no error message.  deflateInit2 does
-   not perform any compression: this will be done by deflate().
-*/
-                            
-ZEXTERN int ZEXPORT zlib_fs_deflateSetDictionary OF((z_streamp strm,
-						     const Bytef *dictionary,
-						     uInt  dictLength));
-/*
-     Initializes the compression dictionary from the given byte sequence
-   without producing any compressed output. This function must be called
-   immediately after deflateInit, deflateInit2 or deflateReset, before any
-   call of deflate. The compressor and decompressor must use exactly the same
-   dictionary (see inflateSetDictionary).
-
-     The dictionary should consist of strings (byte sequences) that are likely
-   to be encountered later in the data to be compressed, with the most commonly
-   used strings preferably put towards the end of the dictionary. Using a
-   dictionary is most useful when the data to be compressed is short and can be
-   predicted with good accuracy; the data can then be compressed better than
-   with the default empty dictionary.
-
-     Depending on the size of the compression data structures selected by
-   deflateInit or deflateInit2, a part of the dictionary may in effect be
-   discarded, for example if the dictionary is larger than the window size in
-   deflate or deflate2. Thus the strings most likely to be useful should be
-   put at the end of the dictionary, not at the front.
-
-     Upon return of this function, strm->adler is set to the Adler32 value
-   of the dictionary; the decompressor may later use this value to determine
-   which dictionary has been used by the compressor. (The Adler32 value
-   applies to the whole dictionary even if only a subset of the dictionary is
-   actually used by the compressor.)
-
-     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent (for example if deflate has already been called for this stream
-   or if the compression method is bsort). deflateSetDictionary does not
-   perform any compression: this will be done by deflate().
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_deflateCopy OF((z_streamp dest,
-					    z_streamp source));
-/*
-     Sets the destination stream as a complete copy of the source stream.
-
-     This function can be useful when several compression strategies will be
-   tried, for example when there are several ways of pre-processing the input
-   data with a filter. The streams that will be discarded should then be freed
-   by calling deflateEnd.  Note that deflateCopy duplicates the internal
-   compression state which can be quite large, so this strategy is slow and
-   can consume lots of memory.
-
-     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
-   (such as zalloc being NULL). msg is left unchanged in both source and
-   destination.
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_deflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to deflateEnd followed by deflateInit,
-   but does not free and reallocate all the internal compression state.
-   The stream will keep the same compression level and any other attributes
-   that may have been set by deflateInit2.
-
-      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_deflateParams OF((z_streamp strm,
-					      int level,
-					      int strategy));
-/*
-     Dynamically update the compression level and compression strategy.  The
-   interpretation of level and strategy is as in deflateInit2.  This can be
-   used to switch between compression and straight copy of the input data, or
-   to switch to a different kind of input data requiring a different
-   strategy. If the compression level is changed, the input available so far
-   is compressed with the old level (and may be flushed); the new level will
-   take effect only at the next call of deflate().
-
-     Before the call of deflateParams, the stream state must be set as for
-   a call of deflate(), since the currently available input may have to
-   be compressed and flushed. In particular, strm->avail_out must be non-zero.
-
-     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
-   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
-   if strm->avail_out was zero.
-*/
-
-/*   
-ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
-                                     int  windowBits));
-
-     This is another version of inflateInit with an extra parameter. The
-   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
-   before by the caller.
-
-     The windowBits parameter is the base two logarithm of the maximum window
-   size (the size of the history buffer).  It should be in the range 8..15 for
-   this version of the library. The default value is 15 if inflateInit is used
-   instead. If a compressed stream with a larger window size is given as
-   input, inflate() will return with the error code Z_DATA_ERROR instead of
-   trying to allocate a larger window.
-
-      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
-   memLevel). msg is set to null if there is no error message.  inflateInit2
-   does not perform any decompression apart from reading the zlib header if
-   present: this will be done by inflate(). (So next_in and avail_in may be
-   modified, but next_out and avail_out are unchanged.)
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_inflateSetDictionary OF((z_streamp strm,
-						     const Bytef *dictionary,
-						     uInt  dictLength));
-/*
-     Initializes the decompression dictionary from the given uncompressed byte
-   sequence. This function must be called immediately after a call of inflate
-   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
-   can be determined from the Adler32 value returned by this call of
-   inflate. The compressor and decompressor must use exactly the same
-   dictionary (see deflateSetDictionary).
-
-     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
-   expected one (incorrect Adler32 value). inflateSetDictionary does not
-   perform any decompression: this will be done by subsequent calls of
-   inflate().
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_inflateSync OF((z_streamp strm));
-/* 
-    Skips invalid compressed data until a full flush point (see above the
-  description of deflate with Z_FULL_FLUSH) can be found, or until all
-  available input is skipped. No output is provided.
-
-    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
-  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
-  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
-  case, the application may save the current current value of total_in which
-  indicates where valid compressed data was found. In the error case, the
-  application may repeatedly call inflateSync, providing more input each time,
-  until success or end of the input data.
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_inflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to inflateEnd followed by inflateInit,
-   but does not free and reallocate all the internal decompression state.
-   The stream will keep attributes that may have been set by inflateInit2.
-
-      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-                        /* checksum functions */
-
-/*
-     These functions are not related to compression but are exported
-   anyway because they might be useful in applications using the
-   compression library.
-*/
-
-ZEXTERN uLong ZEXPORT zlib_fs_adler32 OF((uLong adler, const Bytef *buf, uInt len));
-
-/*
-     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
-   return the updated checksum. If buf is NULL, this function returns
-   the required initial value for the checksum.
-   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
-   much faster. Usage example:
-
-     uLong adler = adler32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       adler = adler32(adler, buffer, length);
-     }
-     if (adler != original_adler) error();
-*/
-
-ZEXTERN uLong ZEXPORT zlib_fs_crc32   OF((uLong crc, const Bytef *buf, uInt len));
-/*
-     Update a running crc with the bytes buf[0..len-1] and return the updated
-   crc. If buf is NULL, this function returns the required initial value
-   for the crc. Pre- and post-conditioning (one's complement) is performed
-   within this function so it shouldn't be done by the application.
-   Usage example:
-
-     uLong crc = crc32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       crc = crc32(crc, buffer, length);
-     }
-     if (crc != original_crc) error();
-*/
-
-
-                        /* various hacks, don't look :) */
-
-/* deflateInit and inflateInit are macros to allow checking the zlib version
- * and the compiler's view of z_stream:
- */
-ZEXTERN int ZEXPORT zlib_fs_deflateInit_ OF((z_streamp strm, int level,
-                                     const char *version, int stream_size));
-ZEXTERN int ZEXPORT zlib_fs_inflateInit_ OF((z_streamp strm,
-                                     const char *version, int stream_size));
-ZEXTERN int ZEXPORT zlib_fs_deflateInit2_ OF((z_streamp strm, int  level, int  method,
-                                      int windowBits, int memLevel,
-                                      int strategy, const char *version,
-                                      int stream_size));
-ZEXTERN int ZEXPORT zlib_fs_inflateInit2_ OF((z_streamp strm, int  windowBits,
-                                      const char *version, int stream_size));
+/* zlib_fs.h -- A compatability file mapping the zlib functions to zlib_fs
+   functions.   This will go away. */
+#ifndef _ZLIB_FS_H
+#define _ZLIB_FS_H
+
+#include <linux/zlib.h>
+
+#define zlib_fs_inflate_workspacesize zlib_inflate_workspacesize
+#define zlib_fs_deflate_workspacesize zlib_deflate_workspacesize
+#define zlib_fs_zlibVersion zlib_zlibVersion
+#define zlib_fs_deflate zlib_deflate
+#define zlib_fs_deflateEnd zlib_deflateEnd
+#define zlib_fs_inflate zlib_inflate
+#define zlib_fs_inflateEnd zlib_inflateEnd
+#define zlib_fs_deflateSetDictionary zlib_deflateSetDictionary
+#define zlib_fs_deflateCopy zlib_deflateCopy
+#define zlib_fs_deflateReset zlib_deflateReset
+#define zlib_fs_deflateParams zlib_deflateParams
+#define zlib_fs_inflateIncomp zlib_inflateIncomp
+#define zlib_fs_inflateSetDictionary zlib_inflateSetDictionary
+#define zlib_fs_inflateSync zlib_inflateSync
+#define zlib_fs_inflateReset zlib_inflateReset
+#define zlib_fs_adler32 zlib_adler32
+#define zlib_fs_crc32 zlib_crc32
 #define zlib_fs_deflateInit(strm, level) \
-        zlib_fs_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+        zlib_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
 #define zlib_fs_inflateInit(strm) \
-        zlib_fs_inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
-#define zlib_fs_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
-        zlib_fs_deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
-                      (strategy), ZLIB_VERSION, sizeof(z_stream))
+        zlib_inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define zlib_fs_deflateInit2(strm, level, method, windowBits, memLevel, strategy)\
+        zlib_deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+		              (strategy), ZLIB_VERSION, sizeof(z_stream))
 #define zlib_fs_inflateInit2(strm, windowBits) \
-        zlib_fs_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
-
-
-#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
-    struct internal_state {int dummy;}; /* hack for buggy compilers */
-#endif
-
-ZEXTERN const char   * ZEXPORT zlib_fs_zError           OF((int err));
-ZEXTERN int            ZEXPORT zlib_fs_inflateSyncPoint OF((z_streamp z));
-ZEXTERN const uLongf * ZEXPORT zlib_fs_get_crc_table    OF((void));
-
-#ifdef __cplusplus
-}
-#endif
+        zlib_inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
+                              sizeof(z_stream))
 
-#endif /* _ZLIB_H */
+#endif /* _ZLIB_FS_H */
diff -u --recursive --new-file v2.5.2/linux/include/net/dn_fib.h linux/include/net/dn_fib.h
--- v2.5.2/linux/include/net/dn_fib.h	Mon Dec 11 13:33:56 2000
+++ linux/include/net/dn_fib.h	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/include/net/inetpeer.h linux/include/net/inetpeer.h
--- v2.5.2/linux/include/net/inetpeer.h	Thu Nov 22 11:47:11 2001
+++ linux/include/net/inetpeer.h	Tue Jan 29 21:41:50 2002
@@ -1,7 +1,7 @@
 /*
  *		INETPEER - A storage for permanent information about peers
  *
- *  Version:	$Id: inetpeer.h,v 1.1 2000/01/06 00:41:51 davem Exp $
+ *  Version:	$Id: inetpeer.h,v 1.2 2002/01/12 07:54:56 davem Exp $
  *
  *  Authors:	Andrey V. Savochkin <saw@msu.ru>
  */
@@ -38,7 +38,7 @@
 extern struct inet_peer *inet_peer_unused_head;
 extern struct inet_peer **inet_peer_unused_tailp;
 /* can be called from BH context or outside */
-extern inline void	inet_putpeer(struct inet_peer *p)
+static inline void	inet_putpeer(struct inet_peer *p)
 {
 	spin_lock_bh(&inet_peer_unused_lock);
 	if (atomic_dec_and_test(&p->refcnt)) {
@@ -53,7 +53,7 @@
 
 extern spinlock_t inet_peer_idlock;
 /* can be called with or without local BH being disabled */
-extern inline __u16	inet_getid(struct inet_peer *p)
+static inline __u16	inet_getid(struct inet_peer *p)
 {
 	__u16 id;
 
diff -u --recursive --new-file v2.5.2/linux/include/net/iw_handler.h linux/include/net/iw_handler.h
--- v2.5.2/linux/include/net/iw_handler.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/iw_handler.h	Tue Jan 29 21:41:52 2002
@@ -0,0 +1,374 @@
+/*
+ * This file define the new driver API for Wireless Extensions
+ *
+ * Version :	2	6.12.01
+ *
+ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
+ */
+
+#ifndef _IW_HANDLER_H
+#define _IW_HANDLER_H
+
+/************************** DOCUMENTATION **************************/
+/*
+ * Initial driver API (1996 -> onward) :
+ * -----------------------------------
+ * The initial API just sends the IOCTL request received from user space
+ * to the driver (via the driver ioctl handler). The driver has to
+ * handle all the rest...
+ *
+ * The initial API also defines a specific handler in struct net_device
+ * to handle wireless statistics.
+ *
+ * The initial APIs served us well and has proven a reasonably good design.
+ * However, there is a few shortcommings :
+ *	o No events, everything is a request to the driver.
+ *	o Large ioctl function in driver with gigantic switch statement
+ *	  (i.e. spaghetti code).
+ *	o Driver has to mess up with copy_to/from_user, and in many cases
+ *	  does it unproperly. Common mistakes are :
+ *		* buffer overflows (no checks or off by one checks)
+ *		* call copy_to/from_user with irq disabled
+ *	o The user space interface is tied to ioctl because of the use
+ *	  copy_to/from_user.
+ *
+ * New driver API (2001 -> onward) :
+ * -------------------------------
+ * The new driver API is just a bunch of standard functions (handlers),
+ * each handling a specific Wireless Extension. The driver just export
+ * the list of handler it supports, and those will be called apropriately.
+ *
+ * I tried to keep the main advantage of the previous API (simplicity,
+ * efficiency and light weight), and also I provide a good dose of backward
+ * compatibility (most structures are the same, driver can use both API
+ * simultaneously, ...).
+ * Hopefully, I've also addressed the shortcomming of the initial API.
+ *
+ * The advantage of the new API are :
+ *	o Handling of Extensions in driver broken in small contained functions
+ *	o Tighter checks of ioctl before calling the driver
+ *	o Flexible commit strategy (at least, the start of it)
+ *	o Backward compatibility (can be mixed with old API)
+ *	o Driver doesn't have to worry about memory and user-space issues
+ * The last point is important for the following reasons :
+ *	o You are now able to call the new driver API from any API you
+ *		want (including from within other parts of the kernel).
+ *	o Common mistakes are avoided (buffer overflow, user space copy
+ *		with irq disabled and so on).
+ *
+ * The Drawback of the new API are :
+ *	o bloat (especially kernel)
+ *	o need to migrate existing drivers to new API
+ * My initial testing shows that the new API adds around 3kB to the kernel
+ * and save between 0 and 5kB from a typical driver.
+ * Also, as all structures and data types are unchanged, the migration is
+ * quite straightforward (but tedious).
+ *
+ * ---
+ *
+ * The new driver API is defined below in this file. User space should
+ * not be aware of what's happening down there...
+ *
+ * A new kernel wrapper is in charge of validating the IOCTLs and calling
+ * the appropriate driver handler. This is implemented in :
+ *	# net/core/wireless.c
+ *
+ * The driver export the list of handlers in :
+ *	# include/linux/netdevice.h (one place)
+ *
+ * The new driver API is available for WIRELESS_EXT >= 13.
+ * Good luck with migration to the new API ;-)
+ */
+
+/* ---------------------- THE IMPLEMENTATION ---------------------- */
+/*
+ * Some of the choice I've made are pretty controversials. Defining an
+ * API is very much weighting compromises. This goes into some of the
+ * details and the thinking behind the implementation.
+ *
+ * Implementation goals :
+ * --------------------
+ * The implementation goals were as follow :
+ *	o Obvious : you should not need a PhD to understand what's happening,
+ *		the benefit is easier maintainance.
+ *	o Flexible : it should accomodate a wide variety of driver
+ *		implementations and be as flexible as the old API.
+ *	o Lean : it should be efficient memory wise to minimise the impact
+ *		on kernel footprint.
+ *	o Transparent to user space : the large number of user space
+ *		applications that use Wireless Extensions should not need
+ *		any modifications.
+ *
+ * Array of functions versus Struct of functions
+ * ---------------------------------------------
+ * 1) Having an array of functions allow the kernel code to access the
+ * handler in a single lookup, which is much more efficient (think hash
+ * table here).
+ * 2) The only drawback is that driver writer may put their handler in
+ * the wrong slot. This is trivial to test (I set the frequency, the
+ * bitrate changes). Once the handler is in the proper slot, it will be
+ * there forever, because the array is only extended at the end.
+ * 3) Backward/forward compatibility : adding new handler just require
+ * extending the array, so you can put newer driver in older kernel
+ * without having to patch the kernel code (and vice versa).
+ *
+ * All handler are of the same generic type
+ * ----------------------------------------
+ * That's a feature !!!
+ * 1) Having a generic handler allow to have generic code, which is more
+ * efficient. If each of the handler was individually typed I would need
+ * to add a big switch in the kernel (== more bloat). This solution is
+ * more scalable, adding new Wireless Extensions doesn't add new code.
+ * 2) You can use the same handler in different slots of the array. For
+ * hardware, it may be more efficient or logical to handle multiple
+ * Wireless Extensions with a single function, and the API allow you to
+ * do that. (An example would be a single record on the card to control
+ * both bitrate and frequency, the handler would read the old record,
+ * modify it according to info->cmd and rewrite it).
+ *
+ * Functions prototype uses union iwreq_data
+ * -----------------------------------------
+ * Some would have prefered functions defined this way :
+ *	static int mydriver_ioctl_setrate(struct net_device *dev, 
+ *					  long rate, int auto)
+ * 1) The kernel code doesn't "validate" the content of iwreq_data, and
+ * can't do it (different hardware may have different notion of what a
+ * valid frequency is), so we don't pretend that we do it.
+ * 2) The above form is not extendable. If I want to add a flag (for
+ * example to distinguish setting max rate and basic rate), I would
+ * break the prototype. Using iwreq_data is more flexible.
+ * 3) Also, the above form is not generic (see above).
+ * 4) I don't expect driver developper using the wrong field of the
+ * union (Doh !), so static typechecking doesn't add much value.
+ * 5) Lastly, you can skip the union by doing :
+ *	static int mydriver_ioctl_setrate(struct net_device *dev,
+ *					  struct iw_request_info *info,
+ *					  struct iw_param *rrq,
+ *					  char *extra)
+ * And then adding the handler in the array like this :
+ *        (iw_handler) mydriver_ioctl_setrate,             // SIOCSIWRATE
+ *
+ * Using functions and not a registry
+ * ----------------------------------
+ * Another implementation option would have been for every instance to
+ * define a registry (a struct containing all the Wireless Extensions)
+ * and only have a function to commit the registry to the hardware.
+ * 1) This approach can be emulated by the current code, but not
+ * vice versa.
+ * 2) Some drivers don't keep any configuration in the driver, for them
+ * adding such a registry would be a significant bloat.
+ * 3) The code to translate from Wireless Extension to native format is
+ * needed anyway, so it would not reduce significantely the amount of code.
+ * 4) The current approach only selectively translate Wireless Extensions
+ * to native format and only selectively set, whereas the registry approach
+ * would require to translate all WE and set all parameters for any single
+ * change.
+ * 5) For many Wireless Extensions, the GET operation return the current
+ * dynamic value, not the value that was set.
+ *
+ * This header is <net/iw_handler.h>
+ * ---------------------------------
+ * 1) This header is kernel space only and should not be exported to
+ * user space. Headers in "include/linux/" are exported, headers in
+ * "include/net/" are not.
+ *
+ * Mixed 32/64 bit issues
+ * ----------------------
+ * The Wireless Extensions are designed to be 64 bit clean, by using only
+ * datatypes with explicit storage size.
+ * There are some issues related to kernel and user space using different
+ * memory model, and in particular 64bit kernel with 32bit user space.
+ * The problem is related to struct iw_point, that contains a pointer
+ * that *may* need to be translated.
+ * This is quite messy. The new API doesn't solve this problem (it can't),
+ * but is a step in the right direction :
+ * 1) Meta data about each ioctl is easily available, so we know what type
+ * of translation is needed.
+ * 2) The move of data between kernel and user space is only done in a single
+ * place in the kernel, so adding specific hooks in there is possible.
+ * 3) In the long term, it allows to move away from using ioctl as the
+ * user space API.
+ *
+ * So many comments and so few code
+ * --------------------------------
+ * That's a feature. Comments won't bloat the resulting kernel binary.
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <linux/wireless.h>		/* IOCTL user space API */
+
+/***************************** VERSION *****************************/
+/*
+ * This constant is used to know which version of the driver API is
+ * available. Hopefully, this will be pretty stable and no changes
+ * will be needed...
+ * I just plan to increment with each new version.
+ */
+#define IW_HANDLER_VERSION	2
+
+/**************************** CONSTANTS ****************************/
+
+/* Special error message for the driver to indicate that we
+ * should do a commit after return from the iw_handler */
+#define EIWCOMMIT	EINPROGRESS
+
+/* Flags available in struct iw_request_info */
+#define IW_REQUEST_FLAG_NONE	0x0000	/* No flag so far */
+
+/* Type of headers we know about (basically union iwreq_data) */
+#define IW_HEADER_TYPE_NULL	0	/* Not available */
+#define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
+#define IW_HEADER_TYPE_UINT	4	/* __u32 */
+#define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
+#define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
+#define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
+#define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
+
+/* Handling flags */
+/* Most are not implemented. I just use them as a reminder of some
+ * cool features we might need one day ;-) */
+#define IW_DESCR_FLAG_NONE	0x0000	/* Obvious */
+/* Wrapper level flags */
+#define IW_DESCR_FLAG_DUMP	0x0001	/* Not part of the dump command */
+#define IW_DESCR_FLAG_EVENT	0x0002	/* Generate an event on SET */
+#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET request is ROOT only */
+/* Driver level flags */
+#define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
+
+/****************************** TYPES ******************************/
+
+/* ----------------------- WIRELESS HANDLER ----------------------- */
+/*
+ * A wireless handler is just a standard function, that looks like the
+ * ioctl handler.
+ * We also define there how a handler list look like... As the Wireless
+ * Extension space is quite dense, we use a simple array, which is faster
+ * (that's the perfect hash table ;-).
+ */
+
+/*
+ * Meta data about the request passed to the iw_handler.
+ * Most handlers can safely ignore what's in there.
+ * The 'cmd' field might come handy if you want to use the same handler
+ * for multiple command...
+ * This struct is also my long term insurance. I can add new fields here
+ * without breaking the prototype of iw_handler...
+ */
+struct iw_request_info
+{
+	__u16		cmd;		/* Wireless Extension command */
+	__u16		flags;		/* More to come ;-) */
+};
+
+/*
+ * This is how a function handling a Wireless Extension should look
+ * like (both get and set, standard and private).
+ */
+typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
+			  union iwreq_data *wrqu, char *extra);
+
+/*
+ * This define all the handler that the driver export.
+ * As you need only one per driver type, please use a static const
+ * shared by all driver instances... Same for the members...
+ * This will be linked from net_device in <linux/netdevice.h>
+ */
+struct iw_handler_def
+{
+	/* Number of handlers defined (more precisely, index of the
+	 * last defined handler + 1) */
+	__u16			num_standard;
+	__u16			num_private;
+	/* Number of private arg description */
+	__u16			num_private_args;
+
+	/* Array of handlers for standard ioctls
+	 * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
+	 */
+	iw_handler *		standard;
+
+	/* Array of handlers for private ioctls
+	 * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
+	 */
+	iw_handler *		private;
+
+	/* Arguments of private handler. This one is just a list, so you
+	 * can put it in any order you want and should not leave holes...
+	 * We will automatically export that to user space... */
+	struct iw_priv_args *	private_args;
+
+	/* In the long term, get_wireless_stats will move from
+	 * 'struct net_device' to here, to minimise bloat. */
+};
+
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/*
+ * Currently we don't support events, so let's just plan for the
+ * future...
+ */
+
+/*
+ * A Wireless Event.
+ */
+// How do we define short header ? We don't want a flag on length.
+// Probably a flag on event ? Highest bit to zero...
+struct iw_event
+{
+	__u16		length;			/* Lenght of this stuff */
+	__u16		event;			/* Wireless IOCTL */
+	union	iwreq_data	header;		/* IOCTL fixed payload */
+	char		extra[0];		/* Optional IOCTL data */
+};
+
+/* ---------------------- IOCTL DESCRIPTION ---------------------- */
+/*
+ * One of the main goal of the new interface is to deal entirely with
+ * user space/kernel space memory move.
+ * For that, we need to know :
+ *	o if iwreq is a pointer or contain the full data
+ *	o what is the size of the data to copy
+ *
+ * For private IOCTLs, we use the same rules as used by iwpriv and
+ * defined in struct iw_priv_args.
+ *
+ * For standard IOCTLs, things are quite different and we need to
+ * use the stuctures below. Actually, this struct is also more
+ * efficient, but that's another story...
+ */
+
+/*
+ * Describe how a standard IOCTL looks like.
+ */
+struct iw_ioctl_description
+{
+	__u8	header_type;		/* NULL, iw_point or other */
+	__u8	token_type;		/* Future */
+	__u16	token_size;		/* Granularity of payload */
+	__u16	min_tokens;		/* Min acceptable token number */
+	__u16	max_tokens;		/* Max acceptable token number */
+	__u32	flags;			/* Special handling of the request */
+};
+
+/* Need to think of short header translation table. Later. */
+
+/**************************** PROTOTYPES ****************************/
+/*
+ * Functions part of the Wireless Extensions (defined in net/core/wireless.c).
+ * Those may be called only within the kernel.
+ */
+
+/* First : function strictly used inside the kernel */
+
+/* Handle /proc/net/wireless, called in net/code/dev.c */
+extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+				 int length);
+
+/* Handle IOCTLs, called in net/code/dev.c */
+extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
+
+/* Second : functions that may be called by driver modules */
+/* None yet */
+
+#endif	/* _LINUX_WIRELESS_H */
diff -u --recursive --new-file v2.5.2/linux/include/net/route.h linux/include/net/route.h
--- v2.5.2/linux/include/net/route.h	Thu Nov 22 11:47:15 2001
+++ linux/include/net/route.h	Tue Jan 29 21:41:56 2002
@@ -30,6 +30,7 @@
 #include <linux/in_route.h>
 #include <linux/rtnetlink.h>
 #include <linux/route.h>
+#include <linux/ip.h>
 #include <linux/cache.h>
 
 #ifndef __KERNEL__
diff -u --recursive --new-file v2.5.2/linux/include/net/sock.h linux/include/net/sock.h
--- v2.5.2/linux/include/net/sock.h	Thu Nov 22 11:47:15 2001
+++ linux/include/net/sock.h	Tue Jan 29 21:41:56 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/include/scsi/sg.h linux/include/scsi/sg.h
--- v2.5.2/linux/include/scsi/sg.h	Fri Sep  7 09:28:37 2001
+++ linux/include/scsi/sg.h	Thu Jan 17 13:59:33 2002
@@ -11,78 +11,71 @@
 Version 2 and 3 extensions to driver:
 *       Copyright (C) 1998 - 2001 Douglas Gilbert
 
-    Version: 3.1.20 (20010814)
-    This version is for 2.4 series kernels.
+    Version: 3.5.23 (20011231)
+    This version is for 2.5 series kernels.
 
-    Changes since 3.1.19 (20010623)
-	- add SG_GET_ACCESS_COUNT ioctl 
-	- make open() increment and close() decrement access_count
-	- only register first 256 devices, reject subsequent devices
-    Changes since 3.1.18 (20010505)
-	- fix bug that caused long wait when large buffer requested
-	- fix leak in error case of sg_new_read() [report: Eric Barton]
-	- add 'online' column to /proc/scsi/sg/devices
-    Changes since 3.1.17 (20000921)
-    	- add CAP_SYS_RAWIO capability for sensitive stuff
-    	- compile in dio stuff, procfs 'allow_dio' defaulted off (0)
-	- make premature close and detach more robust
-	- lun masked into commands <= SCSI_2
-	- poll() and async notification now yield POLL_HUP on detach
-	- various 3rd party tweaks tracking lk 2.4 internal changes
+    Changes since 3.1.22 (20011208)
+    	- branch sg driver for lk 2.5 series
+    	- remove lock_kernel() from sg_close()
+    	- remove code based on scsi mid level dma pool
+    	- change scatterlist 'address' to use page + offset
+    	- add SG_INTERFACE_ID_ORIG
 
 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++
+       3.5.23++          2.5.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 */
@@ -119,20 +112,23 @@
     unsigned int info;          /* [o] auxiliary information */
 } sg_io_hdr_t;  /* 64 bytes long (on i386) */
 
+#define SG_INTERFACE_ID_ORIG 'S'
+
 /* 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 -u --recursive --new-file v2.5.2/linux/init/Config.help linux/init/Config.help
--- v2.5.2/linux/init/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/init/Config.help	Fri Jan 25 16:03:31 2002
@@ -0,0 +1,117 @@
+CONFIG_EXPERIMENTAL
+  Some of the various things that Linux supports (such as network
+  drivers, file systems, network protocols, etc.) can be in a state
+  of development where the functionality, stability, or the level of
+  testing is not yet high enough for general use. This is usually
+  known as the "alpha-test" phase among developers. If a feature is
+  currently in alpha-test, then the developers usually discourage
+  uninformed widespread use of this feature by the general public to
+  avoid "Why doesn't this work?" type mail messages. However, active
+  testing and use of these systems is welcomed. Just be aware that it
+  may not meet the normal level of reliability or it may fail to work
+  in some special cases. Detailed bug reports from people familiar
+  with the kernel internals are usually welcomed by the developers
+  (before submitting bug reports, please read the documents
+  <file:README>, <file:MAINTAINERS>, <file:REPORTING-BUGS>,
+  <file:Documentation/BUG-HUNTING>, and
+  <file:Documentation/oops-tracing.txt> in the kernel source).
+
+  This option will also make obsoleted drivers available. These are
+  drivers that have been replaced by something else, and/or are
+  scheduled to be removed in a future kernel release.
+
+  Unless you intend to help test and develop a feature or driver that
+  falls into this category, or you have a situation that requires
+  using these features, you should probably say N here, which will
+  cause the configurator to present you with fewer choices. If
+  you say Y here, you will be offered the choice of using features or
+  drivers that are currently considered to be in the alpha-test phase.
+
+CONFIG_NET
+  Unless you really know what you are doing, you should say Y here.
+  The reason is that some programs need kernel networking support even
+  when running on a stand-alone machine that isn't connected to any
+  other computer. If you are upgrading from an older kernel, you
+  should consider updating your networking tools too because changes
+  in the kernel and the tools often go hand in hand. The tools are
+  contained in the package net-tools, the location and version number
+  of which are given in <file:Documentation/Changes>.
+
+  For a general introduction to Linux networking, it is highly
+  recommended to read the NET-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+CONFIG_SYSVIPC
+  Inter Process Communication is a suite of library functions and
+  system calls which let processes (running programs) synchronize and
+  exchange information. It is generally considered to be a good thing,
+  and some programs won't run unless you say Y here. In particular, if
+  you want to run the DOS emulator dosemu under Linux (read the
+  DOSEMU-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>), you'll need to say Y
+  here.
+
+  You can find documentation about IPC with "info ipc" and also in
+  section 6.4 of the Linux Programmer's Guide, available from
+  <http://www.linuxdoc.org/docs.html#guide>.
+
+CONFIG_BSD_PROCESS_ACCT
+  If you say Y here, a user level program will be able to instruct the
+  kernel (via a special system call) to write process accounting
+  information to a file: whenever a process exits, information about
+  that process will be appended to the file by the kernel.  The
+  information includes things such as creation time, owning user,
+  command name, memory usage, controlling terminal etc. (the complete
+  list is in the struct acct in <file:include/linux/acct.h>).  It is
+  up to the user level program to do useful things with this
+  information.  This is generally a good idea, so say Y.
+
+CONFIG_SYSCTL
+  The sysctl interface provides a means of dynamically changing
+  certain kernel parameters and variables on the fly without requiring
+  a recompile of the kernel or reboot of the system.  The primary
+  interface consists of a system call, but if you say Y to "/proc
+  file system support", a tree of modifiable sysctl entries will be
+  generated beneath the /proc/sys directory. They are explained in the
+  files in <file:Documentation/sysctl/>.  Note that enabling this
+  option will enlarge the kernel by at least 8 KB.
+
+  As it is generally a good thing, you should say Y here unless
+  building a kernel for install/rescue disks or your system is very
+  limited in memory.
+
+CONFIG_MODULES
+  Kernel modules are small pieces of compiled code which can be
+  inserted in or removed from the running kernel, using the programs
+  insmod and rmmod. This is described in the file
+  <file:Documentation/modules.txt>, including the fact that you have
+  to say "make modules" in order to compile the modules that you chose
+  during kernel configuration.  Modules can be device drivers, file
+  systems, binary executable formats, and so on. If you think that you
+  may want to make use of modules with this kernel in the future, then
+  say Y here.  If unsure, say Y.
+
+CONFIG_MODVERSIONS
+  Usually, modules have to be recompiled whenever you switch to a new
+  kernel.  Saying Y here makes it possible, and safe, to use the
+  same modules even after compiling a new kernel; this requires the
+  program modprobe. All the software needed for module support is in
+  the modutils package (check the file <file:Documentation/Changes>
+  for location and latest version).  NOTE: if you say Y here but don't
+  have the program genksyms (which is also contained in the above
+  mentioned modutils package), then the building of your kernel will
+  fail.  If you are going to use modules that are generated from
+  non-kernel sources, you would benefit from this option.  Otherwise
+  it's not that important.  So, N ought to be a safe bet.
+
+CONFIG_KMOD
+  Normally when you have selected some drivers and/or file systems to
+  be created as loadable modules, you also have the responsibility to
+  load the corresponding modules (using the programs insmod or
+  modprobe) before you can use them. If you say Y here however, the
+  kernel will be able to load modules for itself: when a part of the
+  kernel needs a module, it runs modprobe with the appropriate
+  arguments, thereby loading the module if it is available. (This is a
+  replacement for kerneld.) Say Y here and read about configuring it
+  in <file:Documentation/kmod.txt>.
+
diff -u --recursive --new-file v2.5.2/linux/init/Config.in linux/init/Config.in
--- v2.5.2/linux/init/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/init/Config.in	Thu Jan 24 12:15:55 2002
@@ -0,0 +1,23 @@
+mainmenu_option next_comment
+comment 'General setup'
+
+bool 'Networking support' CONFIG_NET
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
+
+endmenu
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
+   bool '  Kernel module loader' CONFIG_KMOD
+fi
+endmenu
diff -u --recursive --new-file v2.5.2/linux/init/main.c linux/init/main.c
--- v2.5.2/linux/init/main.c	Mon Jan 14 18:25:11 2002
+++ linux/init/main.c	Mon Jan 28 13:13:19 2002
@@ -38,35 +38,10 @@
 #include <asm/ccwcache.h>
 #endif
 
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif
-
-#ifdef CONFIG_DIO
-#include <linux/dio.h>
-#endif
-
-#ifdef CONFIG_ZORRO
-#include <linux/zorro.h>
-#endif
-
 #ifdef CONFIG_MTRR
 #  include <asm/mtrr.h>
 #endif
 
-#ifdef CONFIG_NUBUS
-#include <linux/nubus.h>
-#endif
-
-#ifdef CONFIG_ISAPNP
-#include <linux/isapnp.h>
-#endif
-
-#ifdef CONFIG_IRDA
-extern int irda_proto_init(void);
-extern int irda_device_init(void);
-#endif
-
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/smp.h>
 #endif
@@ -92,10 +67,8 @@
 extern void fork_init(unsigned long);
 extern void mca_init(void);
 extern void sbus_init(void);
-extern void ppc_init(void);
 extern void sysctl_init(void);
 extern void signals_init(void);
-extern int init_pcmcia_ds(void);
 
 extern void free_initmem(void);
 
@@ -103,8 +76,6 @@
 extern void tc_init(void);
 #endif
 
-extern void ecard_init(void);
-
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
 #endif
@@ -290,8 +261,6 @@
 extern void setup_arch(char **);
 extern void cpu_idle(void);
 
-unsigned long wait_init_idle;
-
 #ifndef CONFIG_SMP
 
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -305,13 +274,11 @@
 
 #else
 
-
 /* Called by boot processor to activate the rest. */
 static void __init smp_init(void)
 {
 	/* Get other processors into their bootup holding patterns. */
 	smp_boot_cpus();
-	wait_init_idle = cpu_online_map;
 
 	smp_threads_ready=1;
 	smp_commence();
@@ -411,6 +378,7 @@
 	check_bugs();
 	printk("POSIX conformance testing by UNIFIX\n");
 
+	init_idle(current, smp_processor_id());
 	/* 
 	 *	We count on the initial thread going ok 
 	 *	Like idlers init is an unlocked kernel thread, which will
@@ -418,14 +386,6 @@
 	 */
 	smp_init();
 
-	/*
-	 * Finally, we wait for all other CPU's, and initialize this
-	 * thread that will become the idle thread for the boot CPU.
-	 * After this, the scheduler is fully initialized, and we can
-	 * start creating and running new threads.
-	 */
-	init_idle();
-
 	/* Do the rest non-__init'ed, we're now alive */
 	rest_init();
 }
@@ -490,50 +450,11 @@
 	/* bring up the device tree */
 	device_driver_init();
 
-#ifdef CONFIG_PCI
-	pci_init();
-#endif
-#ifdef CONFIG_SBUS
-	sbus_init();
-#endif
-#if defined(CONFIG_PPC)
-	ppc_init();
-#endif
-#ifdef CONFIG_MCA
-	mca_init();
-#endif
-#ifdef CONFIG_ARCH_ACORN
-	ecard_init();
-#endif
-#ifdef CONFIG_ZORRO
-	zorro_init();
-#endif
-#ifdef CONFIG_DIO
-	dio_init();
-#endif
-#ifdef CONFIG_NUBUS
-	nubus_init();
-#endif
-#ifdef CONFIG_ISAPNP
-	isapnp_init();
-#endif
-#ifdef CONFIG_TC
-	tc_init();
-#endif
-
 	/* Networking initialization needs a process context */ 
 	sock_init();
 
 	start_context_thread();
 	do_initcalls();
-
-#ifdef CONFIG_IRDA
-	irda_proto_init();
-	irda_device_init(); /* Must be done after protocol initialization */
-#endif
-#ifdef CONFIG_PCMCIA
-	init_pcmcia_ds();		/* Do this last */
-#endif
 }
 
 extern void prepare_namespace(void);
diff -u --recursive --new-file v2.5.2/linux/kernel/Makefile linux/kernel/Makefile
--- v2.5.2/linux/kernel/Makefile	Tue Dec 18 14:56:40 2001
+++ linux/kernel/Makefile	Thu Jan 24 14:07:46 2002
@@ -10,12 +10,12 @@
 O_TARGET := kernel.o
 
 export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
-		printk.o device.o
+		printk.o 
 
 obj-y     = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
 	    sysctl.o acct.o capability.o ptrace.o timer.o user.o \
-	    signal.o sys.o kmod.o context.o device.o
+	    signal.o sys.o kmod.o context.o 
 
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
diff -u --recursive --new-file v2.5.2/linux/kernel/device.c linux/kernel/device.c
--- v2.5.2/linux/kernel/device.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/device.c	Wed Dec 31 16:00:00 1969
@@ -1,944 +0,0 @@
-/*
- * device.c
- *
- * Copyright (c) Patrick Mochel <mochel@osdl.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * Please see Documentation/driver-model.txt for more explanation.
- */
-
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
-#include <linux/module.h>
-#include <linux/stat.h>
-#include <linux/driverfs_fs.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/spinlock.h>
-
-#undef DEBUG
-
-#ifdef DEBUG
-# define DBG(x...) printk(x)
-#else
-# define DBG(x...)
-#endif
-
-static struct iobus device_root = {
-	bus_id: "root",
-	name:	"Logical System Root",
-};
-
-int (*platform_notify)(struct device * dev) = NULL;
-int (*platform_notify_remove)(struct device * dev) = NULL;
-
-static spinlock_t device_lock;
-
-static ssize_t device_read_status(char *, size_t, loff_t, void *);
-static ssize_t device_write_status(const char *, size_t, loff_t, void *);
-
-static struct driverfs_operations device_status_ops = {
-	read:	device_read_status,
-	write:	device_write_status,
-};
-
-static ssize_t device_read_power(char *, size_t, loff_t, void *);
-static ssize_t device_write_power(const char *, size_t, loff_t, void *);
-
-static struct driverfs_operations device_power_ops = {
-	read:	device_read_power,
-	write:	device_write_power,
-};
-
-static ssize_t iobus_read_status(char *, size_t, loff_t, void *);
-static ssize_t iobus_write_status(const char *, size_t, loff_t, void *);
-
-static struct driverfs_operations iobus_status_ops = {
-	read:	iobus_read_status,
-	write:	iobus_write_status,
-};
-
-
-/**
- * device_create_file - create a driverfs file for a device
- * @dev:	device requesting file
- * @name:	name of file
- * @mode:	permissions of file
- * @ops:	operations for the file
- * @data:	private data for the file
- *
- * Create a driverfs entry, then create the actual file the entry describes.
- */
-int device_create_file(struct device * dev, const char * name, mode_t mode,
-		       struct driverfs_operations * ops, void * data)
-{
-	int error = -EFAULT;
-	struct driver_file_entry * entry;
-
-	if (!dev)
-		return -EINVAL;
-
-	if (!valid_device(dev))
-		return -EFAULT;
-
-	entry = driverfs_create_entry(name,mode,ops,data);
-	if (entry)
-		error = driverfs_create_file(entry,dev->dir);
-
-	put_device(dev);
-	return error;
-}
-
-/**
- * device_remove_file - remove a device's file by name
- * @dev:	device requesting removal
- * @name:	name of the file
- *
- */
-void device_remove_file(struct device * dev, const char * name)
-{
-	if (!dev)
-		return;
-
-	if (!valid_device(dev))
-		return;
-
-	driverfs_remove_file(dev->dir,name);
-
-	put_device(dev);
-}
-
-/**
- * device_remove_dir - remove a device's directory
- * @dev:	device in question
- */
-void device_remove_dir(struct device * dev)
-{
-	struct driver_dir_entry * dir;
-
-	if (!dev)
-		return;
-
-	lock_device(dev);
-	dir = dev->dir;
-	dev->dir = NULL;
-	unlock_device(dev);
-
-	if (dir)
-		driverfs_remove_dir(dir);
-}
-
-/**
- * device_make_dir - create a driverfs directory
- * @name:	name of directory
- * @parent:	dentry for the parent directory
- *
- * Do the initial creation of the device's driverfs directory
- * and populate it with the one default file.
- *
- * This is just a helper for device_register(), as we
- * don't export this function. (Yes, that means we don't allow
- * devices to create subdirectories).
- */
-static int device_make_dir(struct device * dev)
-{
-	struct driver_dir_entry * entry;
-	int error;
-
-	entry = driverfs_create_dir_entry(dev->bus_id,(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO));
-	if (!entry)
-		return -EFAULT;
-
-	error = driverfs_create_dir(entry,dev->parent->dir);
-
-	if (error) {
-		kfree(entry);
-		return error;
-	}
-
-	lock_device(dev);
-	dev->dir = entry;
-	unlock_device(dev);
-
-	/* first the status file */
-	error = device_create_file(dev, "status", S_IRUGO | S_IWUSR,
-				   &device_status_ops, (void *) dev);
-	if (error) {
-		device_remove_dir(dev);
-		goto done;
-	}
-
-	/* now the power file */
-	error = device_create_file(dev,"power",S_IRUGO | S_IWUSR,
-				   &device_power_ops, (void *) dev);
-	if (error)
-		device_remove_dir(dev);
-
- done:
-	return error;
-}
-
-/* iobus interface.
- * For practical purposes, it's exactly the same as the device interface above.
- * Even below, the two are almost identical, only taking different pointer
- * types.
- * I have fantasized about removing struct iobus completely. It would reduce
- * this file by about 30%, and make life much easier. However, it will take some
- * time to really work everything out..
- */
-
-int iobus_create_file(struct iobus * iobus, const char * name, mode_t mode,
-		      struct driverfs_operations * ops, void * data)
-{
-	int error = -EFAULT;
-	struct driver_file_entry * entry;
-
-	if (!iobus)
-		return -EINVAL;
-
-	if (!valid_iobus(iobus))
-		return -EFAULT;
-
-	entry = driverfs_create_entry(name,mode,ops,data);
-	if (entry)
-		error = driverfs_create_file(entry,iobus->dir);
-
-	put_iobus(iobus);
-	return error;
-}
-
-void iobus_remove_file(struct iobus * iobus, const char * name)
-{
-	if (!iobus)
-		return;
-
-	if (!valid_iobus(iobus))
-		return;
-
-	driverfs_remove_file(iobus->dir,name);
-
-	put_iobus(iobus);
-}
-
-void iobus_remove_dir(struct iobus * iobus)
-{
-	struct driver_dir_entry * dir;
-
-	if (!iobus)
-		return;
-
-	lock_iobus(iobus);
-	dir = iobus->dir;
-	iobus->dir = NULL;
-	unlock_iobus(iobus);
-
-	if (dir)
-		driverfs_remove_dir(dir);
-}
-
-static int iobus_make_dir(struct iobus * iobus)
-{
-	struct driver_dir_entry * entry;
-	struct driver_dir_entry * parent = NULL;
-	int error;
-
-	entry = driverfs_create_dir_entry(iobus->bus_id,(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO));
-	if (!entry)
-		return -EFAULT;
-
-	if (iobus->parent)
-		parent = iobus->parent->dir;
-
-	error = driverfs_create_dir(entry,parent);
-	if (error) {
-		kfree(entry);
-		return error;
-	}
-
-	lock_iobus(iobus);
-	iobus->dir = entry;
-	unlock_iobus(iobus);
-
-	error = iobus_create_file(iobus, "status", S_IRUGO | S_IWUSR,
-				  &iobus_status_ops, (void *)iobus);
-	if (error)
-		iobus_remove_dir(iobus);
-
-	return error;
-}
-
-/**
- * device_register - register a device
- * @dev:	pointer to the device structure
- *
- * First, make sure that the device has a parent, create
- * a directory for it, then add it to the parent's list of
- * children.
- */
-int device_register(struct device *dev)
-{
-	struct iobus * parent;
-	int error = -EFAULT;
-
-	if (!dev)
-		return -EINVAL;
-
-	if (!dev->parent)
-		dev->parent = &device_root;
-	parent = dev->parent;
-
-	if (valid_iobus(parent)) {
-		if (!valid_device(dev)) {
-			put_iobus(parent);
-			goto register_done;
-		}
-	} else
-		return -EFAULT;
-
-	if (!strlen(dev->name)) {
-		error = -EINVAL;
-		goto register_done;
-	}
-
-	error = device_make_dir(dev);
-	if (error)
-		goto register_done;
-
-
-	/* finally add it to its parent's list */
-	lock_iobus(parent);
-	list_add_tail(&dev->node, &parent->devices);
-	unlock_iobus(parent);
-
-	DBG("DEV: registering device: ID = '%s', name = %s, parent = %s\n",
-	    dev->bus_id, dev->name, parent->bus_id);
-
-	/* notify platform of device entry */
-	if (platform_notify)
-		platform_notify(dev);
-
-	return 0;
-
- register_done:
-	put_device(dev);
-	put_iobus(parent);
-
-	return error;
-}
-
-/**
- * put_device - clean up device
- * @dev:	device in question
- *
- * Decrement reference count for device.
- * If it hits 0, we need to clean it up.
- * However, we may be here in interrupt context, and it may
- * take some time to do proper clean up (removing files, calling
- * back down to device to clean up everything it has).
- * So, we remove it from its parent's list and add it to the list of
- * devices to be cleaned up.
- */
-void put_device(struct device * dev)
-{
-	struct iobus * parent;
-
-	if (!atomic_dec_and_lock(&dev->refcount,&dev->lock))
-		return;
-
-	parent = dev->parent;
-	dev->parent = NULL;
-	unlock_device(dev);
-
-	DBG("DEV: Unregistering device. ID = '%s', name = '%s'\n",
-	    dev->bus_id,dev->name);
-
-	/* disavow parent's knowledge */
-	lock_iobus(parent);
-	list_del_init(&dev->node);
-	unlock_iobus(parent);
-
-	/* remove the driverfs directory */
-	device_remove_dir(dev);
-
-	if (dev->subordinate)
-		iobus_remove_dir(dev->subordinate);
-
-	/* Notify the platform of the removal, in case they
-	 * need to do anything...
-	 */
-	if (platform_notify_remove)
-		platform_notify_remove(dev);
-
-	/* Tell the driver to clean up after itself.
-	 * Note that we likely didn't allocate the device,
-	 * so this is the driver's chance to free that up...
-	 */
-	if (dev->driver && dev->driver->remove)
-		dev->driver->remove(dev,REMOVE_FREE_RESOURCES);
-
-	put_iobus(parent);
-}
-
-int iobus_register(struct iobus *bus)
-{
-	struct iobus * parent;
-	int error = -EINVAL;
-
-	if (!bus)
-		return -EINVAL;
-
-	if (!bus->parent)
-		bus->parent = &device_root;
-	parent = bus->parent;
-
-	DBG("DEV: registering bus. ID = '%s' name = '%s' parent = %p\n",
-	    bus->bus_id,bus->name,bus->parent);
-
-	if (valid_iobus(parent)) {
-		if (!valid_iobus(bus)) {
-			put_iobus(parent);
-			goto register_done;
-		}
-	} else
-		goto register_done;
-
-	if (!strlen(bus->bus_id))
-		goto register_done_put;
-
-	error = iobus_make_dir(bus);
-	if (error)
-		goto register_done_put;
-
-	lock_iobus(parent);
-	list_add_tail(&bus->node,&parent->children);
-	unlock_iobus(parent);
-
-	return 0;
-
- register_done_put:
-	put_iobus(bus);
-	put_iobus(parent);
- register_done:
-	return error;
-}
-
-/**
- * iobus_unregister - remove bus and children from device tree
- * @bus:	pointer to bus structure
- *
- * Remove device from parent's list of children and decrement
- * reference count on controlling device. That should take care of
- * the rest of the cleanup.
- */
-void put_iobus(struct iobus * iobus)
-{
-	struct iobus * parent;
-
-	if (!atomic_dec_and_lock(&iobus->refcount,&iobus->lock))
-		return;
-
-	parent = iobus->parent;
-	iobus->parent = NULL;
-	unlock_iobus(iobus);
-
-	if (!list_empty(&iobus->devices) ||
-	    !list_empty(&iobus->children))
-		BUG();
-
-	/* disavow parent's knowledge */
-	if (parent) {
-		lock_iobus(parent);
-		list_del(&iobus->node);
-		unlock_iobus(parent);
-
-		put_iobus(parent);
-	}
-
-	/* unregister itself */
-	put_device(iobus->self);
-
-	return;
-}
-
-/**
- * device_init_dev - initialise a struct device
- * @dev:	pointer to device struct
- */
-void device_init_dev(struct device * dev)
-{
-	INIT_LIST_HEAD(&dev->node);
-	spin_lock_init(&dev->lock);
-	atomic_set(&dev->refcount,1);
-}
-
-/**
- * device_alloc_dev - allocate and initialise a device structure
- *
- */
-struct device * device_alloc(void)
-{
-	struct device * dev;
-
-	dev = kmalloc(sizeof(struct device), GFP_KERNEL);
-
-	if (!dev)
-		return NULL;
-
-	memset(dev,0,sizeof(struct device));
-	device_init_dev(dev);
-
-	return dev;
-}
-
-void iobus_init(struct iobus *bus)
-{
-	spin_lock_init(&bus->lock);
-	atomic_set(&bus->refcount,1);
-
-	INIT_LIST_HEAD(&bus->node);
-	INIT_LIST_HEAD(&bus->children);
-	INIT_LIST_HEAD(&bus->devices);
-}
-
-struct iobus *iobus_alloc(void)
-{
-	struct iobus *bus;
-
-	bus = kmalloc(sizeof(struct iobus), GFP_KERNEL);
-
-	if (!bus)
-		return NULL;
-
-	memset(bus,0,sizeof(struct iobus));
-
-	iobus_init(bus);
-
-	return bus;
-}
-
-static int do_device_suspend(struct device * dev, u32 state)
-{
-	int error = 0;
-
-	if (!dev->driver->suspend)
-		return error;
-
-	error = dev->driver->suspend(dev,state,SUSPEND_NOTIFY);
-
-	if (error)
-		return error;
-
-	error = dev->driver->suspend(dev,state,SUSPEND_SAVE_STATE);
-	if (error) {
-		if (dev->driver->resume)
-			dev->driver->resume(dev,RESUME_RESTORE_STATE);
-		return error;
-	}
-	error = dev->driver->suspend(dev,state,SUSPEND_POWER_DOWN);
-	if (error) {
-		if (dev->driver->resume)
-			dev->driver->resume(dev,RESUME_RESTORE_STATE);
-	}
-	return error;
-}
-
-static int do_device_resume(struct device * dev)
-{
-	int error = 0;
-
-	if (!dev->driver->resume)
-		return 0;
-	error = dev->driver->resume(dev,RESUME_POWER_ON);
-	if (error)
-		return error;
-	error = dev->driver->resume(dev,RESUME_RESTORE_STATE);
-	return error;
-}
-
-/**
- * device_read_status - report some device information
- * @page:	page-sized buffer to write into
- * @count:	number of bytes requested
- * @off:	offset into buffer
- * @data:	device-specific data
- *
- * Report some human-readable information about the device.
- * This includes the name, the bus id, and the current power state.
- */
-static ssize_t device_read_status(char * page, size_t count,
-				  loff_t off, void * data)
-{
-	char *str = page;
-	struct device *dev = (struct device*)data;
-	ssize_t len = 0;
-
-	if (!dev)
-		return -EINVAL;
-
-	if (!valid_device(dev))
-		return -EFAULT;
-
-	if (off)
-		goto done;
-
-	str += sprintf(str,"Name:       %s\n",dev->name);
-	str += sprintf(str,"Bus ID:     %s\n",dev->bus_id);
-
-	len = str - page;
-
-	if (len > count)
-		len = count;
-
-	if (len < 0)
-		len = 0;
-
- done:
-	put_device(dev);
-
-	return len;
-}
-
-/**
- * device_write_status - forward a command to a driver
- * @buf:	encoded command
- * @count:	number of bytes in buffer
- * @off:	offset into buffer to start with
- * @data:	device-specific data
- *
- * Send a comamnd to a device driver.
- * The following actions are supported:
- * probe - scan slot for device
- * remove - detach driver from slot
- * suspend <state> <stage> - perform <stage> for entering <state>
- * resume <stage> - perform <stage> for waking device up.
- * (See Documentation/driver-model.txt for the theory of an n-stage
- * suspend sequence).
- */
-static ssize_t device_write_status(const char* buf, size_t count, loff_t off, void *data)
-{
-	char command[20];
-	struct device *dev = (struct device *)data;
-	int num;
-	int arg = 0;
-	int error = 0;
-
-	if (!dev)
-		return 0;
-
-	if (!valid_device(dev))
-		return -EFAULT;
-
-	if (off)
-		goto done_put;
-
-	/* everything involves dealing with the driver. */
-	if (!dev->driver)
-		goto done_put;
-
-	num = sscanf(buf,"%10s %d",command,&arg);
-
-	if (!num)
-		goto done_put;
-
-	if (!strcmp(command,"probe")) {
-		if (dev->driver->probe)
-			error = dev->driver->probe(dev);
-
-	} else if (!strcmp(command,"remove")) {
-		if (dev->driver->remove)
-			error = dev->driver->remove(dev,REMOVE_NOTIFY);
-	} else
-		error = -EFAULT;
-
- done_put:
-	put_device(dev);
-	return error < 0 ? error : count;
-}
-
-static ssize_t
-device_read_power(char * page, size_t count, loff_t off, void * data)
-{
-	char	* str = page;
-	struct	device * dev = (struct device *)data;
-	ssize_t len = 0;
-
-	if (!dev)
-		return 0;
-
-	if (!valid_device(dev))
-		return 0;
-
-	str += sprintf(str,"State:      %d\n",dev->current_state);
-
-	len = str - page;
-
-	if (off) {
-		if (len < off) {
-			len = 0;
-			goto done;
-		}
-		str += off;
-		len -= off;
-	}
-
-	if (len > count)
-		len = count;
-
- done:
-	put_device(dev);
-	return len;
-}
-
-static ssize_t
-device_write_power(const char * buf, size_t count, loff_t off, void * data)
-{
-	struct	device * dev = (struct device *)data;
-	char	str_command[20];
-	char	str_stage[20];
-	int	num_args;
-	u32	state;
-	u32	int_stage;
-	int	error = 0;
-
-	if (!dev)
-		return 0;
-
-	if (!valid_device(dev))
-		return -EFAULT;
-
-	if (off)
-		goto done;
-	if (!dev->driver)
-		goto done;
-
-	num_args = sscanf(buf,"%s %s %u",str_command,str_stage,&state);
-
-	error = -EINVAL;
-
-	if (!num_args)
-		goto done;
-
-	if (!strnicmp(str_command,"suspend",7)) {
-		if (num_args != 3)
-			goto done;
-		if (!strnicmp(str_stage,"notify",6))
-			int_stage = SUSPEND_NOTIFY;
-		else if (!strnicmp(str_stage,"save",4))
-			int_stage = SUSPEND_SAVE_STATE;
-		else if (!strnicmp(str_stage,"disable",7))
-			int_stage = SUSPEND_DISABLE;
-		else if (!strnicmp(str_stage,"powerdown",8))
-			int_stage = SUSPEND_POWER_DOWN;
-		else
-			goto done;
-
-		if (dev->driver->suspend)
-			error = dev->driver->suspend(dev,state,int_stage);
-		else
-			error = 0;
-	} else if (!strnicmp(str_command,"resume",6)) {
-		if (num_args != 2)
-			goto done;
-
-		if (!strnicmp(str_stage,"poweron",7))
-			int_stage = RESUME_POWER_ON;
-		else if (!strnicmp(str_stage,"restore",7))
-			int_stage = RESUME_RESTORE_STATE;
-		else if (!strnicmp(str_stage,"enable",6))
-			int_stage = RESUME_ENABLE;
-		else
-			goto done;
-
-		if (dev->driver->resume)
-			error = dev->driver->resume(dev,int_stage);
-		else
-			error = 0;
-	}
- done:
-	put_device(dev);
-
-	DBG("%s: returning %d\n",__FUNCTION__,error);
-
-	return error < 0 ? error : count;
-}
-
-/**
- * bus_read_status - report human readable information
- * @page:	page-sized buffer to write into
- * @count:	number of bytes requested
- * @off:	offset into buffer to start at
- * @data:	bus-specific data
- */
-static ssize_t iobus_read_status(char *page, size_t count,
-				 loff_t off, void *data)
-{
-	char *str = page;
-	struct iobus *bus = (struct iobus*)data;
-	ssize_t len = 0;
-
-	if (!bus)
-		return -EINVAL;
-
-	if (!valid_iobus(bus))
-		return -EFAULT;
-
-	if (off)
-		goto done;
-
-	str += sprintf(str,"Name:       %s\n",bus->name);
-	str += sprintf(str,"Bus ID:     %s\n",bus->bus_id);
-
-	if (bus->driver)
-		str += sprintf(str,"Type:       %s\n",bus->driver->name);
-
-	len = str - page;
-	if (len < off)
-		len = 0;
-	if (len > count)
-		len = count;
-	if (len < 0)
-		len = 0;
-
- done:
-	put_iobus(bus);
-	return len;
-}
-
-/**
- * bus_write_status - forward a command to a bus
- * @buf:	string encoded command
- * @count:	number of bytes requested
- * @off:	offset into buffer to start at
- * @data:	bus-specific data
- *
- * Like device_write_status, this sends a command to a bus driver.
- * Supported actions are:
- * scan - scan a bus for devices
- * add_device <id> - add a child device
- */
-static ssize_t iobus_write_status(const char *buf, size_t count, loff_t off, void *data)
-{
-	char command[10];
-	char which[15];
-	char id[10];
-	struct iobus *bus = (struct iobus*)data;
-	int num;
-	int error = -EINVAL;
-
-	if (!bus)
-		return -EINVAL;
-
-	if (!valid_iobus(bus))
-		return -EFAULT;
-
-	if (!bus->driver)
-		goto done;
-
-	num = sscanf(buf,"%10s %15s %10s",command,which,id);
-
-	if (!num)
-		goto done;
-
-	if (!strnicmp(command,"scan",4)) {
-		if (bus->driver->scan)
-			error = bus->driver->scan(bus);
-	} else if (!strnicmp(command,"add",3) && num == 2) {
-		error = bus->driver->add_device(bus,id);
-	} else if (!strnicmp(command, "suspend",7)) {
-		u32 state = simple_strtoul(which,NULL,0);
-		if (state > 0)
-			error = do_device_suspend(bus->self,state);
-
-	} else if (!strnicmp(command,"resume",6)) {
-		error = do_device_resume(bus->self);
-
-	}
-
- done:
-	put_iobus(bus);
-	return error < 0 ? error : count;
-}
-
-static int __init device_init_root(void)
-{
-	/* initialize parent bus lists */
-	iobus_init(&device_root);
-
-	/* don't call iobus_register, as the only thing it really
-	 * needs to do is create the root directory. Easier
-	 * to just do it here than special case it elsewhere..
-	 */
-	iobus_make_dir(&device_root);
-
-	return (device_root.dir ? 0 : -EFAULT);
-}
-
-int __init device_driver_init(void)
-{
-	int error = 0;
-
-	DBG("DEV: Initialising Device Tree\n");
-
-	spin_lock_init(&device_lock);
-
-	error = init_driverfs_fs();
-
-	if (error) {
-		panic("DEV: could not initialise driverfs\n");
-		return error;
-	}
-
-	error = device_init_root();
-	if (error) {
-		printk(KERN_ERR "%s: device root init failed!\n", __FUNCTION__);
-		return error;
-	}
-
-	DBG("DEV: Done Initialising\n");
-	return error;
-}
-
-void __exit device_driver_exit(void)
-{
-
-}
-
-static int __init device_setup(char *str)
-{
-	return 0;
-}
-
-__setup("device=",device_setup);
-
-EXPORT_SYMBOL(device_register);
-EXPORT_SYMBOL(device_alloc);
-EXPORT_SYMBOL(device_init_dev);
-
-EXPORT_SYMBOL(device_create_file);
-EXPORT_SYMBOL(device_remove_file);
-
-EXPORT_SYMBOL(iobus_register);
-EXPORT_SYMBOL(iobus_alloc);
-EXPORT_SYMBOL(iobus_init);
-
-EXPORT_SYMBOL(iobus_create_file);
-EXPORT_SYMBOL(iobus_remove_file);
-
-EXPORT_SYMBOL(device_driver_init);
diff -u --recursive --new-file v2.5.2/linux/kernel/exit.c linux/kernel/exit.c
--- v2.5.2/linux/kernel/exit.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/exit.c	Mon Jan 28 13:06:33 2002
@@ -17,6 +17,7 @@
 #ifdef CONFIG_BSD_PROCESS_ACCT
 #include <linux/acct.h>
 #endif
+#include <linux/file.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -58,6 +59,9 @@
 	current->time_slice += p->time_slice;
 	if (current->time_slice > MAX_TIMESLICE)
 		current->time_slice = MAX_TIMESLICE;
+	if (p->sleep_avg < current->sleep_avg)
+		current->sleep_avg = (current->sleep_avg * EXIT_WEIGHT +
+				p->sleep_avg) / (EXIT_WEIGHT + 1);
 	__restore_flags(flags);
 
 	p->pid = 0;
diff -u --recursive --new-file v2.5.2/linux/kernel/fork.c linux/kernel/fork.c
--- v2.5.2/linux/kernel/fork.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/fork.c	Mon Jan 28 15:11:45 2002
@@ -21,6 +21,7 @@
 #include <linux/completion.h>
 #include <linux/namespace.h>
 #include <linux/personality.h>
+#include <linux/file.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -630,7 +631,7 @@
 	}
 	spin_lock_init(&p->alloc_lock);
 
-	p->sigpending = 0;
+	p->work.sigpending = 0;
 	init_sigpending(&p->pending);
 
 	p->it_real_value = p->it_virt_value = p->it_prof_value = 0;
@@ -646,11 +647,10 @@
 	{
 		int i;
 
-		p->cpu = smp_processor_id();
-
 		/* ?? should we just memset this ?? */
 		for(i = 0; i < smp_num_cpus; i++)
-			p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0;
+			p->per_cpu_utime[cpu_logical_map(i)] =
+				p->per_cpu_stime[cpu_logical_map(i)] = 0;
 		spin_lock_init(&p->sigmask_lock);
 	}
 #endif
@@ -703,10 +703,14 @@
 		 * runqueue lock is not a problem.
 		 */
 		current->time_slice = 1;
-		expire_task(current);
+		scheduler_tick(current);
 	}
+	p->sleep_timestamp = jiffies;
 	__restore_flags(flags);
 
+	if (p->policy == SCHED_OTHER)
+		p->prio = MAX_PRIO - 1 - ((MAX_PRIO - 1 - p->prio) * 1) / 3;
+
 	/*
 	 * Ok, add it to the run-queues and make it
 	 * visible to the rest of the system.
@@ -742,23 +746,16 @@
 	if (p->ptrace & PT_PTRACED)
 		send_sig(SIGSTOP, p, 1);
 
-#define RUN_CHILD_FIRST 1
-#if RUN_CHILD_FIRST
 	wake_up_forked_process(p);		/* do this last */
-#else
-	wake_up_process(p);			/* do this last */
-#endif
 	++total_forks;
 	if (clone_flags & CLONE_VFORK)
 		wait_for_completion(&vfork);
-#if RUN_CHILD_FIRST
 	else
 		/*
 		 * Let the child process run first, to avoid most of the
 		 * COW overhead when the child exec()s afterwards.
 		 */
-		current->need_resched = 1;
-#endif
+		current->work.need_resched = 1;
 
 fork_out:
 	return retval;
diff -u --recursive --new-file v2.5.2/linux/kernel/kmod.c linux/kernel/kmod.c
--- v2.5.2/linux/kernel/kmod.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/kmod.c	Tue Jan 15 11:07:01 2002
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/namespace.h>
 #include <linux/completion.h>
+#include <linux/file.h>
 
 #include <asm/uaccess.h>
 
diff -u --recursive --new-file v2.5.2/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.5.2/linux/kernel/ksyms.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/ksyms.c	Tue Jan 29 10:47:10 2002
@@ -85,9 +85,6 @@
 EXPORT_SYMBOL(do_munmap);
 EXPORT_SYMBOL(do_brk);
 EXPORT_SYMBOL(exit_mm);
-EXPORT_SYMBOL(exit_files);
-EXPORT_SYMBOL(exit_fs);
-EXPORT_SYMBOL(exit_sighand);
 
 /* internal kernel memory management */
 EXPORT_SYMBOL(_alloc_pages);
@@ -140,6 +137,7 @@
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget4);
 EXPORT_SYMBOL(iput);
+EXPORT_SYMBOL(inode_init_once);
 EXPORT_SYMBOL(force_delete);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(follow_down);
@@ -209,6 +207,7 @@
 EXPORT_SYMBOL(block_read_full_page);
 EXPORT_SYMBOL(block_prepare_write);
 EXPORT_SYMBOL(block_sync_page);
+EXPORT_SYMBOL(generic_cont_expand);
 EXPORT_SYMBOL(cont_prepare_write);
 EXPORT_SYMBOL(generic_commit_write);
 EXPORT_SYMBOL(block_truncate_page);
@@ -273,6 +272,8 @@
 EXPORT_SYMBOL(lock_may_read);
 EXPORT_SYMBOL(lock_may_write);
 EXPORT_SYMBOL(dcache_readdir);
+EXPORT_SYMBOL(fd_install);
+EXPORT_SYMBOL(put_unused_fd);
 
 /* for stackable file systems (lofs, wrapfs, cryptfs, etc.) */
 EXPORT_SYMBOL(default_llseek);
@@ -505,17 +506,16 @@
 /* Added to make file system as module */
 EXPORT_SYMBOL(sys_tz);
 EXPORT_SYMBOL(file_fsync);
-EXPORT_SYMBOL(fsync_inode_buffers);
-EXPORT_SYMBOL(fsync_inode_data_buffers);
+EXPORT_SYMBOL(fsync_buffers_list);
 EXPORT_SYMBOL(clear_inode);
 EXPORT_SYMBOL(___strtok);
 EXPORT_SYMBOL(init_special_inode);
 EXPORT_SYMBOL(read_ahead);
 EXPORT_SYMBOL(__get_hash_table);
-EXPORT_SYMBOL(get_empty_inode);
+EXPORT_SYMBOL(new_inode);
 EXPORT_SYMBOL(insert_inode_hash);
 EXPORT_SYMBOL(remove_inode_hash);
-EXPORT_SYMBOL(buffer_insert_inode_queue);
+EXPORT_SYMBOL(buffer_insert_list);
 EXPORT_SYMBOL(make_bad_inode);
 EXPORT_SYMBOL(is_bad_inode);
 EXPORT_SYMBOL(event);
@@ -536,9 +536,6 @@
 
 /* binfmt_aout */
 EXPORT_SYMBOL(get_write_access);
-
-/* time */
-EXPORT_SYMBOL(get_fast_time);
 
 /* library functions */
 EXPORT_SYMBOL(strnicmp);
diff -u --recursive --new-file v2.5.2/linux/kernel/printk.c linux/kernel/printk.c
--- v2.5.2/linux/kernel/printk.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/printk.c	Tue Jan 15 13:53:51 2002
@@ -524,7 +524,7 @@
  */
 void console_conditional_schedule(void)
 {
-	if (console_may_schedule && current->need_resched) {
+	if (console_may_schedule && need_resched()) {
 		set_current_state(TASK_RUNNING);
 		schedule();
 	}
diff -u --recursive --new-file v2.5.2/linux/kernel/sched.c linux/kernel/sched.c
--- v2.5.2/linux/kernel/sched.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/sched.c	Mon Jan 28 15:12:47 2002
@@ -20,10 +20,7 @@
 #include <linux/interrupt.h>
 #include <asm/mmu_context.h>
 
-#define BITMAP_SIZE ((MAX_PRIO+7)/8)
-#define PRIO_INTERACTIVE	(MAX_RT_PRIO + (MAX_PRIO - MAX_RT_PRIO) / 4)
-#define TASK_INTERACTIVE(p)	((p)->prio >= MAX_RT_PRIO && (p)->prio <= PRIO_INTERACTIVE)
-#define JSLEEP_TO_PRIO(t)	(((t) * 20) / HZ)
+#define BITMAP_SIZE ((((MAX_PRIO+7)/8)+sizeof(long)-1)/sizeof(long))
 
 typedef struct runqueue runqueue_t;
 
@@ -31,7 +28,7 @@
 	int nr_active;
 	spinlock_t *lock;
 	runqueue_t *rq;
-	char bitmap[BITMAP_SIZE];
+	unsigned long bitmap[BITMAP_SIZE];
 	list_t queue[MAX_PRIO];
 };
 
@@ -40,41 +37,43 @@
  *
  * Locking rule: those places that want to lock multiple runqueues
  * (such as the load balancing or the process migration code), lock
- * acquire operations must be ordered by rq->cpu.
- *
- * The RT event id is used to avoid calling into the the RT scheduler
- * if there is a RT task active in an SMP system but there is no
- * RT scheduling activity otherwise.
+ * acquire operations must be ordered by ascending &runqueue.
  */
-static struct runqueue {
-	int cpu;
+struct runqueue {
 	spinlock_t lock;
-	unsigned long nr_running, nr_switches;
+	unsigned long nr_running, nr_switches, expired_timestamp;
 	task_t *curr, *idle;
 	prio_array_t *active, *expired, arrays[2];
-	char __pad [SMP_CACHE_BYTES];
-} runqueues [NR_CPUS] __cacheline_aligned;
+	int prev_nr_running[NR_CPUS];
+} ____cacheline_aligned;
+
+static struct runqueue runqueues[NR_CPUS] __cacheline_aligned;
 
-#define this_rq()		(runqueues + smp_processor_id())
-#define task_rq(p)		(runqueues + (p)->cpu)
 #define cpu_rq(cpu)		(runqueues + (cpu))
-#define cpu_curr(cpu)		(runqueues[(cpu)].curr)
+#define this_rq()		cpu_rq(smp_processor_id())
+#define task_rq(p)		cpu_rq((p)->cpu)
+#define cpu_curr(cpu)		(cpu_rq(cpu)->curr)
 #define rt_task(p)		((p)->policy != SCHED_OTHER)
 
-#define lock_task_rq(rq,p,flags)				\
-do {								\
-repeat_lock_task:						\
-	rq = task_rq(p);					\
-	spin_lock_irqsave(&rq->lock, flags);			\
-	if (unlikely((rq)->cpu != (p)->cpu)) {			\
-		spin_unlock_irqrestore(&rq->lock, flags);	\
-		goto repeat_lock_task;				\
-	}							\
-} while (0)
 
-#define unlock_task_rq(rq,p,flags)				\
-	spin_unlock_irqrestore(&rq->lock, flags)
+static inline runqueue_t *lock_task_rq(task_t *p, unsigned long *flags)
+{
+	struct runqueue *__rq;
 
+repeat_lock_task:
+	__rq = task_rq(p);
+	spin_lock_irqsave(&__rq->lock, *flags);
+	if (unlikely(__rq != task_rq(p))) {
+		spin_unlock_irqrestore(&__rq->lock, *flags);
+		goto repeat_lock_task;
+	}
+	return __rq;
+}
+
+static inline void unlock_task_rq(runqueue_t *rq, unsigned long *flags)
+{
+	spin_unlock_irqrestore(&rq->lock, *flags);
+}
 /*
  * Adding/removing a task to/from a priority array:
  */
@@ -83,29 +82,101 @@
 	array->nr_active--;
 	list_del_init(&p->run_list);
 	if (list_empty(array->queue + p->prio))
-		__set_bit(p->prio, array->bitmap);
+		__clear_bit(p->prio, array->bitmap);
 }
 
 static inline void enqueue_task(struct task_struct *p, prio_array_t *array)
 {
 	list_add_tail(&p->run_list, array->queue + p->prio);
-	__clear_bit(p->prio, array->bitmap);
+	__set_bit(p->prio, array->bitmap);
 	array->nr_active++;
 	p->array = array;
 }
 
+/*
+ * A task is 'heavily interactive' if it either has reached the
+ * bottom 25% of the SCHED_OTHER priority range, or if it is below
+ * its default priority by at least 3 priority levels. In this
+ * case we favor it by reinserting it on the active array,
+ * even after it expired its current timeslice.
+ *
+ * A task is a 'CPU hog' if it's either in the upper 25% of the
+ * SCHED_OTHER priority range, or if's not an interactive task.
+ *
+ * A task can get a priority bonus by being 'somewhat
+ * interactive' - and it will get a priority penalty for
+ * being a CPU hog.
+ *
+ */
+
+#define PRIO_INTERACTIVE \
+		(MAX_RT_PRIO + MAX_USER_PRIO*PRIO_INTERACTIVE_RATIO/100)
+#define PRIO_CPU_HOG \
+		(MAX_RT_PRIO + MAX_USER_PRIO*PRIO_CPU_HOG_RATIO/100)
+
+#define TASK_INTERACTIVE(p) \
+	(((p)->prio <= PRIO_INTERACTIVE) || \
+	(((p)->prio < PRIO_CPU_HOG) && \
+		((p)->prio <= NICE_TO_PRIO((p)->__nice) - INTERACTIVE_DELTA)))
+
+/*
+ * We place interactive tasks back into the active array, if possible.
+ *
+ * To guarantee that this does not starve expired tasks we ignore the
+ * interactivity of a task if the first expired task had to wait more
+ * than a 'reasonable' amount of time. This deadline timeout is
+ * load-dependent, as the frequency of array switched decreases with
+ * increasing number of running tasks:
+ */
+#define EXPIRED_STARVING(rq) \
+		((rq)->expired_timestamp && \
+		(jiffies - (rq)->expired_timestamp >= \
+			STARVATION_LIMIT * ((rq)->nr_running) + 1))
+
+static inline int effective_prio(task_t *p)
+{
+	int bonus, prio;
+
+	/*
+	 * Here we scale the actual sleep average [0 .... MAX_SLEEP_AVG]
+	 * into the -14 ... +14 bonus/penalty range.
+	 *
+	 * We use 70% of the full 0...39 priority range so that:
+	 *
+	 * 1) nice +19 CPU hogs do not preempt nice 0 CPU hogs.
+	 * 2) nice -20 interactive tasks do not get preempted by
+	 *    nice 0 interactive tasks.
+	 *
+	 * Both properties are important to certain workloads.
+	 */
+	bonus = MAX_USER_PRIO*PRIO_BONUS_RATIO*p->sleep_avg/MAX_SLEEP_AVG/100 -
+			MAX_USER_PRIO*PRIO_BONUS_RATIO/100/2;
+
+	prio = NICE_TO_PRIO(p->__nice) - bonus;
+	if (prio < MAX_RT_PRIO)
+		prio = MAX_RT_PRIO;
+	if (prio > MAX_PRIO-1)
+		prio = MAX_PRIO-1;
+	return prio;
+}
+
 static inline void activate_task(task_t *p, runqueue_t *rq)
 {
+	unsigned long sleep_time = jiffies - p->sleep_timestamp;
 	prio_array_t *array = rq->active;
 
-	if (!rt_task(p)) {
-		unsigned long prio_bonus = JSLEEP_TO_PRIO(jiffies - p->sleep_jtime);
-
-		if (prio_bonus > MAX_PRIO)
-			prio_bonus = MAX_PRIO;
-		p->prio -= prio_bonus;
-		if (p->prio < MAX_RT_PRIO)
-			p->prio = MAX_RT_PRIO;
+	if (!rt_task(p) && sleep_time) {
+		/*
+		 * This code gives a bonus to interactive tasks. We update
+		 * an 'average sleep time' value here, based on
+		 * sleep_timestamp. The more time a task spends sleeping,
+		 * the higher the average gets - and the higher the priority
+		 * boost gets as well.
+		 */
+		p->sleep_avg += sleep_time;
+		if (p->sleep_avg > MAX_SLEEP_AVG)
+			p->sleep_avg = MAX_SLEEP_AVG;
+		p->prio = effective_prio(p);
 	}
 	enqueue_task(p, array);
 	rq->nr_running++;
@@ -116,17 +187,17 @@
 	rq->nr_running--;
 	dequeue_task(p, p->array);
 	p->array = NULL;
-	p->sleep_jtime = jiffies;
+	p->sleep_timestamp = jiffies;
 }
 
 static inline void resched_task(task_t *p)
 {
 	int need_resched;
 
-	need_resched = p->need_resched;
+	need_resched = p->work.need_resched;
 	wmb();
-	p->need_resched = 1;
-	if (!need_resched)
+	p->work.need_resched = 1;
+	if (!need_resched && (p->cpu != smp_processor_id()))
 		smp_send_reschedule(p->cpu);
 }
 
@@ -147,12 +218,26 @@
 		cpu_relax();
 		barrier();
 	}
-	lock_task_rq(rq, p, flags);
+	rq = lock_task_rq(p, &flags);
 	if (unlikely(rq->curr == p)) {
-		unlock_task_rq(rq, p, flags);
+		unlock_task_rq(rq, &flags);
 		goto repeat;
 	}
-	unlock_task_rq(rq, p, flags);
+	unlock_task_rq(rq, &flags);
+}
+
+/*
+ * The SMP message passing code calls this function whenever
+ * the new task has arrived at the target CPU. We move the
+ * new task into the local runqueue.
+ *
+ * This function must be called with interrupts disabled.
+ */
+void sched_task_migrated(task_t *new_task)
+{
+	wait_task_inactive(new_task);
+	new_task->cpu = smp_processor_id();
+	wake_up_process(new_task);
 }
 
 /*
@@ -185,27 +270,19 @@
 	int success = 0;
 	runqueue_t *rq;
 
-	lock_task_rq(rq, p, flags);
+	rq = lock_task_rq(p, &flags);
 	p->state = TASK_RUNNING;
 	if (!p->array) {
-		if (!rt_task(p) && synchronous && (smp_processor_id() < p->cpu)) {
-			spin_lock(&this_rq()->lock);
-			p->cpu = smp_processor_id();
-			activate_task(p, this_rq());
-			spin_unlock(&this_rq()->lock);
-		} else {
-			activate_task(p, rq);
-			if ((rq->curr == rq->idle) ||
-					(p->prio < rq->curr->prio))
-				resched_task(rq->curr);
-		}
+		activate_task(p, rq);
+		if ((rq->curr == rq->idle) || (p->prio < rq->curr->prio))
+			resched_task(rq->curr);
 		success = 1;
 	}
-	unlock_task_rq(rq, p, flags);
+	unlock_task_rq(rq, &flags);
 	return success;
 }
 
-inline int wake_up_process(task_t * p)
+int wake_up_process(task_t * p)
 {
 	return try_to_wake_up(p, 0);
 }
@@ -214,13 +291,15 @@
 {
 	runqueue_t *rq = this_rq();
 
-	spin_lock_irq(&rq->lock);
 	p->state = TASK_RUNNING;
 	if (!rt_task(p)) {
-		p->prio += MAX_USER_PRIO/10;
-		if (p->prio > MAX_PRIO-1)
-			p->prio = MAX_PRIO-1;
+		p->sleep_avg = p->sleep_avg * CHILD_FORK_PENALTY / 100;
+		p->prio = effective_prio(p);
+
+		current->sleep_avg = current->sleep_avg * PARENT_FORK_PENALTY / 100;
 	}
+	spin_lock_irq(&rq->lock);
+	p->cpu = smp_processor_id();
 	activate_task(p, rq);
 	spin_unlock_irq(&rq->lock);
 }
@@ -237,14 +316,14 @@
 
 	prepare_to_switch();
 
-	if (!mm) {
+	if (unlikely(!mm)) {
 		next->active_mm = oldmm;
 		atomic_inc(&oldmm->mm_count);
 		enter_lazy_tlb(oldmm, next, smp_processor_id());
 	} else
 		switch_mm(oldmm, mm, next, smp_processor_id());
 
-	if (!prev->mm) {
+	if (unlikely(!prev->mm)) {
 		prev->active_mm = NULL;
 		mmdrop(oldmm);
 	}
@@ -267,7 +346,7 @@
 	unsigned long i, sum = 0;
 
 	for (i = 0; i < smp_num_cpus; i++)
-		sum += cpu_rq(i)->nr_running;
+		sum += cpu_rq(cpu_logical_map(i))->nr_running;
 
 	return sum;
 }
@@ -277,82 +356,115 @@
 	unsigned long i, sum = 0;
 
 	for (i = 0; i < smp_num_cpus; i++)
-		sum += cpu_rq(i)->nr_switches;
+		sum += cpu_rq(cpu_logical_map(i))->nr_switches;
 
 	return sum;
 }
 
-static inline unsigned long max_rq_len(void)
+#if CONFIG_SMP
+/*
+ * Lock the busiest runqueue as well, this_rq is locked already.
+ * Recalculate nr_running if we have to drop the runqueue lock.
+ */
+static inline unsigned int double_lock_balance(runqueue_t *this_rq,
+	runqueue_t *busiest, int this_cpu, int idle, unsigned int nr_running)
 {
-	unsigned long i, curr, max = 0;
-
-	for (i = 0; i < smp_num_cpus; i++) {
-		curr = cpu_rq(i)->nr_running;
-		if (curr > max)
-			max = curr;
+	if (unlikely(!spin_trylock(&busiest->lock))) {
+		if (busiest < this_rq) {
+			spin_unlock(&this_rq->lock);
+			spin_lock(&busiest->lock);
+			spin_lock(&this_rq->lock);
+			/* Need to recalculate nr_running */
+			if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu]))
+				nr_running = this_rq->nr_running;
+			else
+				nr_running = this_rq->prev_nr_running[this_cpu];
+		} else
+			spin_lock(&busiest->lock);
 	}
-	return max;
+	return nr_running;
 }
-
 /*
- * Current runqueue is empty, try to find work on
- * other runqueues.
+ * Current runqueue is empty, or rebalance tick: if there is an
+ * inbalance (current runqueue is too short) then pull from
+ * busiest runqueue(s).
  *
  * We call this with the current runqueue locked,
  * irqs disabled.
  */
-static void load_balance(runqueue_t *this_rq)
+static void load_balance(runqueue_t *this_rq, int idle)
 {
-	int nr_tasks, load, prev_max_load, max_load, idx, i;
+	int imbalance, nr_running, load, max_load,
+		idx, i, this_cpu = smp_processor_id();
 	task_t *next = this_rq->idle, *tmp;
-	runqueue_t *busiest, *rq_tmp;
+	runqueue_t *busiest, *rq_src;
 	prio_array_t *array;
 	list_t *head, *curr;
 
-	prev_max_load = max_rq_len();
-	nr_tasks = prev_max_load - this_rq->nr_running;
-	/*
-	 * It needs an at least ~10% imbalance to trigger balancing:
-	 */
-	if (nr_tasks <= 1 + prev_max_load/8)
-		return;
-	prev_max_load++;
-
-repeat_search:
 	/*
 	 * We search all runqueues to find the most busy one.
 	 * We do this lockless to reduce cache-bouncing overhead,
-	 * we re-check the source CPU with the lock held.
+	 * we re-check the 'best' source CPU later on again, with
+	 * the lock held.
+	 *
+	 * We fend off statistical fluctuations in runqueue lengths by
+	 * saving the runqueue length during the previous load-balancing
+	 * operation and using the smaller one the current and saved lengths.
+	 * If a runqueue is long enough for a longer amount of time then
+	 * we recognize it and pull tasks from it.
+	 *
+	 * The 'current runqueue length' is a statistical maximum variable,
+	 * for that one we take the longer one - to avoid fluctuations in
+	 * the other direction. So for a load-balance to happen it needs
+	 * stable long runqueue on the target CPU and stable short runqueue
+	 * on the local runqueue.
+	 *
+	 * We make an exception if this CPU is about to become idle - in
+	 * that case we are less picky about moving a task across CPUs and
+	 * take what can be taken.
 	 */
+	if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu]))
+		nr_running = this_rq->nr_running;
+	else
+		nr_running = this_rq->prev_nr_running[this_cpu];
+
 	busiest = NULL;
-	max_load = 0;
+	max_load = 1;
 	for (i = 0; i < smp_num_cpus; i++) {
-		rq_tmp = cpu_rq(i);
-		load = rq_tmp->nr_running;
-		if ((load > max_load) && (load < prev_max_load) &&
-						(rq_tmp != this_rq)) {
-			busiest = rq_tmp;
+		rq_src = cpu_rq(cpu_logical_map(i));
+		if (idle || (rq_src->nr_running < this_rq->prev_nr_running[i]))
+			load = rq_src->nr_running;
+		else
+			load = this_rq->prev_nr_running[i];
+		this_rq->prev_nr_running[i] = rq_src->nr_running;
+
+		if ((load > max_load) && (rq_src != this_rq)) {
+			busiest = rq_src;
 			max_load = load;
 		}
 	}
 
 	if (likely(!busiest))
 		return;
-	if (max_load <= this_rq->nr_running)
+
+	imbalance = (max_load - nr_running) / 2;
+
+	/* It needs an at least ~25% imbalance to trigger balancing. */
+	if (!idle && (imbalance < (max_load + 3)/4))
 		return;
-	prev_max_load = max_load;
-	if (busiest->cpu < this_rq->cpu) {
-		spin_unlock(&this_rq->lock);
-		spin_lock(&busiest->lock);
-		spin_lock(&this_rq->lock);
-	} else
-		spin_lock(&busiest->lock);
+
+	nr_running = double_lock_balance(this_rq, busiest, this_cpu, idle, nr_running);
+	/*
+	 * Make sure nothing changed since we checked the
+	 * runqueue length.
+	 */
 	if (busiest->nr_running <= this_rq->nr_running + 1)
 		goto out_unlock;
 
 	/*
-	 * We first consider expired tasks. Those will likely not run
-	 * in the near future, thus switching CPUs has the least effect
+	 * We first consider expired tasks. Those will likely not be
+	 * executed in the near future, and they are most likely to
+	 * be cache-cold, thus switching CPUs has the least effect
 	 * on them.
 	 */
 	if (busiest->expired->nr_active)
@@ -367,21 +479,33 @@
 	 */
 	idx = MAX_RT_PRIO;
 skip_bitmap:
-	idx = find_next_zero_bit(array->bitmap, MAX_PRIO, idx);
+	idx = find_next_bit(array->bitmap, MAX_PRIO, idx);
 	if (idx == MAX_PRIO) {
 		if (array == busiest->expired) {
 			array = busiest->active;
 			goto new_array;
 		}
-		spin_unlock(&busiest->lock);
-		goto repeat_search;
+		goto out_unlock;
 	}
 
 	head = array->queue + idx;
-	curr = head->next;
+	curr = head->prev;
 skip_queue:
 	tmp = list_entry(curr, task_t, run_list);
-	if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << smp_processor_id()))) {
+
+	/*
+	 * We do not migrate tasks that are:
+	 * 1) running (obviously), or
+	 * 2) cannot be migrated to this CPU due to cpus_allowed, or
+	 * 3) are cache-hot on their current CPU.
+	 */
+
+#define CAN_MIGRATE_TASK(p,rq,this_cpu)					\
+	((jiffies - (p)->sleep_timestamp > cache_decay_ticks) &&	\
+		((p) != (rq)->curr) &&					\
+			(tmp->cpus_allowed & (1 << (this_cpu))))
+
+	if (!CAN_MIGRATE_TASK(tmp, busiest, this_cpu)) {
 		curr = curr->next;
 		if (curr != head)
 			goto skip_queue;
@@ -395,67 +519,107 @@
 	 */
 	dequeue_task(next, array);
 	busiest->nr_running--;
-	next->cpu = smp_processor_id();
+	next->cpu = this_cpu;
 	this_rq->nr_running++;
 	enqueue_task(next, this_rq->active);
 	if (next->prio < current->prio)
-		current->need_resched = 1;
-	if (--nr_tasks) {
+		current->work.need_resched = 1;
+	if (!idle && --imbalance) {
 		if (array == busiest->expired) {
 			array = busiest->active;
 			goto new_array;
 		}
-		spin_unlock(&busiest->lock);
-		goto repeat_search;
 	}
 out_unlock:
 	spin_unlock(&busiest->lock);
 }
 
-/* Rebalance every 250 msecs */
-#define REBALANCE_TICK (HZ/4)
+/*
+ * One of the idle_cpu_tick() or the busy_cpu_tick() function will
+ * gets called every timer tick, on every CPU. Our balancing action
+ * frequency and balancing agressivity depends on whether the CPU is
+ * idle or not.
+ *
+ * busy-rebalance every 250 msecs. idle-rebalance every 1 msec. (or on
+ * systems with HZ=100, every 10 msecs.)
+ */
+#define BUSY_REBALANCE_TICK (HZ/4 ?: 1)
+#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1)
 
-void idle_tick(void)
+static inline void idle_tick(void)
 {
-	unsigned long flags;
-
-	if (!(jiffies % REBALANCE_TICK) && likely(this_rq()->curr != NULL)) {
-		spin_lock_irqsave(&this_rq()->lock, flags);
-		load_balance(this_rq());
-		spin_unlock_irqrestore(&this_rq()->lock, flags);
-	}
+	if (jiffies % IDLE_REBALANCE_TICK)
+		return;
+	spin_lock(&this_rq()->lock);
+	load_balance(this_rq(), 1);
+	spin_unlock(&this_rq()->lock);
 }
 
-void expire_task(task_t *p)
+#endif
+
+/*
+ * This function gets called by the timer code, with HZ frequency.
+ * We call it with interrupts disabled.
+ */
+void scheduler_tick(task_t *p)
 {
 	runqueue_t *rq = this_rq();
-	unsigned long flags;
+#if CONFIG_SMP
+	unsigned long now = jiffies;
 
+	if (p == rq->idle)
+		return idle_tick();
+#endif
+	/* Task might have expired already, but not scheduled off yet */
 	if (p->array != rq->active) {
-		p->need_resched = 1;
+		p->work.need_resched = 1;
 		return;
 	}
+	spin_lock(&rq->lock);
+	if (unlikely(rt_task(p))) {
+		/*
+		 * RR tasks need a special form of timeslice management.
+		 * FIFO tasks have no timeslices.
+		 */
+		if ((p->policy == SCHED_RR) && !--p->time_slice) {
+			p->time_slice = NICE_TO_TIMESLICE(p->__nice);
+			p->work.need_resched = 1;
+
+			/* put it at the end of the queue: */
+			dequeue_task(p, rq->active);
+			enqueue_task(p, rq->active);
+		}
+		goto out;
+	}
 	/*
-	 * The task cannot change CPUs because it's the current task.
+	 * The task was running during this tick - update the
+	 * time slice counter and the sleep average. Note: we
+	 * do not update a process's priority until it either
+	 * goes to sleep or uses up its timeslice. This makes
+	 * it possible for interactive tasks to use up their
+	 * timeslices at their highest priority levels.
 	 */
-	spin_lock_irqsave(&rq->lock, flags);
-	if ((p->policy != SCHED_FIFO) && !--p->time_slice) {
-		unsigned int time_slice;
-		p->need_resched = 1;
+	if (p->sleep_avg)
+		p->sleep_avg--;
+	if (!--p->time_slice) {
 		dequeue_task(p, rq->active);
-		time_slice = RT_PRIO_TO_TIMESLICE(p->prio);
-		if (!rt_task(p)) {
-			time_slice = PRIO_TO_TIMESLICE(p->prio);
-			if (++p->prio >= MAX_PRIO)
-				p->prio = MAX_PRIO - 1;
-		}
-		p->time_slice = time_slice;
-		if (TASK_INTERACTIVE(p))
-			enqueue_task(p, rq->active);
-		else
+		p->work.need_resched = 1;
+		p->prio = effective_prio(p);
+		p->time_slice = NICE_TO_TIMESLICE(p->__nice);
+
+		if (!TASK_INTERACTIVE(p) || EXPIRED_STARVING(rq)) {
+			if (!rq->expired_timestamp)
+				rq->expired_timestamp = jiffies;
 			enqueue_task(p, rq->expired);
+		} else
+			enqueue_task(p, rq->active);
 	}
-	spin_unlock_irqrestore(&rq->lock, flags);
+out:
+#if CONFIG_SMP
+	if (!(now % BUSY_REBALANCE_TICK))
+		load_balance(rq, 0);
+#endif
+	spin_unlock(&rq->lock);
 }
 
 void scheduling_functions_start_here(void) { }
@@ -465,36 +629,41 @@
  */
 asmlinkage void schedule(void)
 {
-	task_t *prev, *next;
+	task_t *prev = current, *next;
+	runqueue_t *rq = this_rq();
 	prio_array_t *array;
-	runqueue_t *rq;
 	list_t *queue;
 	int idx;
 
 	if (unlikely(in_interrupt()))
 		BUG();
-need_resched_back:
-	prev = current;
 	release_kernel_lock(prev, smp_processor_id());
-	rq = this_rq();
 	spin_lock_irq(&rq->lock);
 
 	switch (prev->state) {
+	case TASK_RUNNING:
+		prev->sleep_timestamp = jiffies;
+		break;
 	case TASK_INTERRUPTIBLE:
 		if (unlikely(signal_pending(prev))) {
 			prev->state = TASK_RUNNING;
+			prev->sleep_timestamp = jiffies;
 			break;
 		}
 	default:
 		deactivate_task(prev, rq);
-	case TASK_RUNNING:
 	}
+#if CONFIG_SMP
 pick_next_task:
+#endif
 	if (unlikely(!rq->nr_running)) {
-		load_balance(rq);
+#if CONFIG_SMP
+		load_balance(rq, 1);
 		if (rq->nr_running)
 			goto pick_next_task;
+#endif
 		next = rq->idle;
+		rq->expired_timestamp = 0;
 		goto switch_tasks;
 	}
 
@@ -506,19 +675,20 @@
 		rq->active = rq->expired;
 		rq->expired = array;
 		array = rq->active;
+		rq->expired_timestamp = 0;
 	}
 
-	idx = sched_find_first_zero_bit(array->bitmap);
+	idx = sched_find_first_bit(array->bitmap);
 	queue = array->queue + idx;
 	next = list_entry(queue->next, task_t, run_list);
 
 switch_tasks:
-	prev->need_resched = 0;
+	prefetch(next);
+	prev->work.need_resched = 0;
 
 	if (likely(prev != next)) {
 		rq->nr_switches++;
 		rq->curr = next;
-		next->cpu = prev->cpu;
 		context_switch(prev, next);
 		/*
 		 * The runqueue pointer might be from another CPU
@@ -531,8 +701,6 @@
 	spin_unlock_irq(&rq->lock);
 
 	reacquire_kernel_lock(current);
-	if (unlikely(current->need_resched))
-		goto need_resched_back;
 	return;
 }
 
@@ -685,45 +853,23 @@
  */
 void set_cpus_allowed(task_t *p, unsigned long new_mask)
 {
-	runqueue_t *this_rq = this_rq(), *target_rq;
-	unsigned long this_mask = 1UL << smp_processor_id();
-	int target_cpu;
-
 	new_mask &= cpu_online_map;
+	if (!new_mask)
+		BUG();
+
 	p->cpus_allowed = new_mask;
 	/*
 	 * Can the task run on the current CPU? If not then
 	 * migrate the process off to a proper CPU.
 	 */
-	if (new_mask & this_mask)
+	if (new_mask & (1UL << smp_processor_id()))
 		return;
-	target_cpu = ffz(~new_mask);
-	target_rq = cpu_rq(target_cpu);
-	if (target_cpu < smp_processor_id()) {
-		spin_lock_irq(&target_rq->lock);
-		spin_lock(&this_rq->lock);
-	} else {
-		spin_lock_irq(&target_rq->lock);
-		spin_lock(&this_rq->lock);
-	}
-	dequeue_task(p, p->array);
-	this_rq->nr_running--;
-	target_rq->nr_running++;
-	enqueue_task(p, target_rq->active);
-	target_rq->curr->need_resched = 1;
-	spin_unlock(&target_rq->lock);
+#if CONFIG_SMP
+	current->state = TASK_UNINTERRUPTIBLE;
+	smp_migrate_task(__ffs(new_mask), current);
 
-	/*
-	 * The easiest solution is to context switch into
-	 * the idle thread - which will pick the best task
-	 * afterwards:
-	 */
-	this_rq->nr_switches++;
-	this_rq->curr = this_rq->idle;
-	this_rq->idle->need_resched = 1;
-	context_switch(current, this_rq->idle);
-	barrier();
-	spin_unlock_irq(&this_rq()->lock);
+	schedule();
+#endif
 }
 
 void scheduling_functions_end_here(void) { }
@@ -740,21 +886,20 @@
 	 * We have to be careful, if called from sys_setpriority(),
 	 * the task might be in the middle of scheduling on another CPU.
 	 */
-	lock_task_rq(rq, p, flags);
+	rq = lock_task_rq(p, &flags);
 	if (rt_task(p)) {
 		p->__nice = nice;
 		goto out_unlock;
 	}
 	array = p->array;
-	if (array) {
+	if (array)
 		dequeue_task(p, array);
-	}
 	p->__nice = nice;
 	p->prio = NICE_TO_PRIO(nice);
 	if (array) {
 		enqueue_task(p, array);
 		/*
-		 * If the task is runnable and lowered its priority,
+		 * If the task is running and lowered its priority,
 		 * or increased its priority then reschedule its CPU:
 		 */
 		if ((nice < p->__nice) ||
@@ -762,7 +907,7 @@
 			resched_task(rq->curr);
 	}
 out_unlock:
-	unlock_task_rq(rq, p, flags);
+	unlock_task_rq(rq, &flags);
 }
 
 #ifndef __alpha__
@@ -839,7 +984,7 @@
 	 * To be able to change p->policy safely, the apropriate
 	 * runqueue lock must be held.
 	 */
-	lock_task_rq(rq,p,flags);
+	rq = lock_task_rq(p, &flags);
 
 	if (policy < 0)
 		policy = p->policy;
@@ -861,7 +1006,7 @@
 		goto out_unlock;
 
 	retval = -EPERM;
-	if ((policy == SCHED_FIFO || policy == SCHED_RR) && 
+	if ((policy == SCHED_FIFO || policy == SCHED_RR) &&
 	    !capable(CAP_SYS_NICE))
 		goto out_unlock;
 	if ((current->euid != p->euid) && (current->euid != p->uid) &&
@@ -882,7 +1027,7 @@
 		activate_task(p, task_rq(p));
 
 out_unlock:
-	unlock_task_rq(rq,p,flags);
+	unlock_task_rq(rq, &flags);
 out_unlock_tasklist:
 	read_unlock_irq(&tasklist_lock);
 
@@ -890,7 +1035,7 @@
 	return retval;
 }
 
-asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, 
+asmlinkage long sys_sched_setscheduler(pid_t pid, int policy,
 				      struct sched_param *param)
 {
 	return setscheduler(pid, policy, param);
@@ -967,12 +1112,22 @@
 	 */
 	spin_lock_irq(&rq->lock);
 	array = current->array;
-	dequeue_task(current, array);
-	if (likely(!rt_task(current)))
-		if (current->prio < MAX_PRIO-1)
-			current->prio++;
-	enqueue_task(current, array);
-	spin_unlock_irq(&rq->lock);
+	/*
+	 * If the task has reached maximum priority (or is a RT task)
+	 * then just requeue the task to the end of the runqueue:
+	 */
+	if (likely(current->prio == MAX_PRIO-1 || rt_task(current))) {
+		list_del(&current->run_list);
+		list_add_tail(&current->run_list, array->queue + current->prio);
+	} else {
+		list_del(&current->run_list);
+		if (list_empty(array->queue + current->prio))
+			__clear_bit(current->prio, array->bitmap);
+		current->prio++;
+		list_add_tail(&current->run_list, array->queue + current->prio);
+		__set_bit(current->prio, array->bitmap);
+	}
+	spin_unlock(&rq->lock);
 
 	schedule();
 
@@ -1024,7 +1179,7 @@
 	p = find_process_by_pid(pid);
 	if (p)
 		jiffies_to_timespec(p->policy & SCHED_FIFO ?
-					 0 : RT_PRIO_TO_TIMESLICE(p->prio), &t);
+					 0 : NICE_TO_TIMESLICE(p->__nice), &t);
 	read_unlock(&tasklist_lock);
 	if (p)
 		retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
@@ -1039,7 +1194,7 @@
 	static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
 
 	printk("%-13.13s ", p->comm);
-	state = p->state ? ffz(~p->state) + 1 : 0;
+	state = p->state ? __ffs(p->state) + 1 : 0;
 	if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *))
 		printk(stat_nam[state]);
 	else
@@ -1125,14 +1280,12 @@
 	read_unlock(&tasklist_lock);
 }
 
-extern unsigned long wait_init_idle;
-
 static inline void double_rq_lock(runqueue_t *rq1, runqueue_t *rq2)
 {
 	if (rq1 == rq2)
 		spin_lock(&rq1->lock);
 	else {
-		if (rq1->cpu < rq2->cpu) {
+		if (rq1 < rq2) {
 			spin_lock(&rq1->lock);
 			spin_lock(&rq2->lock);
 		} else {
@@ -1149,28 +1302,24 @@
 		spin_unlock(&rq2->lock);
 }
 
-void __init init_idle(void)
+void __init init_idle(task_t *idle, int cpu)
 {
-	runqueue_t *this_rq = this_rq(), *rq = current->array->rq;
+	runqueue_t *idle_rq = cpu_rq(cpu), *rq = idle->array->rq;
 	unsigned long flags;
 
 	__save_flags(flags);
 	__cli();
-	double_rq_lock(this_rq, rq);
+	double_rq_lock(idle_rq, rq);
 
-	this_rq->curr = this_rq->idle = current;
-	deactivate_task(current, rq);
-	current->array = NULL;
-	current->prio = MAX_PRIO;
-	current->state = TASK_RUNNING;
-	clear_bit(smp_processor_id(), &wait_init_idle);
-	double_rq_unlock(this_rq, rq);
-	while (wait_init_idle) {
-		cpu_relax();
-		barrier();
-	}
-	current->need_resched = 1;
-	__sti();
+	idle_rq->curr = idle_rq->idle = idle;
+	deactivate_task(idle, rq);
+	idle->array = NULL;
+	idle->prio = MAX_PRIO;
+	idle->state = TASK_RUNNING;
+	idle->cpu = cpu;
+	double_rq_unlock(idle_rq, rq);
+	idle->work.need_resched = 1;
+	__restore_flags(flags);
 }
 
 extern void init_timervecs(void);
@@ -1190,17 +1339,17 @@
 		rq->active = rq->arrays + 0;
 		rq->expired = rq->arrays + 1;
 		spin_lock_init(&rq->lock);
-		rq->cpu = i;
 
 		for (j = 0; j < 2; j++) {
 			array = rq->arrays + j;
 			array->rq = rq;
 			array->lock = &rq->lock;
-			for (k = 0; k < MAX_PRIO; k++)
+			for (k = 0; k < MAX_PRIO; k++) {
 				INIT_LIST_HEAD(array->queue + k);
-			memset(array->bitmap, 0xff, BITMAP_SIZE);
-			// zero delimiter for bitsearch
-			clear_bit(MAX_PRIO, array->bitmap);
+				__clear_bit(k, array->bitmap);
+			}
+			// delimiter for bitsearch
+			__set_bit(MAX_PRIO, array->bitmap);
 		}
 	}
 	/*
@@ -1209,11 +1358,8 @@
 	 */
 	rq = this_rq();
 	rq->curr = current;
-	rq->idle = NULL;
+	rq->idle = current;
 	wake_up_process(current);
-
-	for (i = 0; i < PIDHASH_SZ; i++)
-		pidhash[i] = NULL;
 
 	init_timervecs();
 	init_bh(TIMER_BH, timer_bh);
diff -u --recursive --new-file v2.5.2/linux/kernel/signal.c linux/kernel/signal.c
--- v2.5.2/linux/kernel/signal.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/signal.c	Mon Jan 28 15:11:45 2002
@@ -105,7 +105,7 @@
 void
 flush_signals(struct task_struct *t)
 {
-	t->sigpending = 0;
+	t->work.sigpending = 0;
 	flush_sigqueue(&t->pending);
 }
 
@@ -119,7 +119,7 @@
 		if (atomic_dec_and_test(&sig->count))
 			kmem_cache_free(sigact_cachep, sig);
 	}
-	tsk->sigpending = 0;
+	tsk->work.sigpending = 0;
 	flush_sigqueue(&tsk->pending);
 	spin_unlock_irq(&tsk->sigmask_lock);
 }
@@ -246,7 +246,7 @@
 		if (current->notifier) {
 			if (sigismember(current->notifier_mask, sig)) {
 				if (!(current->notifier)(current->notifier_data)) {
-					current->sigpending = 0;
+					current->work.sigpending = 0;
 					return 0;
 				}
 			}
@@ -465,7 +465,7 @@
  */
 static inline void signal_wake_up(struct task_struct *t)
 {
-	t->sigpending = 1;
+	t->work.sigpending = 1;
 
 #ifdef CONFIG_SMP
 	/*
diff -u --recursive --new-file v2.5.2/linux/kernel/softirq.c linux/kernel/softirq.c
--- v2.5.2/linux/kernel/softirq.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/softirq.c	Tue Jan 15 13:53:51 2002
@@ -387,8 +387,7 @@
 
 		while (softirq_pending(cpu)) {
 			do_softirq();
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 		}
 
 		__set_current_state(TASK_INTERRUPTIBLE);
diff -u --recursive --new-file v2.5.2/linux/kernel/time.c linux/kernel/time.c
--- v2.5.2/linux/kernel/time.c	Mon Oct 16 12:58:51 2000
+++ linux/kernel/time.c	Wed Jan 23 15:28:39 2002
@@ -36,24 +36,6 @@
  */
 struct timezone sys_tz;
 
-static void do_normal_gettime(struct timeval * tm)
-{
-        *tm=xtime;
-}
-
-void (*do_get_fast_time)(struct timeval *) = do_normal_gettime;
-
-/*
- * Generic way to access 'xtime' (the current time of day).
- * This can be changed if the platform provides a more accurate (and fast!) 
- * version.
- */
-
-void get_fast_time(struct timeval * t)
-{
-	do_get_fast_time(t);
-}
-
 /* The xtime_lock is not only serializing the xtime read/writes but it's also
    serializing all accesses to the global NTP variables now. */
 extern rwlock_t xtime_lock;
diff -u --recursive --new-file v2.5.2/linux/kernel/timer.c linux/kernel/timer.c
--- v2.5.2/linux/kernel/timer.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/timer.c	Tue Jan 15 14:33:55 2002
@@ -585,17 +585,16 @@
 
 	update_one_process(p, user_tick, system, cpu);
 	if (p->pid) {
-		expire_task(p);
 		if (p->__nice > 0)
 			kstat.per_cpu_nice[cpu] += user_tick;
 		else
 			kstat.per_cpu_user[cpu] += user_tick;
 		kstat.per_cpu_system[cpu] += system;
 	} else {
-		idle_tick();
 		if (local_bh_count(cpu) || local_irq_count(cpu) > 1)
 			kstat.per_cpu_system[cpu] += system;
 	}
+	scheduler_tick(p);
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/lib/Config.help linux/lib/Config.help
--- v2.5.2/linux/lib/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/lib/Config.help	Fri Jan 25 16:04:33 2002
@@ -0,0 +1,6 @@
+CONFIG_CRC32
+  This option is provided for the case where no in-kernel-tree
+  modules require CRC32 functions, but a module built outside the
+  kernel tree does. Such modules that use library CRC32 functions
+  require M here.
+
diff -u --recursive --new-file v2.5.2/linux/lib/Config.in linux/lib/Config.in
--- v2.5.2/linux/lib/Config.in	Mon Jan 14 18:25:11 2002
+++ linux/lib/Config.in	Tue Jan 29 21:30:49 2002
@@ -5,4 +5,36 @@
 comment 'Library routines'
 
 tristate 'CRC32 functions' CONFIG_CRC32
+
+#
+# Do we need the compression support?
+#
+if [ "$CONFIG_CRAMFS" = "y" -o \
+     "$CONFIG_PPP_DEFLATE" = "y" -o \
+     "$CONFIG_JFFS2_FS" = "y" -o \
+     "$CONFIG_ZISOFS_FS" = "y" ]; then
+   define_tristate CONFIG_ZLIB_INFLATE y
+else
+  if [ "$CONFIG_CRAMFS" = "m" -o \
+       "$CONFIG_PPP_DEFLATE" = "m" -o \
+       "$CONFIG_JFFS2_FS" = "m" -o \
+       "$CONFIG_ZISOFS_FS" = "m" ]; then
+     define_tristate CONFIG_ZLIB_INFLATE m
+  else
+     define_tristate CONFIG_ZLIB_INFLATE n
+  fi
+fi
+
+if [ "$CONFIG_PPP_DEFLATE" = "y" -o \
+     "$CONFIG_JFFS2_FS" = "y" ]; then
+   define_tristate CONFIG_ZLIB_DEFLATE y
+else
+  if [ "$CONFIG_PPP_DEFLATE" = "m" -o \
+       "$CONFIG_JFFS2_FS" = "m" ]; then
+     define_tristate CONFIG_ZLIB_DEFLATE m
+  else
+     define_tristate CONFIG_ZLIB_DEFLATE n
+  fi
+fi
+
 endmenu
diff -u --recursive --new-file v2.5.2/linux/lib/Makefile linux/lib/Makefile
--- v2.5.2/linux/lib/Makefile	Mon Jan 14 18:25:11 2002
+++ linux/lib/Makefile	Tue Jan 29 21:30:41 2002
@@ -20,6 +20,13 @@
 endif
 
 obj-$(CONFIG_CRC32)	+= crc32.o
+
+subdir-$(CONFIG_ZLIB_INFLATE) += zlib_inflate
+subdir-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate
+
+# Include the subdirs, if necessary.
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
 include $(TOPDIR)/drivers/net/Makefile.lib
 include $(TOPDIR)/drivers/usb/Makefile.lib
 include $(TOPDIR)/fs/Makefile.lib
diff -u --recursive --new-file v2.5.2/linux/lib/crc32.c linux/lib/crc32.c
--- v2.5.2/linux/lib/crc32.c	Mon Jan 14 18:25:11 2002
+++ linux/lib/crc32.c	Tue Jan 15 11:08:05 2002
@@ -558,7 +558,7 @@
 /**
  * cleanup_crc32(): frees crc32 data when no longer needed
  */
-static void cleanup_crc32(void)
+static void __exit cleanup_crc32(void)
 {
 	crc32cleanup_le();
 	crc32cleanup_be();
diff -u --recursive --new-file v2.5.2/linux/lib/vsprintf.c linux/lib/vsprintf.c
--- v2.5.2/linux/lib/vsprintf.c	Thu Oct 11 11:17:22 2001
+++ linux/lib/vsprintf.c	Tue Jan 15 11:05:25 2002
@@ -616,8 +616,9 @@
 		case 'X':
 			base = 16;
 			break;
-		case 'd':
 		case 'i':
+                        base = 0;
+		case 'd':
 			is_sign = 1;
 		case 'u':
 			break;
@@ -637,7 +638,11 @@
 		while (isspace(*str))
 			str++;
 
-		if (!*str || !isdigit(*str))
+		if (!*str
+                    || (base == 16 && !isxdigit(*str))
+                    || (base == 10 && !isdigit(*str))
+                    || (base == 8 && (!isdigit(*str) || *str > '7'))
+                    || (base == 0 && !isdigit(*str)))
 			break;
 
 		switch(qualifier) {
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_deflate/Makefile linux/lib/zlib_deflate/Makefile
--- v2.5.2/linux/lib/zlib_deflate/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_deflate/Makefile	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,18 @@
+#
+# This is a modified version of zlib, which does all memory
+# allocation ahead of time.
+#
+# This is the compression code, see zlib_inflate for the
+# decompression code.
+#
+
+O_TARGET    := zlib_deflate.o
+
+export-objs := deflate_syms.o
+
+obj-y := deflate.o deftree.o deflate_syms.o
+obj-m := $(O_TARGET)
+
+EXTRA_CFLAGS += -I $(TOPDIR)/lib/zlib_deflate
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_deflate/deflate.c linux/lib/zlib_deflate/deflate.c
--- v2.5.2/linux/lib/zlib_deflate/deflate.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_deflate/deflate.c	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,1250 @@
+/* +++ deflate.c */
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/zutil.h>
+#include "defutil.h"
+
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG_ZLIB
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+local const config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    memset((charf *)s->head, 0, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int zlib_deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return zlib_deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS,
+			      DEF_MEM_LEVEL,
+			      Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int zlib_deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+		       version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int noheader = 0;
+    static char* my_version = ZLIB_VERSION;
+    deflate_workspace *mem;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+	return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+    mem = (deflate_workspace *) strm->workspace;
+
+    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+        noheader = 1;
+        windowBits = -windowBits;
+    }
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+	strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) &(mem->deflate_memory);
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->noheader = noheader;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) mem->window_memory;
+    s->prev   = (Posf *)  mem->prev_memory;
+    s->head   = (Posf *)  mem->head_memory;
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) mem->overlay_memory;
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return zlib_deflateReset(strm);
+}
+
+/* ========================================================================= */
+int zlib_deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
+	return Z_STREAM_ERROR;
+
+    s = (deflate_state *) strm->state;
+    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
+
+    strm->adler = zlib_adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+	length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+	dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+    }
+    memcpy((charf *)s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+	INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int zlib_deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+    
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return Z_STREAM_ERROR;
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL;
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->noheader < 0) {
+        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+    }
+    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+    strm->adler = 1;
+    s->last_flush = Z_NO_FLUSH;
+
+    zlib_tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int zlib_deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    if (level == Z_DEFAULT_COMPRESSION) {
+	level = 6;
+    }
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+	return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+	/* Flush the last buffer: */
+	err = zlib_deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    if (s->level != level) {
+	s->level = level;
+	s->max_lazy_match   = configuration_table[level].max_lazy;
+	s->good_match       = configuration_table[level].good_length;
+	s->nice_match       = configuration_table[level].nice_length;
+	s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}   
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    deflate_state *s = (deflate_state *) strm->state;
+    unsigned len = s->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    if (strm->next_out != Z_NULL) {
+	memcpy(strm->next_out, s->pending_out, len);
+	strm->next_out += len;
+    }
+    s->pending_out += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    s->pending -= len;
+    if (s->pending == 0) {
+        s->pending_out = s->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int zlib_deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+	flush > Z_FINISH || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) strm->state;
+
+    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
+	(s->status == FINISH_STATE && flush != Z_FINISH)) {
+        return Z_STREAM_ERROR;
+    }
+    if (strm->avail_out == 0) return Z_BUF_ERROR;
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the zlib header */
+    if (s->status == INIT_STATE) {
+
+        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+        uInt level_flags = (s->level-1) >> 1;
+
+        if (level_flags > 3) level_flags = 3;
+        header |= (level_flags << 6);
+	if (s->strstart != 0) header |= PRESET_DICT;
+        header += 31 - (header % 31);
+
+        s->status = BUSY_STATE;
+        putShortMSB(s, header);
+
+	/* Save the adler32 of the preset dictionary: */
+	if (s->strstart != 0) {
+	    putShortMSB(s, (uInt)(strm->adler >> 16));
+	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+	}
+	strm->adler = 1L;
+    }
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+	    /* Since avail_out is 0, deflate will be called again with
+	     * more output space, but possibly with both pending and
+	     * avail_in equal to zero. There won't be anything to do,
+	     * but this is not an error situation so make sure we
+	     * return OK instead of BUF_ERROR at next call of deflate:
+             */
+	    s->last_flush = -1;
+	    return Z_OK;
+	}
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+	       flush != Z_FINISH) {
+        return Z_BUF_ERROR;
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        return Z_BUF_ERROR;
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+	bstate = (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+	    if (strm->avail_out == 0) {
+	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+	    }
+	    return Z_OK;
+	    /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+	     * of deflate should use the same flush parameter to make sure
+	     * that the flush is complete. So we don't have to output an
+	     * empty block here, this will be done at next call. This also
+	     * ensures that for a very small output buffer, we emit at most
+	     * one empty block.
+	     */
+	}
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                zlib_tr_align(s);
+	    } else if (flush == Z_PACKET_FLUSH) {
+		/* Output just the 3-bit `stored' block type value,
+		   but not a zero length. */
+		zlib_tr_stored_type_only(s);
+            } else { /* FULL_FLUSH or SYNC_FLUSH */
+                zlib_tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                }
+            }
+            flush_pending(strm);
+	    if (strm->avail_out == 0) {
+	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+	      return Z_OK;
+	    }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->noheader) return Z_STREAM_END;
+
+    /* Write the zlib trailer (adler32) */
+    putShortMSB(s, (uInt)(strm->adler >> 16));
+    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    s->noheader = -1; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int zlib_deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    status = s->status;
+    if (status != INIT_STATE && status != BUSY_STATE &&
+	status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ */
+int zlib_deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+#ifdef MAXSEG_64K
+    return Z_STREAM_ERROR;
+#else
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+    deflate_workspace *mem;
+
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+        return Z_STREAM_ERROR;
+    }
+
+    ss = (deflate_state *) source->state;
+
+    *dest = *source;
+
+    mem = (deflate_workspace *) dest->workspace;
+
+    ds = &(mem->deflate_memory);
+
+    dest->state = (struct internal_state FAR *) ds;
+    *ds = *ss;
+    ds->strm = dest;
+
+    ds->window = (Bytef *) mem->window_memory;
+    ds->prev   = (Posf *)  mem->prev_memory;
+    ds->head   = (Posf *)  mem->head_memory;
+    overlay = (ushf *) mem->overlay_memory;
+    ds->pending_buf = (uchf *) overlay;
+
+    memcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    memcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    memcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    memcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+#endif
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    Bytef *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (!((deflate_state *)(strm->state))->noheader) {
+        strm->adler = zlib_adler32(strm->adler, strm->next_in, len);
+    }
+    memcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2:
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return best_len;
+    return s->lookahead;
+}
+
+#ifdef DEBUG_ZLIB
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (memcmp((charf *)s->window + match,
+                (charf *)s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+		start, match, length);
+        do {
+	    fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+	} while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+            more = wsize;
+
+        } else if (more == (unsigned)(-1)) {
+            /* Very unlikely, but possible on 16 bit machine if strstart == 0
+             * and lookahead == 1 (input done one byte at time)
+             */
+            more--;
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        } else if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            memcpy((charf *)s->window, (charf *)s->window+wsize,
+                   (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            } while (--n);
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+   zlib_tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+		(ulg)((long)s->strstart - s->block_start), \
+		(eof)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+   FLUSH_BLOCK_ONLY(s, eof); \
+   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+		   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+	Assert(s->block_start >= 0L, "block gone");
+
+	s->strstart += s->lookahead;
+	s->lookahead = 0;
+
+	/* Emit a stored block if pending_buf will be full: */
+ 	max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+	    /* strstart == 0 is possible when wraparound on 16-bit machine */
+	    s->lookahead = (uInt)(s->strstart - max_start);
+	    s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+	}
+	/* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+	}
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL; /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+	        return need_more;
+	    }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            bflush = zlib_tr_tally(s, s->strstart - s->match_start,
+                               s->match_length - MIN_MATCH);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in hash table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++; 
+            } else {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            bflush = zlib_tr_tally (s, 0, s->window[s->strstart]);
+            s->lookahead--;
+            s->strstart++; 
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL;    /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+	        return need_more;
+	    }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+                 (s->match_length == MIN_MATCH &&
+                  s->strstart - s->match_start > TOO_FAR))) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            bflush = zlib_tr_tally(s, s->strstart -1 - s->prev_match,
+				   s->prev_length - MIN_MATCH);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            if (zlib_tr_tally (s, 0, s->window[s->strstart-1])) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        zlib_tr_tally (s, 0, s->window[s->strstart-1]);
+        s->match_available = 0;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+ZEXTERN int ZEXPORT zlib_deflate_workspacesize ()
+{
+    return sizeof(deflate_workspace);
+}
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_deflate/deflate_syms.c linux/lib/zlib_deflate/deflate_syms.c
--- v2.5.2/linux/lib/zlib_deflate/deflate_syms.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_deflate/deflate_syms.c	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,21 @@
+/*
+ * linux/lib/zlib_deflate/deflate_syms.c
+ *
+ * Exported symbols for the deflate functionality.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/zlib.h>
+
+EXPORT_SYMBOL(zlib_deflate_workspacesize);
+EXPORT_SYMBOL(zlib_deflate);
+EXPORT_SYMBOL(zlib_deflateInit_);
+EXPORT_SYMBOL(zlib_deflateInit2_);
+EXPORT_SYMBOL(zlib_deflateEnd);
+EXPORT_SYMBOL(zlib_deflateReset);
+EXPORT_SYMBOL(zlib_deflateCopy);
+EXPORT_SYMBOL(zlib_deflateParams);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_deflate/deftree.c linux/lib/zlib_deflate/deftree.c
--- v2.5.2/linux/lib/zlib_deflate/deftree.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_deflate/deftree.c	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,1096 @@
+/* +++ trees.c */
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-1996 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
+
+/* #include "deflate.h" */
+
+#include <linux/zutil.h>
+#include "defutil.h"
+
+#ifdef DEBUG_ZLIB
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see zlib_tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+struct static_tree_desc_s {
+    const ct_data *static_tree;  /* static tree or NULL */
+    const intf *extra_bits;      /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+                              ct_data *dtree));
+local void set_data_type  OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifndef DEBUG_ZLIB
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG_ZLIB */
+#  define send_code(s, c, tree) \
+     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG_ZLIB
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (value << s->bi_valid);
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG_ZLIB */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (val << s->bi_valid);\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG_ZLIB */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables. In a multi-threaded environment,
+ * this function may be called by two threads concurrently, but this is
+ * harmless since both invocations do exactly the same thing.
+ */
+local void tr_static_init()
+{
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+}
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void zlib_tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->compressed_len = 0L;
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG_ZLIB
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree        = desc->dyn_tree;
+    int max_code         = desc->max_code;
+    const ct_data *stree = desc->stat_desc->static_tree;
+    const intf *extra    = desc->stat_desc->extra_bits;
+    int base             = desc->stat_desc->extra_base;
+    int max_length       = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if (tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree         = desc->dyn_tree;
+    const ct_data *stree  = desc->stat_desc->static_tree;
+    int elems             = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void zlib_tr_stored_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* Send just the `stored block' type code without any length bytes or data.
+ */
+void zlib_tr_stored_type_only(s)
+    deflate_state *s;
+{
+    send_bits(s, (STORED_BLOCK << 1), 3);
+    bi_windup(s);
+    s->compressed_len = (s->compressed_len + 3) & ~7L;
+}
+
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void zlib_tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+    bi_flush(s);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+        s->compressed_len += 10L;
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+ulg zlib_tr_flush_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+	 /* Check if the file is ascii or binary */
+	if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+	/* Construct the literal and distance trees */
+	build_tree(s, (tree_desc *)(&(s->l_desc)));
+	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+		s->static_len));
+
+	build_tree(s, (tree_desc *)(&(s->d_desc)));
+	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+		s->static_len));
+	/* At this point, opt_len and static_len are the total bit lengths of
+	 * the compressed block data, excluding the tree representations.
+	 */
+
+	/* Build the bit length tree for the above two trees, and get the index
+	 * in bl_order of the last bit length code to send.
+	 */
+	max_blindex = build_bl_tree(s);
+
+	/* Determine the best encoding. Compute first the block length in bytes*/
+	opt_lenb = (s->opt_len+3+7)>>3;
+	static_lenb = (s->static_len+3+7)>>3;
+
+	Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+		opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+		s->last_lit));
+
+	if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+	opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+    /* If compression failed and this is the first and last block,
+     * and if the .zip file can be seeked (to rewrite the local header),
+     * the whole file is transformed into a stored file:
+     */
+#ifdef STORED_FILE_OK
+#  ifdef FORCE_STORED_FILE
+    if (eof && s->compressed_len == 0L) { /* force stored file */
+#  else
+    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
+#  endif
+        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+        if (buf == (charf*)0) error ("block vanished");
+
+        copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
+        s->compressed_len = stored_len << 3;
+        s->method = STORED;
+    } else
+#endif /* STORED_FILE_OK */
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        zlib_tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+        s->compressed_len += 3 + s->static_len;
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+        s->compressed_len += 3 + s->opt_len;
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    init_block(s);
+
+    if (eof) {
+        bi_windup(s);
+        s->compressed_len += 7;  /* align on byte boundary */
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*eof));
+
+    return s->compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int zlib_tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "zlib_tr_tally: bad match");
+
+        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+    /* Try to guess if it is profitable to stop the current block here */
+    if ((s->last_lit & 0xfff) == 0 && s->level > 2) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+    deflate_state *s;
+{
+    int n = 0;
+    unsigned ascii_freq = 0;
+    unsigned bin_freq = 0;
+    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
+    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
+    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);   
+        put_short(s, (ush)~len);
+#ifdef DEBUG_ZLIB
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG_ZLIB
+    s->bits_sent += (ulg)len<<3;
+#endif
+    /* bundle up the put_byte(s, *buf++) calls */
+    memcpy(&s->pending_buf[s->pending], buf, len);
+    s->pending += len;
+}
+
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_deflate/defutil.h linux/lib/zlib_deflate/defutil.h
--- v2.5.2/linux/lib/zlib_deflate/defutil.h	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_deflate/defutil.h	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,335 @@
+
+
+
+#define Assert(err, str) 
+#define Trace(dummy) 
+#define Tracev(dummy) 
+#define Tracecv(err, dummy) 
+#define Tracevv(dummy) 
+
+
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct deflate_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    int   pending;       /* nb of bytes in the pending buffer */
+    int   noheader;      /* suppress zlib header and adler32 */
+    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to supress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    ulg compressed_len; /* total bit length of compressed file */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG_ZLIB
+    ulg bits_sent;      /* bit length of the compressed data */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+} FAR deflate_state;
+
+typedef struct deflate_workspace {
+    /* State memory for the deflator */
+    deflate_state deflate_memory;
+    Byte window_memory[2 * (1 << MAX_WBITS)];
+    Pos prev_memory[1 << MAX_WBITS];
+    Pos head_memory[1 << (MAX_MEM_LEVEL + 7)];
+    char overlay_memory[(1 << (MAX_MEM_LEVEL + 6)) * (sizeof(ush)+2)];
+} deflate_workspace;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+        /* in trees.c */
+void zlib_tr_init         OF((deflate_state *s));
+int  zlib_tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
+ulg  zlib_tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
+			      int eof));
+void zlib_tr_align        OF((deflate_state *s));
+void zlib_tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+			      int eof));
+void zlib_tr_stored_type_only OF((deflate_state *));
+
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+static inline unsigned bi_reverse(unsigned code, /* the value to invert */
+				  int len)       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+static inline void bi_flush(deflate_state *s)
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+static inline void bi_windup(deflate_state *s)
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG_ZLIB
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/Makefile linux/lib/zlib_inflate/Makefile
--- v2.5.2/linux/lib/zlib_inflate/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/Makefile	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,26 @@
+#
+# This is a modified version of zlib, which does all memory
+# allocation ahead of time.
+#
+# This is only the decompression, see zlib_deflate for the
+# the compression
+#
+# Decompression needs to be serialized for each memory
+# allocation.
+#
+# (The upsides of the simplification is that you can't get in
+# any nasty situations wrt memory management, and that the
+# uncompression can be done without blocking on allocation).
+#
+
+O_TARGET    := zlib_inflate.o
+
+export-objs := inflate_syms.o
+
+obj-y := infblock.o infcodes.o inffast.o inflate.o \
+	 inftrees.o infutil.o inflate_syms.o
+obj-m := $(O_TARGET)
+
+EXTRA_CFLAGS += -I $(TOPDIR)/lib/zlib_inflate
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/infblock.c linux/lib/zlib_inflate/infblock.c
--- v2.5.2/linux/lib/zlib_inflate/infblock.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/infblock.c	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,355 @@
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state;
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+
+void zlib_inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+  if (c != Z_NULL)
+    *c = s->check;
+  if (s->mode == CODES)
+    zlib_inflate_codes_free(s->sub.decode.codes, z);
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
+}
+
+inflate_blocks_statef *zlib_inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+
+  s = &WS(z)->working_blocks_state;
+  s->hufts = WS(z)->working_hufts;
+  s->window = WS(z)->working_window;
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  zlib_inflate_blocks_reset(s, z, Z_NULL);
+  return s;
+}
+
+
+int zlib_inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt t;               /* temporary storage */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input based on current state */
+  while (1) switch (s->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            zlib_inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+            s->sub.decode.codes = zlib_inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = B_BAD;
+          z->msg = (char*)"invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+      {
+        s->mode = B_BAD;
+        z->msg = (char*)"invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      memcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = B_BAD;
+        z->msg = (char*)"too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      {
+      	s->sub.trees.blens = WS(z)->working_blens;
+      }
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = zlib_inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+				  &s->sub.trees.tb, s->hufts, z);
+      if (t != Z_OK)
+      {
+        r = t;
+        if (r == Z_DATA_ERROR)
+          s->mode = B_BAD;
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & zlib_inflate_mask[t]);
+        t = h->bits;
+        c = h->base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->sub.trees.index++] = c;
+        }
+        else /* c == 16..18 */
+        {
+          i = c == 18 ? 7 : c - 14;
+          j = c == 18 ? 11 : 3;
+          NEEDBITS(t + i)
+          DUMPBITS(t)
+          j += (uInt)b & zlib_inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            s->mode = B_BAD;
+            z->msg = (char*)"invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+        t = zlib_inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+				       s->sub.trees.blens, &bl, &bd, &tl, &td,
+				       s->hufts, z);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+            s->mode = B_BAD;
+          r = t;
+          LEAVE
+        }
+        if ((c = zlib_inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+        s->sub.decode.codes = c;
+      }
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = zlib_inflate_codes(s, z, r)) != Z_STREAM_END)
+        return zlib_inflate_flush(s, z, r);
+      r = Z_OK;
+      zlib_inflate_codes_free(s->sub.decode.codes, z);
+      LOAD
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = B_DONE;
+    case B_DONE:
+      r = Z_STREAM_END;
+      LEAVE
+    case B_BAD:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+int zlib_inflate_blocks_free(s, z)
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  zlib_inflate_blocks_reset(s, z, Z_NULL);
+  return Z_OK;
+}
+
+
+void zlib_inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt  n;
+{
+  memcpy(s->window, d, n);
+  s->read = s->write = s->window + n;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
+ * IN assertion: s != Z_NULL
+ */
+int zlib_inflate_blocks_sync_point(s)
+inflate_blocks_statef *s;
+{
+  return s->mode == LENS;
+}
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/infblock.h linux/lib/zlib_inflate/infblock.h
--- v2.5.2/linux/lib/zlib_inflate/infblock.h	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/infblock.h	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,44 @@
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFBLOCK_H
+#define _INFBLOCK_H
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * zlib_inflate_blocks_new OF((
+    z_streamp z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+extern int zlib_inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));                      /* initial return code */
+
+extern void zlib_inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    uLongf *));                  /* check value on output */
+
+extern int zlib_inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_streamp));
+
+extern void zlib_inflate_set_dictionary OF((
+    inflate_blocks_statef *s,
+    const Bytef *d,  /* dictionary */
+    uInt  n));       /* dictionary length */
+
+extern int zlib_inflate_blocks_sync_point OF((
+    inflate_blocks_statef *s));
+
+#endif /* _INFBLOCK_H */
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/infcodes.c linux/lib/zlib_inflate/infcodes.c
--- v2.5.2/linux/lib/zlib_inflate/infcodes.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/infcodes.c	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,204 @@
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+inflate_codes_statef *zlib_inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+  inflate_codes_statef *c;
+
+  c = &WS(z)->working_state;
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+  }
+  return c;
+}
+
+
+int zlib_inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt j;               /* temporary storage */
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  Bytef *f;             /* pointer to copy strings from */
+  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input and output based on current state */
+  while (1) switch (c->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = zlib_inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & zlib_inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t + t->base;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & zlib_inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & zlib_inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t + t->base;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & zlib_inflate_mask[j];
+      DUMPBITS(j)
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+      f = (uInt)(q - s->window) < c->sub.copy.dist ?
+          s->end - (c->sub.copy.dist - (q - s->window)) :
+          q - c->sub.copy.dist;
+#else
+      f = q - c->sub.copy.dist;
+      if ((uInt)(q - s->window) < c->sub.copy.dist)
+        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
+#endif
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      if (k > 7)        /* return unused byte, if any */
+      {
+        k -= 8;
+        n++;
+        p--;            /* can always return one */
+      }
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->mode = END;
+    case END:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADCODE:       /* x: got error */
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+#ifdef NEED_DUMMY_RETURN
+  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
+#endif
+}
+
+
+void zlib_inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+}
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/infcodes.h linux/lib/zlib_inflate/infcodes.h
--- v2.5.2/linux/lib/zlib_inflate/infcodes.h	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/infcodes.h	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,33 @@
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFCODES_H
+#define _INFCODES_H
+
+#include "infblock.h"
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *zlib_inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_streamp ));
+
+extern int zlib_inflate_codes OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+extern void zlib_inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_streamp ));
+
+#endif /* _INFCODES_H */
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/inffast.c linux/lib/zlib_inflate/inffast.c
--- v2.5.2/linux/lib/zlib_inflate/inffast.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/inffast.c	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,161 @@
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+struct inflate_codes_state;
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
+
+/* Called with number of bytes left to write in window at least 258
+   (the maximum string length) and number of input bytes available
+   at least ten.  The ten bytes are six bytes for the longest length/
+   distance pair plus four bytes for overloading the bit buffer. */
+
+int zlib_inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  uInt ml;              /* mask for literal/length tree */
+  uInt md;              /* mask for distance tree */
+  uInt c;               /* bytes to copy */
+  uInt d;               /* distance back to copy from */
+  Bytef *r;             /* copy source pointer */
+
+  /* load input, output, bit values */
+  LOAD
+
+  /* initialize masks */
+  ml = zlib_inflate_mask[bl];
+  md = zlib_inflate_mask[bd];
+
+  /* do until not enough input or output space for fast loop */
+  do {                          /* assume called with m >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & zlib_inflate_mask[e]);
+        DUMPBITS(e)
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & zlib_inflate_mask[e]);
+            DUMPBITS(e)
+
+            /* do the copy */
+            m -= c;
+            if ((uInt)(q - s->window) >= d)     /* offset before dest */
+            {                                   /*  just copy */
+              r = q - d;
+              *q++ = *r++;  c--;        /* minimum count is three, */
+              *q++ = *r++;  c--;        /*  so unroll loop a little */
+            }
+            else                        /* else offset after destination */
+            {
+              e = d - (uInt)(q - s->window); /* bytes from offset to end */
+              r = s->end - e;           /* pointer to offset */
+              if (c > e)                /* if source crosses, */
+              {
+                c -= e;                 /* copy to end of window */
+                do {
+                  *q++ = *r++;
+                } while (--e);
+                r = s->window;          /* copy rest from start of window */
+              }
+            }
+            do {                        /* copy all or what's left */
+              *q++ = *r++;
+            } while (--c);
+            break;
+          }
+          else if ((e & 64) == 0)
+          {
+            t += t->base;
+            e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop;
+          }
+          else
+          {
+            z->msg = (char*)"invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        t += t->base;
+        if ((e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = (char*)"invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 10);
+
+  /* not enough input or output--restore pointers and return */
+  UNGRAB
+  UPDATE
+  return Z_OK;
+}
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/inffast.h linux/lib/zlib_inflate/inffast.h
--- v2.5.2/linux/lib/zlib_inflate/inffast.h	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/inffast.h	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,17 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+extern int zlib_inflate_fast OF((
+    uInt,
+    uInt,
+    inflate_huft *,
+    inflate_huft *,
+    inflate_blocks_statef *,
+    z_streamp ));
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/inffixed.h linux/lib/zlib_inflate/inffixed.h
--- v2.5.2/linux/lib/zlib_inflate/inffixed.h	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/inffixed.h	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,151 @@
+/* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by the maketree.c program
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+local uInt fixed_bl = 9;
+local uInt fixed_bd = 5;
+local inflate_huft fixed_tl[] = {
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
+    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
+    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
+    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
+    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
+    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
+    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
+  };
+local inflate_huft fixed_td[] = {
+    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
+    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
+    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
+    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
+    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
+    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
+    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
+    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
+  };
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/inflate.c linux/lib/zlib_inflate/inflate.c
--- v2.5.2/linux/lib/zlib_inflate/inflate.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/inflate.c	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,382 @@
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/module.h>
+#include <linux/zutil.h>
+#include "infblock.h"
+#include "infutil.h"
+
+int ZEXPORT zlib_inflate_workspacesize(void)
+{
+  return sizeof(struct inflate_workspace);
+}
+
+
+int ZEXPORT zlib_inflateReset(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->workspace == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  zlib_inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+  return Z_OK;
+}
+
+
+int ZEXPORT zlib_inflateEnd(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->workspace == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    zlib_inflate_blocks_free(z->state->blocks, z);
+  z->state = Z_NULL;
+  return Z_OK;
+}
+
+
+int ZEXPORT zlib_inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+      stream_size != sizeof(z_stream) || z->workspace == Z_NULL)
+      return Z_VERSION_ERROR;
+
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->msg = Z_NULL;
+  z->state = &WS(z)->internal_state;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    zlib_inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+      zlib_inflate_blocks_new(z, z->state->nowrap ? Z_NULL : zlib_adler32, (uInt)1 << w))
+      == Z_NULL)
+  {
+    zlib_inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+
+  /* reset state */
+  zlib_inflateReset(z);
+  return Z_OK;
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+static int zlib_inflate_packet_flush(inflate_blocks_statef *s)
+{
+    if (s->mode != LENS)
+	return Z_DATA_ERROR;
+    s->mode = TYPE;
+    return Z_OK;
+}
+
+
+int ZEXPORT zlib_inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+  return zlib_inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=f;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int ZEXPORT zlib_inflate(z, f)
+z_streamp z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
+    return Z_STREAM_ERROR;
+  f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+      {
+        z->state->mode = I_BAD;
+        z->msg = (char*)"unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = I_BAD;
+        z->msg = (char*)"invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      b = NEXTBYTE;
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = I_BAD;
+        z->msg = (char*)"incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if (!(b & PRESET_DICT))
+      {
+        z->state->mode = BLOCKS;
+        break;
+      }
+      z->state->mode = DICT4;
+    case DICT4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = DICT3;
+    case DICT3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = DICT2;
+    case DICT2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = DICT1;
+    case DICT1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+      z->adler = z->state->sub.check.need;
+      z->state->mode = DICT0;
+      return Z_NEED_DICT;
+    case DICT0:
+      z->state->mode = I_BAD;
+      z->msg = (char*)"need dictionary";
+      z->state->sub.marker = 0;       /* can try inflateSync */
+      return Z_STREAM_ERROR;
+    case BLOCKS:
+      r = zlib_inflate_blocks(z->state->blocks, z, r);
+      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+	  r = zlib_inflate_packet_flush(z->state->blocks);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = I_BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r == Z_OK)
+        r = f;
+      if (r != Z_STREAM_END)
+        return r;
+      r = f;
+      zlib_inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = I_DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = I_BAD;
+        z->msg = (char*)"incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = I_DONE;
+    case I_DONE:
+      return Z_STREAM_END;
+    case I_BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+ empty:
+  if (f != Z_PACKET_FLUSH)
+    return r;
+  z->state->mode = I_BAD;
+  z->msg = (char *)"need more for packet flush";
+  z->state->sub.marker = 0;       /* can try inflateSync */
+  return Z_DATA_ERROR;
+}
+
+
+int ZEXPORT zlib_inflateSync(z)
+z_streamp z;
+{
+  uInt n;       /* number of bytes to look at */
+  Bytef *p;     /* pointer to bytes */
+  uInt m;       /* number of marker bytes found in a row */
+  uLong r, w;   /* temporaries to save total_in and total_out */
+
+  /* set up */
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != I_BAD)
+  {
+    z->state->mode = I_BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    static const Byte mark[4] = {0, 0, 0xff, 0xff};
+    if (*p == mark[m])
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  zlib_inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+ * but removes the length bytes of the resulting empty stored block. When
+ * decompressing, PPP checks that at the end of input packet, inflate is
+ * waiting for these length bytes.
+ */
+int ZEXPORT zlib_inflateSyncPoint(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
+    return Z_STREAM_ERROR;
+  return zlib_inflate_blocks_sync_point(z->state->blocks);
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+static int zlib_inflate_addhistory(inflate_blocks_statef *s,
+				      z_stream              *z)
+{
+    uLong b;              /* bit buffer */  /* NOT USED HERE */
+    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
+    uInt t;               /* temporary storage */
+    Bytef *p;             /* input data pointer */
+    uInt n;               /* bytes available there */
+    Bytef *q;             /* output window write pointer */
+    uInt m;               /* bytes to end of window or read pointer */
+
+    if (s->read != s->write)
+	return Z_STREAM_ERROR;
+    if (s->mode != TYPE)
+	return Z_DATA_ERROR;
+
+    /* we're ready to rock */
+    LOAD
+    /* while there is input ready, copy to output buffer, moving
+     * pointers as needed.
+     */
+    while (n) {
+	t = n;  /* how many to do */
+	/* is there room until end of buffer? */
+	if (t > m) t = m;
+	/* update check information */
+	if (s->checkfn != Z_NULL)
+	    s->check = (*s->checkfn)(s->check, q, t);
+	memcpy(q, p, t);
+	q += t;
+	p += t;
+	n -= t;
+	z->total_out += t;
+	s->read = q;    /* drag read pointer forward */
+/*      WWRAP  */ 	/* expand WWRAP macro by hand to handle s->read */
+	if (q == s->end) {
+	    s->read = q = s->window;
+	    m = WAVAIL;
+	}
+    }
+    UPDATE
+    return Z_OK;
+}
+
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int ZEXPORT zlib_inflateIncomp(z)
+z_stream *z;
+{
+    if (z->state->mode != BLOCKS)
+	return Z_DATA_ERROR;
+    return zlib_inflate_addhistory(z->state->blocks, z);
+}
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/inflate_syms.c linux/lib/zlib_inflate/inflate_syms.c
--- v2.5.2/linux/lib/zlib_inflate/inflate_syms.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/inflate_syms.c	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,21 @@
+/*
+ * linux/lib/zlib_inflate/inflate_syms.c
+ *
+ * Exported symbols for the inflate functionality.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/zlib.h>
+
+EXPORT_SYMBOL(zlib_inflate_workspacesize);
+EXPORT_SYMBOL(zlib_inflate);
+EXPORT_SYMBOL(zlib_inflateInit_);
+EXPORT_SYMBOL(zlib_inflateInit2_);
+EXPORT_SYMBOL(zlib_inflateEnd);
+EXPORT_SYMBOL(zlib_inflateSync);
+EXPORT_SYMBOL(zlib_inflateReset);
+EXPORT_SYMBOL(zlib_inflateSyncPoint);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/inftrees.c linux/lib/zlib_inflate/inftrees.c
--- v2.5.2/linux/lib/zlib_inflate/inftrees.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/inftrees.c	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,391 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "inftrees.h"
+#include "infutil.h"
+
+static const char inflate_copyright[] =
+   " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+struct internal_state;
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+    uIntf *,            /* code lengths in bits */
+    uInt,               /* number of codes */
+    uInt,               /* number of "simple" codes */
+    const uIntf *,      /* list of base values for non-simple codes */
+    const uIntf *,      /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    inflate_huft *,     /* space for trees */
+    uInt *,             /* hufts used in space */
+    uIntf * ));         /* space for values */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15         /* maximum bit length of any code */
+
+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= 288) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+const uIntf *d;         /* list of base values for non-simple codes */
+const uIntf *e;         /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+inflate_huft *hp;       /* space for trees */
+uInt *hn;               /* hufts used in space */
+uIntf *v;               /* working area: values in order of bit length */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+   if the given code set is incomplete (the tables are still built in this
+   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+   lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+  uInt a;                       /* counter for codes of length k */
+  uInt c[BMAX+1];               /* bit length count table */
+  uInt f;                       /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register uInt i;              /* counter, current code */
+  register uInt j;              /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */
+  register uIntf *p;            /* pointer into c[], b[], or v[] */
+  inflate_huft *q;              /* points to current table */
+  struct inflate_huft_s r;      /* table entry for structure assignment */
+  inflate_huft *u[BMAX];        /* table stack */
+  register int w;               /* bits before this table == (l * h) */
+  uInt x[BMAX+1];               /* bit offsets, then code stack */
+  uIntf *xp;                    /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  uInt z;                       /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+  C4                            /* clear c[]--assume BMAX+1 is 16 */
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (inflate_huft *)Z_NULL;
+    *m = 0;
+    return Z_OK;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 0)
+    return Z_DATA_ERROR;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+  n = x[g];                     /* set n to length of v */
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
+  q = (inflate_huft *)Z_NULL;   /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = g - w;
+        z = z > (uInt)l ? l : z;        /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate new table */
+        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */
+          return Z_MEM_ERROR;   /* not enough memory */
+        u[h] = q = hp + *hn;
+        *hn += z;
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.bits = (Byte)l;     /* bits to dump before this table */
+          r.exop = (Byte)j;     /* bits in this table */
+          j = i >> (w - l);
+          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+        else
+          *t = q;               /* first table is returned result */
+      }
+
+      /* set up table entry in r */
+      r.bits = (Byte)(k - w);
+      if (p >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
+        r.base = *p++;          /* simple code is just the value */
+      }
+      else
+      {
+        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+        r.base = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */
+      while ((i & mask) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+        mask = (1 << w) - 1;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int zlib_inflate_trees_bits(c, bb, tb, hp, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+  
+  v = WS(z)->tree_work_area_1;
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
+                 tb, bb, hp, &hn, v);
+  if (r == Z_DATA_ERROR)
+    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR || *bb == 0)
+  {
+    z->msg = (char*)"incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  return r;
+}
+
+int zlib_inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
+uInt nl;                /* number of literal/length codes */
+uInt nd;                /* number of distance codes */
+uIntf *c;               /* that many (total) code lengths */
+uIntf *bl;              /* literal desired/actual bit depth */
+uIntf *bd;              /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+
+  /* allocate work area */
+  v = WS(z)->tree_work_area_2;
+
+  /* build literal/length tree */
+  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+  if (r != Z_OK || *bl == 0)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed literal/length tree";
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+  }
+
+  /* build distance tree */
+  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+  if (r != Z_OK || (*bd == 0 && nl > 257))
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed distance tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      z->msg = (char*)"incomplete distance tree";
+      r = Z_DATA_ERROR;
+    }
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"empty distance tree with lengths";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+#endif
+  }
+
+  /* done */
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+#include "inffixed.h"
+
+
+int zlib_inflate_trees_fixed(bl, bd, tl, td, z)
+uIntf *bl;               /* literal desired/actual bit depth */
+uIntf *bd;               /* distance desired/actual bit depth */
+inflate_huft * FAR *tl;  /* literal/length tree result */
+inflate_huft * FAR *td;  /* distance tree result */
+z_streamp z;             /* for memory allocation */
+{
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/inftrees.h linux/lib/zlib_inflate/inftrees.h
--- v2.5.2/linux/lib/zlib_inflate/inftrees.h	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/inftrees.h	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,63 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+#ifndef _INFTREES_H
+#define _INFTREES_H
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+    uInt pad;           /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
+  uInt base;            /* literal, length base, distance base,
+                           or table offset */
+};
+
+/* Maximum size of dynamic tree.  The maximum found in a long but non-
+   exhaustive search was 1004 huft structures (850 for length/literals
+   and 154 for distances, the latter actually the result of an
+   exhaustive search).  The actual maximum is not known, but the
+   value below is more than safe. */
+#define MANY 1440
+
+extern int zlib_inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+extern int zlib_inflate_trees_dynamic OF((
+    uInt,                       /* number of literal/length codes */
+    uInt,                       /* number of distance codes */
+    uIntf *,                    /* that many (total) code lengths */
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+extern int zlib_inflate_trees_fixed OF((
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    z_streamp));                /* for memory allocation */
+
+#endif /* _INFTREES_H */
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/infutil.c linux/lib/zlib_inflate/infutil.c
--- v2.5.2/linux/lib/zlib_inflate/infutil.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/infutil.c	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,87 @@
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state;
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt zlib_inflate_mask[17] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int zlib_inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt n;
+  Bytef *p;
+  Bytef *q;
+
+  /* local copies of source and destination pointers */
+  p = z->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  memcpy(p, q, n);
+  p += n;
+  q += n;
+
+  /* see if more to copy at beginning of window */
+  if (q == s->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    memcpy(p, q, n);
+    p += n;
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
diff -u --recursive --new-file v2.5.2/linux/lib/zlib_inflate/infutil.h linux/lib/zlib_inflate/infutil.h
--- v2.5.2/linux/lib/zlib_inflate/infutil.h	Wed Dec 31 16:00:00 1969
+++ linux/lib/zlib_inflate/infutil.h	Tue Jan 29 21:30:41 2002
@@ -0,0 +1,197 @@
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+#include "zconf.h"
+#include "inftrees.h"
+#include "infcodes.h"
+
+typedef enum {
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      B_DONE,   /* finished last block, done */
+      B_BAD}    /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  inflate_block_mode  mode;     /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf *blens;             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_codes_statef 
+         *codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+  uInt last;            /* true if this block is the last block */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  inflate_huft *hufts;  /* single malloc for tree space */
+  Bytef *window;        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  check_func checkfn;   /* check function */
+  uLong check;          /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/*   update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return zlib_inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=zlib_inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/*   load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt zlib_inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int zlib_inflate_flush OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+/* inflate private state */
+typedef enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      DICT4,    /* four dictionary check bytes to go */
+      DICT3,    /* three dictionary check bytes to go */
+      DICT2,    /* two dictionary check bytes to go */
+      DICT1,    /* one dictionary check byte to go */
+      DICT0,    /* waiting for inflateSetDictionary */
+      BLOCKS,   /* decompressing blocks */
+      CHECK4,   /* four check bytes to go */
+      CHECK3,   /* three check bytes to go */
+      CHECK2,   /* two check bytes to go */
+      CHECK1,   /* one check byte to go */
+      I_DONE,   /* finished check, done */
+      I_BAD}    /* got an error--stay here */
+inflate_mode;
+
+struct internal_state {
+
+  /* mode */
+  inflate_mode  mode;   /* current inflate mode */
+
+  /* mode dependent information */
+  union {
+    uInt method;        /* if FLAGS, method byte */
+    struct {
+      uLong was;                /* computed check value */
+      uLong need;               /* stream check value */
+    } check;            /* if CHECK, check values to compare */
+    uInt marker;        /* if BAD, inflateSync's marker bytes count */
+  } sub;        /* submode */
+
+  /* mode independent information */
+  int  nowrap;          /* flag for no wrapper */
+  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
+  inflate_blocks_statef 
+    *blocks;            /* current inflate_blocks state */
+
+};
+
+/* inflate codes private state */
+typedef enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      START,    /* x: set up for LEN */
+      LEN,      /* i: get length/literal/eob next */
+      LENEXT,   /* i: getting length extra (have base) */
+      DIST,     /* i: get distance next */
+      DISTEXT,  /* i: getting distance extra */
+      COPY,     /* o: copying bytes in window, waiting for space */
+      LIT,      /* o: got literal, waiting for output space */
+      WASH,     /* o: got eob, possibly still output waiting */
+      END,      /* x: got eob and all data flushed */
+      BADCODE}  /* x: got error */
+inflate_codes_mode;
+
+struct inflate_codes_state {
+
+  /* mode */
+  inflate_codes_mode mode;      /* current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+/* memory allocation for inflation */
+
+struct inflate_workspace {
+	inflate_codes_statef working_state;
+	struct inflate_blocks_state working_blocks_state;
+	struct internal_state internal_state;
+	unsigned int tree_work_area_1[19];
+	unsigned int tree_work_area_2[288];
+	unsigned working_blens[258 + 0x1f + 0x1f];
+	inflate_huft working_hufts[MANY];
+	unsigned char working_window[1 << MAX_WBITS];
+};
+
+#define WS(z) ((struct inflate_workspace *)(z->workspace))
+
+#endif
diff -u --recursive --new-file v2.5.2/linux/linux/zconf.h linux/linux/zconf.h
--- v2.5.2/linux/linux/zconf.h	Wed Dec 31 16:00:00 1969
+++ linux/linux/zconf.h	Tue Jan 29 21:30:49 2002
@@ -0,0 +1,90 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+#if defined(__GNUC__) || defined(__386__) || defined(i386)
+#  ifndef __32BIT__
+#    define __32BIT__
+#  endif
+#endif
+
+#if defined(__STDC__) || defined(__cplusplus)
+#  ifndef STDC
+#    define STDC
+#  endif
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  define MAX_MEM_LEVEL 9
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef FAR
+#   define FAR
+#endif
+
+typedef unsigned char  Byte;  /* 8 bits */
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+typedef Byte  FAR Bytef;
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+typedef void FAR *voidpf;
+typedef void     *voidp;
+
+#include <linux/types.h> /* for off_t */
+#include <linux/unistd.h>    /* for SEEK_* and off_t */
+#define z_off_t  off_t
+
+#endif /* _ZCONF_H */
diff -u --recursive --new-file v2.5.2/linux/linux/zutil.h linux/linux/zutil.h
--- v2.5.2/linux/linux/zutil.h	Wed Dec 31 16:00:00 1969
+++ linux/linux/zutil.h	Tue Jan 29 21:30:49 2002
@@ -0,0 +1,126 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: zutil.h,v 1.1 2000/01/01 03:32:23 davem Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include <linux/zlib.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+        /* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+         /* functions */
+
+typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
+				       uInt len));
+
+
+                        /* checksum functions */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+static inline uLong zlib_adler32(uLong adler,
+				 const Bytef *buf,
+				 uInt len)
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+	    buf += 16;
+            k -= 16;
+        }
+        if (k != 0) do {
+            s1 += *buf++;
+	    s2 += s1;
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
+
+#endif /* _Z_UTIL_H */
diff -u --recursive --new-file v2.5.2/linux/mm/filemap.c linux/mm/filemap.c
--- v2.5.2/linux/mm/filemap.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/filemap.c	Tue Jan 15 13:53:51 2002
@@ -290,7 +290,7 @@
 
 			page_cache_release(page);
 
-			if (current->need_resched) {
+			if (need_resched()) {
 				__set_current_state(TASK_RUNNING);
 				schedule();
 			}
@@ -400,7 +400,7 @@
 		}
 
 		page_cache_release(page);
-		if (current->need_resched) {
+		if (need_resched()) {
 			__set_current_state(TASK_RUNNING);
 			schedule();
 		}
@@ -2094,7 +2094,7 @@
 	spin_lock(&vma->vm_mm->page_table_lock);
 
 	dir = pgd_offset(vma->vm_mm, address);
-	flush_cache_range(vma->vm_mm, end - size, end);
+	flush_cache_range(vma, end - size, end);
 	if (address >= end)
 		BUG();
 	do {
@@ -2102,7 +2102,7 @@
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (address && (address < end));
-	flush_tlb_range(vma->vm_mm, end - size, end);
+	flush_tlb_range(vma, end - size, end);
 
 	spin_unlock(&vma->vm_mm->page_table_lock);
 
@@ -2436,7 +2436,7 @@
 	if (vma->vm_flags & VM_LOCKED)
 		return -EINVAL;
 
-	zap_page_range(vma->vm_mm, start, end - start);
+	zap_page_range(vma, start, end - start);
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.2/linux/mm/highmem.c linux/mm/highmem.c
--- v2.5.2/linux/mm/highmem.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/highmem.c	Thu Jan 17 13:59:33 2002
@@ -367,12 +367,6 @@
 		if (pfn >= blk_max_pfn)
 			return;
 
-#ifndef CONFIG_HIGHMEM
-		/*
-		 * should not hit for non-highmem case
-		 */
-		BUG();
-#endif
 		bio_gfp = GFP_NOHIGHIO;
 		pool = page_pool;
 	} else {
diff -u --recursive --new-file v2.5.2/linux/mm/memory.c linux/mm/memory.c
--- v2.5.2/linux/mm/memory.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/memory.c	Tue Jan 15 10:56:36 2002
@@ -355,8 +355,9 @@
 /*
  * remove user pages in a given range.
  */
-void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)
+void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned long size)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	mmu_gather_t *tlb;
 	pgd_t * dir;
 	unsigned long start = address, end = address + size;
@@ -374,8 +375,8 @@
 	if (address >= end)
 		BUG();
 	spin_lock(&mm->page_table_lock);
-	flush_cache_range(mm, address, end);
-	tlb = tlb_gather_mmu(mm);
+	flush_cache_range(vma, address, end);
+	tlb = tlb_gather_mmu(vma);
 
 	do {
 		freed += zap_pmd_range(tlb, dir, address, end - address);
@@ -757,16 +758,16 @@
 	return 0;
 }
 
-int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot)
+int zeromap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned long size, pgprot_t prot)
 {
 	int error = 0;
 	pgd_t * dir;
 	unsigned long beg = address;
 	unsigned long end = address + size;
-	struct mm_struct *mm = current->mm;
+	struct mm_struct *mm = vma->vm_mm;
 
 	dir = pgd_offset(mm, address);
-	flush_cache_range(mm, beg, end);
+	flush_cache_range(vma, beg, end);
 	if (address >= end)
 		BUG();
 
@@ -783,7 +784,7 @@
 		dir++;
 	} while (address && (address < end));
 	spin_unlock(&mm->page_table_lock);
-	flush_tlb_range(mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return error;
 }
 
@@ -838,17 +839,17 @@
 }
 
 /*  Note: this is only safe if the mm semaphore is held when called. */
-int remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot)
+int remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot)
 {
 	int error = 0;
 	pgd_t * dir;
 	unsigned long beg = from;
 	unsigned long end = from + size;
-	struct mm_struct *mm = current->mm;
+	struct mm_struct *mm = vma->vm_mm;
 
 	phys_addr -= from;
 	dir = pgd_offset(mm, from);
-	flush_cache_range(mm, beg, end);
+	flush_cache_range(vma, beg, end);
 	if (from >= end)
 		BUG();
 
@@ -865,7 +866,7 @@
 		dir++;
 	} while (from && (from < end));
 	spin_unlock(&mm->page_table_lock);
-	flush_tlb_range(mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return error;
 }
 
@@ -976,7 +977,6 @@
 static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long pgoff)
 {
 	do {
-		struct mm_struct *mm = mpnt->vm_mm;
 		unsigned long start = mpnt->vm_start;
 		unsigned long end = mpnt->vm_end;
 		unsigned long len = end - start;
@@ -984,7 +984,7 @@
 
 		/* mapping wholly truncated? */
 		if (mpnt->vm_pgoff >= pgoff) {
-			zap_page_range(mm, start, len);
+			zap_page_range(mpnt, start, len);
 			continue;
 		}
 
@@ -997,7 +997,7 @@
 		/* Ok, partially affected.. */
 		start += diff << PAGE_SHIFT;
 		len = (len - diff) << PAGE_SHIFT;
-		zap_page_range(mm, start, len);
+		zap_page_range(mpnt, start, len);
 	} while ((mpnt = mpnt->vm_next_share) != NULL);
 }
 
@@ -1238,7 +1238,7 @@
 			page_cache_release(new_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;
diff -u --recursive --new-file v2.5.2/linux/mm/mmap.c linux/mm/mmap.c
--- v2.5.2/linux/mm/mmap.c	Sun Nov  4 10:17:20 2001
+++ linux/mm/mmap.c	Tue Jan 15 10:56:36 2002
@@ -569,7 +569,7 @@
 	fput(file);
 
 	/* Undo any partial mapping done by a device driver. */
-	zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start);
+	zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start);
 free_vma:
 	kmem_cache_free(vm_area_cachep, vma);
 	return error;
@@ -967,7 +967,7 @@
 		remove_shared_vm_struct(mpnt);
 		mm->map_count--;
 
-		zap_page_range(mm, st, size);
+		zap_page_range(mpnt, st, size);
 
 		/*
 		 * Fix the mapping, and free the old area if it wasn't reused.
@@ -1127,7 +1127,7 @@
 		}
 		mm->map_count--;
 		remove_shared_vm_struct(mpnt);
-		zap_page_range(mm, start, size);
+		zap_page_range(mpnt, start, size);
 		if (mpnt->vm_file)
 			fput(mpnt->vm_file);
 		kmem_cache_free(vm_area_cachep, mpnt);
diff -u --recursive --new-file v2.5.2/linux/mm/mprotect.c linux/mm/mprotect.c
--- v2.5.2/linux/mm/mprotect.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/mprotect.c	Tue Jan 15 10:56:36 2002
@@ -72,13 +72,13 @@
 	} while (address && (address < end));
 }
 
-static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot)
+static void change_protection(struct vm_area_struct *vma, unsigned long start, unsigned long end, pgprot_t newprot)
 {
 	pgd_t *dir;
 	unsigned long beg = start;
 
 	dir = pgd_offset(current->mm, start);
-	flush_cache_range(current->mm, beg, end);
+	flush_cache_range(vma, beg, end);
 	if (start >= end)
 		BUG();
 	spin_lock(&current->mm->page_table_lock);
@@ -88,7 +88,7 @@
 		dir++;
 	} while (start && (start < end));
 	spin_unlock(&current->mm->page_table_lock);
-	flush_tlb_range(current->mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return;
 }
 
@@ -261,7 +261,7 @@
 	if (error)
 		return error;
 
-	change_protection(start, end, newprot);
+	change_protection(vma, start, end, newprot);
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.2/linux/mm/mremap.c linux/mm/mremap.c
--- v2.5.2/linux/mm/mremap.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/mremap.c	Tue Jan 15 10:56:36 2002
@@ -88,12 +88,13 @@
 	return error;
 }
 
-static int move_page_tables(struct mm_struct * mm,
+static int move_page_tables(struct vm_area_struct *vma,
 	unsigned long new_addr, unsigned long old_addr, unsigned long len)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long offset = len;
 
-	flush_cache_range(mm, old_addr, old_addr + len);
+	flush_cache_range(vma, old_addr, old_addr + len);
 
 	/*
 	 * This is not the clever way to do this, but we're taking the
@@ -105,7 +106,7 @@
 		if (move_one_page(mm, old_addr + offset, new_addr + offset))
 			goto oops_we_failed;
 	}
-	flush_tlb_range(mm, old_addr, old_addr + len);
+	flush_tlb_range(vma, old_addr, old_addr + len);
 	return 0;
 
 	/*
@@ -116,10 +117,10 @@
 	 * the old page tables)
 	 */
 oops_we_failed:
-	flush_cache_range(mm, new_addr, new_addr + len);
+	flush_cache_range(vma, new_addr, new_addr + len);
 	while ((offset += PAGE_SIZE) < len)
 		move_one_page(mm, new_addr + offset, old_addr + offset);
-	zap_page_range(mm, new_addr, len);
+	zap_page_range(vma, new_addr, len);
 	return -1;
 }
 
@@ -177,7 +178,7 @@
 		allocated_vma = 1;
 	}
 
-	if (!move_page_tables(current->mm, new_addr, addr, old_len)) {
+	if (!move_page_tables(vma, new_addr, addr, old_len)) {
 		if (allocated_vma) {
 			*new_vma = *vma;
 			new_vma->vm_start = new_addr;
diff -u --recursive --new-file v2.5.2/linux/mm/oom_kill.c linux/mm/oom_kill.c
--- v2.5.2/linux/mm/oom_kill.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/oom_kill.c	Mon Jan 21 15:55:46 2002
@@ -110,8 +110,7 @@
 
 /*
  * Simple selection loop. We chose the process with the highest
- * number of 'points'. We need the locks to make sure that the
- * list of task structs doesn't change while we look the other way.
+ * number of 'points'. We expect the caller will lock the tasklist.
  *
  * (not docbooked, we don't want this one cluttering up the manual)
  */
@@ -121,7 +120,6 @@
 	struct task_struct *p = NULL;
 	struct task_struct *chosen = NULL;
 
-	read_lock(&tasklist_lock);
 	for_each_task(p) {
 		if (p->pid) {
 			int points = badness(p);
@@ -131,7 +129,6 @@
 			}
 		}
 	}
-	read_unlock(&tasklist_lock);
 	return chosen;
 }
 
@@ -170,14 +167,16 @@
  */
 static void oom_kill(void)
 {
-	struct task_struct *p = select_bad_process(), *q;
+	struct task_struct *p, *q;
+	
+	read_lock(&tasklist_lock);
+	p = select_bad_process();
 
 	/* Found nothing?!?! Either we hang forever, or we panic. */
 	if (p == NULL)
 		panic("Out of memory and no killable processes...\n");
 
 	/* kill all processes that share the ->mm (i.e. all threads) */
-	read_lock(&tasklist_lock);
 	for_each_task(q) {
 		if(q->mm == p->mm) oom_kill_task(q);
 	}
@@ -197,7 +196,7 @@
  */
 void out_of_memory(void)
 {
-	static unsigned long first, last, count;
+	static unsigned long first, last, count, lastkill;
 	unsigned long now, since;
 
 	/*
@@ -234,8 +233,18 @@
 		return;
 
 	/*
+	 * If we just killed a process, wait a while
+	 * to give that task a chance to exit. This
+	 * avoids killing multiple processes needlessly.
+	 */
+	since = now - lastkill;
+	if (since < HZ*5)
+		return;
+
+	/*
 	 * Ok, really out of memory. Kill something.
 	 */
+	lastkill = now;
 	oom_kill();
 
 reset:
diff -u --recursive --new-file v2.5.2/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.5.2/linux/mm/page_alloc.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/page_alloc.c	Mon Jan 28 13:01:29 2002
@@ -394,6 +394,7 @@
 		return NULL;
 
 	/* Yield for kswapd, and try again */
+	__set_current_state(TASK_RUNNING);
 	yield();
 	goto rebalance;
 }
diff -u --recursive --new-file v2.5.2/linux/mm/shmem.c linux/mm/shmem.c
--- v2.5.2/linux/mm/shmem.c	Wed Nov 21 09:57:57 2001
+++ linux/mm/shmem.c	Mon Jan 21 15:37:32 2002
@@ -26,6 +26,7 @@
 #include <linux/pagemap.h>
 #include <linux/string.h>
 #include <linux/locks.h>
+#include <linux/slab.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
@@ -385,7 +386,7 @@
 	return 0;
 found:
 	delete_from_swap_cache(page);
-	add_to_page_cache(page, info->inode->i_mapping, offset + idx);
+	add_to_page_cache(page, info->vfs_inode.i_mapping, offset + idx);
 	SetPageDirty(page);
 	SetPageUptodate(page);
 	info->swapped--;
@@ -685,9 +686,13 @@
 		inode->i_mapping->a_ops = &shmem_aops;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 		info = SHMEM_I(inode);
-		info->inode = inode;
 		spin_lock_init (&info->lock);
 		sema_init (&info->sem, 1);
+		info->next_index = 0;
+		memset (info->i_direct, 0, sizeof(info->i_direct));
+		info->i_indirect = NULL;
+		info->swapped = 0;
+		info->locked = 0;
 		switch (mode & S_IFMT) {
 		default:
 			init_special_inode(inode, mode, dev);
@@ -1308,7 +1313,48 @@
 	return sb;
 }
 
+static kmem_cache_t * shmem_inode_cachep;
 
+static struct inode *shmem_alloc_inode(struct super_block *sb)
+{
+	struct shmem_inode_info *p;
+	p = (struct shmem_inode_info *)kmem_cache_alloc(shmem_inode_cachep, SLAB_KERNEL);
+	if (!p)
+		return NULL;
+	return &p->vfs_inode;
+}
+
+static void shmem_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct shmem_inode_info *p = (struct shmem_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		inode_init_once(&p->vfs_inode);
+	}
+}
+ 
+static int init_inodecache(void)
+{
+	shmem_inode_cachep = kmem_cache_create("shmem_inode_cache",
+					     sizeof(struct shmem_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (shmem_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(shmem_inode_cachep))
+		printk(KERN_INFO "shmem_inode_cache: not all structures were freed\n");
+}
 
 static struct address_space_operations shmem_aops = {
 	writepage:	shmem_writepage,
@@ -1350,6 +1396,8 @@
 };
 
 static struct super_operations shmem_ops = {
+	alloc_inode:	shmem_alloc_inode,
+	destroy_inode:	shmem_destroy_inode,
 #ifdef CONFIG_TMPFS
 	statfs:		shmem_statfs,
 	remount_fs:	shmem_remount_fs,
@@ -1376,30 +1424,45 @@
 	int error;
 	struct vfsmount * res;
 
-	if ((error = register_filesystem(&tmpfs_fs_type))) {
+	error = init_inodecache();
+	if (error)
+		goto out3;
+
+	error = register_filesystem(&tmpfs_fs_type);
+	if (error) {
 		printk (KERN_ERR "Could not register tmpfs\n");
-		return error;
+		goto out2;
 	}
 #ifdef CONFIG_TMPFS
-	if ((error = register_filesystem(&shmem_fs_type))) {
+	error = register_filesystem(&shmem_fs_type);
+	if (error) {
 		printk (KERN_ERR "Could not register shm fs\n");
-		return error;
+		goto out1;
 	}
 	devfs_mk_dir (NULL, "shm", NULL);
 #endif
 	res = kern_mount(&tmpfs_fs_type);
 	if (IS_ERR (res)) {
+		error = PTR_ERR(res);
 		printk (KERN_ERR "could not kern_mount tmpfs\n");
-		unregister_filesystem(&tmpfs_fs_type);
-		return PTR_ERR(res);
+		goto out;
 	}
 	shm_mnt = res;
 
 	/* The internal instance should not do size checking */
-	if ((error = shmem_set_size(SHMEM_SB(res->mnt_sb), ULONG_MAX, ULONG_MAX)))
-		printk (KERN_ERR "could not set limits on internal tmpfs\n");
-
+	shmem_set_size(SHMEM_SB(res->mnt_sb), ULONG_MAX, ULONG_MAX);
 	return 0;
+
+out:
+#ifdef CONFIG_TMPFS
+	unregister_filesystem(&shmem_fs_type);
+out1:
+#endif
+	unregister_filesystem(&tmpfs_fs_type);
+out2:
+	destroy_inodecache();
+out3:
+	return error;
 }
 
 static void __exit exit_shmem_fs(void)
@@ -1409,6 +1472,7 @@
 #endif
 	unregister_filesystem(&tmpfs_fs_type);
 	mntput(shm_mnt);
+	destroy_inodecache();
 }
 
 module_init(init_shmem_fs)
diff -u --recursive --new-file v2.5.2/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.5.2/linux/mm/swapfile.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/swapfile.c	Mon Jan 21 15:59:00 2002
@@ -344,7 +344,7 @@
 	if (page) {
 		page_cache_get(page);
 		/* Only cache user (+us), or swap space full? Free it! */
-		if (page_count(page) == 2 || vm_swap_full()) {
+		if (page_count(page) - !!page->buffers == 2 || vm_swap_full()) {
 			delete_from_swap_cache(page);
 			SetPageDirty(page);
 		}
@@ -696,7 +696,7 @@
 		 * interactive performance.  Interruptible check on
 		 * signal_pending() would be nice, but changes the spec?
 		 */
-		if (current->need_resched)
+		if (need_resched())
 			schedule();
 	}
 
@@ -904,11 +904,12 @@
 	swap_file = filp_open(name, O_RDWR, 0);
 	putname(name);
 	error = PTR_ERR(swap_file);
-	if (error)
+	if (IS_ERR(swap_file))
 		goto bad_swap_2;
 
 	p->swap_file = swap_file;
 
+	error = -EINVAL;
 	if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) {
 		p->swap_device = swap_file->f_dentry->d_inode->i_rdev;
 		set_blocksize(p->swap_device, PAGE_SIZE);
diff -u --recursive --new-file v2.5.2/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.5.2/linux/mm/vmscan.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/vmscan.c	Tue Jan 15 13:53:51 2002
@@ -300,7 +300,7 @@
 
 	counter = mmlist_nr;
 	do {
-		if (unlikely(current->need_resched)) {
+		if (need_resched()) {
 			__set_current_state(TASK_RUNNING);
 			schedule();
 		}
@@ -345,7 +345,7 @@
 	while (--max_scan >= 0 && (entry = inactive_list.prev) != &inactive_list) {
 		struct page * page;
 
-		if (unlikely(current->need_resched)) {
+		if (need_resched()) {
 			spin_unlock(&pagemap_lru_lock);
 			__set_current_state(TASK_RUNNING);
 			schedule();
@@ -625,8 +625,7 @@
 
 	for (i = pgdat->nr_zones-1; i >= 0; i--) {
 		zone = pgdat->node_zones + i;
-		if (unlikely(current->need_resched))
-			schedule();
+		cond_resched();
 		if (!zone->need_balance)
 			continue;
 		if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) {
diff -u --recursive --new-file v2.5.2/linux/net/Config.help linux/net/Config.help
--- v2.5.2/linux/net/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/Config.help	Fri Jan 25 16:03:43 2002
@@ -0,0 +1,509 @@
+CONFIG_FILTER
+  The Linux Socket Filter is derived from the Berkeley Packet Filter.
+  If you say Y here, user-space programs can attach a filter to any
+  socket and thereby tell the kernel that it should allow or disallow
+  certain types of data to get through the socket.  Linux Socket
+  Filtering works on all socket types except TCP for now.  See the
+  text file <file:Documentation/networking/filter.txt> for more
+  information.
+
+  You need to say Y here if you want to use PPP packet filtering
+  (see the CONFIG_PPP_FILTER option below).
+
+  If unsure, say N.
+
+CONFIG_NETFILTER
+  Netfilter is a framework for filtering and mangling network packets
+  that pass through your Linux box.
+
+  The most common use of packet filtering is to run your Linux box as
+  a firewall protecting a local network from the Internet. The type of
+  firewall provided by this kernel support is called a "packet
+  filter", which means that it can reject individual network packets
+  based on type, source, destination etc. The other kind of firewall,
+  a "proxy-based" one, is more secure but more intrusive and more
+  bothersome to set up; it inspects the network traffic much more
+  closely, modifies it and has knowledge about the higher level
+  protocols, which a packet filter lacks. Moreover, proxy-based
+  firewalls often require changes to the programs running on the local
+  clients. Proxy-based firewalls don't need support by the kernel, but
+  they are often combined with a packet filter, which only works if
+  you say Y here.
+
+  You should also say Y here if you intend to use your Linux box as
+  the gateway to the Internet for a local network of machines without
+  globally valid IP addresses. This is called "masquerading": if one
+  of the computers on your local network wants to send something to
+  the outside, your box can "masquerade" as that computer, i.e. it
+  forwards the traffic to the intended outside destination, but
+  modifies the packets to make it look like they came from the
+  firewall box itself. It works both ways: if the outside host
+  replies, the Linux box will silently forward the traffic to the
+  correct local computer. This way, the computers on your local net
+  are completely invisible to the outside world, even though they can
+  reach the outside and can receive replies. It is even possible to
+  run globally visible servers from within a masqueraded local network
+  using a mechanism called portforwarding. Masquerading is also often
+  called NAT (Network Address Translation).
+
+  Another use of Netfilter is in transparent proxying: if a machine on
+  the local network tries to connect to an outside host, your Linux
+  box can transparently forward the traffic to a local server,
+  typically a caching proxy server.
+
+  Various modules exist for netfilter which replace the previous
+  masquerading (ipmasqadm), packet filtering (ipchains), transparent
+  proxying, and portforwarding mechanisms. Please see
+  <file:Documentation/Changes> under "iptables" for the location of
+  these packages.
+
+  Make sure to say N to "Fast switching" below if you intend to say Y
+  here, as Fast switching currently bypasses netfilter.
+
+  Chances are that you should say Y here if you compile a kernel which
+  will run as a router and N for regular hosts. If unsure, say N.
+
+CONFIG_NETFILTER_DEBUG
+  You can say Y here if you want to get additional messages useful in
+  debugging the netfilter code.
+
+CONFIG_INET
+  These are the protocols used on the Internet and on most local
+  Ethernets. It is highly recommended to say Y here (this will enlarge
+  your kernel by about 144 KB), since some programs (e.g. the X window
+  system) use TCP/IP even if your machine is not connected to any
+  other computer. You will get the so-called loopback device which
+  allows you to ping yourself (great fun, that!).
+
+  For an excellent introduction to Linux networking, please read the
+  NET-3-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This option is also necessary if you want to use the full power of
+  term (term is a program which gives you almost full Internet
+  connectivity if you have a regular dial up shell account on some
+  Internet connected Unix computer; for more information, read
+  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>).
+
+  If you say Y here and also to "/proc file system support" and
+  "Sysctl support" below, you can change various aspects of the
+  behavior of the TCP/IP code by writing to the (virtual) files in
+  /proc/sys/net/ipv4/*; the options are explained in the file
+  <file:Documentation/networking/ip-sysctl.txt>.
+
+  Short answer: say Y.
+
+CONFIG_UNIX
+  If you say Y here, you will include support for Unix domain sockets;
+  sockets are the standard Unix mechanism for establishing and
+  accessing network connections.  Many commonly used programs such as
+  the X Window system and syslog use these sockets even if your
+  machine is not connected to any network.  Unless you are working on
+  an embedded system or something similar, you therefore definitely
+  want to say Y here.
+
+  However, the socket support is also available 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>. The module will be
+  called unix.o.  If you try building this as a module and you have
+  said Y to "Kernel module loader support" above, be sure to add
+  'alias net-pf-1 unix' to your /etc/modules.conf file. Note that
+  several important services won't work correctly if you say M here
+  and then neglect to load the module.
+
+  Say Y unless you know what you are doing.
+
+CONFIG_IPV6
+  This is experimental support for the next version of the Internet
+  Protocol: IP version 6 (also called IPng "IP next generation").
+  Features of this new protocol include: expanded address space,
+  authentication and privacy, and seamless interoperability with the
+  current version of IP (IP version 4). For general information about
+  IPv6, see <http://playground.sun.com/pub/ipng/html/ipng-main.html>;
+  for specific information about IPv6 under Linux read the HOWTO at
+  <http://www.bieringer.de/linux/IPv6/> and the file net/ipv6/README
+  in the kernel source.
+
+  If you want to use IPv6, please upgrade to the newest net-tools as
+  given in <file:Documentation/Changes>. You will still be able to do
+  regular IPv4 networking as well.
+
+  This protocol support 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 ipv6.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+  It is safe to say N here for now.
+
+CONFIG_IPX
+  This is support for the Novell networking protocol, IPX, commonly
+  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://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
+  support", below.
+
+  IPX is similar in scope to IP, while SPX, which runs on top of IPX,
+  is similar to TCP. There is also experimental support for SPX in
+  Linux (see "SPX networking", below).
+
+  To turn your Linux box into a fully featured NetWare file server and
+  IPX router, say Y here and fetch either lwared from
+  <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>.
+
+  General information about how to connect Linux, Windows machines and
+  Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
+
+  The IPX driver would enlarge your kernel by about 16 KB. 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 ipx.o.  If you want to compile it as a module, say M here
+  and read <file:Documentation/modules.txt>.  Unless you want to
+  integrate your Linux box with a local Novell network, say N.
+
+CONFIG_DECNET
+  The DECnet networking protocol was used in many products made by
+  Digital (now Compaq).  It provides reliable stream and sequenced
+  packet communications over which run a variety of services similar
+  to those which run over TCP/IP.
+
+  To find some tools to use with the kernel layer support, please
+  look at Patrick Caulfield's web site:
+  <http://linux.dreamtime.org/decnet/>.
+
+  More detailed documentation is available in
+  <file:Documentation/networking/decnet.txt>.
+
+  Be sure to say Y to "/proc file system support" and "Sysctl support"
+  below when using DECnet, since you will need sysctl support to aid
+  in configuration at run time.
+
+  The DECnet code 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 decnet.o.
+
+CONFIG_ATALK
+  AppleTalk is the way Apple computers speak to each other on a
+  network.  If your Linux box is connected to such a network and you
+  want to join the conversation, say Y.  You will need to use the
+  netatalk package so that your Linux box can act as a print and file
+  server for Macs as well as access AppleTalk printers.  Check out
+  <http://www.zettabyte.net/netatalk/> on the WWW for details.
+  EtherTalk is the name used for AppleTalk over Ethernet and the
+  cheaper and slower LocalTalk is AppleTalk over a proprietary Apple
+  network using serial links.  EtherTalk and LocalTalk are fully
+  supported by Linux.
+
+  General information about how to connect Linux, Windows machines and
+  Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.  The
+  NET-3-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+  information as well.
+
+  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 is called appletalk.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.  You
+  almost certainly want to compile it as a module so you can restart
+  your AppleTalk stack without rebooting your machine.  I hear that
+  the GNU boycott of Apple is over, so even politically correct people
+  are allowed to say Y here.
+
+CONFIG_X25
+  X.25 is a set of standardized network protocols, similar in scope to
+  frame relay; the one physical line from your box to the X.25 network
+  entry point can carry several logical point-to-point connections
+  (called "virtual circuits") to other computers connected to the X.25
+  network. Governments, banks, and other organizations tend to use it
+  to connect to each other or to form Wide Area Networks (WANs). Many
+  countries have public X.25 networks. X.25 consists of two
+  protocols: the higher level Packet Layer Protocol (PLP) (say Y here
+  if you want that) and the lower level data link layer protocol LAPB
+  (say Y to "LAPB Data Link Driver" below if you want that).
+
+  You can read more about X.25 at <http://www.sangoma.com/x25.htm> and
+  <http://www.cisco.com/univercd/data/doc/software/11_0/rpcg/cx25.htm>.
+  Information about X.25 for Linux is contained in the files
+  <file:Documentation/networking/x25.txt> and
+  <file:Documentation/networking/x25-iface.txt>.
+
+  One connects to an X.25 network either with a dedicated network card
+  using the X.21 protocol (not yet supported by Linux) or one can do
+  X.25 over a standard telephone line using an ordinary modem (say Y
+  to "X.25 async driver" below) or over Ethernet using an ordinary
+  Ethernet card and either the 802.2 LLC protocol (say Y to "802.2
+  LLC" below) or LAPB over Ethernet (say Y to "LAPB Data Link Driver"
+  and "LAPB over Ethernet driver" below).
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called x25.o. If unsure, say N.
+
+CONFIG_LAPB
+  Link Access Procedure, Balanced (LAPB) is the data link layer (i.e.
+  the lower) part of the X.25 protocol. It offers a reliable
+  connection service to exchange data frames with one other host, and
+  it is used to transport higher level protocols (mostly X.25 Packet
+  Layer, the higher part of X.25, but others are possible as well).
+  Usually, LAPB is used with specialized X.21 network cards, but Linux
+  currently supports LAPB only over Ethernet connections. If you want
+  to use LAPB connections over Ethernet, say Y here and to "LAPB over
+  Ethernet driver" below. Read
+  <file:Documentation/networking/lapb-module.txt> for technical
+  details.
+
+  If you want to compile this driver as a module though ( = 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 lapb.o.  If unsure, say N.
+
+CONFIG_LLC
+  This is a Logical Link Layer protocol used for X.25 connections over
+  Ethernet, using ordinary Ethernet cards.
+
+CONFIG_NET_DIVERT
+  The Frame Diverter allows you to divert packets from the
+  network, that are not aimed at the interface receiving it (in
+  promisc. mode). Typically, a Linux box setup as an Ethernet bridge
+  with the Frames Diverter on, can do some *really* transparent www
+  caching using a Squid proxy for example.
+
+  This is very useful when you don't want to change your router's
+  config (or if you simply don't have access to it).
+
+  The other possible usages of diverting Ethernet Frames are
+  numberous:
+   - reroute smtp traffic to another interface
+   - traffic-shape certain network streams
+   - transparently proxy smtp connections
+   - etc...
+
+  For more informations, please refer to:
+    <http://diverter.sourceforge.net/>
+    <http://perso.wanadoo.fr/magpie/EtherDivert.html>
+
+  If unsure, say N.
+
+CONFIG_BRIDGE
+  If you say Y here, then your Linux box will be able to act as an
+  Ethernet bridge, which means that the different Ethernet segments it
+  is connected to will appear as one Ethernet to the participants.
+  Several such bridges can work together to create even larger
+  networks of Ethernets using the IEEE 802.1 spanning tree algorithm.
+  As this is a standard, Linux bridges will cooperate properly with
+  other third party bridge products.
+
+  In order to use the Ethernet bridge, you'll need the bridge
+  configuration tools; see <file:Documentation/networking/bridge.txt>
+  for location. Please read the Bridge mini-HOWTO for more
+  information.
+
+  Note that if your box acts as a bridge, it probably contains several
+  Ethernet devices, but the kernel is not able to recognize more than
+  one at boot time without help; for details read the Ethernet-HOWTO,
+  available from in <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this code 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 bridge.o.
+
+  If unsure, say N.
+
+CONFIG_PACKET
+  The Packet protocol is used by applications which communicate
+  directly with network devices without an intermediate network
+  protocol implemented in the kernel, e.g. tcpdump.  If you want them
+  to work, choose Y.
+
+  This driver is also available as a module called af_packet.o ( =
+  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>; if you use modprobe
+  or kmod, you may also want to add "alias net-pf-17 af_packet" to
+  /etc/modules.conf.
+
+  If unsure, say Y.
+
+CONFIG_PACKET_MMAP
+  If you say Y here, the Packet protocol driver will use an IO
+  mechanism that results in faster communication.
+
+  If unsure, say N.
+
+CONFIG_NETLINK_DEV
+  This option will be removed soon. Any programs that want to use
+  character special nodes like /dev/tap0 or /dev/route (all with major
+  number 36) need this option, and need to be rewritten soon to use
+  the real netlink socket.
+  This is a backward compatibility option, choose Y for now.
+
+CONFIG_ATM
+  ATM is a high-speed networking technology for Local Area Networks
+  and Wide Area Networks.  It uses a fixed packet size and is
+  connection oriented, allowing for the negotiation of minimum
+  bandwidth requirements.
+
+  In order to participate in an ATM network, your Linux box needs an
+  ATM networking card. If you have that, say Y here and to the driver
+  of your ATM card below.
+
+  Note that you need a set of user-space programs to actually make use
+  of ATM.  See the file <file:Documentation/networking/atm.txt> for
+  further details.
+
+CONFIG_ATM_CLIP
+  Classical IP over ATM for PVCs and SVCs, supporting InARP and
+  ATMARP. If you want to communication with other IP hosts on your ATM
+  network, you will typically either say Y here or to "LAN Emulation
+  (LANE)" below.
+
+CONFIG_ATM_CLIP_NO_ICMP
+  Normally, an "ICMP host unreachable" message is sent if a neighbour
+  cannot be reached because there is no VC to it in the kernel's
+  ATMARP table. This may cause problems when ATMARP table entries are
+  briefly removed during revalidation. If you say Y here, packets to
+  such neighbours are silently discarded instead.
+
+CONFIG_ATM_LANE
+  LAN Emulation emulates services of existing LANs across an ATM
+  network. Besides operating as a normal ATM end station client, Linux
+  LANE client can also act as an proxy client bridging packets between
+  ELAN and Ethernet segments. You need LANE if you want to try MPOA.
+
+CONFIG_ATM_MPOA
+  Multi-Protocol Over ATM allows ATM edge devices such as routers,
+  bridges and ATM attached hosts establish direct ATM VCs across
+  subnetwork boundaries. These shortcut connections bypass routers
+  enhancing overall network performance.
+
+CONFIG_ECONET
+  Econet is a fairly old and slow networking protocol mainly used by
+  Acorn computers to access file and print servers. It uses native
+  Econet network cards. AUN is an implementation of the higher level
+  parts of Econet that runs over ordinary Ethernet connections, on
+  top of the UDP packet protocol, which in turn runs on top of the
+  Internet protocol IP.
+
+  If you say Y here, you can choose with the next two options whether
+  to send Econet/AUN traffic over a UDP Ethernet connection or over
+  a native Econet network card.
+
+  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 econet.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_ECONET_AUNUDP
+  Say Y here if you want to send Econet/AUN traffic over a UDP
+  connection (UDP is a packet based protocol that runs on top of the
+  Internet protocol IP) using an ordinary Ethernet network card.
+
+CONFIG_ECONET_NATIVE
+  Say Y here if you have a native Econet network card installed in
+  your computer.
+
+CONFIG_WAN_ROUTER
+  Wide Area Networks (WANs), such as X.25, frame relay and leased
+  lines, are used to interconnect Local Area Networks (LANs) over vast
+  distances with data transfer rates significantly higher than those
+  achievable with commonly used asynchronous modem connections.
+  Usually, a quite expensive external device called a `WAN router' is
+  needed to connect to a WAN.
+
+  As an alternative, WAN routing can be built into the Linux kernel.
+  With relatively inexpensive WAN interface cards available on the
+  market, a perfectly usable router can be built for less than half
+  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/>.
+  Read <file:Documentation/networking/wan-router.txt> for more
+  information.
+
+  The WAN routing support is also available as a module called
+  wanrouter.o ( = 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>.
+
+  If unsure, say N.
+
+CONFIG_NET_FASTROUTE
+  Saying Y here enables direct NIC-to-NIC (NIC = Network Interface
+  Card) data transfers on the local network, which is fast.
+
+  IMPORTANT NOTE: This option is NOT COMPATIBLE with "Network packet
+  filtering" (CONFIG_NETFILTER). Say N here if you say Y there.
+
+  However, it will work with all options in the "Advanced router"
+  section (except for "Use TOS value as routing key" and
+  "Use FWMARK value as routing key").
+
+  At the moment, few devices support fast switching (tulip is one of
+  them, a modified 8390 driver can be found at
+  <ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz>).
+
+  If unsure, say N.
+
+CONFIG_NET_HW_FLOWCONTROL
+  This option enables NIC (Network Interface Card) hardware throttling
+  during periods of extremal congestion. At the moment only a couple
+  of device drivers support it (really only one -- tulip, a modified
+  8390 driver can be found at
+  <ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz>).
+
+  Really, this option is applicable to any machine attached to a fast
+  enough network, and even a 10 Mb NIC is able to kill a not very slow
+  box, such as a 120MHz Pentium.
+
+  However, do not say Y here if you did not experience any serious
+  problems.
+
+CONFIG_NET_SCHED
+  When the kernel has several packets to send out over a network
+  device, it has to decide which ones to send first, which ones to
+  delay, and which ones to drop. This is the job of the packet
+  scheduler, and several different algorithms for how to do this
+  "fairly" have been proposed.
+
+  If you say N here, you will get the standard packet scheduler, which
+  is a FIFO (first come, first served). If you say Y here, you will be
+  able to choose from among several alternative algorithms which can
+  then be attached to different network devices. This is useful for
+  example if some of your network devices are real time devices that
+  need a certain minimum data flow rate, or if you need to limit the
+  maximum data flow rate for traffic which matches specified criteria.
+  This code is considered to be experimental.
+
+  To administer these schedulers, you'll need the user-level utilities
+  from the package iproute2+tc at <ftp://ftp.inr.ac.ru/ip-routing/>.
+  That package also contains some documentation; for more, check out
+  <http://snafu.freedom.org/linux2.2/iproute-notes.html>.
+
+  This Quality of Service (QoS) support will enable you to use
+  Differentiated Services (diffserv) and Resource Reservation Protocol
+  (RSVP) on your Linux router if you also say Y to "QoS support",
+  "Packet classifier API" and to some classifiers below. Documentation
+  and software is at <http://icawww1.epfl.ch/linux-diffserv/>.
+
+  If you say Y here and to "/proc file system" below, you will be able
+  to read status information about packet schedulers from the file
+  /proc/net/psched.
+
+  The available schedulers are listed in the following questions; you
+  can say Y to as many as you like. If unsure, say N now.
+
+CONFIG_NET_PROFILE
+  If you say Y here and to "/proc file system support" below, some
+  obscure and undocumented information about the network code's
+  performance will be written to /proc/net/profile. If you don't know
+  what it is about, you don't need it: say N.
+
diff -u --recursive --new-file v2.5.2/linux/net/Config.in linux/net/Config.in
--- v2.5.2/linux/net/Config.in	Mon Jan 14 18:25:11 2002
+++ linux/net/Config.in	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/Makefile linux/net/Makefile
--- v2.5.2/linux/net/Makefile	Tue Oct 30 15:08:12 2001
+++ linux/net/Makefile	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ax25/Config.help linux/net/ax25/Config.help
--- v2.5.2/linux/net/ax25/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/ax25/Config.help	Fri Jan 25 16:03:34 2002
@@ -0,0 +1,88 @@
+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 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
+  the questions about amateur radio.
+
+CONFIG_AX25
+  This is the protocol used for computer communication over amateur
+  radio. It is either used by itself for point-to-point links, or to
+  carry other protocols such as tcp/ip. To use it, you need a device
+  that connects your Linux box to your amateur radio. You can either
+  use a low speed TNC (a Terminal Node Controller acts as a kind of
+  modem connecting your computer's serial port to your radio's
+  microphone input and speaker output) supporting the KISS protocol or
+  one of the various SCC cards that are supported by the generic Z8530
+  or the DMA SCC driver. Another option are the Baycom modem serial
+  and parallel port hacks or the sound card modem (supported by their
+  own drivers). If you say Y here, you also have to say Y to one of
+  those drivers.
+
+  Information about where to get supporting software for Linux amateur
+  radio as well as information about how to configure an AX.25 port is
+  contained in the AX25-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. You might also want to
+  check out the file <file:Documentation/networking/ax25.txt> in the
+  kernel source. More information about digital amateur radio in
+  general is on the WWW at
+  <http://www.tapr.org/tapr/html/pkthome.html>.
+
+  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 ax25.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_AX25_DAMA_SLAVE
+  DAMA is a mechanism to prevent collisions when doing AX.25
+  networking. A DAMA server (called "master") accepts incoming traffic
+  from clients (called "slaves") and redistributes it to other slaves.
+  If you say Y here, your Linux box will act as a DAMA slave; this is
+  transparent in that you don't have to do any special DAMA
+  configuration. (Linux cannot yet act as a DAMA server.) If unsure,
+  say N.
+
+CONFIG_AX25_DAMA_MASTER
+  DAMA is a mechanism to prevent collisions when doing AX.25
+  networking. A DAMA server (called "master") accepts incoming traffic
+  from clients (called "slaves") and redistributes it to other
+  slaves. If you say Y here, your Linux box will act as a DAMA server.
+  If unsure, say N.
+
+CONFIG_NETROM
+  NET/ROM is a network layer protocol on top of AX.25 useful for
+  routing.
+
+  A comprehensive listing of all the software for Linux amateur radio
+  users as well as information about how to configure an AX.25 port is
+  contained in the AX25-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. You also might want to
+  check out the file <file:Documentation/networking/ax25.txt>. More
+  information about digital amateur radio in general is on the WWW at
+  <http://www.tapr.org/tapr/html/pkthome.html>.
+
+  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 netrom.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_ROSE
+  The Packet Layer Protocol (PLP) is a way to route packets over X.25
+  connections in general and amateur radio AX.25 connections in
+  particular, essentially an alternative to NET/ROM.
+
+  A comprehensive listing of all the software for Linux amateur radio
+  users as well as information about how to configure an AX.25 port is
+  contained in the AX25-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  You also might want to
+  check out the file <file:Documentation/networking/ax25.txt>. More
+  information about digital amateur radio in general is on the WWW at
+  <http://www.tapr.org/tapr/html/pkthome.html>.
+
+  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 rose.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
diff -u --recursive --new-file v2.5.2/linux/net/bluetooth/Config.help linux/net/bluetooth/Config.help
--- v2.5.2/linux/net/bluetooth/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/bluetooth/Config.help	Fri Jan 25 16:04:13 2002
@@ -0,0 +1,30 @@
+CONFIG_BLUEZ
+  Bluetooth is low-cost, low-power, short-range wireless technology.
+  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/>.
+
+  Linux Bluetooth subsystem consist of several layers:
+               HCI Core (device and connection manager, scheduler)
+               HCI Device drivers (interface to the hardware)
+               L2CAP Module (L2CAP protocol)
+
+  Say Y here to enable Linux Bluetooth support and to build HCI Core
+  layer.
+
+  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.sourceforge.net/>.
+
+  If you want to compile HCI Core as module (hci.o) say M here.
+
+CONFIG_BLUEZ_L2CAP
+  L2CAP (Logical Link Control and Adaptation Protocol) provides
+  connection oriented and connection-less data transport.  L2CAP
+  support is required for most Bluetooth applications.
+
+  Say Y here to compile L2CAP support into the kernel or say M to
+  compile it as module (l2cap.o).
+
diff -u --recursive --new-file v2.5.2/linux/net/bridge/br_fdb.c linux/net/bridge/br_fdb.c
--- v2.5.2/linux/net/bridge/br_fdb.c	Thu Nov  9 15:57:53 2000
+++ linux/net/bridge/br_fdb.c	Wed Jan 23 15:28:40 2002
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_fdb.c,v 1.5 2000/11/08 05:16:40 davem Exp $
+ *	$Id: br_fdb.c,v 1.6 2002/01/17 00:57:07 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -292,7 +292,8 @@
 	write_lock_bh(&br->hash_lock);
 	fdb = br->hash[hash];
 	while (fdb != NULL) {
-		if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
+		if (!fdb->is_local &&
+		    !memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
 			__fdb_possibly_replace(fdb, source, is_local);
 			write_unlock_bh(&br->hash_lock);
 			return;
diff -u --recursive --new-file v2.5.2/linux/net/core/Makefile linux/net/core/Makefile
--- v2.5.2/linux/net/core/Makefile	Tue Oct 30 15:08:12 2001
+++ linux/net/core/Makefile	Mon Jan 21 16:10:13 2002
@@ -26,5 +26,8 @@
 obj-$(CONFIG_NETFILTER) += netfilter.o
 obj-$(CONFIG_NET_DIVERT) += dv.o
 obj-$(CONFIG_NET_PROFILE) += profile.o
+obj-$(CONFIG_NET_RADIO) += wireless.o
+# Ugly. I wish all wireless drivers were moved in drivers/net/wireless
+obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.5.2/linux/net/core/datagram.c linux/net/core/datagram.c
--- v2.5.2/linux/net/core/datagram.c	Thu Apr 12 12:11:39 2001
+++ linux/net/core/datagram.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/core/dev.c linux/net/core/dev.c
--- v2.5.2/linux/net/core/dev.c	Wed Nov  7 14:39:36 2001
+++ linux/net/core/dev.c	Wed Jan 23 15:28:40 2002
@@ -102,6 +102,7 @@
 #include <linux/module.h>
 #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
 #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
+#include <net/iw_handler.h>
 #endif	/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
 #ifdef CONFIG_PLIP
 extern int plip_init(void);
@@ -238,7 +239,7 @@
 
 #ifdef CONFIG_NET_FASTROUTE
 	/* Hack to detect packet socket */
-	if (pt->data) {
+	if ((pt->data) && ((int)(pt->data)!=1)) {
 		netdev_fastroute_obstacles++;
 		dev_clear_fastroute(pt->dev);
 	}
@@ -875,7 +876,7 @@
 void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct packet_type *ptype;
-	get_fast_time(&skb->stamp);
+	do_gettimeofday(&skb->stamp);
 
 	br_read_lock(BR_NETPROTO_LOCK);
 	for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) 
@@ -1218,7 +1219,7 @@
 	unsigned long flags;
 
 	if (skb->stamp.tv_sec == 0)
-		get_fast_time(&skb->stamp);
+		do_gettimeofday(&skb->stamp);
 
 	/* The code is rearranged so that the path is the most
 	   short when CPU is congested, but is still operating.
@@ -1796,122 +1797,6 @@
 #endif	/* CONFIG_PROC_FS */
 
 
-#ifdef WIRELESS_EXT
-#ifdef CONFIG_PROC_FS
-
-/*
- * Print one entry of /proc/net/wireless
- * This is a clone of /proc/net/dev (just above)
- */
-static int sprintf_wireless_stats(char *buffer, struct net_device *dev)
-{
-	/* Get stats from the driver */
-	struct iw_statistics *stats = (dev->get_wireless_stats ?
-				       dev->get_wireless_stats(dev) :
-				       (struct iw_statistics *) NULL);
-	int size;
-
-	if (stats != (struct iw_statistics *) NULL) {
-		size = sprintf(buffer,
-			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d %6d %6d   %6d\n",
-			       dev->name,
-			       stats->status,
-			       stats->qual.qual,
-			       stats->qual.updated & 1 ? '.' : ' ',
-			       stats->qual.level,
-			       stats->qual.updated & 2 ? '.' : ' ',
-			       stats->qual.noise,
-			       stats->qual.updated & 4 ? '.' : ' ',
-			       stats->discard.nwid,
-			       stats->discard.code,
-			       stats->discard.fragment,
-			       stats->discard.retries,
-			       stats->discard.misc,
-			       stats->miss.beacon);
-		stats->qual.updated = 0;
-	}
-	else
-		size = 0;
-
-	return size;
-}
-
-/*
- * Print info for /proc/net/wireless (print all entries)
- * This is a clone of /proc/net/dev (just above)
- */
-static int dev_get_wireless_info(char * buffer, char **start, off_t offset,
-			  int length)
-{
-	int		len = 0;
-	off_t		begin = 0;
-	off_t		pos = 0;
-	int		size;
-	
-	struct net_device *	dev;
-
-	size = sprintf(buffer,
-		       "Inter-| sta-|   Quality        |   Discarded packets               | Missed\n"
-		       " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon\n"
-			);
-	
-	pos += size;
-	len += size;
-
-	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
-		size = sprintf_wireless_stats(buffer + len, dev);
-		len += size;
-		pos = begin + len;
-
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-		if (pos > offset + length)
-			break;
-	}
-	read_unlock(&dev_base_lock);
-
-	*start = buffer + (offset - begin);	/* Start of wanted data */
-	len -= (offset - begin);		/* Start slop */
-	if (len > length)
-		len = length;			/* Ending slop */
-	if (len < 0)
-		len = 0;
-
-	return len;
-}
-#endif	/* CONFIG_PROC_FS */
-
-/*
- *	Allow programatic access to /proc/net/wireless even if /proc
- *	doesn't exist... Also more efficient...
- */
-static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
-{
-	/* Get stats from the driver */
-	struct iw_statistics *stats = (dev->get_wireless_stats ?
-				       dev->get_wireless_stats(dev) :
-				       (struct iw_statistics *) NULL);
-
-	if (stats != (struct iw_statistics *) NULL) {
-		struct iwreq *	wrq = (struct iwreq *)ifr;
-
-		/* Copy statistics to the user buffer */
-		if(copy_to_user(wrq->u.data.pointer, stats,
-				sizeof(struct iw_statistics)))
-			return -EFAULT;
-
-		/* Check if we need to clear the update flag */
-		if(wrq->u.data.flags != 0)
-			stats->qual.updated = 0;
-		return(0);
-	} else
-		return -EOPNOTSUPP;
-}
-#endif	/* WIRELESS_EXT */
-
 /**
  *	netdev_set_master	-	set up master/slave pair
  *	@slave: slave device
@@ -2209,11 +2094,6 @@
 			notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
 			return 0;
 
-#ifdef WIRELESS_EXT
-		case SIOCGIWSTATS:
-			return dev_iwstats(dev, ifr);
-#endif	/* WIRELESS_EXT */
-
 		/*
 		 *	Unknown or private ioctl
 		 */
@@ -2239,17 +2119,6 @@
 				return -EOPNOTSUPP;
 			}
 
-#ifdef WIRELESS_EXT
-			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
-				if (dev->do_ioctl) {
-					if (!netif_device_present(dev))
-						return -ENODEV;
-					return dev->do_ioctl(dev, ifr, cmd);
-				}
-				return -EOPNOTSUPP;
-			}
-#endif	/* WIRELESS_EXT */
-
 	}
 	return -EINVAL;
 }
@@ -2431,7 +2300,8 @@
 				}
 				dev_load(ifr.ifr_name);
 				rtnl_lock();
-				ret = dev_ifsioc(&ifr, cmd);
+				/* Follow me in net/core/wireless.c */
+				ret = wireless_process_ioctl(&ifr, cmd);
 				rtnl_unlock();
 				if (!ret && IW_IS_GET(cmd) &&
 				    copy_to_user(arg, &ifr, sizeof(struct ifreq)))
@@ -2856,6 +2726,7 @@
 	proc_net_create("dev", 0, dev_get_info);
 	create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL);
 #ifdef WIRELESS_EXT
+	/* Available in net/core/wireless.c */
 	proc_net_create("wireless", 0, dev_get_wireless_info);
 #endif	/* WIRELESS_EXT */
 #endif	/* CONFIG_PROC_FS */
diff -u --recursive --new-file v2.5.2/linux/net/core/neighbour.c linux/net/core/neighbour.c
--- v2.5.2/linux/net/core/neighbour.c	Mon Oct  1 09:19:56 2001
+++ linux/net/core/neighbour.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/core/rtnetlink.c linux/net/core/rtnetlink.c
--- v2.5.2/linux/net/core/rtnetlink.c	Sun Aug  5 13:12:41 2001
+++ linux/net/core/rtnetlink.c	Tue Jan 15 10:56:35 2002
@@ -45,7 +45,6 @@
 #include <net/protocol.h>
 #include <net/arp.h>
 #include <net/route.h>
-#include <net/tcp.h>
 #include <net/udp.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
@@ -77,15 +76,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 +527,3 @@
 	rtnetlink_links[PF_UNSPEC] = link_rtnetlink_table;
 	rtnetlink_links[PF_PACKET] = link_rtnetlink_table;
 }
-
-
-
-#endif
diff -u --recursive --new-file v2.5.2/linux/net/core/scm.c linux/net/core/scm.c
--- v2.5.2/linux/net/core/scm.c	Thu Nov  9 15:57:53 2000
+++ linux/net/core/scm.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.5.2/linux/net/core/skbuff.c	Tue Aug  7 08:30:50 2001
+++ linux/net/core/skbuff.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/core/sock.c linux/net/core/sock.c
--- v2.5.2/linux/net/core/sock.c	Sat Jul 28 12:12:38 2001
+++ linux/net/core/sock.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/core/wireless.c linux/net/core/wireless.c
--- v2.5.2/linux/net/core/wireless.c	Wed Dec 31 16:00:00 1969
+++ linux/net/core/wireless.c	Mon Jan 21 16:10:13 2002
@@ -0,0 +1,733 @@
+/*
+ * This file implement the Wireless Extensions APIs.
+ *
+ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+
+/************************** DOCUMENTATION **************************/
+/*
+ * API definition :
+ * --------------
+ * See <linux/wireless.h> for details of the APIs and the rest.
+ *
+ * History :
+ * -------
+ *
+ * v1 - 5.12.01 - Jean II
+ *	o Created this file.
+ *
+ * v2 - 13.12.01 - Jean II
+ *	o Move /proc/net/wireless stuff from net/core/dev.c to here
+ *	o Make Wireless Extension IOCTLs go through here
+ *	o Added iw_handler handling ;-)
+ *	o Added standard ioctl description
+ *	o Initial dumb commit strategy based on orinoco.c
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <asm/uaccess.h>		/* copy_to_user() */
+#include <linux/config.h>		/* Not needed ??? */
+#include <linux/types.h>		/* off_t */
+#include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
+
+#include <linux/wireless.h>		/* Pretty obvious */
+#include <net/iw_handler.h>		/* New driver API */
+
+/**************************** CONSTANTS ****************************/
+
+/* This will be turned on later on... */
+#undef WE_STRICT_WRITE		/* Check write buffer size */
+
+/* Debuging stuff */
+#undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
+
+/************************* GLOBAL VARIABLES *************************/
+/*
+ * You should not use global variables, because or re-entrancy.
+ * On our case, it's only const, so it's OK...
+ */
+static const struct iw_ioctl_description	standard_ioctl[] = {
+	/* SIOCSIWCOMMIT (internal) */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWNAME */
+	{ IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWNWID */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
+	/* SIOCGIWNWID */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWFREQ */
+	{ IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
+	/* SIOCGIWFREQ */
+	{ IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWMODE */
+	{ IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
+	/* SIOCGIWMODE */
+	{ IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWSENS */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWSENS */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWRANGE */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWRANGE */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWPRIV */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWPRIV (handled directly by us) */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCSIWSTATS */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWSTATS (handled directly by us) */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWSPY */
+	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
+	/* SIOCGIWSPY */
+	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCSIWAP */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+	/* SIOCGIWAP */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWAPLIST */
+	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCSIWESSID */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
+	/* SIOCGIWESSID */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWNICKN */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
+	/* SIOCGIWNICKN */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCSIWRATE */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWRATE */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWRTS */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWRTS */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWFRAG */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWFRAG */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWTXPOW */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWTXPOW */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWRETRY */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWRETRY */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWENCODE */
+	{ IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
+	/* SIOCGIWENCODE */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
+	/* SIOCSIWPOWER */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWPOWER */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+};
+
+/* Size (in bytes) of the various private data types */
+char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+
+/************************ COMMON SUBROUTINES ************************/
+/*
+ * Stuff that may be used in various place or doesn't fit in one
+ * of the section below.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Return the driver handler associated with a specific Wireless Extension.
+ * Called from various place, so make sure it remains efficient.
+ */
+static inline iw_handler get_handler(struct net_device *dev,
+				     unsigned int cmd)
+{
+	unsigned int	index;		/* MUST be unsigned */
+
+	/* Check if we have some wireless handlers defined */
+	if(dev->wireless_handlers == NULL)
+		return NULL;
+
+	/* Try as a standard command */
+	index = cmd - SIOCIWFIRST;
+	if(index < dev->wireless_handlers->num_standard)
+		return dev->wireless_handlers->standard[index];
+
+	/* Try as a private command */
+	index = cmd - SIOCIWFIRSTPRIV;
+	if(index < dev->wireless_handlers->num_private)
+		return dev->wireless_handlers->private[index];
+
+	/* Not found */
+	return NULL;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Get statistics out of the driver
+ */
+static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
+{
+	return (dev->get_wireless_stats ?
+		dev->get_wireless_stats(dev) :
+		(struct iw_statistics *) NULL);
+	/* In the future, get_wireless_stats may move from 'struct net_device'
+	 * to 'struct iw_handler_def', to de-bloat struct net_device.
+	 * Definitely worse a thought... */
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Call the commit handler in the driver
+ * (if exist and if conditions are right)
+ *
+ * Note : our current commit strategy is currently pretty dumb,
+ * but we will be able to improve on that...
+ * The goal is to try to agreagate as many changes as possible
+ * before doing the commit. Drivers that will define a commit handler
+ * are usually those that need a reset after changing parameters, so
+ * we want to minimise the number of reset.
+ * A cool idea is to use a timer : at each "set" command, we re-set the
+ * timer, when the timer eventually fires, we call the driver.
+ * Hopefully, more on that later.
+ *
+ * Also, I'm waiting to see how many people will complain about the
+ * netif_running(dev) test. I'm open on that one...
+ * Hopefully, the driver will remember to do a commit in "open()" ;-)
+ */
+static inline int call_commit_handler(struct net_device *	dev)
+{
+	if((netif_running(dev)) &&
+	   (dev->wireless_handlers->standard[0] != NULL)) {
+		/* Call the commit handler on the driver */
+		return dev->wireless_handlers->standard[0](dev, NULL,
+							   NULL, NULL);
+	} else
+		return 0;		/* Command completed successfully */
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Number of private arguments
+ */
+static inline int get_priv_size(__u16	args)
+{
+	int	num = args & IW_PRIV_SIZE_MASK;
+	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+	return num * priv_type_size[type];
+}
+
+
+/******************** /proc/net/wireless SUPPORT ********************/
+/*
+ * The /proc/net/wireless file is a human readable user-space interface
+ * exporting various wireless specific statistics from the wireless devices.
+ * This is the most popular part of the Wireless Extensions ;-)
+ *
+ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
+ * The content of the file is basically the content of "struct iw_statistics".
+ */
+
+#ifdef CONFIG_PROC_FS
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print one entry (line) of /proc/net/wireless
+ */
+static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev)
+{
+	/* Get stats from the driver */
+	struct iw_statistics *stats;
+	int size;
+
+	stats = get_wireless_stats(dev);
+	if (stats != (struct iw_statistics *) NULL) {
+		size = sprintf(buffer,
+			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d %6d %6d   %6d\n",
+			       dev->name,
+			       stats->status,
+			       stats->qual.qual,
+			       stats->qual.updated & 1 ? '.' : ' ',
+			       stats->qual.level,
+			       stats->qual.updated & 2 ? '.' : ' ',
+			       stats->qual.noise,
+			       stats->qual.updated & 4 ? '.' : ' ',
+			       stats->discard.nwid,
+			       stats->discard.code,
+			       stats->discard.fragment,
+			       stats->discard.retries,
+			       stats->discard.misc,
+			       stats->miss.beacon);
+		stats->qual.updated = 0;
+	}
+	else
+		size = 0;
+
+	return size;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print info for /proc/net/wireless (print all entries)
+ */
+int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+			  int length)
+{
+	int		len = 0;
+	off_t		begin = 0;
+	off_t		pos = 0;
+	int		size;
+	
+	struct net_device *	dev;
+
+	size = sprintf(buffer,
+		       "Inter-| sta-|   Quality        |   Discarded packets               | Missed\n"
+		       " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon\n"
+			);
+	
+	pos += size;
+	len += size;
+
+	read_lock(&dev_base_lock);
+	for (dev = dev_base; dev != NULL; dev = dev->next) {
+		size = sprintf_wireless_stats(buffer + len, dev);
+		len += size;
+		pos = begin + len;
+
+		if (pos < offset) {
+			len = 0;
+			begin = pos;
+		}
+		if (pos > offset + length)
+			break;
+	}
+	read_unlock(&dev_base_lock);
+
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);		/* Start slop */
+	if (len > length)
+		len = length;			/* Ending slop */
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif	/* CONFIG_PROC_FS */
+
+/************************** IOCTL SUPPORT **************************/
+/*
+ * The original user space API to configure all those Wireless Extensions
+ * is through IOCTLs.
+ * In there, we check if we need to call the new driver API (iw_handler)
+ * or just call the driver ioctl handler.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ *	Allow programatic access to /proc/net/wireless even if /proc
+ *	doesn't exist... Also more efficient...
+ */
+static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
+{
+	/* Get stats from the driver */
+	struct iw_statistics *stats;
+
+	stats = get_wireless_stats(dev);
+	if (stats != (struct iw_statistics *) NULL) {
+		struct iwreq *	wrq = (struct iwreq *)ifr;
+
+		/* Copy statistics to the user buffer */
+		if(copy_to_user(wrq->u.data.pointer, stats,
+				sizeof(struct iw_statistics)))
+			return -EFAULT;
+
+		/* Check if we need to clear the update flag */
+		if(wrq->u.data.flags != 0)
+			stats->qual.updated = 0;
+		return 0;
+	} else
+		return -EOPNOTSUPP;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Export the driver private handler definition
+ * They will be picked up by tools like iwpriv...
+ */
+static inline int ioctl_export_private(struct net_device *	dev,
+				       struct ifreq *		ifr)
+{
+	struct iwreq *				iwr = (struct iwreq *) ifr;
+
+	/* Check if the driver has something to export */
+	if((dev->wireless_handlers->num_private_args == 0) ||
+	   (dev->wireless_handlers->private_args == NULL))
+		return -EOPNOTSUPP;
+
+	/* Check NULL pointer */
+	if(iwr->u.data.pointer == NULL)
+		return -EFAULT;
+#ifdef WE_STRICT_WRITE
+	/* Check if there is enough buffer up there */
+	if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
+		return -E2BIG;
+#endif	/* WE_STRICT_WRITE */
+
+	/* Set the number of available ioctls. */
+	iwr->u.data.length = dev->wireless_handlers->num_private_args;
+
+	/* Copy structure to the user buffer. */
+	if (copy_to_user(iwr->u.data.pointer,
+			 dev->wireless_handlers->private_args,
+			 sizeof(struct iw_priv_args) * iwr->u.data.length))
+		return -EFAULT;
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Wrapper to call a standard Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ */
+static inline int ioctl_standard_call(struct net_device *	dev,
+				      struct ifreq *		ifr,
+				      unsigned int		cmd,
+				      iw_handler		handler)
+{
+	struct iwreq *				iwr = (struct iwreq *) ifr;
+	const struct iw_ioctl_description *	descr;
+	struct iw_request_info			info;
+	int					ret = -EINVAL;
+
+	/* Get the description of the IOCTL */
+	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+
+#ifdef WE_IOCTL_DEBUG
+	printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
+	       ifr->ifr_name, cmd);
+	printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
+#endif	/* WE_IOCTL_DEBUG */
+
+	/* Prepare the call */
+	info.cmd = cmd;
+	info.flags = 0;
+
+	/* Check if we have a pointer to user space data or not */
+	if(descr->header_type != IW_HEADER_TYPE_POINT) {
+		/* No extra arguments. Trivial to handle */
+		ret = handler(dev, &info, &(iwr->u), NULL);
+	} else {
+		char *	extra;
+		int	err;
+
+		/* Check what user space is giving us */
+		if(IW_IS_SET(cmd)) {
+			/* Check NULL pointer */
+			if((iwr->u.data.pointer == NULL) &&
+			   (iwr->u.data.length != 0))
+				return -EFAULT;
+			/* Check if number of token fits within bounds */
+			if(iwr->u.data.length > descr->max_tokens)
+				return -E2BIG;
+			if(iwr->u.data.length < descr->min_tokens)
+				return -EINVAL;
+		} else {
+			/* Check NULL pointer */
+			if(iwr->u.data.pointer == NULL)
+				return -EFAULT;
+#ifdef WE_STRICT_WRITE
+			/* Check if there is enough buffer up there */
+			if(iwr->u.data.length < descr->max_tokens)
+				return -E2BIG;
+#endif	/* WE_STRICT_WRITE */
+		}
+
+#ifdef WE_IOCTL_DEBUG
+		printk(KERN_DEBUG "Malloc %d bytes\n",
+		       descr->max_tokens * descr->token_size);
+#endif	/* WE_IOCTL_DEBUG */
+
+		/* Always allocate for max space. Easier, and won't last
+		 * long... */
+		extra = kmalloc(descr->max_tokens * descr->token_size,
+				GFP_KERNEL);
+		if (extra == NULL) {
+			return -ENOMEM;
+		}
+
+		/* If it is a SET, get all the extra data in here */
+		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+			err = copy_from_user(extra, iwr->u.data.pointer,
+					     iwr->u.data.length *
+					     descr->token_size);
+			if (err) {
+				kfree(extra);
+				return -EFAULT;
+			}
+#ifdef WE_IOCTL_DEBUG
+			printk(KERN_DEBUG "Got %d bytes\n",
+			       iwr->u.data.length * descr->token_size);
+#endif	/* WE_IOCTL_DEBUG */
+		}
+
+		/* Call the handler */
+		ret = handler(dev, &info, &(iwr->u), extra);
+
+		/* If we have something to return to the user */
+		if (!ret && IW_IS_GET(cmd)) {
+			err = copy_to_user(iwr->u.data.pointer, extra,
+					   iwr->u.data.length *
+					   descr->token_size);
+			if (err)
+				ret =  -EFAULT;				   
+#ifdef WE_IOCTL_DEBUG
+			printk(KERN_DEBUG "Wrote %d bytes\n",
+			       iwr->u.data.length * descr->token_size);
+#endif	/* WE_IOCTL_DEBUG */
+		}
+
+		/* Cleanup - I told you it wasn't that long ;-) */
+		kfree(extra);
+	}
+
+	/* Call commit handler if needed and defined */
+	if(ret == -EIWCOMMIT)
+		ret = call_commit_handler(dev);
+
+	/* Here, we will generate the appropriate event if needed */
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Wrapper to call a private Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ * It's not as nice and slimline as the standard wrapper. The cause
+ * is struct iw_priv_args, which was not really designed for the
+ * job we are going here.
+ *
+ * IMPORTANT : This function prevent to set and get data on the same
+ * IOCTL and enforce the SET/GET convention. Not doing it would be
+ * far too hairy...
+ * If you need to set and get data at the same time, please don't use
+ * a iw_handler but process it in your ioctl handler (i.e. use the
+ * old driver API).
+ */
+static inline int ioctl_private_call(struct net_device *	dev,
+				     struct ifreq *		ifr,
+				     unsigned int		cmd,
+				     iw_handler		handler)
+{
+	struct iwreq *			iwr = (struct iwreq *) ifr;
+	struct iw_priv_args *		descr = NULL;
+	struct iw_request_info		info;
+	int				extra_size = 0;
+	int				i;
+	int				ret = -EINVAL;
+
+	/* Get the description of the IOCTL */
+	for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
+		if(cmd == dev->wireless_handlers->private_args[i].cmd) {
+			descr = &(dev->wireless_handlers->private_args[i]);
+			break;
+		}
+
+#ifdef WE_IOCTL_DEBUG
+	printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
+	       ifr->ifr_name, cmd);
+	if(descr) {
+		printk(KERN_DEBUG "Name %s, set %X, get %X\n",
+		       descr->name, descr->set_args, descr->get_args);
+	}
+#endif	/* WE_IOCTL_DEBUG */
+
+	/* Compute the size of the set/get arguments */
+	if(descr != NULL) {
+		if(IW_IS_SET(cmd)) {
+			/* Size of set arguments */
+			extra_size = get_priv_size(descr->set_args);
+
+			/* Does it fits in iwr ? */
+			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
+			   (extra_size < IFNAMSIZ))
+				extra_size = 0;
+		} else {
+			/* Size of set arguments */
+			extra_size = get_priv_size(descr->get_args);
+
+			/* Does it fits in iwr ? */
+			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
+			   (extra_size < IFNAMSIZ))
+				extra_size = 0;
+		}
+	}
+
+	/* Prepare the call */
+	info.cmd = cmd;
+	info.flags = 0;
+
+	/* Check if we have a pointer to user space data or not. */
+	if(extra_size == 0) {
+		/* No extra arguments. Trivial to handle */
+		ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
+	} else {
+		char *	extra;
+		int	err;
+
+		/* Check what user space is giving us */
+		if(IW_IS_SET(cmd)) {
+			/* Check NULL pointer */
+			if((iwr->u.data.pointer == NULL) &&
+			   (iwr->u.data.length != 0))
+				return -EFAULT;
+
+			/* Does it fits within bounds ? */
+			if(iwr->u.data.length > (descr->set_args &
+						 IW_PRIV_SIZE_MASK))
+				return -E2BIG;
+		} else {
+			/* Check NULL pointer */
+			if(iwr->u.data.pointer == NULL)
+				return -EFAULT;
+		}
+
+#ifdef WE_IOCTL_DEBUG
+		printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
+#endif	/* WE_IOCTL_DEBUG */
+
+		/* Always allocate for max space. Easier, and won't last
+		 * long... */
+		extra = kmalloc(extra_size, GFP_KERNEL);
+		if (extra == NULL) {
+			return -ENOMEM;
+		}
+
+		/* If it is a SET, get all the extra data in here */
+		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+			err = copy_from_user(extra, iwr->u.data.pointer,
+					     extra_size);
+			if (err) {
+				kfree(extra);
+				return -EFAULT;
+			}
+#ifdef WE_IOCTL_DEBUG
+			printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
+#endif	/* WE_IOCTL_DEBUG */
+		}
+
+		/* Call the handler */
+		ret = handler(dev, &info, &(iwr->u), extra);
+
+		/* If we have something to return to the user */
+		if (!ret && IW_IS_GET(cmd)) {
+			err = copy_to_user(iwr->u.data.pointer, extra,
+					   extra_size);
+			if (err)
+				ret =  -EFAULT;				   
+#ifdef WE_IOCTL_DEBUG
+			printk(KERN_DEBUG "Wrote %d elem\n",
+			       iwr->u.data.length);
+#endif	/* WE_IOCTL_DEBUG */
+		}
+
+		/* Cleanup - I told you it wasn't that long ;-) */
+		kfree(extra);
+	}
+
+
+	/* Call commit handler if needed and defined */
+	if(ret == -EIWCOMMIT)
+		ret = call_commit_handler(dev);
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Main IOCTl dispatcher. Called from the main networking code
+ * (dev_ioctl() in net/core/dev.c).
+ * Check the type of IOCTL and call the appropriate wrapper...
+ */
+int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
+{
+	struct net_device *dev;
+	iw_handler	handler;
+
+	/* Permissions are already checked in dev_ioctl() before calling us.
+	 * The copy_to/from_user() of ifr is also dealt with in there */
+
+	/* Make sure the device exist */
+	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
+		return -ENODEV;
+
+	/* A bunch of special cases, then the generic case...
+	 * Note that 'cmd' is already filtered in dev_ioctl() with
+	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
+	switch(cmd) 
+	{
+		case SIOCGIWSTATS:
+			/* Get Wireless Stats */
+			return dev_iwstats(dev, ifr);
+
+		case SIOCGIWPRIV:
+			/* Check if we have some wireless handlers defined */
+			if(dev->wireless_handlers != NULL) {
+				/* We export to user space the definition of
+				 * the private handler ourselves */
+				return ioctl_export_private(dev, ifr);
+			}
+			// ## Fall-through for old API ##
+		default:
+			/* Generic IOCTL */
+			/* Basic check */
+			if (!netif_device_present(dev))
+				return -ENODEV;
+			/* New driver API : try to find the handler */
+			handler = get_handler(dev, cmd);
+			if(handler != NULL) {
+				/* Standard and private are not the same */
+				if(cmd < SIOCIWFIRSTPRIV)
+					return ioctl_standard_call(dev,
+								   ifr,
+								   cmd,
+								   handler);
+				else
+					return ioctl_private_call(dev,
+								  ifr,
+								  cmd,
+								  handler);
+			}
+			/* Old driver API : call driver ioctl handler */
+			if (dev->do_ioctl) {
+				return dev->do_ioctl(dev, ifr, cmd);
+			}
+			return -EOPNOTSUPP;
+	}
+	/* Not reached */
+	return -EINVAL;
+}
diff -u --recursive --new-file v2.5.2/linux/net/decnet/Config.help linux/net/decnet/Config.help
--- v2.5.2/linux/net/decnet/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/decnet/Config.help	Fri Jan 25 16:03:33 2002
@@ -0,0 +1,25 @@
+CONFIG_DECNET_SIOCGIFCONF
+  This option should only be turned on if you are really sure that
+  you know what you are doing. It can break other applications which
+  use this system call and the proper way to get the information
+  provided by this call is to use rtnetlink.
+
+  If unsure, say N.
+
+CONFIG_DECNET_ROUTER
+  Add support for turning your DECnet Endnode into a level 1 or 2
+  router.  This is an unfinished option for developers only.  If you
+  do say Y here, then make sure that you also say Y to "Kernel/User
+  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
+  will be required for the forthcoming routing daemon to work.
+
+  See <file:Documentation/networking/decnet.txt> for more information.
+
+CONFIG_DECNET_ROUTE_FWMARK
+  If you say Y here, you will be able to specify different routes for
+  packets with different FWMARK ("firewalling mark") values
+  (see ipchains(8), "-m" argument).
+
diff -u --recursive --new-file v2.5.2/linux/net/decnet/README linux/net/decnet/README
--- v2.5.2/linux/net/decnet/README	Wed May 26 09:36:36 1999
+++ linux/net/decnet/README	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- v2.5.2/linux/net/decnet/af_decnet.c	Mon Jan 14 18:25:11 2002
+++ linux/net/decnet/af_decnet.c	Tue Jan 15 10:56:35 2002
@@ -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
  */
 
 
@@ -138,9 +139,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);
@@ -153,18 +158,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;
 }
@@ -237,6 +262,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)
 {
@@ -327,10 +394,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;
@@ -364,7 +432,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;
@@ -1044,6 +1113,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);
@@ -1199,6 +1271,7 @@
 	sk->ack_backlog     = 0;
 	sk->state           = TCP_LISTEN;
 	err                 = 0;
+	dn_rehash_sock(sk);
 
 out:
 	release_sock(sk);
@@ -2062,44 +2135,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);
 
@@ -2157,7 +2233,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 -u --recursive --new-file v2.5.2/linux/net/decnet/dn_dev.c linux/net/decnet/dn_dev.c
--- v2.5.2/linux/net/decnet/dn_dev.c	Fri Jul  6 16:46:22 2001
+++ linux/net/decnet/dn_dev.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/decnet/dn_fib.c linux/net/decnet/dn_fib.c
--- v2.5.2/linux/net/decnet/dn_fib.c	Mon Jan 22 13:32:10 2001
+++ linux/net/decnet/dn_fib.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/decnet/dn_route.c linux/net/decnet/dn_route.c
--- v2.5.2/linux/net/decnet/dn_route.c	Fri Nov  9 14:12:54 2001
+++ linux/net/decnet/dn_route.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/decnet/dn_rules.c linux/net/decnet/dn_rules.c
--- v2.5.2/linux/net/decnet/dn_rules.c	Mon Jan 22 13:32:10 2001
+++ linux/net/decnet/dn_rules.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/decnet/dn_table.c linux/net/decnet/dn_table.c
--- v2.5.2/linux/net/decnet/dn_table.c	Mon Jan 22 13:32:10 2001
+++ linux/net/decnet/dn_table.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/Config.help linux/net/ipv4/Config.help
--- v2.5.2/linux/net/ipv4/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/Config.help	Fri Jan 25 16:03:33 2002
@@ -0,0 +1,279 @@
+CONFIG_INET_ECN
+  Explicit Congestion Notification (ECN) allows routers to notify
+  clients about network congestion, resulting in fewer dropped packets
+  and increased network performance.  This option adds ECN support to
+  the Linux kernel, as well as a sysctl (/proc/sys/net/ipv4/tcp_ecn)
+  which allows ECN support to be disabled at runtime.
+
+  Note that, on the Internet, there are many broken firewalls which
+  refuse connections from ECN-enabled machines, and it may be a while
+  before these firewalls are fixed.  Until then, to access a site
+  behind such a firewall (some of which are major sites, at the time
+  of this writing) you will have to disable this option, either by
+  saying N now or by using the sysctl.
+
+  If in doubt, say N.
+
+CONFIG_SYN_COOKIES
+  Normal TCP/IP networking is open to an attack known as "SYN
+  flooding". This denial-of-service attack prevents legitimate remote
+  users from being able to connect to your computer during an ongoing
+  attack and requires very little work from the attacker, who can
+  operate from anywhere on the Internet.
+
+  SYN cookies provide protection against this type of attack. If you
+  say Y here, the TCP/IP stack will use a cryptographic challenge
+  protocol known as "SYN cookies" to enable legitimate users to
+  continue to connect, even when your machine is under attack. There
+  is no need for the legitimate users to change their TCP/IP software;
+  SYN cookies work transparently to them. For technical information
+  about SYN cookies, check out <http://cr.yp.to/syncookies.html>.
+
+  If you are SYN flooded, the source address reported by the kernel is
+  likely to have been forged by the attacker; it is only reported as
+  an aid in tracing the packets to their actual source and should not
+  be taken as absolute truth.
+
+  SYN cookies may prevent correct error reporting on clients when the
+  server is really overloaded. If this happens frequently better turn
+  them off.
+
+  If you say Y here, note that SYN cookies aren't enabled by default;
+  you can enable them by saying Y to "/proc file system support" and
+  "Sysctl support" below and executing the command
+
+    echo 1 >/proc/sys/net/ipv4/tcp_syncookies
+
+  at boot time after the /proc file system has been mounted.
+
+  If unsure, say N.
+
+CONFIG_ARPD
+  Normally, the kernel maintains an internal cache which maps IP
+  addresses to hardware addresses on the local network, so that
+  Ethernet/Token Ring/ etc. frames are sent to the proper address on
+  the physical networking layer. For small networks having a few
+  hundred directly connected hosts or less, keeping this address
+  resolution (ARP) cache inside the kernel works well. However,
+  maintaining an internal ARP cache does not work well for very large
+  switched networks, and will use a lot of kernel memory if TCP/IP
+  connections are made to many machines on the network.
+
+  If you say Y here, the kernel's internal ARP cache will never grow
+  to more than 256 entries (the oldest entries are expired in a LIFO
+  manner) and communication will be attempted with the user space ARP
+  daemon arpd. Arpd then answers the address resolution request either
+  from its own cache or by asking the net.
+
+  This code is experimental and also obsolete. If you want to use it,
+  you need to find a version of the daemon arpd on the net somewhere,
+  and you should also say Y to "Kernel/User network link driver",
+  below. If unsure, say N.
+
+CONFIG_IP_MULTICAST
+  This is code for addressing several networked computers at once,
+  enlarging your kernel by about 2 KB. You need multicasting if you
+  intend to participate in the MBONE, a high bandwidth network on top
+  of the Internet which carries audio and video broadcasts. More
+  information about the MBONE is on the WWW at
+  <http://www-itg.lbl.gov/mbone/>. Information about the multicast
+  capabilities of the various network cards is contained in
+  <file:Documentation/networking/multicast.txt>. For most people, it's
+  safe to say N.
+
+CONFIG_IP_ADVANCED_ROUTER
+  If you intend to run your Linux box mostly as a router, i.e. as a
+  computer that forwards and redistributes network packets, say Y; you
+  will then be presented with several options that allow more precise
+  control about the routing process.
+
+  The answer to this question won't directly affect the kernel:
+  answering N will just cause the configurator to skip all the
+  questions about advanced routing.
+
+  Note that your box can only act as a router if you enable IP
+  forwarding in your kernel; you can do that by saying Y to "/proc
+  file system support" and "Sysctl support" below and executing the
+  line
+
+    echo "1" > /proc/sys/net/ipv4/ip_forward
+
+  at boot time after the /proc file system has been mounted.
+
+  If you turn on IP forwarding, you will also get the rp_filter, which
+  automatically rejects incoming packets if the routing table entry
+  for their source address doesn't match the network interface they're
+  arriving on. This has security advantages because it prevents the
+  so-called IP spoofing, however it can pose problems if you use
+  asymmetric routing (packets from you to a host take a different path
+  than packets from that host to you) or if you operate a non-routing
+  host which has several IP addresses on different interfaces. To turn
+  rp_filter off use:
+
+        echo 0 > /proc/sys/net/ipv4/conf/<device>/rp_filter
+  or
+        echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
+
+  If unsure, say N here.
+
+CONFIG_IP_MULTIPLE_TABLES
+  Normally, a router decides what to do with a received packet based
+  solely on the packet's final destination address. If you say Y here,
+  the Linux router will also be able to take the packet's source
+  address into account. Furthermore, if you also say Y to "Use TOS
+  value as routing key" below, the TOS (Type-Of-Service) field of the
+  packet can be used for routing decisions as well. In addition, if
+  you say Y here and to "Fast network address translation" below,
+  the router will also be able to modify source and destination
+  addresses of forwarded packets.
+
+  If you are interested in this, please see the preliminary
+  documentation at <http://www.compendium.com.ar/policy-routing.txt>
+  and <ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex>.
+  You will need supporting software from
+  <ftp://ftp.inr.ac.ru/ip-routing/>.
+
+  If unsure, say N.
+
+CONFIG_IP_ROUTE_MULTIPATH
+  Normally, the routing tables specify a single action to be taken in
+  a deterministic manner for a given packet. If you say Y here
+  however, it becomes possible to attach several actions to a packet
+  pattern, in effect specifying several alternative paths to travel
+  for those packets. The router considers all these paths to be of
+  equal "cost" and chooses one of them in a non-deterministic fashion
+  if a matching packet arrives.
+
+CONFIG_IP_ROUTE_TOS
+  The header of every IP packet carries a TOS (Type Of Service) value
+  with which the packet requests a certain treatment, e.g. low
+  latency (for interactive traffic), high throughput, or high
+  reliability.  If you say Y here, you will be able to specify
+  different routes for packets with different TOS values.
+
+CONFIG_IP_ROUTE_FWMARK
+  If you say Y here, you will be able to specify different routes for
+  packets with different mark values (see iptables(8), MARK target).
+
+CONFIG_IP_ROUTE_VERBOSE
+  If you say Y here, which is recommended, then the kernel will print
+  verbose messages regarding the routing, for example warnings about
+  received packets which look strange and could be evidence of an
+  attack or a misconfigured system somewhere. The information is
+  handled by the klogd daemon which is responsible for kernel messages
+  ("man klogd").
+
+CONFIG_IP_ROUTE_LARGE_TABLES
+  If you have routing zones that grow to more than about 64 entries,
+  you may want to say Y here to speed up the routing process.
+
+CONFIG_IP_ROUTE_NAT
+  If you say Y here, your router will be able to modify source and
+  destination addresses of packets that pass through it, in a manner
+  you specify.  General information about Network Address Translation
+  can be gotten from the document
+  <http://www.csn.tu-chemnitz.de/~mha/linux-ip-nat/diplom/nat.html>.
+
+CONFIG_IP_PNP
+  This enables automatic configuration of IP addresses of devices and
+  of the routing table during kernel boot, based on either information
+  supplied on the kernel command line or by BOOTP or RARP protocols.
+  You need to say Y only for diskless machines requiring network
+  access to boot (in which case you want to say Y to "Root file system
+  on NFS" as well), because all other machines configure the network
+  in their startup scripts.
+
+CONFIG_IP_PNP_BOOTP
+  If you want your Linux box to mount its whole root file system (the
+  one containing the directory /) from some other computer over the
+  net via NFS and you want the IP address of your computer to be
+  discovered automatically at boot time using the BOOTP protocol (a
+  special protocol designed for doing this job), say Y here. In case
+  the boot ROM of your network card was designed for booting Linux and
+  does BOOTP itself, providing all necessary information on the kernel
+  command line, you can say N here. If unsure, say Y. Note that if you
+  want to use BOOTP, a BOOTP server must be operating on your network.
+  Read <file:Documentation/nfsroot.txt> for details.
+
+CONFIG_IP_PNP_DHCP
+  If you want your Linux box to mount its whole root file system (the
+  one containing the directory /) from some other computer over the
+  net via NFS and you want the IP address of your computer to be
+  discovered automatically at boot time using the DHCP protocol (a
+  special protocol designed for doing this job), say Y here. In case
+  the boot ROM of your network card was designed for booting Linux and
+  does DHCP itself, providing all necessary information on the kernel
+  command line, you can say N here.
+
+  If unsure, say Y. Note that if you want to use DHCP, a DHCP server
+  must be operating on your network.  Read
+  <file:Documentation/nfsroot.txt> for details.
+
+CONFIG_IP_PNP_RARP
+  If you want your Linux box to mount its whole root file system (the
+  one containing the directory /) from some other computer over the
+  net via NFS and you want the IP address of your computer to be
+  discovered automatically at boot time using the RARP protocol (an
+  older protocol which is being obsoleted by BOOTP and DHCP), say Y
+  here. Note that if you want to use RARP, a RARP server must be
+  operating on your network. Read <file:Documentation/nfsroot.txt> for
+  details.
+
+CONFIG_NET_IPIP
+  Tunneling means encapsulating data of one protocol type within
+  another protocol and sending it over a channel that understands the
+  encapsulating protocol. This particular tunneling driver implements
+  encapsulation of IP within IP, which sounds kind of pointless, but
+  can be useful if you want to make your (or some other) machine
+  appear on a different network than it physically is, or to use
+  mobile-IP facilities (allowing laptops to seamlessly move between
+  networks without changing their IP addresses; check out
+  <http://anchor.cs.binghamton.edu/~mobileip/LJ/index.html>).
+
+  Saying Y to this option will produce two modules ( = code which can
+  be inserted in and removed from the running kernel whenever you
+  want). Most people won't need this and can say N.
+
+CONFIG_NET_IPGRE
+  Tunneling means encapsulating data of one protocol type within
+  another protocol and sending it over a channel that understands the
+  encapsulating protocol. This particular tunneling driver implements
+  GRE (Generic Routing Encapsulation) and at this time allows
+  encapsulating of IPv4 or IPv6 over existing IPv4 infrastructure.
+  This driver is useful if the other endpoint is a Cisco router: Cisco
+  likes GRE much better than the other Linux tunneling driver ("IP
+  tunneling" above). In addition, GRE allows multicast redistribution
+  through the tunnel.
+
+CONFIG_NET_IPGRE_BROADCAST
+  One application of GRE/IP is to construct a broadcast WAN (Wide Area
+  Network), which looks like a normal Ethernet LAN (Local Area
+  Network), but can be distributed all over the Internet. If you want
+  to do that, say Y here and to "IP multicast routing" below.
+
+CONFIG_IP_MROUTE
+  This is used if you want your machine to act as a router for IP
+  packets that have several destination addresses. It is needed on the
+  MBONE, a high bandwidth network on top of the Internet which carries
+  audio and video broadcasts. In order to do that, you would most
+  likely run the program mrouted. Information about the multicast
+  capabilities of the various network cards is contained in
+  <file:Documentation/networking/multicast.txt>. If you haven't heard
+  about it, you don't need it.
+
+CONFIG_IP_PIMSM_V1
+  Kernel side support for Sparse Mode PIM (Protocol Independent
+  Multicast) version 1. This multicast routing protocol is used widely
+  because Cisco supports it. You need special software to use it
+  (pimd-v1). Please see <http://netweb.usc.edu/pim/> for more
+  information about PIM.
+
+  Say Y if you want to use PIM-SM v1. Note that you can say N here if
+  you just want to use Dense Mode PIM.
+
+CONFIG_IP_PIMSM_V2
+  Kernel side support for Sparse Mode PIM version 2. In order to use
+  this, you need an experimental routing daemon supporting it (pimd or
+  gated-5). This routing protocol is not used widely, so say N unless
+  you want to play with it.
+
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- v2.5.2/linux/net/ipv4/Config.in	Tue May  1 20:59:24 2001
+++ linux/net/ipv4/Config.in	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/Makefile linux/net/ipv4/Makefile
--- v2.5.2/linux/net/ipv4/Makefile	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/Makefile	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.5.2/linux/net/ipv4/af_inet.c	Mon Nov  5 09:46:12 2001
+++ linux/net/ipv4/af_inet.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.5.2/linux/net/ipv4/devinet.c	Mon Oct  1 09:19:57 2001
+++ linux/net/ipv4/devinet.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- v2.5.2/linux/net/ipv4/fib_frontend.c	Mon Jun 11 19:15:27 2001
+++ linux/net/ipv4/fib_frontend.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c
--- v2.5.2/linux/net/ipv4/fib_hash.c	Tue Aug 31 11:23:03 1999
+++ linux/net/ipv4/fib_hash.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/fib_rules.c linux/net/ipv4/fib_rules.c
--- v2.5.2/linux/net/ipv4/fib_rules.c	Tue May  1 20:59:24 2001
+++ linux/net/ipv4/fib_rules.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c
--- v2.5.2/linux/net/ipv4/fib_semantics.c	Tue Aug 22 08:59:00 2000
+++ linux/net/ipv4/fib_semantics.c	Tue Jan 15 10:56:35 2002
@@ -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.19 2002/01/12 07:54:56 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -134,7 +134,7 @@
 	write_unlock(&fib_info_lock);
 }
 
-extern __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
+static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
 {
 	const struct fib_nh *onh = ofi->fib_nh;
 
@@ -155,7 +155,7 @@
 	return 0;
 }
 
-extern __inline__ struct fib_info * fib_find_info(const struct fib_info *nfi)
+static __inline__ struct fib_info * fib_find_info(const struct fib_info *nfi)
 {
 	for_fib_info() {
 		if (fi->fib_nhs != nfi->fib_nhs)
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.5.2/linux/net/ipv4/icmp.c	Mon Jan 14 18:25:11 2002
+++ linux/net/ipv4/icmp.c	Mon Jan 28 13:20:44 2002
@@ -181,8 +181,7 @@
  *	all layers. All Socketless IP sends will soon be gone.
  */
 	
-struct inode icmp_inode;
-struct socket *icmp_socket = &icmp_inode.u.socket_i;
+struct socket *icmp_socket;
 
 /* ICMPv4 socket is only a bit non-reenterable (unlike ICMPv6,
    which is strongly non-reenterable). A bit later it will be made
@@ -979,20 +978,9 @@
 
 void __init icmp_init(struct net_proto_family *ops)
 {
-	int err;
+	int err = sock_create(PF_INET, SOCK_RAW, IPPROTO_ICMP, &icmp_socket);
 
-	icmp_inode.i_mode = S_IFSOCK;
-	icmp_inode.i_sock = 1;
-	icmp_inode.i_uid = 0;
-	icmp_inode.i_gid = 0;
-	init_waitqueue_head(&icmp_inode.i_wait);
-	init_waitqueue_head(&icmp_inode.u.socket_i.wait);
-
-	icmp_socket->inode = &icmp_inode;
-	icmp_socket->state = SS_UNCONNECTED;
-	icmp_socket->type=SOCK_RAW;
-
-	if ((err=ops->create(icmp_socket, IPPROTO_ICMP))<0)
+	if (err < 0)
 		panic("Failed to create the ICMP control socket.\n");
 	icmp_socket->sk->allocation=GFP_ATOMIC;
 	icmp_socket->sk->sndbuf = SK_WMEM_MAX*2;
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.5.2/linux/net/ipv4/ip_fragment.c	Fri Sep  7 11:01:21 2001
+++ linux/net/ipv4/ip_fragment.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		The IP fragmentation functionality.
  *		
- * Version:	$Id: ip_fragment.c,v 1.58 2001/09/01 00:31:50 davem Exp $
+ * Version:	$Id: ip_fragment.c,v 1.59 2002/01/12 07:54:56 davem Exp $
  *
  * Authors:	Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox <Alan.Cox@linux.org>
@@ -130,19 +130,19 @@
 atomic_t ip_frag_mem = ATOMIC_INIT(0);	/* Memory used for fragments */
 
 /* Memory Tracking Functions. */
-extern __inline__ void frag_kfree_skb(struct sk_buff *skb)
+static __inline__ void frag_kfree_skb(struct sk_buff *skb)
 {
 	atomic_sub(skb->truesize, &ip_frag_mem);
 	kfree_skb(skb);
 }
 
-extern __inline__ void frag_free_queue(struct ipq *qp)
+static __inline__ void frag_free_queue(struct ipq *qp)
 {
 	atomic_sub(sizeof(struct ipq), &ip_frag_mem);
 	kfree(qp);
 }
 
-extern __inline__ struct ipq *frag_alloc_queue(void)
+static __inline__ struct ipq *frag_alloc_queue(void)
 {
 	struct ipq *qp = kmalloc(sizeof(struct ipq), GFP_ATOMIC);
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- v2.5.2/linux/net/ipv4/ip_input.c	Wed Nov  7 14:39:36 2001
+++ linux/net/ipv4/ip_input.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) module.
  *
- * Version:	$Id: ip_input.c,v 1.54 2001/11/06 22:33:52 davem Exp $
+ * Version:	$Id: ip_input.c,v 1.55 2002/01/12 07:39:45 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -224,8 +224,7 @@
 	nf_debug_ip_local_deliver(skb);
 #endif /*CONFIG_NETFILTER_DEBUG*/
 
-	/* Pull out additionl 8 bytes to save some space in protocols. */
-	if (!pskb_may_pull(skb, ihl+8))
+	if (!pskb_may_pull(skb, ihl))
 		goto out;
 	__skb_pull(skb, ihl);
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.5.2/linux/net/ipv4/ipconfig.c	Mon Jan 14 18:25:11 2002
+++ linux/net/ipv4/ipconfig.c	Tue Jan 15 10:56:35 2002
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.42 2001/11/10 07:23:12 davem Exp $
+ *  $Id: ipconfig.c,v 1.45 2002/01/08 16:00:20 davem Exp $
  *
  *  Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or
  *  user-supplied information to configure own IP address and routes.
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.5.2/linux/net/ipv4/ipmr.c	Thu Sep 20 14:12:56 2001
+++ linux/net/ipv4/ipmr.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/Config.help linux/net/ipv4/netfilter/Config.help
--- v2.5.2/linux/net/ipv4/netfilter/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/Config.help	Fri Jan 25 16:03:22 2002
@@ -0,0 +1,292 @@
+CONFIG_IP_NF_CONNTRACK
+  Connection tracking keeps a record of what packets have passed
+  through your machine, in order to figure out how they are related
+  into connections.
+
+  This is required to do Masquerading or other kinds of Network
+  Address Translation (except for Fast NAT).  It can also be used to
+  enhance packet filtering (see `Connection state match support'
+  below).
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_IRC
+  There is a commonly-used extension to IRC called
+  Direct Client-to-Client Protocol (DCC).  This enables users to send
+  files to each other, and also chat to each other without the need
+  of a server.  DCC Sending is used anywhere you send files over IRC,
+  and DCC Chat is most commonly used by Eggdrop bots.  If you are
+  using NAT, this extension will enable you to send files and initiate
+  chats.  Note that you do NOT need this extension to get files or
+  have others initiate chats, or everything else in IRC.
+
+  If you want to compile it as a module, say 'M' here and read
+  Documentation/modules.txt.  If unsure, say 'N'.
+
+CONFIG_IP_NF_FTP
+  Tracking FTP connections is problematic: special helpers are
+  required for tracking them, and doing masquerading and other forms
+  of Network Address Translation on them.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `Y'.
+
+CONFIG_IP_NF_QUEUE
+  Netfilter has the ability to queue packets to user space: the
+  netlink device can be used to access them using this driver.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_IPTABLES
+  iptables is a general, extensible packet identification framework.
+  The packet filtering and full NAT (masquerading, port forwarding,
+  etc) subsystems now use this: say `Y' or `M' here if you want to use
+  either of those.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_MATCH_LIMIT
+  limit matching allows you to control the rate at which a rule can be
+  matched: mainly useful in combination with the LOG target ("LOG
+  target support", below) and to avoid some Denial of Service attacks.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_MATCH_MAC
+  MAC matching allows you to match packets based on the source
+  Ethernet address of the packet.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_MATCH_MARK
+  Netfilter mark matching allows you to match packets based on the
+  `nfmark' value in the packet.  This can be set by the MARK target
+  (see below).
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_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'.
+
+CONFIG_IP_NF_MATCH_TTL
+  This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user
+  to match packets by their TTL value.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+CONFIG_IP_NF_MATCH_LENGTH
+  This option allows you to match the length of a packet against a
+  specific value or range of values.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_MATCH_AH_ESP
+  These two match extensions (`ah' and `esp') allow you to match a
+  range of SPIs inside AH or ESP headers of IPSec packets.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+CONFIG_IP_NF_MATCH_TOS
+  TOS matching allows you to match packets based on the Type Of
+  Service fields of the IP packet.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_MATCH_STATE
+  Connection state matching allows you to match packets based on their
+  relationship to a tracked connection (ie. previous packets).  This
+  is a powerful tool for packet classification.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_MATCH_UNCLEAN
+  Unclean packet matching matches any strange or invalid packets, by
+  looking at a series of fields in the IP, TCP, UDP and ICMP headers.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_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'.
+
+CONFIG_IP_NF_FILTER
+  Packet filtering defines a table `filter', which has a series of
+  rules for simple packet filtering at local input, forwarding and
+  local output.  See the man page for iptables(8).
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_TARGET_REJECT
+  The REJECT target allows a filtering rule to specify that an ICMP
+  error should be issued in response to an incoming packet, rather
+  than silently being dropped.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_TARGET_MIRROR
+  The MIRROR target allows a filtering rule to specify that an
+  incoming packet should be bounced back to the sender.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_NAT
+  The Full NAT option allows masquerading, port forwarding and other
+  forms of full Network Address Port Translation.  It is controlled by
+  the `nat' table in iptables: see the man page for iptables(8).
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_TARGET_MASQUERADE
+  Masquerading is a special case of NAT: all outgoing connections are
+  changed to seem to come from a particular interface's address, and
+  if the interface goes down, those connections are lost.  This is
+  only useful for dialup accounts with dynamic IP address (ie. your IP
+  address will be different on next dialup).
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_NAT_SNMP_BASIC
+
+  This module implements an Application Layer Gateway (ALG) for
+  SNMP payloads.  In conjunction with NAT, it allows a network
+  management system to access multiple private networks with
+  conflicting addresses.  It works by modifying IP addresses
+  inside SNMP payloads to match IP-layer NAT mapping.
+
+  This is the "basic" form of SNMP-ALG, as described in RFC 2962
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_TARGET_REDIRECT
+  REDIRECT is a special case of NAT: all incoming connections are
+  mapped onto the incoming interface's address, causing the packets to
+  come to the local machine instead of passing through.  This is
+  useful for transparent proxies.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_MANGLE
+  This option adds a `mangle' table to iptables: see the man page for
+  iptables(8).  This table is used for various packet alterations
+  which can effect how the packet is routed.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_TARGET_TOS
+  This option adds a `TOS' target, which allows you to create rules in
+  the `mangle' table which alter the Type Of Service field of an IP
+  packet prior to routing.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_TARGET_MARK
+  This option adds a `MARK' target, which allows you to create rules
+  in the `mangle' table which alter the netfilter mark (nfmark) field
+  associated with the packet prior to routing. This can change
+  the routing method (see `Use netfilter MARK value as routing
+  key') and can also be used by other subsystems to change their
+  behavior.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_TARGET_TCPMSS
+  This option adds a `TCPMSS' target, which allows you to alter the
+  MSS value of TCP SYN packets, to control the maximum size for that
+  connection (usually limiting it to your outgoing interface's MTU
+  minus 40).
+
+  This is used to overcome criminally braindead ISPs or servers which
+  block ICMP Fragmentation Needed packets.  The symptoms of this
+  problem are that everything works fine from your Linux
+  firewall/router, but machines behind it can never exchange large
+  packets:
+	1) Web browsers connect, then hang with no data received.
+	2) Small mail works fine, but large emails hang.
+	3) ssh works fine, but scp hangs after initial handshaking.
+
+  Workaround: activate this option and add a rule to your firewall
+  configuration like:
+
+        iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
+		 -j TCPMSS --clamp-mss-to-pmtu
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_MATCH_TCPMSS
+  This option adds a `tcpmss' match, which allows you to examine the
+  MSS value of TCP SYN packets, which control the maximum packet size
+  for that connection.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_TARGET_ULOG
+  This option adds a `ULOG' target, which allows you to create rules in
+  any iptables table. The packet is passed to a userspace logging
+  daemon using netlink multicast sockets; unlike the LOG target
+  which can only be viewed through syslog.
+
+  The apropriate userspace logging daemon (ulogd) may be obtained from
+  http://www.gnumonks.org/projects/ulogd
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+CONFIG_IP_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'.
+
+CONFIG_IP_NF_COMPAT_IPCHAINS
+  This option places ipchains (with masquerading and redirection
+  support) back into the kernel, using the new netfilter
+  infrastructure.  It is not recommended for new installations (see
+  `Packet filtering').  With this enabled, you should be able to use
+  the ipchains tool exactly as in 2.2 kernels.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP_NF_COMPAT_IPFWADM
+  This option places ipfwadm (with masquerading and redirection
+  support) back into the kernel, using the new netfilter
+  infrastructure.  It is not recommended for new installations (see
+  `Packet filtering').  With this enabled, you should be able to use
+  the ipfwadm tool exactly as in 2.0 kernels.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/Config.in linux/net/ipv4/netfilter/Config.in
--- v2.5.2/linux/net/ipv4/netfilter/Config.in	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/netfilter/Config.in	Wed Jan 23 15:28:40 2002
@@ -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
@@ -21,6 +21,7 @@
   dep_tristate '  netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
   dep_tristate '  Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  AH/ESP match support' CONFIG_IP_NF_MATCH_AH_ESP $CONFIG_IP_NF_IPTABLES
   dep_tristate '  LENGTH match support' CONFIG_IP_NF_MATCH_LENGTH $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TTL match support' CONFIG_IP_NF_MATCH_TTL $CONFIG_IP_NF_IPTABLES
   dep_tristate '  tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES
@@ -74,6 +75,9 @@
     dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
   fi
   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
+  if [ "$CONFIG_NETLINK" != "n" ]; then
+     dep_tristate '  ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_NETLINK $CONFIG_IP_NF_IPTABLES
+  fi
   dep_tristate '  TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES
 fi
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
--- v2.5.2/linux/net/ipv4/netfilter/Makefile	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/netfilter/Makefile	Wed Jan 23 15:28:40 2002
@@ -56,6 +56,7 @@
 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
 
 obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
 
@@ -73,6 +74,7 @@
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
+obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
 
 # backwards compatibility 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ip_fw_compat_masq.c linux/net/ipv4/netfilter/ip_fw_compat_masq.c
--- v2.5.2/linux/net/ipv4/netfilter/ip_fw_compat_masq.c	Fri Sep 14 14:04:08 2001
+++ linux/net/ipv4/netfilter/ip_fw_compat_masq.c	Wed Jan 23 15:28:40 2002
@@ -157,7 +157,7 @@
 		/* Fall thru... */
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
-		IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
+		IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
 
 		if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
 			if (net_ratelimit())
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ip_fw_compat_redir.c linux/net/ipv4/netfilter/ip_fw_compat_redir.c
--- v2.5.2/linux/net/ipv4/netfilter/ip_fw_compat_redir.c	Mon Jan 14 18:25:11 2002
+++ linux/net/ipv4/netfilter/ip_fw_compat_redir.c	Wed Jan 16 10:29:38 2002
@@ -20,6 +20,9 @@
 
 #include <linux/netfilter_ipv4/lockhelp.h>
 
+/* Very simple timeout pushed back by each packet */
+#define REDIR_TIMEOUT (240*HZ)
+
 static DECLARE_LOCK(redir_lock);
 #define ASSERT_READ_LOCK(x) MUST_BE_LOCKED(&redir_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_LOCKED(&redir_lock)
@@ -150,6 +153,14 @@
 	skb->nfcache |= NFC_ALTERED;
 }
 
+static void destroyme(unsigned long me)
+{
+	LOCK_BH(&redir_lock);
+	LIST_DELETE(&redirs, (struct redir *)me);
+	UNLOCK_BH(&redir_lock);
+	kfree((struct redir *)me);
+}
+
 /* REDIRECT a packet. */
 unsigned int
 do_redirect(struct sk_buff *skb,
@@ -172,6 +183,10 @@
 		struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph
 							+ iph->ihl);
 
+		/* Must have whole header */
+		if (skb->len < iph->ihl*4 + sizeof(*udph))
+			return NF_DROP;
+
 		if (udph->check) /* 0 is a special case meaning no checksum */
 			udph->check = cheat_check(~iph->daddr, newdst,
 					  cheat_check(udph->dest ^ 0xFFFF,
@@ -191,6 +206,10 @@
 		struct redir *redir;
 		int ret;
 
+		/* Must have whole header */
+		if (skb->len < iph->ihl*4 + sizeof(*tcph))
+			return NF_DROP;
+
 		DEBUGP("Doing tcp redirect. %08X:%u %08X:%u -> %08X:%u\n",
 		       iph->saddr, tcph->source, iph->daddr, tcph->dest,
 		       newdst, redirpt);
@@ -206,7 +225,9 @@
 			}
 			list_prepend(&redirs, redir);
 			init_timer(&redir->destroyme);
-			redir->destroyme.expires = jiffies + 75*HZ;
+			redir->destroyme.function = destroyme;
+			redir->destroyme.data = (unsigned long)redir;
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
 			add_timer(&redir->destroyme);
 		}
 		/* In case mangling has changed, rewrite this part. */
@@ -227,13 +248,6 @@
 	}
 }
 
-static void destroyme(unsigned long me)
-{
-	LOCK_BH(&redir_lock);
-	LIST_DELETE(&redirs, (struct redir *)me);
-	UNLOCK_BH(&redir_lock);
-}
-
 /* Incoming packet: is it a reply to a masqueraded connection, or
    part of an already-redirected TCP connection? */
 void
@@ -247,15 +261,18 @@
 	if (iph->protocol != IPPROTO_TCP)
 		return;
 
+	/* Must have whole header */
+	if (skb->len < iph->ihl*4 + sizeof(*tcph))
+		return;
+
 	LOCK_BH(&redir_lock);
 	redir = find_redir(iph->saddr, iph->daddr, tcph->source, tcph->dest);
 	if (redir) {
 		DEBUGP("Doing tcp redirect again.\n");
 		do_tcp_redir(skb, redir);
-		if (tcph->rst || tcph->fin) {
-			redir->destroyme.function = destroyme;
-			redir->destroyme.data = (unsigned long)redir;
-			mod_timer(&redir->destroyme, 75*HZ);
+		if (del_timer(&redir->destroyme)) {
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
+			add_timer(&redir->destroyme);
 		}
 	}
 	UNLOCK_BH(&redir_lock);
@@ -272,15 +289,18 @@
 	if (iph->protocol != IPPROTO_TCP)
 		return;
 
+	/* Must have whole header */
+	if (skb->len < iph->ihl*4 + sizeof(*tcph))
+		return;
+
 	LOCK_BH(&redir_lock);
 	redir = find_unredir(iph->saddr, iph->daddr, tcph->source, tcph->dest);
 	if (redir) {
 		DEBUGP("Doing tcp unredirect.\n");
 		do_tcp_unredir(skb, redir);
-		if (tcph->rst || tcph->fin) {
-			redir->destroyme.function = destroyme;
-			redir->destroyme.data = (unsigned long)redir;
-			mod_timer(&redir->destroyme, 75*HZ);
+		if (del_timer(&redir->destroyme)) {
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
+			add_timer(&redir->destroyme);
 		}
 	}
 	UNLOCK_BH(&redir_lock);
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ip_nat_rule.c linux/net/ipv4/netfilter/ip_nat_rule.c
--- v2.5.2/linux/net/ipv4/netfilter/ip_nat_rule.c	Fri Apr 27 14:15:01 2001
+++ linux/net/ipv4/netfilter/ip_nat_rule.c	Wed Jan 23 15:28:40 2002
@@ -104,7 +104,7 @@
 
 static struct ipt_table nat_table
 = { { NULL, NULL }, "nat", &nat_initial_table.repl,
-    NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 LIST_HEAD(nat_expect_list);
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c
--- v2.5.2/linux/net/ipv4/netfilter/ip_nat_standalone.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ip_nat_standalone.c	Thu Jan 24 22:05:04 2002
@@ -166,34 +166,6 @@
 	return ip_nat_fn(hooknum, pskb, in, out, okfn);
 }
 
-/* FIXME: change in oif may mean change in hh_len.  Check and realloc
-   --RR */
-static int
-route_me_harder(struct sk_buff *skb)
-{
-	struct iphdr *iph = skb->nh.iph;
-	struct rtable *rt;
-	struct rt_key key = { dst:iph->daddr,
-			      src:iph->saddr,
-			      oif:skb->sk ? skb->sk->bound_dev_if : 0,
-			      tos:RT_TOS(iph->tos)|RTO_CONN,
-#ifdef CONFIG_IP_ROUTE_FWMARK
-			      fwmark:skb->nfmark
-#endif
-			    };
-
-	if (ip_route_output_key(&rt, &key) != 0) {
-		printk("route_me_harder: No more route.\n");
-		return -EINVAL;
-	}
-
-	/* Drop old route. */
-	dst_release(skb->dst);
-
-	skb->dst = &rt->u.dst;
-	return 0;
-}
-
 static unsigned int
 ip_nat_local_fn(unsigned int hooknum,
 		struct sk_buff **pskb,
@@ -216,7 +188,7 @@
 	if (ret != NF_DROP && ret != NF_STOLEN
 	    && ((*pskb)->nh.iph->saddr != saddr
 		|| (*pskb)->nh.iph->daddr != daddr))
-		return route_me_harder(*pskb) == 0 ? ret : NF_DROP;
+		return route_me_harder(pskb) == 0 ? ret : NF_DROP;
 	return ret;
 }
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ip_queue.c linux/net/ipv4/netfilter/ip_queue.c
--- v2.5.2/linux/net/ipv4/netfilter/ip_queue.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ip_queue.c	Thu Jan 24 22:05:04 2002
@@ -216,32 +216,6 @@
 	kfree(q);
 }
 
-/* With a chainsaw... */
-static int route_me_harder(struct sk_buff *skb)
-{
-	struct iphdr *iph = skb->nh.iph;
-	struct rtable *rt;
-
-	struct rt_key key = {
-				dst:iph->daddr, src:iph->saddr,
-				oif:skb->sk ? skb->sk->bound_dev_if : 0,
-				tos:RT_TOS(iph->tos)|RTO_CONN,
-#ifdef CONFIG_IP_ROUTE_FWMARK
-				fwmark:skb->nfmark
-#endif
-			};
-
-	if (ip_route_output_key(&rt, &key) != 0) {
-		printk("route_me_harder: No more route.\n");
-		return -EINVAL;
-	}
-
-	/* Drop old route. */
-	dst_release(skb->dst);
-	skb->dst = &rt->u.dst;
-	return 0;
-}
-
 static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
 {
 	int diff;
@@ -287,7 +261,7 @@
 		if (!(iph->tos == e->rt_info.tos
 		      && iph->daddr == e->rt_info.daddr
 		      && iph->saddr == e->rt_info.saddr))
-			return route_me_harder(e->skb);
+			return route_me_harder(&e->skb);
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ip_tables.c linux/net/ipv4/netfilter/ip_tables.c
--- v2.5.2/linux/net/ipv4/netfilter/ip_tables.c	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/netfilter/ip_tables.c	Wed Jan 23 15:28:40 2002
@@ -2,6 +2,11 @@
  * Packet matching code.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2009-2002 Netfilter core team <coreteam@netfilter.org>
+ *
+ * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
+ * 	- increase module usage count as soon as we have rules inside
+ * 	  a table
  */
 #include <linux/config.h>
 #include <linux/skbuff.h>
@@ -84,6 +89,8 @@
 	unsigned int size;
 	/* Number of entries: FIXME. --RR */
 	unsigned int number;
+	/* Initial number of entries. Needed for module usage count */
+	unsigned int initial_entries;
 
 	/* Entry points and underflows */
 	unsigned int hook_entry[NF_IP_NUMHOOKS];
@@ -902,6 +909,7 @@
 	}
 	oldinfo = table->private;
 	table->private = newinfo;
+	newinfo->initial_entries = oldinfo->initial_entries;
 	write_unlock_bh(&table->lock);
 
 	return oldinfo;
@@ -1105,6 +1113,16 @@
 	if (!oldinfo)
 		goto free_newinfo_counters_untrans_unlock;
 
+	/* Update module usage count based on number of rules */
+	duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
+		oldinfo->number, oldinfo->initial_entries, newinfo->number);
+	if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
+ 	    (newinfo->number > oldinfo->initial_entries))
+		__MOD_INC_USE_COUNT(t->me);
+	else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
+	 	 (newinfo->number <= oldinfo->initial_entries))
+		__MOD_DEC_USE_COUNT(t->me);
+
 	/* Get the old counters. */
 	get_counters(oldinfo, counters);
 	/* Decrease module usage counts and free resource */
@@ -1363,7 +1381,7 @@
 	int ret;
 	struct ipt_table_info *newinfo;
 	static struct ipt_table_info bootstrap
-		= { 0, 0, { 0 }, { 0 }, { } };
+		= { 0, 0, 0, { 0 }, { 0 }, { } };
 
 	MOD_INC_USE_COUNT;
 	newinfo = vmalloc(sizeof(struct ipt_table_info)
@@ -1406,6 +1424,9 @@
 
 	duprintf("table->private->number = %u\n",
 		 table->private->number);
+	
+	/* save number of initial entries */
+	table->private->initial_entries = table->private->number;
 
 	table->lock = RW_LOCK_UNLOCKED;
 	list_prepend(&ipt_tables, table);
@@ -1746,7 +1767,7 @@
 	}
 #endif
 
-	printk("ip_tables: (c)2000 Netfilter core team\n");
+	printk("ip_tables: (C) 2000-2002 Netfilter core team\n");
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ipchains_core.c linux/net/ipv4/netfilter/ipchains_core.c
--- v2.5.2/linux/net/ipv4/netfilter/ipchains_core.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ipchains_core.c	Wed Jan 23 15:28:40 2002
@@ -838,6 +838,7 @@
 			i->branch->refcount--;
 		kfree(i);
 		i = tmp;
+		MOD_DEC_USE_COUNT;
 	}
 	return 0;
 }
@@ -875,13 +876,16 @@
 		 * interrupts is not necessary. */
 		chainptr->chain = rule;
 		if (rule->branch) rule->branch->refcount++;
-		return 0;
+		goto append_successful;
 	}
 
 	/* Find the rule before the end of the chain */
 	for (i = chainptr->chain; i->next; i = i->next);
 	i->next = rule;
 	if (rule->branch) rule->branch->refcount++;
+
+append_successful:
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -900,7 +904,7 @@
 		frwl->next = chainptr->chain;
 		if (frwl->branch) frwl->branch->refcount++;
 		chainptr->chain = frwl;
-		return 0;
+		goto insert_successful;
 	}
 	position--;
 	while (--position && f != NULL) f = f->next;
@@ -910,6 +914,9 @@
 	frwl->next = f->next;
 
 	f->next = frwl;
+
+insert_successful:
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -943,6 +950,8 @@
 		i->next = i->next->next;
 		kfree(tmp);
 	}
+
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1049,6 +1058,7 @@
 		else
 			chainptr->chain = ftmp->next;
 		kfree(ftmp);
+		MOD_DEC_USE_COUNT;
 		break;
 	}
 
@@ -1089,6 +1099,8 @@
 
 	tmp->next = tmp2->next;
 	kfree(tmp2);
+
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1141,6 +1153,7 @@
 					      * user defined chain *
 					      * and therefore can be
 					      * deleted */
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ipfwadm_core.c linux/net/ipv4/netfilter/ipfwadm_core.c
--- v2.5.2/linux/net/ipv4/netfilter/ipfwadm_core.c	Thu Sep 20 14:12:56 2001
+++ linux/net/ipv4/netfilter/ipfwadm_core.c	Thu Jan 24 22:05:04 2002
@@ -20,7 +20,7 @@
  *	license in recognition of the original copyright.
  *				-- Alan Cox.
  *
- *	$Id: ipfwadm_core.c,v 1.9 2001/09/18 22:29:10 davem Exp $
+ *	$Id: ipfwadm_core.c,v 1.11 2002/01/24 15:50:31 davem Exp $
  *
  *	Ported from BSD to Linux,
  *		Alan Cox 22/Nov/1994.
@@ -104,6 +104,7 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/module.h>
 
 #include <linux/socket.h>
 #include <linux/sockios.h>
@@ -687,6 +688,7 @@
 		ftmp = *chainptr;
 		*chainptr = ftmp->fw_next;
 		kfree(ftmp);
+		MOD_DEC_USE_COUNT;
 	}
 	restore_flags(flags);
 }
@@ -730,6 +732,7 @@
 	ftmp->fw_next = *chainptr;
        	*chainptr=ftmp;
 	restore_flags(flags);
+	MOD_INC_USE_COUNT;
 	return(0);
 }
 
@@ -780,6 +783,7 @@
 	else
         	*chainptr=ftmp;
 	restore_flags(flags);
+	MOD_INC_USE_COUNT;
 	return(0);
 }
 
@@ -853,9 +857,10 @@
 		 }
 	}
 	restore_flags(flags);
-	if (was_found)
+	if (was_found) {
+		MOD_DEC_USE_COUNT;
 		return 0;
-	else
+	} else
 		return(EINVAL);
 }
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ipt_LOG.c linux/net/ipv4/netfilter/ipt_LOG.c
--- v2.5.2/linux/net/ipv4/netfilter/ipt_LOG.c	Mon Nov  5 09:53:07 2001
+++ linux/net/ipv4/netfilter/ipt_LOG.c	Wed Jan 23 15:28:40 2002
@@ -217,7 +217,7 @@
 				printk("[");
 				dump_packet(info,
 					    (struct iphdr *)(icmph + 1),
-					    datalen-sizeof(struct iphdr),
+					    datalen-sizeof(struct icmphdr),
 					    0);
 				printk("] ");
 			}
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ipt_REDIRECT.c linux/net/ipv4/netfilter/ipt_REDIRECT.c
--- v2.5.2/linux/net/ipv4/netfilter/ipt_REDIRECT.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ipt_REDIRECT.c	Wed Jan 23 15:28:40 2002
@@ -74,10 +74,17 @@
 	/* Local packets: make them go to loopback */
 	if (hooknum == NF_IP_LOCAL_OUT)
 		newdst = htonl(0x7F000001);
-	else
+	else {
+		struct in_device *indev;
+
+		/* Device might not have an associated in_device. */
+		indev = (struct in_device *)(*pskb)->dev->ip_ptr;
+		if (indev == NULL)
+			return NF_DROP;
+
 		/* Grab first address on interface. */
-		newdst = (((struct in_device *)(*pskb)->dev->ip_ptr)
-			  ->ifa_list->ifa_local);
+		newdst = indev->ifa_list->ifa_local;
+	}
 
 	/* Transfer from original range. */
 	newrange = ((struct ip_nat_multi_range)
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ipt_ULOG.c linux/net/ipv4/netfilter/ipt_ULOG.c
--- v2.5.2/linux/net/ipv4/netfilter/ipt_ULOG.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/ipt_ULOG.c	Wed Jan 23 15:28:40 2002
@@ -0,0 +1,349 @@
+/*
+ * netfilter module for userspace packet logging daemons
+ *
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 2000/09/22 ulog-cprange feature added
+ * 2001/01/04 in-kernel queue as proposed by Sebastian Zander 
+ * 						<zander@fokus.gmd.de>
+ * 2001/01/30 per-rule nlgroup conflicts with global queue. 
+ *            nlgroup now global (sysctl)
+ * 2001/04/19 ulog-queue reworked, now fixed buffer size specified at
+ * 	      module loadtime -HW
+ *
+ * Released under the terms of the GPL
+ *
+ * This module accepts two parameters: 
+ * 
+ * nlbufsiz:
+ *   The parameter specifies how big the buffer for each netlink multicast
+ * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will
+ * get accumulated in the kernel until they are sent to userspace. It is
+ * NOT possible to allocate more than 128kB, and it is strongly discouraged,
+ * because atomically allocating 128kB inside the network rx softirq is not
+ * reliable. Please also keep in mind that this buffer size is allocated for
+ * each nlgroup you are using, so the total kernel memory usage increases
+ * by that factor.
+ *
+ * flushtimeout:
+ *   Specify, after how many clock ticks (intel: 100 per second) the queue
+ * should be flushed even if it is not full yet.
+ *
+ * ipt_ULOG.c,v 1.15 2002/01/18 21:33:19 laforge Exp
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/netlink.h>
+#include <linux/netdevice.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_ULOG.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <net/sock.h>
+
+MODULE_LICENSE("GPL");
+
+#define ULOG_NL_EVENT		111		/* Harald's favorite number */
+#define ULOG_MAXNLGROUPS	32		/* numer of nlgroups */
+
+#if 0
+#define DEBUGP(format, args...)	printk(__FILE__ ":" __FUNCTION__ ":" \
+				       format, ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0);
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables userspace logging module");
+
+
+static unsigned int nlbufsiz = 4096;
+MODULE_PARM(nlbufsiz, "i");
+MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
+
+static unsigned int flushtimeout = 10 * HZ;
+MODULE_PARM(flushtimeout, "i");
+MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
+
+/* global data structures */
+
+typedef struct {
+	unsigned int qlen;		/* number of nlmsgs' in the skb */
+	struct nlmsghdr *lastnlh;	/* netlink header of last msg in skb */
+	struct sk_buff *skb;		/* the pre-allocated skb */
+	struct timer_list timer;	/* the timer function */
+} ulog_buff_t;
+
+static ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS];	/* array of buffers */
+
+static struct sock *nflognl;	/* our socket */
+static size_t qlen;		/* current length of multipart-nlmsg */
+DECLARE_LOCK(ulog_lock);	/* spinlock */
+
+/* send one ulog_buff_t to userspace */
+static void ulog_send(unsigned int nlgroup)
+{
+	ulog_buff_t *ub = &ulog_buffers[nlgroup];
+
+	if (timer_pending(&ub->timer)) {
+		DEBUGP("ipt_ULOG: ulog_send: timer was pending, deleting\n");
+		del_timer(&ub->timer);
+	}
+
+	/* last nlmsg needs NLMSG_DONE */
+	if (ub->qlen > 1)
+		ub->lastnlh->nlmsg_type = NLMSG_DONE;
+
+	NETLINK_CB(ub->skb).dst_groups = nlgroup;
+	DEBUGP("ipt_ULOG: throwing %d packets to netlink mask %u\n",
+		ub->qlen, nlgroup);
+	netlink_broadcast(nflognl, ub->skb, 0, nlgroup, GFP_ATOMIC);
+
+	ub->qlen = 0;
+	ub->skb = NULL;
+	ub->lastnlh = NULL;
+
+}
+
+
+/* timer function to flush queue in ULOG_FLUSH_INTERVAL time */
+static void ulog_timer(unsigned long data)
+{
+	DEBUGP("ipt_ULOG: timer function called, calling ulog_send\n");
+
+	/* lock to protect against somebody modifying our structure
+	 * from ipt_ulog_target at the same time */
+	LOCK_BH(&ulog_lock);
+	ulog_send(data);
+	UNLOCK_BH(&ulog_lock);
+}
+
+static void nflog_rcv(struct sock *sk, int len)
+{
+	printk("ipt_ULOG:nflog_rcv() did receive netlink message ?!?\n");
+}
+
+struct sk_buff *ulog_alloc_skb(unsigned int size)
+{
+	struct sk_buff *skb;
+
+	/* alloc skb which should be big enough for a whole
+	 * multipart message. WARNING: has to be <= 131000
+	 * due to slab allocator restrictions */
+
+	skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
+	if (!skb) {
+		PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n",
+			nlbufsiz);
+
+		/* try to allocate only as much as we need for 
+		 * current packet */
+
+		skb = alloc_skb(size, GFP_ATOMIC);
+		if (!skb)
+			PRINTR("ipt_ULOG: can't even allocate %ub\n", size);
+	}
+
+	return skb;
+}
+
+static unsigned int ipt_ulog_target(struct sk_buff **pskb,
+				    unsigned int hooknum,
+				    const struct net_device *in,
+				    const struct net_device *out,
+				    const void *targinfo, void *userinfo)
+{
+	ulog_buff_t *ub;
+	ulog_packet_msg_t *pm;
+	size_t size, copy_len;
+	struct nlmsghdr *nlh;
+	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+
+	/* calculate the size of the skb needed */
+	if ((loginfo->copy_range == 0) ||
+	    (loginfo->copy_range > (*pskb)->len)) {
+		copy_len = (*pskb)->len;
+	} else {
+		copy_len = loginfo->copy_range;
+	}
+
+	size = NLMSG_SPACE(sizeof(*pm) + copy_len);
+
+	ub = &ulog_buffers[loginfo->nl_group];
+	
+	LOCK_BH(&ulog_lock);
+
+	if (!ub->skb) {
+		if (!(ub->skb = ulog_alloc_skb(size)))
+			goto alloc_failure;
+	} else if (ub->qlen >= loginfo->qthreshold ||
+		   size > skb_tailroom(ub->skb)) {
+		/* either the queue len is too high or we don't have 
+		 * enough room in nlskb left. send it to userspace. */
+
+		ulog_send(loginfo->nl_group);
+
+		if (!(ub->skb = ulog_alloc_skb(size)))
+			goto alloc_failure;
+	}
+
+	DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, 
+		loginfo->qthreshold);
+
+	/* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
+	nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, 
+			size - sizeof(*nlh));
+	ub->qlen++;
+
+	pm = NLMSG_DATA(nlh);
+
+	/* copy hook, prefix, timestamp, payload, etc. */
+	pm->data_len = copy_len;
+	pm->timestamp_sec = (*pskb)->stamp.tv_sec;
+	pm->timestamp_usec = (*pskb)->stamp.tv_usec;
+	pm->mark = (*pskb)->nfmark;
+	pm->hook = hooknum;
+	if (loginfo->prefix[0] != '\0')
+		strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
+	else
+		*(pm->prefix) = '\0';
+
+	if (in && in->hard_header_len > 0
+	    && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
+	    && in->hard_header_len <= ULOG_MAC_LEN) {
+		memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
+		pm->mac_len = in->hard_header_len;
+	}
+
+	if (in)
+		strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
+	else
+		pm->indev_name[0] = '\0';
+
+	if (out)
+		strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
+	else
+		pm->outdev_name[0] = '\0';
+
+	if (copy_len)
+		memcpy(pm->payload, (*pskb)->data, copy_len);
+	
+	/* check if we are building multi-part messages */
+	if (ub->qlen > 1) {
+		ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
+	}
+
+	/* if threshold is reached, send message to userspace */
+	if (qlen >= loginfo->qthreshold) {
+		if (loginfo->qthreshold > 1)
+			nlh->nlmsg_type = NLMSG_DONE;
+	}
+
+	ub->lastnlh = nlh;
+
+	/* if timer isn't already running, start it */
+	if (!timer_pending(&ub->timer)) {
+		ub->timer.expires = jiffies + flushtimeout;
+		add_timer(&ub->timer);
+	}
+
+	UNLOCK_BH(&ulog_lock);
+
+	return IPT_CONTINUE;
+
+
+nlmsg_failure:
+	PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
+
+alloc_failure:
+	PRINTR("ipt_ULOG: Error building netlink message\n");
+
+	UNLOCK_BH(&ulog_lock);
+
+	return IPT_CONTINUE;
+}
+
+static int ipt_ulog_checkentry(const char *tablename,
+			       const struct ipt_entry *e,
+			       void *targinfo,
+			       unsigned int targinfosize,
+			       unsigned int hookmask)
+{
+	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) {
+		DEBUGP("ipt_ULOG: targinfosize %u != 0\n", targinfosize);
+		return 0;
+	}
+
+	if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
+		DEBUGP("ipt_ULOG: prefix term %i\n",
+		       loginfo->prefix[sizeof(loginfo->prefix) - 1]);
+		return 0;
+	}
+
+	if (loginfo->qthreshold > ULOG_MAX_QLEN) {
+		DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n",
+			loginfo->qthreshold);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_ulog_reg =
+    { {NULL, NULL}, "ULOG", ipt_ulog_target, ipt_ulog_checkentry, NULL,
+THIS_MODULE
+};
+
+static int __init init(void)
+{
+	int i;
+
+	DEBUGP("ipt_ULOG: init module\n");
+
+	if (nlbufsiz >= 128*1024) {
+		printk("Netlink buffer has to be <= 128kB\n");
+		return -EINVAL;
+	}
+
+	/* initialize ulog_buffers */
+	for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
+		memset(&ulog_buffers[i], 0, sizeof(ulog_buff_t));
+		init_timer(&ulog_buffers[i].timer);
+		ulog_buffers[i].timer.function = ulog_timer;
+		ulog_buffers[i].timer.data = i;
+	}
+
+	nflognl = netlink_kernel_create(NETLINK_NFLOG, nflog_rcv);
+	if (!nflognl)
+		return -ENOMEM;
+
+	if (ipt_register_target(&ipt_ulog_reg) != 0) {
+		sock_release(nflognl->socket);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	DEBUGP("ipt_ULOG: cleanup_module\n");
+
+	ipt_unregister_target(&ipt_ulog_reg);
+	sock_release(nflognl->socket);
+}
+
+module_init(init);
+module_exit(fini);
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ipt_ah.c linux/net/ipv4/netfilter/ipt_ah.c
--- v2.5.2/linux/net/ipv4/netfilter/ipt_ah.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/ipt_ah.c	Wed Jan 23 15:28:40 2002
@@ -0,0 +1,105 @@
+/* Kernel module to match AH parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_ah.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG_CONNTRACK
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+struct ahhdr {
+	__u32   spi;
+};
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+	int r=0;
+        duprintf("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+        	min,spi,max);
+	r=(spi >= min && spi <= max) ^ invert;
+	duprintf(" result %s\n",r? "PASS" : "FAILED");
+	return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ahhdr *ah = hdr;
+	const struct ipt_ah *ahinfo = matchinfo;
+
+	if (offset == 0 && datalen < sizeof(struct ahhdr)) {
+		/* We've been asked to examine this packet, and we
+		   can't.  Hence, no choice but to drop. */
+		duprintf("Dropping evil AH tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	/* Must not be a fragment. */
+	return !offset
+		&& spi_match(ahinfo->spis[0], ahinfo->spis[1],
+			      ntohl(ah->spi),
+			      !!(ahinfo->invflags & IPT_AH_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+	   const struct ipt_ip *ip,
+	   void *matchinfo,
+	   unsigned int matchinfosize,
+	   unsigned int hook_mask)
+{
+	const struct ipt_ah *ahinfo = matchinfo;
+
+	/* Must specify proto == AH, and no unknown invflags */
+	if (ip->proto != IPPROTO_AH || (ip->invflags & IPT_INV_PROTO)) {
+		duprintf("ipt_ah: Protocol %u != %u\n", ip->proto,
+			 IPPROTO_AH);
+		return 0;
+	}
+	if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_ah))) {
+		duprintf("ipt_ah: matchsize %u != %u\n",
+			 matchinfosize, IPT_ALIGN(sizeof(struct ipt_ah)));
+		return 0;
+	}
+	if (ahinfo->invflags & ~IPT_AH_INV_MASK) {
+		duprintf("ipt_ah: unknown flags %X\n",
+			 ahinfo->invflags);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_match ah_match
+= { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
+
+int __init init(void)
+{
+	return ipt_register_match(&ah_match);
+}
+
+void __exit cleanup(void)
+{
+	ipt_unregister_match(&ah_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ipt_esp.c linux/net/ipv4/netfilter/ipt_esp.c
--- v2.5.2/linux/net/ipv4/netfilter/ipt_esp.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/ipt_esp.c	Wed Jan 23 15:28:40 2002
@@ -0,0 +1,105 @@
+/* Kernel module to match ESP parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_esp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG_CONNTRACK
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+struct esphdr {
+	__u32   spi;
+};
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+	int r=0;
+        duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+        	min,spi,max);
+	r=(spi >= min && spi <= max) ^ invert;
+	duprintf(" result %s\n",r? "PASS" : "FAILED");
+	return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct esphdr *esp = hdr;
+	const struct ipt_esp *espinfo = matchinfo;
+
+	if (offset == 0 && datalen < sizeof(struct esphdr)) {
+		/* We've been asked to examine this packet, and we
+		   can't.  Hence, no choice but to drop. */
+		duprintf("Dropping evil ESP tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	/* Must not be a fragment. */
+	return !offset
+		&& spi_match(espinfo->spis[0], espinfo->spis[1],
+			      ntohl(esp->spi),
+			      !!(espinfo->invflags & IPT_ESP_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+	   const struct ipt_ip *ip,
+	   void *matchinfo,
+	   unsigned int matchinfosize,
+	   unsigned int hook_mask)
+{
+	const struct ipt_esp *espinfo = matchinfo;
+
+	/* Must specify proto == ESP, and no unknown invflags */
+	if (ip->proto != IPPROTO_ESP || (ip->invflags & IPT_INV_PROTO)) {
+		duprintf("ipt_esp: Protocol %u != %u\n", ip->proto,
+			 IPPROTO_ESP);
+		return 0;
+	}
+	if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_esp))) {
+		duprintf("ipt_esp: matchsize %u != %u\n",
+			 matchinfosize, IPT_ALIGN(sizeof(struct ipt_esp)));
+		return 0;
+	}
+	if (espinfo->invflags & ~IPT_ESP_INV_MASK) {
+		duprintf("ipt_esp: unknown flags %X\n",
+			 espinfo->invflags);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_match esp_match
+= { { NULL, NULL }, "esp", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&esp_match);
+}
+
+static void __exit cleanup(void)
+{
+	ipt_unregister_match(&esp_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/iptable_filter.c linux/net/ipv4/netfilter/iptable_filter.c
--- v2.5.2/linux/net/ipv4/netfilter/iptable_filter.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/iptable_filter.c	Wed Jan 23 15:28:40 2002
@@ -83,7 +83,7 @@
 
 static struct ipt_table packet_filter
 = { { NULL, NULL }, "filter", &initial_table.repl,
-    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/iptable_mangle.c linux/net/ipv4/netfilter/iptable_mangle.c
--- v2.5.2/linux/net/ipv4/netfilter/iptable_mangle.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/iptable_mangle.c	Thu Jan 24 22:05:04 2002
@@ -2,6 +2,8 @@
  * This is the 1999 rewrite of IP Firewalling, aiming for kernel 2.3.x.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ *
+ * Extended to all five netfilter hooks by Brad Chapman & Harald Welte
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -12,7 +14,11 @@
 #include <net/route.h>
 #include <linux/ip.h>
 
-#define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
+#define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | \
+			    (1 << NF_IP_LOCAL_IN) | \
+			    (1 << NF_IP_FORWARD) | \
+			    (1 << NF_IP_LOCAL_OUT) | \
+			    (1 << NF_IP_POST_ROUTING))
 
 /* Standard entry. */
 struct ipt_standard
@@ -33,18 +39,25 @@
 	struct ipt_error_target target;
 };
 
+/* Ouch - five different hooks? Maybe this should be a config option..... -- BC */
 static struct
 {
 	struct ipt_replace repl;
-	struct ipt_standard entries[2];
+	struct ipt_standard entries[5];
 	struct ipt_error term;
 } initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 3,
-      sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
-      { [NF_IP_PRE_ROUTING] 0,
-	[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
-      { [NF_IP_PRE_ROUTING] 0,
-	[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
+= { { "mangle", MANGLE_VALID_HOOKS, 6,
+      sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
+      { [NF_IP_PRE_ROUTING] 	0,
+	[NF_IP_LOCAL_IN] 	sizeof(struct ipt_standard),
+	[NF_IP_FORWARD] 	sizeof(struct ipt_standard) * 2,
+	[NF_IP_LOCAL_OUT] 	sizeof(struct ipt_standard) * 3,
+	[NF_IP_POST_ROUTING] 	sizeof(struct ipt_standard) * 4 },
+      { [NF_IP_PRE_ROUTING] 	0,
+	[NF_IP_LOCAL_IN] 	sizeof(struct ipt_standard),
+	[NF_IP_FORWARD] 	sizeof(struct ipt_standard) * 2,
+	[NF_IP_LOCAL_OUT] 	sizeof(struct ipt_standard) * 3,
+	[NF_IP_POST_ROUTING]	sizeof(struct ipt_standard) * 4 },
       0, NULL, { } },
     {
 	    /* PRE_ROUTING */
@@ -55,6 +68,22 @@
 		0, { 0, 0 }, { } },
 	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
 		-NF_ACCEPT - 1 } },
+	    /* LOCAL_IN */
+ 	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* FORWARD */
+ 	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
 	    /* LOCAL_OUT */
 	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
 		0,
@@ -62,7 +91,15 @@
 		sizeof(struct ipt_standard),
 		0, { 0, 0 }, { } },
 	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } }
+		-NF_ACCEPT - 1 } },
+	    /* POST_ROUTING */
+	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
     },
     /* ERROR */
     { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
@@ -79,11 +116,11 @@
 
 static struct ipt_table packet_mangler
 = { { NULL, NULL }, "mangle", &initial_table.repl,
-    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
-ipt_hook(unsigned int hook,
+ipt_route_hook(unsigned int hook,
 	 struct sk_buff **pskb,
 	 const struct net_device *in,
 	 const struct net_device *out,
@@ -92,36 +129,8 @@
 	return ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
 }
 
-/* FIXME: change in oif may mean change in hh_len.  Check and realloc
-   --RR */
-static int
-route_me_harder(struct sk_buff *skb)
-{
-	struct iphdr *iph = skb->nh.iph;
-	struct rtable *rt;
-	struct rt_key key = { dst:iph->daddr,
-			      src:iph->saddr,
-			      oif:skb->sk ? skb->sk->bound_dev_if : 0,
-			      tos:RT_TOS(iph->tos)|RTO_CONN,
-#ifdef CONFIG_IP_ROUTE_FWMARK
-			      fwmark:skb->nfmark
-#endif
-			    };
-
-	if (ip_route_output_key(&rt, &key) != 0) {
-		printk("route_me_harder: No more route.\n");
-		return -EINVAL;
-	}
-
-	/* Drop old route. */
-	dst_release(skb->dst);
-
-	skb->dst = &rt->u.dst;
-	return 0;
-}
-
 static unsigned int
-ipt_local_out_hook(unsigned int hook,
+ipt_local_hook(unsigned int hook,
 		   struct sk_buff **pskb,
 		   const struct net_device *in,
 		   const struct net_device *out,
@@ -153,15 +162,22 @@
 		|| (*pskb)->nh.iph->daddr != daddr
 		|| (*pskb)->nfmark != nfmark
 		|| (*pskb)->nh.iph->tos != tos))
-		return route_me_harder(*pskb) == 0 ? ret : NF_DROP;
+		return route_me_harder(pskb) == 0 ? ret : NF_DROP;
 
 	return ret;
 }
 
 static struct nf_hook_ops ipt_ops[]
-= { { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_MANGLE },
-    { { NULL, NULL }, ipt_local_out_hook, PF_INET, NF_IP_LOCAL_OUT,
-		NF_IP_PRI_MANGLE }
+= { { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_PRE_ROUTING, 
+	NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_IN,
+	NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_FORWARD,
+	NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_OUT,
+	NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_POST_ROUTING,
+	NF_IP_PRI_MANGLE }
 };
 
 static int __init init(void)
@@ -182,8 +198,26 @@
 	if (ret < 0)
 		goto cleanup_hook0;
 
+	ret = nf_register_hook(&ipt_ops[2]);
+	if (ret < 0)
+		goto cleanup_hook1;
+
+	ret = nf_register_hook(&ipt_ops[3]);
+	if (ret < 0)
+		goto cleanup_hook2;
+
+	ret = nf_register_hook(&ipt_ops[4]);
+	if (ret < 0)
+		goto cleanup_hook3;
+
 	return ret;
 
+ cleanup_hook3:
+        nf_unregister_hook(&ipt_ops[3]);
+ cleanup_hook2:
+        nf_unregister_hook(&ipt_ops[2]);
+ cleanup_hook1:
+	nf_unregister_hook(&ipt_ops[1]);
  cleanup_hook0:
 	nf_unregister_hook(&ipt_ops[0]);
  cleanup_table:
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.5.2/linux/net/ipv4/route.c	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/route.c	Tue Jan 15 10:56:35 2002
@@ -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.103 2002/01/12 07:44:09 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -214,7 +214,7 @@
 {
 	int len = 0;
 	off_t pos = 128;
-	char temp[129];
+	char temp[256];
 	struct rtable *r;
 	int i;
 
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.5.2/linux/net/ipv4/tcp.c	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/tcp.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/tcp_diag.c linux/net/ipv4/tcp_diag.c
--- v2.5.2/linux/net/ipv4/tcp_diag.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/tcp_diag.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.5.2/linux/net/ipv4/tcp_input.c	Tue Dec 18 14:56:41 2001
+++ linux/net/ipv4/tcp_input.c	Tue Jan 15 10:56:35 2002
@@ -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.242 2001/12/11 06:11:53 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.5.2/linux/net/ipv4/tcp_ipv4.c	Mon Nov  5 09:46:12 2001
+++ linux/net/ipv4/tcp_ipv4.c	Mon Jan 28 13:20:44 2002
@@ -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.238 2002/01/15 08:49:21 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -69,8 +69,7 @@
 #define ICMP_MIN_LENGTH 8
 
 /* Socket used for sending RSTs */ 	
-static struct inode tcp_inode;
-static struct socket *tcp_socket=&tcp_inode.u.socket_i;
+static struct socket *tcp_socket;
 
 void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len, 
 		       struct sk_buff *skb);
@@ -754,21 +753,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 +936,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 +1472,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);
 
@@ -2061,7 +2063,7 @@
 	/* First, walk listening socket table. */
 	tcp_listen_lock();
 	for(i = 0; i < TCP_LHTABLE_SIZE; i++) {
-		struct sock *sk = tcp_listening_hash[i];
+		struct sock *sk;
 		struct tcp_listen_opt *lopt;
 		int k;
 
@@ -2191,20 +2193,8 @@
 
 void __init tcp_v4_init(struct net_proto_family *ops)
 {
-	int err;
-
-	tcp_inode.i_mode = S_IFSOCK;
-	tcp_inode.i_sock = 1;
-	tcp_inode.i_uid = 0;
-	tcp_inode.i_gid = 0;
-	init_waitqueue_head(&tcp_inode.i_wait);
-	init_waitqueue_head(&tcp_inode.u.socket_i.wait);
-
-	tcp_socket->inode = &tcp_inode;
-	tcp_socket->state = SS_UNCONNECTED;
-	tcp_socket->type=SOCK_RAW;
-
-	if ((err=ops->create(tcp_socket, IPPROTO_TCP))<0)
+	int err = sock_create(PF_INET, SOCK_RAW, IPPROTO_TCP, &tcp_socket);
+	if (err < 0)
 		panic("Failed to create the TCP control socket.\n");
 	tcp_socket->sk->allocation=GFP_ATOMIC;
 	tcp_socket->sk->protinfo.af_inet.ttl = MAXTTL;
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.5.2/linux/net/ipv4/tcp_output.c	Mon Jan 14 18:25:11 2002
+++ linux/net/ipv4/tcp_output.c	Tue Jan 15 10:56:35 2002
@@ -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.145 2002/01/11 08:45:37 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.5.2/linux/net/ipv4/udp.c	Wed Oct 17 14:16:39 2001
+++ linux/net/ipv4/udp.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.100 2001/10/15 12:34:50 davem Exp $
+ * Version:	$Id: udp.c,v 1.101 2002/01/12 07:39:45 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -886,6 +886,9 @@
 	/*
 	 *	Validate the packet and the UDP length.
 	 */
+	if (!pskb_may_pull(skb, sizeof(struct udphdr)))
+		goto no_header;
+
 	ulen = ntohs(skb->h.uh->len);
 
 	if (ulen > len || ulen < sizeof(*uh))
@@ -926,6 +929,7 @@
 
 short_packet:
 	NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len));
+no_header:
 	UDP_INC_STATS_BH(UdpInErrors);
 	kfree_skb(skb);
 	return(0);
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/Config.in linux/net/ipv6/Config.in
--- v2.5.2/linux/net/ipv6/Config.in	Wed May 16 10:31:27 2001
+++ linux/net/ipv6/Config.in	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- v2.5.2/linux/net/ipv6/addrconf.c	Fri Sep  7 11:01:21 2001
+++ linux/net/ipv6/addrconf.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c
--- v2.5.2/linux/net/ipv6/ip6_fib.c	Thu Jun 14 14:16:58 2001
+++ linux/net/ipv6/ip6_fib.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv6/ip6_fw.c linux/net/ipv6/ip6_fw.c
--- v2.5.2/linux/net/ipv6/ip6_fw.c	Tue Aug 31 11:23:03 1999
+++ linux/net/ipv6/ip6_fw.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c
--- v2.5.2/linux/net/ipv6/ndisc.c	Mon Sep 10 07:57:00 2001
+++ linux/net/ipv6/ndisc.c	Wed Jan 23 15:28:40 2002
@@ -957,6 +957,7 @@
 	struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
 	struct neighbour *neigh;
 	struct inet6_ifaddr *ifp;
+	unsigned int payload_len;
 
 	__skb_push(skb, skb->data-skb->h.raw);
 
@@ -979,10 +980,11 @@
 	 *	(Some checking in ndisc_find_option)
 	 */
 
+	payload_len = ntohs(skb->nh.ipv6h->payload_len);
 	switch (msg->icmph.icmp6_type) {
 	case NDISC_NEIGHBOUR_SOLICITATION:
 		/* XXX: import nd_neighbor_solicit from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 8+16) {
+		if (payload_len < 8+16) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP NS: packet too short\n");
 			return 0;
@@ -1112,7 +1114,7 @@
 
 	case NDISC_NEIGHBOUR_ADVERTISEMENT:
 		/* XXX: import nd_neighbor_advert from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 16+8 ) {
+		if (payload_len < 16+8 ) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP NA: packet too short\n");
 			return 0;
@@ -1174,7 +1176,7 @@
 
 	case NDISC_ROUTER_ADVERTISEMENT:
 		/* XXX: import nd_router_advert from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 8+4+4) {
+		if (payload_len < 8+4+4) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP RA: packet too short\n");
 			return 0;
@@ -1184,7 +1186,7 @@
 
 	case NDISC_REDIRECT:
 		/* XXX: import nd_redirect from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 8+16+16) {
+		if (payload_len < 8+16+16) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP redirect: packet too short\n");
 			return 0;
@@ -1196,7 +1198,7 @@
 		/* No RS support in the kernel, but we do some required checks */
 
 		/* XXX: import nd_router_solicit from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 8) {
+		if (payload_len < 8) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP RS: packet too short\n");
 			return 0;
@@ -1207,81 +1209,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 +1246,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 +1255,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 -u --recursive --new-file v2.5.2/linux/net/ipv6/netfilter/Config.help linux/net/ipv6/netfilter/Config.help
--- v2.5.2/linux/net/ipv6/netfilter/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv6/netfilter/Config.help	Fri Jan 25 16:03:23 2002
@@ -0,0 +1,97 @@
+CONFIG_IP6_NF_MATCH_MAC
+  mac matching allows you to match packets based on the source
+  Ethernet address of the packet.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP6_NF_MATCH_MARK
+  Netfilter mark matching allows you to match packets based on the
+  `nfmark' value in the packet.  This can be set by the MARK target
+  (see below).
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+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'.
+
+CONFIG_IP6_NF_QUEUE
+
+  This option adds a queue handler to the kernel for IPv6
+  packets which lets us to receive the filtered packets
+  with QUEUE target using libiptc as we can do with
+  the IPv4 now.
+
+  (C) Fernando Anton 2001
+  IPv64 Project - Work based in IPv64 draft by Arturo Azcorra.
+  Universidad Carlos III de Madrid
+  Universidad Politecnica de Alcala de Henares
+  email: fanton@it.uc3m.es
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. If unsure, say `N'.
+
+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'.
+
+CONFIG_IP6_NF_FILTER
+  Packet filtering defines a table `filter', which has a series of
+  rules for simple packet filtering at local input, forwarding and
+  local output.  See the man page for iptables(8).
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP6_NF_MANGLE
+  This option adds a `mangle' table to iptables: see the man page for
+  iptables(8).  This table is used for various packet alterations
+  which can effect how the packet is routed.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP6_NF_TARGET_MARK
+  This option adds a `MARK' target, which allows you to create rules
+  in the `mangle' table which alter the netfilter mark (nfmark) field
+  associated with the packet packet prior to routing. This can change
+  the routing method (see `Use netfilter MARK value as routing
+  key') and can also be used by other subsystems to change their
+  behavior.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP6_NF_IPTABLES
+  ip6tables is a general, extensible packet identification framework.
+  Currently only the packet filtering and packet mangling subsystem
+  for IPv6 use this, but connection tracking is going to follow.
+  Say 'Y' or 'M' here if you want to use either of those.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_IP6_NF_MATCH_LIMIT
+  limit matching allows you to control the rate at which a rule can be
+  matched: mainly useful in combination with the LOG target ("LOG
+  target support", below) and to avoid some Denial of Service attacks.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+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'.
+
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/netfilter/Config.in linux/net/ipv6/netfilter/Config.in
--- v2.5.2/linux/net/ipv6/netfilter/Config.in	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv6/netfilter/Config.in	Wed Jan 23 15:28:40 2002
@@ -9,9 +9,10 @@
 #  dep_tristate '  FTP protocol support' CONFIG_IP6_NF_FTP $CONFIG_IP6_NF_CONNTRACK
 #fi
 
-#if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NETLINK" = "y" ]; then
-#  tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP6_NF_QUEUE
-#fi
+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
 if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then
 # The simple matches.
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/netfilter/Makefile linux/net/ipv6/netfilter/Makefile
--- v2.5.2/linux/net/ipv6/netfilter/Makefile	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv6/netfilter/Makefile	Wed Jan 23 15:28:40 2002
@@ -21,6 +21,7 @@
 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
+obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/netfilter/ip6_queue.c linux/net/ipv6/netfilter/ip6_queue.c
--- v2.5.2/linux/net/ipv6/netfilter/ip6_queue.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv6/netfilter/ip6_queue.c	Wed Jan 23 15:28:40 2002
@@ -0,0 +1,721 @@
+/*
+ * This is a module which is used for queueing IPv6 packets and
+ * communicating with userspace via netlink.
+ *
+ * (C) 2001 Fernando Anton, this code is GPL.
+ *     IPv64 Project - Work based in IPv64 draft by Arturo Azcorra.
+ *     Universidad Carlos III de Madrid - Leganes (Madrid) - Spain
+ *     Universidad Politecnica de Alcala de Henares - Alcala de H. (Madrid) - Spain
+ *     email: fanton@it.uc3m.es
+ *
+ * 2001-11-06: First try. Working with ip_queue.c for IPv4 and trying
+ *             to adapt it to IPv6
+ *             HEAVILY based in ipqueue.c by James Morris. It's just
+ *             a little modified version of it, so he's nearly the
+ *             real coder of this.
+ *             Few changes needed, mainly the hard_routing code and
+ *             the netlink socket protocol (we're NETLINK_IP6_FW).
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/ipv6.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/netlink.h>
+#include <linux/spinlock.h>
+#include <linux/rtnetlink.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+
+/* We're still usign the following structs. No need to change them: */
+/*   ipq_packet_msg                                                 */
+/*   ipq_mode_msg                                                   */
+/*   ipq_verdict_msg                                                */
+/*   ipq_peer_msg                                                   */
+#include <linux/netfilter_ipv4/ip_queue.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+#define IPQ_QMAX_DEFAULT 1024
+#define IPQ_PROC_FS_NAME "ip6_queue"
+#define NET_IPQ_QMAX 2088
+#define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
+
+typedef struct ip6q_rt_info {
+	struct in6_addr daddr;
+	struct in6_addr saddr;
+} ip6q_rt_info_t;
+
+typedef struct ip6q_queue_element {
+	struct list_head list;		/* Links element into queue */
+	int verdict;			/* Current verdict */
+	struct nf_info *info;		/* Extra info from netfilter */
+	struct sk_buff *skb;		/* Packet inside */
+	ip6q_rt_info_t rt_info;		/* May need post-mangle routing */
+} ip6q_queue_element_t;
+
+typedef int (*ip6q_send_cb_t)(ip6q_queue_element_t *e);
+
+typedef struct ip6q_peer {
+	pid_t pid;			/* PID of userland peer */
+	unsigned char died;		/* We think the peer died */
+	unsigned char copy_mode;	/* Copy packet as well as metadata? */
+	size_t copy_range;		/* Range past metadata to copy */
+	ip6q_send_cb_t send;		/* Callback for sending data to peer */
+} ip6q_peer_t;
+
+typedef struct ip6q_queue {
+ 	int len;			/* Current queue len */
+ 	int *maxlen;			/* Maximum queue len, via sysctl */
+ 	unsigned char flushing;		/* If queue is being flushed */
+ 	unsigned char terminate;	/* If the queue is being terminated */
+ 	struct list_head list;		/* Head of packet queue */
+ 	spinlock_t lock;		/* Queue spinlock */
+ 	ip6q_peer_t peer;		/* Userland peer */
+} ip6q_queue_t;
+
+/****************************************************************************
+ *
+ * Packet queue
+ *
+ ****************************************************************************/
+/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
+static ip6q_queue_element_t *
+ip6q_dequeue(ip6q_queue_t *q,
+            int (*cmp)(ip6q_queue_element_t *, unsigned long),
+            unsigned long data)
+{
+	struct list_head *i;
+
+	spin_lock_bh(&q->lock);
+	for (i = q->list.prev; i != &q->list; i = i->prev) {
+		ip6q_queue_element_t *e = (ip6q_queue_element_t *)i;
+		
+		if (!cmp || cmp(e, data)) {
+			list_del(&e->list);
+			q->len--;
+			spin_unlock_bh(&q->lock);
+			return e;
+		}
+	}
+	spin_unlock_bh(&q->lock);
+	return NULL;
+}
+
+/* Flush all packets */
+static void ip6q_flush(ip6q_queue_t *q)
+{
+	ip6q_queue_element_t *e;
+	
+	spin_lock_bh(&q->lock);
+	q->flushing = 1;
+	spin_unlock_bh(&q->lock);
+	while ((e = ip6q_dequeue(q, NULL, 0))) {
+		e->verdict = NF_DROP;
+		nf_reinject(e->skb, e->info, e->verdict);
+		kfree(e);
+	}
+	spin_lock_bh(&q->lock);
+	q->flushing = 0;
+	spin_unlock_bh(&q->lock);
+}
+
+static ip6q_queue_t *ip6q_create_queue(nf_queue_outfn_t outfn,
+                                     ip6q_send_cb_t send_cb,
+                                     int *errp, int *sysctl_qmax)
+{
+	int status;
+	ip6q_queue_t *q;
+
+	*errp = 0;
+	q = kmalloc(sizeof(ip6q_queue_t), GFP_KERNEL);
+	if (q == NULL) {
+		*errp = -ENOMEM;
+		return NULL;
+	}
+	q->peer.pid = 0;
+	q->peer.died = 0;
+	q->peer.copy_mode = IPQ_COPY_NONE;
+	q->peer.copy_range = 0;
+	q->peer.send = send_cb;
+	q->len = 0;
+	q->maxlen = sysctl_qmax;
+	q->flushing = 0;
+	q->terminate = 0;
+	INIT_LIST_HEAD(&q->list);
+	spin_lock_init(&q->lock);
+	status = nf_register_queue_handler(PF_INET6, outfn, q);
+	if (status < 0) {
+		*errp = -EBUSY;
+		kfree(q);
+		return NULL;
+	}
+	return q;
+}
+
+static int ip6q_enqueue(ip6q_queue_t *q,
+                       struct sk_buff *skb, struct nf_info *info)
+{
+	ip6q_queue_element_t *e;
+	int status;
+	
+	e = kmalloc(sizeof(*e), GFP_ATOMIC);
+	if (e == NULL) {
+		printk(KERN_ERR "ip6_queue: OOM in enqueue\n");
+		return -ENOMEM;
+	}
+
+	e->verdict = NF_DROP;
+	e->info = info;
+	e->skb = skb;
+
+	if (e->info->hook == NF_IP_LOCAL_OUT) {
+		struct ipv6hdr *iph = skb->nh.ipv6h;
+
+		e->rt_info.daddr = iph->daddr;
+		e->rt_info.saddr = iph->saddr;
+	}
+
+	spin_lock_bh(&q->lock);
+	if (q->len >= *q->maxlen) {
+		spin_unlock_bh(&q->lock);
+		if (net_ratelimit()) 
+			printk(KERN_WARNING "ip6_queue: full at %d entries, "
+			       "dropping packet(s).\n", q->len);
+		goto free_drop;
+	}
+	if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
+	    || q->peer.pid == 0 || q->peer.died || q->terminate) {
+		spin_unlock_bh(&q->lock);
+		goto free_drop;
+	}
+	status = q->peer.send(e);
+	if (status > 0) {
+		list_add(&e->list, &q->list);
+		q->len++;
+		spin_unlock_bh(&q->lock);
+		return status;
+	}
+	spin_unlock_bh(&q->lock);
+	if (status == -ECONNREFUSED) {
+		printk(KERN_INFO "ip6_queue: peer %d died, "
+		       "resetting state and flushing queue\n", q->peer.pid);
+			q->peer.died = 1;
+			q->peer.pid = 0;
+			q->peer.copy_mode = IPQ_COPY_NONE;
+			q->peer.copy_range = 0;
+			ip6q_flush(q);
+	}
+free_drop:
+	kfree(e);
+	return -EBUSY;
+}
+
+static void ip6q_destroy_queue(ip6q_queue_t *q)
+{
+	nf_unregister_queue_handler(PF_INET6);
+	spin_lock_bh(&q->lock);
+	q->terminate = 1;
+	spin_unlock_bh(&q->lock);
+	ip6q_flush(q);
+	kfree(q);
+}
+
+/*
+ * Taken from net/ipv6/ip6_output.c
+ *
+ * We should use the one there, but is defined static
+ * so we put this just here and let the things as
+ * they are now.
+ *
+ * If that one is modified, this one should be modified too.
+ */
+static int route6_me_harder(struct sk_buff *skb)
+{
+	struct ipv6hdr *iph = skb->nh.ipv6h;
+	struct dst_entry *dst;
+	struct flowi fl;
+
+	fl.proto = iph->nexthdr;
+	fl.fl6_dst = &iph->daddr;
+	fl.fl6_src = &iph->saddr;
+	fl.oif = skb->sk ? skb->sk->bound_dev_if : 0;
+	fl.fl6_flowlabel = 0;
+	fl.uli_u.ports.dport = 0;
+	fl.uli_u.ports.sport = 0;
+
+	dst = ip6_route_output(skb->sk, &fl);
+
+	if (dst->error) {
+		if (net_ratelimit())
+			printk(KERN_DEBUG "route6_me_harder: No more route.\n");
+		return -EINVAL;
+	}
+
+	/* Drop old route. */
+	dst_release(skb->dst);
+
+	skb->dst = dst;
+	return 0;
+}
+static int ip6q_mangle_ipv6(ipq_verdict_msg_t *v, ip6q_queue_element_t *e)
+{
+	int diff;
+	struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
+
+	if (v->data_len < sizeof(*user_iph))
+		return 0;
+	diff = v->data_len - e->skb->len;
+	if (diff < 0)
+		skb_trim(e->skb, v->data_len);
+	else if (diff > 0) {
+		if (v->data_len > 0xFFFF)
+			return -EINVAL;
+		if (diff > skb_tailroom(e->skb)) {
+			struct sk_buff *newskb;
+			
+			newskb = skb_copy_expand(e->skb,
+			                         skb_headroom(e->skb),
+			                         diff,
+			                         GFP_ATOMIC);
+			if (newskb == NULL) {
+				printk(KERN_WARNING "ip6_queue: OOM "
+				      "in mangle, dropping packet\n");
+				return -ENOMEM;
+			}
+			if (e->skb->sk)
+				skb_set_owner_w(newskb, e->skb->sk);
+			kfree_skb(e->skb);
+			e->skb = newskb;
+		}
+		skb_put(e->skb, diff);
+	}
+	memcpy(e->skb->data, v->payload, v->data_len);
+	e->skb->nfcache |= NFC_ALTERED;
+
+	/*
+	 * Extra routing may needed on local out, as the QUEUE target never
+	 * returns control to the table.
+         * Not a nice way to cmp, but works
+	 */
+	if (e->info->hook == NF_IP_LOCAL_OUT) {
+		struct ipv6hdr *iph = e->skb->nh.ipv6h;
+		if (!(   iph->daddr.in6_u.u6_addr32[0] == e->rt_info.daddr.in6_u.u6_addr32[0]
+                      && iph->daddr.in6_u.u6_addr32[1] == e->rt_info.daddr.in6_u.u6_addr32[1]
+                      && iph->daddr.in6_u.u6_addr32[2] == e->rt_info.daddr.in6_u.u6_addr32[2]
+                      && iph->daddr.in6_u.u6_addr32[3] == e->rt_info.daddr.in6_u.u6_addr32[3]
+		      && iph->saddr.in6_u.u6_addr32[0] == e->rt_info.saddr.in6_u.u6_addr32[0]
+		      && iph->saddr.in6_u.u6_addr32[1] == e->rt_info.saddr.in6_u.u6_addr32[1]
+		      && iph->saddr.in6_u.u6_addr32[2] == e->rt_info.saddr.in6_u.u6_addr32[2]
+		      && iph->saddr.in6_u.u6_addr32[3] == e->rt_info.saddr.in6_u.u6_addr32[3]))
+			return route6_me_harder(e->skb);
+	}
+	return 0;
+}
+
+static inline int id_cmp(ip6q_queue_element_t *e, unsigned long id)
+{
+	return (id == (unsigned long )e);
+}
+
+static int ip6q_set_verdict(ip6q_queue_t *q,
+                           ipq_verdict_msg_t *v, unsigned int len)
+{
+	ip6q_queue_element_t *e;
+
+	if (v->value > NF_MAX_VERDICT)
+		return -EINVAL;
+	e = ip6q_dequeue(q, id_cmp, v->id);
+	if (e == NULL)
+		return -ENOENT;
+	else {
+		e->verdict = v->value;
+		if (v->data_len && v->data_len == len)
+			if (ip6q_mangle_ipv6(v, e) < 0)
+				e->verdict = NF_DROP;
+		nf_reinject(e->skb, e->info, e->verdict);
+		kfree(e);
+		return 0;
+	}
+}
+
+static int ip6q_receive_peer(ip6q_queue_t* q, ipq_peer_msg_t *m,
+                            unsigned char type, unsigned int len)
+{
+
+	int status = 0;
+	int busy;
+		
+	spin_lock_bh(&q->lock);
+	busy = (q->terminate || q->flushing);
+	spin_unlock_bh(&q->lock);
+	if (busy)
+		return -EBUSY;
+	if (len < sizeof(ipq_peer_msg_t))
+		return -EINVAL;
+	switch (type) {
+		case IPQM_MODE:
+			switch (m->msg.mode.value) {
+				case IPQ_COPY_META:
+					q->peer.copy_mode = IPQ_COPY_META;
+					q->peer.copy_range = 0;
+					break;
+				case IPQ_COPY_PACKET:
+					q->peer.copy_mode = IPQ_COPY_PACKET;
+					q->peer.copy_range = m->msg.mode.range;
+					if (q->peer.copy_range > 0xFFFF)
+						q->peer.copy_range = 0xFFFF;
+					break;
+				default:
+					status = -EINVAL;
+			}
+			break;
+		case IPQM_VERDICT:
+			if (m->msg.verdict.value > NF_MAX_VERDICT)
+				status = -EINVAL;
+			else
+				status = ip6q_set_verdict(q,
+				                         &m->msg.verdict,
+				                         len - sizeof(*m));
+			break;
+		default:
+			 status = -EINVAL;
+	}
+	return status;
+}
+
+static inline int dev_cmp(ip6q_queue_element_t *e, unsigned long ifindex)
+{
+	if (e->info->indev)
+		if (e->info->indev->ifindex == ifindex)
+			return 1;
+	if (e->info->outdev)
+		if (e->info->outdev->ifindex == ifindex)
+			return 1;
+	return 0;
+}
+
+/* Drop any queued packets associated with device ifindex */
+static void ip6q_dev_drop(ip6q_queue_t *q, int ifindex)
+{
+	ip6q_queue_element_t *e;
+	
+	while ((e = ip6q_dequeue(q, dev_cmp, ifindex))) {
+		e->verdict = NF_DROP;
+		nf_reinject(e->skb, e->info, e->verdict);
+		kfree(e);
+	}
+}
+
+/****************************************************************************
+ *
+ * Netfilter interface
+ *
+ ****************************************************************************/
+
+/*
+ * Packets arrive here from netfilter for queuing to userspace.
+ * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
+ */
+static int netfilter6_receive(struct sk_buff *skb,
+                             struct nf_info *info, void *data)
+{
+	return ip6q_enqueue((ip6q_queue_t *)data, skb, info);
+}
+
+/****************************************************************************
+ *
+ * Netlink interface.
+ *
+ ****************************************************************************/
+
+static struct sock *nfnl = NULL;
+/* This is not a static one, so we should not repeat its name */
+ip6q_queue_t *nlq6 = NULL;
+
+static struct sk_buff *netlink_build_message(ip6q_queue_element_t *e, int *errp)
+{
+	unsigned char *old_tail;
+	size_t size = 0;
+	size_t data_len = 0;
+	struct sk_buff *skb;
+	ipq_packet_msg_t *pm;
+	struct nlmsghdr *nlh;
+
+	switch (nlq6->peer.copy_mode) {
+		size_t copy_range;
+
+		case IPQ_COPY_META:
+			size = NLMSG_SPACE(sizeof(*pm));
+			data_len = 0;
+			break;
+		case IPQ_COPY_PACKET:
+			copy_range = nlq6->peer.copy_range;
+			if (copy_range == 0 || copy_range > e->skb->len)
+				data_len = e->skb->len;
+			else
+				data_len = copy_range;
+			size = NLMSG_SPACE(sizeof(*pm) + data_len);
+			
+			break;
+		case IPQ_COPY_NONE:
+		default:
+			*errp = -EINVAL;
+			return NULL;
+	}
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		goto nlmsg_failure;
+	old_tail = skb->tail;
+	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
+	pm = NLMSG_DATA(nlh);
+	memset(pm, 0, sizeof(*pm));
+	pm->packet_id = (unsigned long )e;
+	pm->data_len = data_len;
+	pm->timestamp_sec = e->skb->stamp.tv_sec;
+	pm->timestamp_usec = e->skb->stamp.tv_usec;
+	pm->mark = e->skb->nfmark;
+	pm->hook = e->info->hook;
+	if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
+	else pm->indev_name[0] = '\0';
+	if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
+	else pm->outdev_name[0] = '\0';
+	pm->hw_protocol = e->skb->protocol;
+	if (e->info->indev && e->skb->dev) {
+		pm->hw_type = e->skb->dev->type;
+		if (e->skb->dev->hard_header_parse)
+			pm->hw_addrlen =
+				e->skb->dev->hard_header_parse(e->skb,
+				                               pm->hw_addr);
+	}
+	if (data_len)
+		memcpy(pm->payload, e->skb->data, data_len);
+	nlh->nlmsg_len = skb->tail - old_tail;
+	NETLINK_CB(skb).dst_groups = 0;
+	return skb;
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	*errp = 0;
+	printk(KERN_ERR "ip6_queue: error creating netlink message\n");
+	return NULL;
+}
+
+static int netlink_send_peer(ip6q_queue_element_t *e)
+{
+	int status = 0;
+	struct sk_buff *skb;
+
+	skb = netlink_build_message(e, &status);
+	if (skb == NULL)
+		return status;
+	return netlink_unicast(nfnl, skb, nlq6->peer.pid, MSG_DONTWAIT);
+}
+
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0);
+
+static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
+{
+	int status, type;
+	struct nlmsghdr *nlh;
+
+	if (skb->len < sizeof(struct nlmsghdr))
+		return;
+
+	nlh = (struct nlmsghdr *)skb->data;
+	if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
+	    || skb->len < nlh->nlmsg_len)
+	    	return;
+
+	if(nlh->nlmsg_pid <= 0
+	    || !(nlh->nlmsg_flags & NLM_F_REQUEST)
+	    || nlh->nlmsg_flags & NLM_F_MULTI)
+		RCV_SKB_FAIL(-EINVAL);
+	if (nlh->nlmsg_flags & MSG_TRUNC)
+		RCV_SKB_FAIL(-ECOMM);
+	type = nlh->nlmsg_type;
+	if (type < NLMSG_NOOP || type >= IPQM_MAX)
+		RCV_SKB_FAIL(-EINVAL);
+	if (type <= IPQM_BASE)
+		return;
+	if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+		RCV_SKB_FAIL(-EPERM);
+	if (nlq6->peer.pid && !nlq6->peer.died
+	    && (nlq6->peer.pid != nlh->nlmsg_pid)) {
+	    	printk(KERN_WARNING "ip6_queue: peer pid changed from %d to "
+	    	      "%d, flushing queue\n", nlq6->peer.pid, nlh->nlmsg_pid);
+		ip6q_flush(nlq6);
+	}	
+	nlq6->peer.pid = nlh->nlmsg_pid;
+	nlq6->peer.died = 0;
+	status = ip6q_receive_peer(nlq6, NLMSG_DATA(nlh),
+	                          type, skb->len - NLMSG_LENGTH(0));
+	if (status < 0)
+		RCV_SKB_FAIL(status);
+	if (nlh->nlmsg_flags & NLM_F_ACK)
+		netlink_ack(skb, nlh, 0);
+        return;
+}
+
+/* Note: we are only dealing with single part messages at the moment. */
+static void netlink_receive_user_sk(struct sock *sk, int len)
+{
+	do {
+		struct sk_buff *skb;
+
+		if (rtnl_shlock_nowait())
+			return;
+		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+			netlink_receive_user_skb(skb);
+			kfree_skb(skb);
+		}
+		up(&rtnl_sem);
+	} while (nfnl && nfnl->receive_queue.qlen);
+}
+
+/****************************************************************************
+ *
+ * System events
+ *
+ ****************************************************************************/
+
+static int receive_event(struct notifier_block *this,
+                         unsigned long event, void *ptr)
+{
+	struct net_device *dev = ptr;
+
+	/* Drop any packets associated with the downed device */
+	if (event == NETDEV_DOWN)
+		ip6q_dev_drop(nlq6, dev->ifindex);
+	return NOTIFY_DONE;
+}
+
+struct notifier_block ip6q_dev_notifier = {
+	receive_event,
+	NULL,
+	0
+};
+
+/****************************************************************************
+ *
+ * Sysctl - queue tuning.
+ *
+ ****************************************************************************/
+
+static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+
+static struct ctl_table_header *ip6q_sysctl_header;
+
+static ctl_table ip6q_table[] = {
+	{ NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &sysctl_maxlen,
+	  sizeof(sysctl_maxlen), 0644,  NULL, proc_dointvec },
+ 	{ 0 }
+};
+
+static ctl_table ip6q_dir_table[] = {
+	{NET_IPV6, "ipv6", NULL, 0, 0555, ip6q_table, 0, 0, 0, 0, 0},
+	{ 0 }
+};
+
+static ctl_table ip6q_root_table[] = {
+	{CTL_NET, "net", NULL, 0, 0555, ip6q_dir_table, 0, 0, 0, 0, 0},
+	{ 0 }
+};
+
+/****************************************************************************
+ *
+ * Procfs - debugging info.
+ *
+ ****************************************************************************/
+
+static int ip6q_get_info(char *buffer, char **start, off_t offset, int length)
+{
+	int len;
+
+	spin_lock_bh(&nlq6->lock);
+	len = sprintf(buffer,
+	              "Peer pid            : %d\n"
+	              "Peer died           : %d\n"
+	              "Peer copy mode      : %d\n"
+	              "Peer copy range     : %Zu\n"
+	              "Queue length        : %d\n"
+	              "Queue max. length   : %d\n"
+	              "Queue flushing      : %d\n"
+	              "Queue terminate     : %d\n",
+	              nlq6->peer.pid,
+	              nlq6->peer.died,
+	              nlq6->peer.copy_mode,
+	              nlq6->peer.copy_range,
+	              nlq6->len,
+	              *nlq6->maxlen,
+	              nlq6->flushing,
+	              nlq6->terminate);
+	spin_unlock_bh(&nlq6->lock);
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
+	else if (len < 0)
+		len = 0;
+	return len;
+}
+
+/****************************************************************************
+ *
+ * Module stuff.
+ *
+ ****************************************************************************/
+
+static int __init init(void)
+{
+	int status = 0;
+	struct proc_dir_entry *proc;
+	
+        /* We must create the NETLINK_IP6_FW protocol service */
+	nfnl = netlink_kernel_create(NETLINK_IP6_FW, netlink_receive_user_sk);
+	if (nfnl == NULL) {
+		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
+		       "create kernel netlink socket\n");
+		return -ENOMEM;
+	}
+	nlq6 = ip6q_create_queue(netfilter6_receive,
+	                       netlink_send_peer, &status, &sysctl_maxlen);
+	if (nlq6 == NULL) {
+		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
+		       "create queue\n");
+		sock_release(nfnl->socket);
+		return status;
+	}
+        /* The file will be /proc/net/ip6_queue */
+	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ip6q_get_info);
+	if (proc) proc->owner = THIS_MODULE;
+	else {
+		ip6q_destroy_queue(nlq6);
+		sock_release(nfnl->socket);
+		return -ENOMEM;
+	}
+	register_netdevice_notifier(&ip6q_dev_notifier);
+	ip6q_sysctl_header = register_sysctl_table(ip6q_root_table, 0);
+	return status;
+}
+
+static void __exit fini(void)
+{
+	unregister_sysctl_table(ip6q_sysctl_header);
+	proc_net_remove(IPQ_PROC_FS_NAME);
+	unregister_netdevice_notifier(&ip6q_dev_notifier);
+	ip6q_destroy_queue(nlq6);
+	sock_release(nfnl->socket);
+}
+
+MODULE_DESCRIPTION("IPv6 packet queue handler");
+MODULE_LICENSE("GPL");
+
+module_init(init);
+module_exit(fini);
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/netfilter/ip6_tables.c linux/net/ipv6/netfilter/ip6_tables.c
--- v2.5.2/linux/net/ipv6/netfilter/ip6_tables.c	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv6/netfilter/ip6_tables.c	Wed Jan 23 15:28:40 2002
@@ -2,6 +2,11 @@
  * Packet matching code.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2000-2002 Netfilter core team <coreteam@netfilter.org>
+ *
+ * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
+ * 	- increase module usage count as soon as we have rules inside
+ * 	  a table
  */
 #include <linux/config.h>
 #include <linux/skbuff.h>
@@ -86,6 +91,8 @@
 	unsigned int size;
 	/* Number of entries: FIXME. --RR */
 	unsigned int number;
+	/* Initial number of entries. Needed for module usage count */
+	unsigned int initial_entries;
 
 	/* Entry points and underflows */
 	unsigned int hook_entry[NF_IP6_NUMHOOKS];
@@ -949,6 +956,7 @@
 	}
 	oldinfo = table->private;
 	table->private = newinfo;
+	newinfo->initial_entries = oldinfo->initial_entries;
 	write_unlock_bh(&table->lock);
 
 	return oldinfo;
@@ -1148,6 +1156,16 @@
 	if (!oldinfo)
 		goto free_newinfo_counters_untrans_unlock;
 
+	/* Update module usage count based on number of rules */
+	duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
+		oldinfo->number, oldinfo->initial_entries, newinfo->number);
+	if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
+ 	    (newinfo->number > oldinfo->initial_entries))
+		__MOD_INC_USE_COUNT(t->me);
+	else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
+	 	 (newinfo->number <= oldinfo->initial_entries))
+		__MOD_DEC_USE_COUNT(t->me);
+
 	/* Get the old counters. */
 	get_counters(oldinfo, counters);
 	/* Decrease module usage counts and free resource */
@@ -1406,7 +1424,7 @@
 	int ret;
 	struct ip6t_table_info *newinfo;
 	static struct ip6t_table_info bootstrap
-		= { 0, 0, { 0 }, { 0 }, { }, { } };
+		= { 0, 0, 0, { 0 }, { 0 }, { }, { } };
 
 	MOD_INC_USE_COUNT;
 	newinfo = vmalloc(sizeof(struct ip6t_table_info)
@@ -1783,7 +1801,7 @@
 	}
 #endif
 
-	printk("ip6_tables: (c)2000 Netfilter core team\n");
+	printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/netfilter/ip6t_MARK.c linux/net/ipv6/netfilter/ip6t_MARK.c
--- v2.5.2/linux/net/ipv6/netfilter/ip6t_MARK.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv6/netfilter/ip6t_MARK.c	Wed Jan 23 15:28:40 2002
@@ -51,7 +51,7 @@
 
 static int __init init(void)
 {
-	printk(KERN_DEBUG "registreing ipv6 mark target\n");
+	printk(KERN_DEBUG "registering ipv6 mark target\n");
 	if (ip6t_register_target(&ip6t_mark_reg))
 		return -EINVAL;
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/netfilter/ip6table_filter.c linux/net/ipv6/netfilter/ip6table_filter.c
--- v2.5.2/linux/net/ipv6/netfilter/ip6table_filter.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv6/netfilter/ip6table_filter.c	Wed Jan 23 15:28:40 2002
@@ -83,7 +83,7 @@
 
 static struct ip6t_table packet_filter
 = { { NULL, NULL }, "filter", &initial_table.repl,
-    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/netfilter/ip6table_mangle.c linux/net/ipv6/netfilter/ip6table_mangle.c
--- v2.5.2/linux/net/ipv6/netfilter/ip6table_mangle.c	Sun Sep 30 12:26:09 2001
+++ linux/net/ipv6/netfilter/ip6table_mangle.c	Wed Jan 23 15:28:40 2002
@@ -1,14 +1,18 @@
 /*
  * IPv6 packet mangling table, a port of the IPv4 mangle table to IPv6
  *
- * Copyright (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * Copyright (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
  */
 #include <linux/module.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
-#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
+#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | \
+			    (1 << NF_IP6_LOCAL_IN) | \
+			    (1 << NF_IP6_FORWARD) | \
+			    (1 << NF_IP6_LOCAL_OUT) | \
+			    (1 << NF_IP6_POST_ROUTING))
 
-#if 1
+#if 0
 #define DEBUGP(x, args...)	printk(KERN_DEBUG x, ## args)
 #else
 #define DEBUGP(x, args...)
@@ -36,19 +40,41 @@
 static struct
 {
 	struct ip6t_replace repl;
-	struct ip6t_standard entries[2];
+	struct ip6t_standard entries[5];
 	struct ip6t_error term;
 } initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 3,
-      sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
-      { [NF_IP6_PRE_ROUTING] 0,
-	[NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
-      { [NF_IP6_PRE_ROUTING] 0,
-	[NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
+= { { "mangle", MANGLE_VALID_HOOKS, 6,
+      sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
+      { [NF_IP6_PRE_ROUTING] 	0,
+	[NF_IP6_LOCAL_IN]	sizeof(struct ip6t_standard),
+	[NF_IP6_FORWARD]	sizeof(struct ip6t_standard) * 2,
+	[NF_IP6_LOCAL_OUT] 	sizeof(struct ip6t_standard) * 3,
+	[NF_IP6_POST_ROUTING]	sizeof(struct ip6t_standard) * 4},
+      { [NF_IP6_PRE_ROUTING] 	0,
+	[NF_IP6_LOCAL_IN]	sizeof(struct ip6t_standard),
+	[NF_IP6_FORWARD]	sizeof(struct ip6t_standard) * 2,
+	[NF_IP6_LOCAL_OUT] 	sizeof(struct ip6t_standard) * 3,
+	[NF_IP6_POST_ROUTING]	sizeof(struct ip6t_standard) * 4},
       0, NULL, { } },
     {
 	    /* PRE_ROUTING */
-	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ip6t_entry),
+		sizeof(struct ip6t_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* LOCAL_IN */
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ip6t_entry),
+		sizeof(struct ip6t_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* FORWARD */
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
 		0,
 		sizeof(struct ip6t_entry),
 		sizeof(struct ip6t_standard),
@@ -56,6 +82,14 @@
 	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
 		-NF_ACCEPT - 1 } },
 	    /* LOCAL_OUT */
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ip6t_entry),
+		sizeof(struct ip6t_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* POST_ROUTING */
 	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
 		0,
 		sizeof(struct ip6t_entry),
@@ -79,11 +113,11 @@
 
 static struct ip6t_table packet_mangler
 = { { NULL, NULL }, "mangle", &initial_table.repl,
-    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
-ip6t_hook(unsigned int hook,
+ip6t_route_hook(unsigned int hook,
 	 struct sk_buff **pskb,
 	 const struct net_device *in,
 	 const struct net_device *out,
@@ -93,7 +127,7 @@
 }
 
 static unsigned int
-ip6t_local_out_hook(unsigned int hook,
+ip6t_local_hook(unsigned int hook,
 		   struct sk_buff **pskb,
 		   const struct net_device *in,
 		   const struct net_device *out,
@@ -142,9 +176,11 @@
 }
 
 static struct nf_hook_ops ip6t_ops[]
-= { { { NULL, NULL }, ip6t_hook, PF_INET6, NF_IP6_PRE_ROUTING, NF_IP6_PRI_MANGLE },
-    { { NULL, NULL }, ip6t_local_out_hook, PF_INET6, NF_IP6_LOCAL_OUT,
-		NF_IP6_PRI_MANGLE }
+= { { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_PRE_ROUTING,  NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_local_hook, PF_INET6, NF_IP6_LOCAL_IN,     NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_FORWARD,      NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_local_hook, PF_INET6, NF_IP6_LOCAL_OUT,    NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_POST_ROUTING, NF_IP6_PRI_MANGLE }
 };
 
 static int __init init(void)
@@ -165,8 +201,26 @@
 	if (ret < 0)
 		goto cleanup_hook0;
 
+	ret = nf_register_hook(&ip6t_ops[2]);
+	if (ret < 0)
+		goto cleanup_hook1;
+
+	ret = nf_register_hook(&ip6t_ops[3]);
+	if (ret < 0)
+		goto cleanup_hook2;
+
+	ret = nf_register_hook(&ip6t_ops[4]);
+	if (ret < 0)
+		goto cleanup_hook3;
+
 	return ret;
 
+ cleanup_hook3:
+        nf_unregister_hook(&ip6t_ops[3]);
+ cleanup_hook2:
+	nf_unregister_hook(&ip6t_ops[2]);
+ cleanup_hook1:
+	nf_unregister_hook(&ip6t_ops[1]);
  cleanup_hook0:
 	nf_unregister_hook(&ip6t_ops[0]);
  cleanup_table:
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/proc.c linux/net/ipv6/proc.c
--- v2.5.2/linux/net/ipv6/proc.c	Sun Jul  9 22:30:41 2000
+++ linux/net/ipv6/proc.c	Thu Jan 24 22:05:04 2002
@@ -7,7 +7,7 @@
  *		PROC file system.  This is very similar to the IPv4 version,
  *		except it reports the sockets in the INET6 address family.
  *
- * Version:	$Id: proc.c,v 1.15 2000/07/07 22:29:42 davem Exp $
+ * Version:	$Id: proc.c,v 1.16 2002/01/24 15:45:51 davem Exp $
  *
  * Authors:	David S. Miller (davem@caip.rutgers.edu)
  *
@@ -37,7 +37,7 @@
 	return res;
 }
 
-int afinet6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+int afinet6_get_info(char *buffer, char **start, off_t offset, int length)
 {
 	int len = 0;
 	len += sprintf(buffer+len, "TCP6: inuse %d\n",
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/route.c linux/net/ipv6/route.c
--- v2.5.2/linux/net/ipv6/route.c	Thu Sep 20 14:12:56 2001
+++ linux/net/ipv6/route.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/ipx/Config.help linux/net/ipx/Config.help
--- v2.5.2/linux/net/ipx/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/ipx/Config.help	Fri Jan 25 16:03:33 2002
@@ -0,0 +1,47 @@
+CONFIG_IPX_INTERN
+  Every IPX network has an address that identifies it. Sometimes it is
+  useful to give an IPX "network" address to your Linux box as well
+  (for example if your box is acting as a file server for different
+  IPX networks: it will then be accessible from everywhere using the
+  same address). The way this is done is to create a virtual internal
+  "network" inside your box and to assign an IPX address to this
+  network. Say Y here if you want to do this; read the IPX-HOWTO at
+  <http://www.linuxdoc.org/docs.html#howto> for details.
+
+  The full internal IPX network enables you to allocate sockets on
+  different virtual nodes of the internal network. This is done by
+  evaluating the field sipx_node of the socket address given to the
+  bind call. So applications should always initialize the node field
+  to 0 when binding a socket on the primary network. In this case the
+  socket is assigned the default node that has been given to the
+  kernel when the internal network was created. By enabling the full
+  internal IPX network the cross-forwarding of packets targeted at
+  '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/>.
+
+  If you don't know what you are doing, say N.
+
+CONFIG_SPX
+  * Orphaned entry retained 20 April 2001 by Petr Vandrovec     *
+  * If you read this note from the configurator, please contact *
+  * the Configure.help maintainers.                             *
+  The Sequenced Packet eXchange protocol is a transport layer protocol
+  built on top of IPX. It is used in Novell NetWare systems for
+  client-server applications and is similar to TCP (which runs on top
+  of IP).
+
+  Note that Novell NetWare file sharing does not use SPX; it uses a
+  protocol called NCP, for which separate Linux support is available
+  ("NCP file system support" below for the client side, and the user
+  space programs lwared or mars_nwe for the server side).
+
+  Say Y here if you have use for SPX; read the IPX-HOWTO at
+  <http://www.linuxdoc.org/docs.html#howto> for details.
+
+  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 af_spx.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
diff -u --recursive --new-file v2.5.2/linux/net/irda/Config.help linux/net/irda/Config.help
--- v2.5.2/linux/net/irda/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/Config.help	Fri Jan 25 16:04:22 2002
@@ -0,0 +1,63 @@
+CONFIG_IRDA
+  Say Y here if you want to build support for the IrDA (TM) protocols.
+  The Infrared Data Associations (tm) specifies standards for wireless
+  infrared communication and is supported by most laptops and PDA's.
+
+  To use Linux support for the IrDA (tm) protocols, you will also need
+  some user-space utilities like irattach.  For more information, see
+  the file <file:Documentation/networking/irda.txt>.  You also want to
+  read the IR-HOWTO, available at
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to exchange bits of data (vCal, vCard) with a PDA, you
+  will need to install some OBEX application, such as OpenObex :
+  <http://sourceforge.net/projects/openobex/>
+
+  This support is also available as a module called irda.o.  If you
+  want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+
+CONFIG_IRDA_ULTRA
+  Say Y here to support the connectionless Ultra IRDA protocol.
+  Ultra allows to exchange data over IrDA with really simple devices
+  (watch, beacon) without the overhead of the IrDA protocol (no handshaking,
+  no management frames, simple fixed header).
+  Ultra is available as a special socket : socket(AF_IRDA, SOCK_DGRAM, 1);
+
+CONFIG_IRDA_CACHE_LAST_LSAP
+  Say Y here if you want IrLMP to cache the last LSAP used.  This
+  makes sense since most frames will be sent/received on the same
+  connection.  Enabling this option will save a hash-lookup per frame.
+
+  If unsure, say Y.
+
+CONFIG_IRDA_FAST_RR
+  Say Y here is you want IrLAP to send fast RR (Receive Ready) frames
+  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 Y.
+
+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).
+
diff -u --recursive --new-file v2.5.2/linux/net/irda/af_irda.c linux/net/irda/af_irda.c
--- v2.5.2/linux/net/irda/af_irda.c	Tue Dec 18 14:56:41 2001
+++ linux/net/irda/af_irda.c	Wed Jan 23 10:54:42 2002
@@ -2590,14 +2590,11 @@
 	register_netdevice_notifier(&irda_dev_notifier);
 
 	irda_init();
-#ifdef MODULE
- 	irda_device_init();  /* Called by init/main.c when non-modular */
-#endif
+ 	irda_device_init();
 	return 0;
 }
-#ifdef MODULE
-module_init(irda_proto_init);	/* If non-module, called from init/main.c */
-#endif
+
+late_initcall(irda_proto_init);
 
 /*
  * Function irda_proto_cleanup (void)
diff -u --recursive --new-file v2.5.2/linux/net/irda/ircomm/Config.help linux/net/irda/ircomm/Config.help
--- v2.5.2/linux/net/irda/ircomm/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/ircomm/Config.help	Fri Jan 25 16:04:23 2002
@@ -0,0 +1,10 @@
+CONFIG_IRCOMM
+  Say Y here if you want to build support for the IrCOMM protocol.  If
+  you want to compile it as a module (you will get ircomm.o and
+  ircomm-tty.o), say M here and read <file:Documentation/modules.txt>.
+  IrCOMM implements serial port emulation, and makes it possible to
+  use all existing applications that understands TTY's with an
+  infrared link.  Thus you should be able to use application like PPP,
+  minicom and others.  Enabling this option will create two modules
+  called ircomm and ircomm_tty.
+
diff -u --recursive --new-file v2.5.2/linux/net/irda/irlan/Config.help linux/net/irda/irlan/Config.help
--- v2.5.2/linux/net/irda/irlan/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/irlan/Config.help	Fri Jan 25 16:04:23 2002
@@ -0,0 +1,11 @@
+CONFIG_IRLAN
+  Say Y here if you want to build support for the IrLAN protocol.  If
+  you want to compile it as a module (irlan.o), say M here and read
+  <file:Documentation/modules.txt>.  IrLAN emulates an Ethernet and
+  makes it possible to put up a wireless LAN using infrared beams.
+
+  The IrLAN protocol can be used to talk with infrared access points
+  like the HP NetbeamIR, or the ESI JetEye NET.  You can also connect
+  to another Linux machine running the IrLAN protocol for ad-hoc
+  networking!
+
diff -u --recursive --new-file v2.5.2/linux/net/irda/irnet/Config.help linux/net/irda/irnet/Config.help
--- v2.5.2/linux/net/irda/irnet/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/irda/irnet/Config.help	Fri Jan 25 16:04:23 2002
@@ -0,0 +1,11 @@
+CONFIG_IRNET
+  Say Y here if you want to build support for the IrNET protocol.  If
+  you want to compile it as a module (irnet.o), say M here and read
+  <file:Documentation/modules.txt>.  IrNET is a PPP driver, so you
+  will also need a working PPP subsystem (driver, daemon and
+  config)...
+
+  IrNET is an alternate way to tranfer TCP/IP traffic over IrDA.  It
+  uses synchronous PPP over a set of point to point IrDA sockets.  You
+  can use it between Linux machine or with W2k.
+
diff -u --recursive --new-file v2.5.2/linux/net/khttpd/Config.help linux/net/khttpd/Config.help
--- v2.5.2/linux/net/khttpd/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/khttpd/Config.help	Fri Jan 25 16:03:33 2002
@@ -0,0 +1,18 @@
+CONFIG_KHTTPD
+  The kernel httpd acceleration daemon (kHTTPd) is a (limited) web
+  server built into the kernel. It is limited since it can only serve
+  files from the file system and cannot deal with executable content
+  such as CGI scripts. Serving files is sped up if you use kHTTPd.
+  If kHTTPd is not able to fulfill a request, it can transparently
+  pass it through to a user space web server such as apache.
+
+  Saying "M" here builds the kHTTPd module; this is NOT enough to have
+  a working kHTTPd. For safety reasons, the module has to be activated
+  by doing a "echo 1 > /proc/sys/net/khttpd/start" after inserting the
+  module.
+
+  Before using this, read the README in net/khttpd !
+
+  The kHTTPd is experimental. Be careful when using it on a production
+  machine. Also note that kHTTPd doesn't support virtual servers yet.
+
diff -u --recursive --new-file v2.5.2/linux/net/khttpd/main.c linux/net/khttpd/main.c
--- v2.5.2/linux/net/khttpd/main.c	Sun Mar 25 18:14:25 2001
+++ linux/net/khttpd/main.c	Mon Jan 21 15:55:46 2002
@@ -390,3 +390,5 @@
 
 	module_init(khttpd_init)
 	module_exit(khttpd_cleanup)
+
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.2/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- v2.5.2/linux/net/netlink/af_netlink.c	Fri Jun 29 19:38:26 2001
+++ linux/net/netlink/af_netlink.c	Wed Jan 23 15:28:40 2002
@@ -36,7 +36,7 @@
 #include <asm/uaccess.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
 #include <net/sock.h>
@@ -48,8 +48,6 @@
 #define NL_EMULATE_DEV
 #endif
 
-#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
-
 struct netlink_opt
 {
 	u32			pid;
@@ -996,3 +994,5 @@
 
 module_init(netlink_proto_init);
 module_exit(netlink_proto_exit);
+
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.2/linux/net/netlink/netlink_dev.c linux/net/netlink/netlink_dev.c
--- v2.5.2/linux/net/netlink/netlink_dev.c	Mon Jan 14 18:25:11 2002
+++ linux/net/netlink/netlink_dev.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/netsyms.c linux/net/netsyms.c
--- v2.5.2/linux/net/netsyms.c	Mon Nov  5 09:46:12 2001
+++ linux/net/netsyms.c	Wed Jan 23 15:28:40 2002
@@ -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);
@@ -291,6 +292,8 @@
 EXPORT_SYMBOL(ndisc_mc_map);
 EXPORT_SYMBOL(register_inet6addr_notifier);
 EXPORT_SYMBOL(unregister_inet6addr_notifier);
+#include <net/ip6_route.h>
+EXPORT_SYMBOL(ip6_route_output);
 #endif
 #if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE)
 /* inet functions common to v4 and v6 */
@@ -406,7 +409,6 @@
 
 #endif
 
-#ifdef CONFIG_NETLINK
 EXPORT_SYMBOL(netlink_set_err);
 EXPORT_SYMBOL(netlink_broadcast);
 EXPORT_SYMBOL(netlink_unicast);
@@ -418,9 +420,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 +430,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);
@@ -522,6 +521,10 @@
 EXPORT_SYMBOL(hippi_type_trans);
 #endif
 
+#ifdef CONFIG_NET_FASTROUTE
+EXPORT_SYMBOL(netdev_fastroute);
+#endif
+
 #ifdef CONFIG_SYSCTL
 EXPORT_SYMBOL(sysctl_wmem_max);
 EXPORT_SYMBOL(sysctl_rmem_max);
@@ -553,9 +556,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 -u --recursive --new-file v2.5.2/linux/net/packet/af_packet.c linux/net/packet/af_packet.c
--- v2.5.2/linux/net/packet/af_packet.c	Mon Jan 14 18:25:11 2002
+++ linux/net/packet/af_packet.c	Tue Jan 15 10:56:36 2002
@@ -5,7 +5,7 @@
  *
  *		PACKET - implements raw packet sockets.
  *
- * Version:	$Id: af_packet.c,v 1.58 2001/11/28 21:02:10 davem Exp $
+ * Version:	$Id: af_packet.c,v 1.59 2001/12/21 04:56:17 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1763,7 +1763,7 @@
 	start = vma->vm_start;
 	err = -EAGAIN;
 	for (i=0; i<po->pg_vec_len; i++) {
-		if (remap_page_range(start, __pa(po->pg_vec[i]),
+		if (remap_page_range(vma, start, __pa(po->pg_vec[i]),
 				     po->pg_vec_pages*PAGE_SIZE,
 				     vma->vm_page_prot))
 			goto out;
diff -u --recursive --new-file v2.5.2/linux/net/sched/Config.help linux/net/sched/Config.help
--- v2.5.2/linux/net/sched/Config.help	Wed Dec 31 16:00:00 1969
+++ linux/net/sched/Config.help	Fri Jan 25 16:03:43 2002
@@ -0,0 +1,238 @@
+CONFIG_NET_SCH_CBQ
+  Say Y here if you want to use the Class-Based Queueing (CBQ) packet
+  scheduling algorithm for some of your network devices.  This
+  algorithm classifies the waiting packets into a tree-like hierarchy
+  of classes; the leaves of this tree are in turn scheduled by
+  separate algorithms (called "disciplines" in this context).
+
+  See the top of <file:net/sched/sch_cbq.c> for references about the
+  CBQ algorithm.
+
+  CBQ is a commonly used scheduler, so if you're unsure, you should
+  say Y here. Then say Y to all the queueing algorithms below that you
+  want to use as CBQ disciplines.  Then say Y to "Packet classifier
+  API" and say Y to all the classifiers you want to use; a classifier
+  is a routine that allows you to sort your outgoing traffic into
+  classes based on a certain criterion.
+
+  This code is also available as a module called sch_cbq.o ( = 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>.
+
+CONFIG_NET_SCH_CSZ
+  Say Y here if you want to use the Clark-Shenker-Zhang (CSZ) packet
+  scheduling algorithm for some of your network devices.  At the
+  moment, this is the only algorithm that can guarantee service for
+  real-time applications (see the top of <file:net/sched/sch_csz.c>
+  for details and references about the algorithm).
+
+  Note: this scheduler is currently broken.
+
+  This code is also available as a module called sch_csz.o ( = 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>.
+
+CONFIG_NET_SCH_ATM
+  Say Y here if you want to use the ATM pseudo-scheduler.  This
+  provides a framework for invoking classifiers (aka "filters"), which
+  in turn select classes of this queuing discipline.  Each class maps
+  the flow(s) it is handling to a given virtual circuit (see the top of
+  <file:net/sched/sch_atm.c>).
+
+  This code is also available as a module called sch_atm.o ( = 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>.
+
+CONFIG_NET_SCH_PRIO
+  Say Y here if you want to use an n-band priority queue packet
+  "scheduler" for some of your network devices or as a leaf discipline
+  for the CBQ scheduling algorithm. If unsure, say Y.
+
+  This code is also available as a module called sch_prio.o ( = 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>.
+
+CONFIG_NET_SCH_DSMARK
+  Say Y if you want to schedule packets avccording to the
+  Differentiated Services architecture proposed in RFC 2475.
+  Technical information on this method, with pointers to associated
+  RFCs, is available at <http://www.gta.ufrj.br/diffserv/>.
+
+  This code is also available as a module called sch_dsmark.o ( = 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>.
+
+CONFIG_NET_SCH_GRED
+  Say Y here if you want to use the Generic Random Early Detection
+  (RED) packet scheduling algorithm for some of your network devices
+  (see the top of <file:net/sched/sch_red.c> for details and
+  references about the algorithm).
+
+  This code is also available as a module called sch_gred.o ( = 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>.
+
+CONFIG_NET_SCH_RED
+  Say Y here if you want to use the Random Early Detection (RED)
+  packet scheduling algorithm for some of your network devices (see
+  the top of <file:net/sched/sch_red.c> for details and references
+  about the algorithm).
+
+  This code is also available as a module called sch_red.o ( = 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>.
+
+CONFIG_NET_SCH_SFQ
+  Say Y here if you want to use the Stochastic Fairness Queueing (SFQ)
+  packet scheduling algorithm for some of your network devices or as a
+  leaf discipline for the CBQ scheduling algorithm (see the top of
+  <file:net/sched/sch_sfq.c> for details and references about the SFQ
+  algorithm).
+
+  This code is also available as a module called sch_sfq.o ( = 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>.
+
+CONFIG_NET_SCH_TEQL
+  Say Y here if you want to use the True Link Equalizer (TLE) packet
+  scheduling algorithm for some of your network devices or as a leaf
+  discipline for the CBQ scheduling algorithm. This queueing
+  discipline allows the combination of several physical devices into
+  one virtual device. (see the top of <file:net/sched/sch_teql.c> for
+  details).
+
+  This code is also available as a module called sch_teql.o ( = 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>.
+
+CONFIG_NET_SCH_TBF
+  Say Y here if you want to use the Simple Token Bucket Filter (TBF)
+  packet scheduling algorithm for some of your network devices or as a
+  leaf discipline for the CBQ scheduling algorithm (see the top of
+  <file:net/sched/sch_tbf.c> for a description of the TBF algorithm).
+
+  This code is also available as a module called sch_tbf.o ( = 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>.
+
+CONFIG_NET_SCH_INGRESS
+  If you say Y here, you will be able to police incoming bandwidth
+  and drop packets when this bandwidth exceeds your desired rate.
+  If unsure, say Y.
+
+  This code is also available as a module called cls_ingress.o
+  ( = 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>.
+
+CONFIG_NET_QOS
+  Say Y here if you want to include Quality Of Service scheduling
+  features, which means that you will be able to request certain
+  rate-of-flow limits for your network devices.
+
+  This Quality of Service (QoS) support will enable you to use
+  Differentiated Services (diffserv) and Resource Reservation Protocol
+  (RSVP) on your Linux router if you also say Y to "Packet classifier
+  API" and to some classifiers below. Documentation and software is at
+  <http://icawww1.epfl.ch/linux-diffserv/>.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause the configurator to skip all
+  the questions about QoS support.
+
+CONFIG_NET_ESTIMATOR
+  In order for Quality of Service scheduling to work, the current
+  rate-of-flow for a network device has to be estimated; if you say Y
+  here, the kernel will do just that.
+
+CONFIG_NET_CLS
+  The CBQ scheduling algorithm requires that network packets which are
+  scheduled to be sent out over a network device be classified
+  according to some criterion. If you say Y here, you will get a
+  choice of several different packet classifiers with the following
+  questions.
+
+  This will enable you to use Differentiated Services (diffserv) and
+  Resource Reservation Protocol (RSVP) on your Linux router.
+  Documentation and software is at
+  <http://icawww1.epfl.ch/linux-diffserv/>.
+
+CONFIG_NET_CLS_POLICE
+  Say Y to support traffic policing (bandwidth limits).  Needed for
+  ingress and egress rate limiting.
+
+CONFIG_NET_CLS_TCINDEX
+  If you say Y here, you will be able to classify outgoing packets
+  according to the tc_index field of the skb. You will want this
+  feature if you want to implement Differentiated Services using
+  sch_dsmark. If unsure, say Y.
+
+  This code is also available as a module called cls_tcindex.o
+  ( = 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>.
+
+CONFIG_NET_CLS_ROUTE4
+  If you say Y here, you will be able to classify outgoing packets
+  according to the route table entry they matched. If unsure, say Y.
+
+  This code is also available as a module called cls_route.o ( = 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>.
+
+CONFIG_NET_CLS_FW
+  If you say Y here, you will be able to classify outgoing packets
+  according to firewall criteria you specified.
+
+  This code is also available as a module called cls_fw.o ( = 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>.
+
+CONFIG_NET_CLS_U32
+  If you say Y here, you will be able to classify outgoing packets
+  according to their destination address. If unsure, say Y.
+
+  This code is also available as a module called cls_u32.o ( = 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>.
+
+CONFIG_NET_CLS_RSVP
+  The Resource Reservation Protocol (RSVP) permits end systems to
+  request a minimum and maximum data flow rate for a connection; this
+  is important for real time data such as streaming sound or video.
+
+  Say Y here if you want to be able to classify outgoing packets based
+  on their RSVP requests.
+
+  This code is also available as a module called cls_rsvp.o ( = 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>.
+
+CONFIG_NET_CLS_RSVP6
+  The Resource Reservation Protocol (RSVP) permits end systems to
+  request a minimum and maximum data flow rate for a connection; this
+  is important for real time data such as streaming sound or video.
+
+  Say Y here if you want to be able to classify outgoing packets based
+  on their RSVP requests and you are using the new Internet Protocol
+  IPv6 as opposed to the older and more common IPv4.
+
+  This code is also available as a module called cls_rsvp6.o ( = 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>.
+
diff -u --recursive --new-file v2.5.2/linux/net/sched/Config.in linux/net/sched/Config.in
--- v2.5.2/linux/net/sched/Config.in	Fri Jan 14 19:18:53 2000
+++ linux/net/sched/Config.in	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/cls_api.c linux/net/sched/cls_api.c
--- v2.5.2/linux/net/sched/cls_api.c	Fri Jan  7 16:57:13 2000
+++ linux/net/sched/cls_api.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/cls_fw.c linux/net/sched/cls_fw.c
--- v2.5.2/linux/net/sched/cls_fw.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/cls_fw.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/cls_route.c linux/net/sched/cls_route.c
--- v2.5.2/linux/net/sched/cls_route.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/cls_route.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/cls_rsvp.h linux/net/sched/cls_rsvp.h
--- v2.5.2/linux/net/sched/cls_rsvp.h	Mon Dec 11 13:30:43 2000
+++ linux/net/sched/cls_rsvp.h	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/cls_tcindex.c linux/net/sched/cls_tcindex.c
--- v2.5.2/linux/net/sched/cls_tcindex.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/cls_tcindex.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/cls_u32.c linux/net/sched/cls_u32.c
--- v2.5.2/linux/net/sched/cls_u32.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/cls_u32.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/police.c linux/net/sched/police.c
--- v2.5.2/linux/net/sched/police.c	Mon Aug 23 10:01:02 1999
+++ linux/net/sched/police.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/sch_api.c linux/net/sched/sch_api.c
--- v2.5.2/linux/net/sched/sch_api.c	Fri Nov  9 14:12:54 2001
+++ linux/net/sched/sch_api.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/sch_atm.c linux/net/sched/sch_atm.c
--- v2.5.2/linux/net/sched/sch_atm.c	Fri Feb  9 11:34:13 2001
+++ linux/net/sched/sch_atm.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/sch_cbq.c linux/net/sched/sch_cbq.c
--- v2.5.2/linux/net/sched/sch_cbq.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_cbq.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/sch_csz.c linux/net/sched/sch_csz.c
--- v2.5.2/linux/net/sched/sch_csz.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_csz.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/sch_dsmark.c linux/net/sched/sch_dsmark.c
--- v2.5.2/linux/net/sched/sch_dsmark.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_dsmark.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/sch_fifo.c linux/net/sched/sch_fifo.c
--- v2.5.2/linux/net/sched/sch_fifo.c	Mon Aug 23 10:01:02 1999
+++ linux/net/sched/sch_fifo.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/sch_gred.c linux/net/sched/sch_gred.c
--- v2.5.2/linux/net/sched/sch_gred.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_gred.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/sch_ingress.c linux/net/sched/sch_ingress.c
--- v2.5.2/linux/net/sched/sch_ingress.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_ingress.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/sch_prio.c linux/net/sched/sch_prio.c
--- v2.5.2/linux/net/sched/sch_prio.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_prio.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/sch_red.c linux/net/sched/sch_red.c
--- v2.5.2/linux/net/sched/sch_red.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_red.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/sch_sfq.c linux/net/sched/sch_sfq.c
--- v2.5.2/linux/net/sched/sch_sfq.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_sfq.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/sched/sch_tbf.c linux/net/sched/sch_tbf.c
--- v2.5.2/linux/net/sched/sch_tbf.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_tbf.c	Tue Jan 15 10:56:35 2002
@@ -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 -u --recursive --new-file v2.5.2/linux/net/socket.c linux/net/socket.c
--- v2.5.2/linux/net/socket.c	Mon Jan 14 18:25:11 2002
+++ linux/net/socket.c	Fri Jan 18 16:00:26 2002
@@ -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>
 
@@ -280,16 +278,17 @@
 
 static struct super_block * sockfs_read_super(struct super_block *sb, void *data, int silent)
 {
-	struct inode *root = new_inode(sb);
+	struct inode *root;
+	sb->s_blocksize = 1024;
+	sb->s_blocksize_bits = 10;
+	sb->s_magic = SOCKFS_MAGIC;
+	sb->s_op	= &sockfs_ops;
+	root = new_inode(sb);
 	if (!root)
 		return NULL;
 	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
 	root->i_uid = root->i_gid = 0;
 	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
-	sb->s_blocksize = 1024;
-	sb->s_blocksize_bits = 10;
-	sb->s_magic = SOCKFS_MAGIC;
-	sb->s_op	= &sockfs_ops;
 	sb->s_root = d_alloc(NULL, &(const struct qstr) { "socket:", 7, 0 });
 	if (!sb->s_root) {
 		iput(root);
@@ -439,11 +438,11 @@
 	struct inode * inode;
 	struct socket * sock;
 
-	inode = get_empty_inode();
+	inode = new_inode(sock_mnt->mnt_sb);
 	if (!inode)
 		return NULL;
 
-	inode->i_sb = sock_mnt->mnt_sb;
+	inode->i_dev = NODEV;
 	sock = socki_lookup(inode);
 
 	inode->i_mode = S_IFSOCK|S_IRWXUGO;
@@ -1723,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 -u --recursive --new-file v2.5.2/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- v2.5.2/linux/net/sunrpc/sched.c	Mon Jan 14 18:25:11 2002
+++ linux/net/sunrpc/sched.c	Mon Jan 28 15:11:45 2002
@@ -721,7 +721,7 @@
 
 		__rpc_execute(task);
 
-		if (++count >= 200 || current->need_resched) {
+		if (++count >= 200 || need_resched()) {
 			count = 0;
 			schedule();
 		}
@@ -1109,7 +1109,7 @@
 	unsigned long flags;
 
 	while (all_tasks) {
-		current->sigpending = 0;
+		current->work.sigpending = 0;
 		rpc_killall_tasks(NULL);
 		__rpc_schedule();
 		if (all_tasks) {
@@ -1183,7 +1183,7 @@
 	 * Usually rpciod will exit very quickly, so we
 	 * wait briefly before checking the process id.
 	 */
-	current->sigpending = 0;
+	current->work.sigpending = 0;
 	yield();
 	/*
 	 * Display a message if we're going to wait longer.
diff -u --recursive --new-file v2.5.2/linux/net/sunrpc/svc.c linux/net/sunrpc/svc.c
--- v2.5.2/linux/net/sunrpc/svc.c	Fri Sep  7 10:48:39 2001
+++ linux/net/sunrpc/svc.c	Mon Jan 28 15:11:45 2002
@@ -185,7 +185,7 @@
 		progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port);
 
 	if (!port)
-		current->sigpending = 0;
+		current->work.sigpending = 0;
 
 	for (i = 0; i < progp->pg_nvers; i++) {
 		if (progp->pg_vers[i] == NULL)
diff -u --recursive --new-file v2.5.2/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.5.2/linux/net/unix/af_unix.c	Mon Jan 14 18:25:11 2002
+++ linux/net/unix/af_unix.c	Tue Jan 15 10:56:35 2002
@@ -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.131 2002/01/14 07:08:27 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
@@ -101,13 +101,14 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <linux/tcp.h>
 #include <net/af_unix.h>
 #include <linux/proc_fs.h>
 #include <net/scm.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
+#include <linux/rtnetlink.h>
 
 #include <asm/checksum.h>
 
@@ -483,7 +484,7 @@
 	sk->protinfo.af_unix.dentry=NULL;
 	sk->protinfo.af_unix.mnt=NULL;
 	sk->protinfo.af_unix.lock = RW_LOCK_UNLOCKED;
-	atomic_set(&sk->protinfo.af_unix.inflight, 0);
+	atomic_set(&sk->protinfo.af_unix.inflight, sock ? 0 : -1);
 	init_MUTEX(&sk->protinfo.af_unix.readsem);/* single task reading lock */
 	init_waitqueue_head(&sk->protinfo.af_unix.peer_wait);
 	sk->protinfo.af_unix.list=NULL;
@@ -988,7 +989,12 @@
 	unix_state_wunlock(sk);
 
 	/* take ten and and send info to listening sock */
-	skb_queue_tail(&other->receive_queue,skb);
+	spin_lock(&other->receive_queue.lock);
+	__skb_queue_tail(&other->receive_queue,skb);
+	/* Undo artificially decreased inflight after embrion
+	 * is installed to listening socket. */
+	atomic_inc(&newsk->protinfo.af_unix.inflight);
+	spin_unlock(&other->receive_queue.lock);
 	unix_state_runlock(other);
 	other->data_ready(other, 0);
 	sock_put(other);
@@ -1051,8 +1057,12 @@
 	 */
 
 	skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err);
-	if (!skb)
+	if (!skb) {
+		/* This means receive shutdown. */
+		if (err == 0)
+			err = -EINVAL;
 		goto out;
+	}
 
 	tsk = skb->sk;
 	skb_free_datagram(sk, skb);
diff -u --recursive --new-file v2.5.2/linux/net/unix/garbage.c linux/net/unix/garbage.c
--- v2.5.2/linux/net/unix/garbage.c	Fri Jun 29 19:38:26 2001
+++ linux/net/unix/garbage.c	Tue Jan 15 10:56:35 2002
@@ -76,9 +76,9 @@
 #include <linux/netdevice.h>
 #include <linux/file.h>
 #include <linux/proc_fs.h>
+#include <linux/tcp.h>
 
 #include <net/sock.h>
-#include <net/tcp.h>
 #include <net/af_unix.h>
 #include <net/scm.h>
 
@@ -205,12 +205,21 @@
 
 	forall_unix_sockets(i, s)
 	{
+		int open_count = 0;
+
 		/*
 		 *	If all instances of the descriptor are not
 		 *	in flight we are in use.
+		 *
+		 *	Special case: when socket s is embrion, it may be
+		 *	hashed but still not in queue of listening socket.
+		 *	In this case (see unix_create1()) we set artificial
+		 *	negative inflight counter to close race window.
+		 *	It is trick of course and dirty one.
 		 */
-		if(s->socket && s->socket->file &&
-		   file_count(s->socket->file) > atomic_read(&s->protinfo.af_unix.inflight))
+		if(s->socket && s->socket->file)
+			open_count = file_count(s->socket->file);
+		if (open_count > atomic_read(&s->protinfo.af_unix.inflight))
 			maybe_unmark_and_push(s);
 	}
 
diff -u --recursive --new-file v2.5.2/linux/scripts/Configure linux/scripts/Configure
--- v2.5.2/linux/scripts/Configure	Mon Jul  2 13:56:40 2001
+++ linux/scripts/Configure	Thu Jan 24 11:10:41 2002
@@ -81,12 +81,11 @@
 #       help variable
 #
 function help () {
-  if [ -f Documentation/Configure.help ]
-  then
-     #first escape regexp special characters in the argument:
-     var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
-     #now pick out the right help text:
-     text=$(sed -n "/^$var[ 	]*\$/,\${
+   #first escape regexp special characters in the argument:
+   var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
+   #now pick out the right help text:
+   text=$(cat /dev/null $(find . -name Config.help) |
+	sed -n "/^$var[ 	]*\$/,\${
 			/^$var[ 	]*\$/c\\
 ${var}:\\
 
@@ -94,19 +93,13 @@
 			/^[^ 	]/q
 			/<file:\\([^>]*\\)>/s//\\1/g
 			p
-		    }" Documentation/Configure.help)
-     if [ -z "$text" ]
-     then
-	  echo; echo "  Sorry, no help available for this option yet.";echo
-     else
-	  (echo; echo "$text") | ${PAGER:-more}
-     fi
-  else
-     echo;
-     echo "  Can't access the file Documentation/Configure.help which"
-     echo "  should contain the help texts."
-     echo
-  fi
+		    }")
+   if [ -z "$text" ]
+   then
+	echo; echo "  Sorry, no help available for this option yet.";echo
+   else
+	(echo; echo "$text"; echo) | ${PAGER:-more}
+   fi
 }
 
 
diff -u --recursive --new-file v2.5.2/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.5.2/linux/scripts/Menuconfig	Sun Aug  5 13:12:41 2001
+++ linux/scripts/Menuconfig	Tue Jan 29 22:31:46 2002
@@ -357,19 +357,18 @@
 
 
 #
-# Extract available help for an option from Configure.help
+# Extract available help for an option from Config.help
 # and send it to standard output.
 #
 # Most of this function was borrowed from the original kernel
 # Configure script.
 #
 function extract_help () {
-  if [ -f Documentation/Configure.help ]
-  then
-     #first escape regexp special characters in the argument:
-     var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
-     #now pick out the right help text:
-     text=$(sed -n "/^$var[ 	]*\$/,\${
+   #first escape regexp special characters in the argument:
+   var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
+   #now pick out the right help text:
+   text=$(cat /dev/null $(find . -name Config.help) |
+          sed -n "/^$var[ 	]*\$/,\${
                         /^$var[ 	]*\$/c\\
 ${var}:\\
 
@@ -378,19 +377,15 @@
                         s/^  //
 			/<file:\\([^>]*\\)>/s//\\1/g
                         p
-                    }" Documentation/Configure.help)
+                    }")
 
-     if [ -z "$text" ]
-     then
-          echo "There is no help available for this kernel option."
-	  return 1
-     else
-	  echo "$text"
-     fi
-  else
-	 echo "There is no help available for this kernel option."
-         return 1
-  fi
+   if [ -z "$text" ]
+   then
+        echo "There is no help available for this kernel option."
+        return 1
+   else
+	echo "$text"
+   fi
 }
 
 #
